MachineFrameInfo

这是属于 CodeGen 的一个子文件,暂且把他认定为 Pass。他实现的是“栈帧布局和栈内对象管理相关的核心模块”。是 LLVM 用于管理函数栈帧中所有栈上对象(如局部变量、Spill槽、调用帧等)的位置、对齐和属性的模块,并辅助生成正确的栈布局与栈帧大小。

概念 简要说明
栈帧(Stack Frame) 每个函数调用分配的一块栈内存,用于保存局部变量、返回地址、保存的寄存器等
对齐(Alignment) 指定内存对象在栈上的对齐要求,通常是 4/8/16 字节
Spill Slot 当寄存器不够用时,变量会被“溢出”到栈上,称为 Spill
可变大小对象 alloca 分配的大小运行时决定的数组
固定栈对象(Fixed Object) 位于栈帧固定位置的对象,如返回地址、保存寄存器
StackRealignable 当前目标是否允许动态栈对齐
Call Frame Size 为函数调用参数保留的栈空间
Frame Pointer / Stack Pointer 栈帧地址计算常用寄存器,影响对象定位
因为是重点工具函数集合,所以这边直接讲每个函数在干什么

① CreateStackObject(uint64_t Size, Align Alignment, …)
这个函数用于创建一个普通的局部栈对象,也可以是 spill 对象(由寄存器溢出产生)。它会执行以下操作:

  • 对齐检查:如果目标平台不支持栈实对齐(StackRealignable = false),将强制限制对齐大小;
  • 将对象信息(大小、对齐、是否Spill、是否可变等)压入 Objects 向量;
  • 更新最大对齐要求 MaxAlignment;
  • 返回对象的 FrameIndex,供后续访问使用。
    ② CreateSpillStackObject(uint64_t Size, Align Alignment)
    专门用于为寄存器溢出创建栈空间(Spill Slot)。内部调用上面的 CreateStackObject,设置 IsSpillSlot = true。
    其本质和局部变量没太大差别,但在寄存器分配失败时自动调用。
    ③ CreateVariableSizedObject(Align Alignment, const AllocaInst *Alloca)
    用于处理运行时才确定大小的变量(例如 alloca 分配的数组)。其行为是:
  • 标记当前函数含有可变栈对象:HasVarSizedObjects = true;
  • 由于大小不确定,设置 Size = 0;
  • 依然要设置对齐要求,并更新最大对齐;
  • 会影响后续是否使用 Frame Pointer,以及栈帧如何对齐。
    ④ CreateFixedObject(uint64_t Size, int64_t SPOffset, …)
    这个函数创建一个固定位置的栈对象。它主要用于处理函数调用约定中ABI保留的栈空间,如返回地址、保存的寄存器等。
    特点是:
  • 必须传入一个固定偏移 SPOffset;
  • 对齐方式由偏移值和栈对齐策略推导出来;
  • 这些对象被插入在 Objects 的最前面,编号为负数(FixedObject index);
  • 通常在函数开始就确定,不随后续变量变化。
    ⑤ CreateFixedSpillStackObject(uint64_t Size, int64_t SPOffset, bool IsImmutable)
    和上面的 CreateFixedObject 类似,只不过专门用于创建固定位置的 Spill 对象
    如:某些平台对特定寄存器要求必须保存到特定位置。
    ⑥ estimateStackSize(const MachineFunction &MF)
    这个函数用于估算当前函数的总栈帧大小,具体包括:
  • 累加所有非固定、未死亡的栈对象的大小;
  • 每次增加时按对象的对齐要求进行对齐(alignTo);
  • 考虑是否需要保留调用帧空间(Call Frame);
  • 最终将总大小对齐到全局 StackAlignment 或 TransientStackAlignment;
  • 如果有 FramePointer 被消除,还需保证对齐到最大对齐要求。
    这是生成目标代码时确定函数栈帧边界的核心函数之一。
    ⑦ getPristineRegs(const MachineFunction &MF)
    返回一个 BitVector,表示当前函数中哪些物理寄存器没有被破坏(即“干净的”)。
    流程如下:
  • 遍历所有 Callee-Saved 寄存器;
  • 把真正被使用(并保存)的寄存器剔除掉;
  • 结果就是可以复用或省略保存的寄存器集合。