Skip to content

Commit

Permalink
Update frame layout & CFI generation to handle frames larger than 2gb
Browse files Browse the repository at this point in the history
For very large stack frames, the offset from the stack pointer to a
local can be more than 2^31 which overflows various `int` offsets
in the frame lowering code.

This patch updates the frame lowering code to calculate the offsets as
64-bit values and fixes CFI to use the corrected sizes.

After this patch, additional work is needed to fix offset truncations in
each target's codegen.
  • Loading branch information
wesleywiser committed Jul 17, 2024
1 parent 27b2f4f commit 461eed4
Show file tree
Hide file tree
Showing 19 changed files with 66 additions and 65 deletions.
14 changes: 7 additions & 7 deletions llvm/include/llvm/CodeGen/MachineFrameInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ class MachineFrameInfo {
/// targets, this value is only used when generating debug info (via
/// TargetRegisterInfo::getFrameIndexReference); when generating code, the
/// corresponding adjustments are performed directly.
int OffsetAdjustment = 0;
int64_t OffsetAdjustment = 0;

/// The prolog/epilog code inserter may process objects that require greater
/// alignment than the default alignment the target provides.
Expand Down Expand Up @@ -280,7 +280,7 @@ class MachineFrameInfo {
/// setup/destroy pseudo instructions (as defined in the TargetFrameInfo
/// class). This information is important for frame pointer elimination.
/// It is only valid during and after prolog/epilog code insertion.
unsigned MaxCallFrameSize = ~0u;
uint64_t MaxCallFrameSize = ~UINT64_C(0);

/// The number of bytes of callee saved registers that the target wants to
/// report for the current function in the CodeView S_FRAMEPROC record.
Expand Down Expand Up @@ -593,10 +593,10 @@ class MachineFrameInfo {
uint64_t estimateStackSize(const MachineFunction &MF) const;

/// Return the correction for frame offsets.
int getOffsetAdjustment() const { return OffsetAdjustment; }
int64_t getOffsetAdjustment() const { return OffsetAdjustment; }

/// Set the correction for frame offsets.
void setOffsetAdjustment(int Adj) { OffsetAdjustment = Adj; }
void setOffsetAdjustment(int64_t Adj) { OffsetAdjustment = Adj; }

/// Return the alignment in bytes that this function must be aligned to,
/// which is greater than the default stack alignment provided by the target.
Expand Down Expand Up @@ -663,17 +663,17 @@ class MachineFrameInfo {
/// CallFrameSetup/Destroy pseudo instructions are used by the target, and
/// then only during or after prolog/epilog code insertion.
///
unsigned getMaxCallFrameSize() const {
uint64_t getMaxCallFrameSize() const {
// TODO: Enable this assert when targets are fixed.
//assert(isMaxCallFrameSizeComputed() && "MaxCallFrameSize not computed yet");
if (!isMaxCallFrameSizeComputed())
return 0;
return MaxCallFrameSize;
}
bool isMaxCallFrameSizeComputed() const {
return MaxCallFrameSize != ~0u;
return MaxCallFrameSize != ~UINT64_C(0);
}
void setMaxCallFrameSize(unsigned S) { MaxCallFrameSize = S; }
void setMaxCallFrameSize(uint64_t S) { MaxCallFrameSize = S; }

/// Returns how many bytes of callee-saved registers the target pushed in the
/// prologue. Only used for debug info.
Expand Down
4 changes: 2 additions & 2 deletions llvm/include/llvm/CodeGen/TargetFrameLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class TargetFrameLowering {
// Maps a callee saved register to a stack slot with a fixed offset.
struct SpillSlot {
unsigned Reg;
int Offset; // Offset relative to stack pointer on function entry.
int64_t Offset; // Offset relative to stack pointer on function entry.
};

struct DwarfFrameBase {
Expand All @@ -66,7 +66,7 @@ class TargetFrameLowering {
// Used with FrameBaseKind::Register.
unsigned Reg;
// Used with FrameBaseKind::CFA.
int Offset;
int64_t Offset;
struct WasmFrameBase WasmLoc;
} Location;
};
Expand Down
2 changes: 1 addition & 1 deletion llvm/include/llvm/MC/MCAsmBackend.h
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ class MCAsmBackend {
virtual void handleAssemblerFlag(MCAssemblerFlag Flag) {}

/// Generate the compact unwind encoding for the CFI instructions.
virtual uint32_t generateCompactUnwindEncoding(const MCDwarfFrameInfo *FI,
virtual uint64_t generateCompactUnwindEncoding(const MCDwarfFrameInfo *FI,
const MCContext *Ctxt) const {
return 0;
}
Expand Down
44 changes: 22 additions & 22 deletions llvm/include/llvm/MC/MCDwarf.h
Original file line number Diff line number Diff line change
Expand Up @@ -509,11 +509,11 @@ class MCCFIInstruction {
union {
struct {
unsigned Register;
int Offset;
int64_t Offset;
} RI;
struct {
unsigned Register;
int Offset;
int64_t Offset;
unsigned AddressSpace;
} RIA;
struct {
Expand All @@ -527,7 +527,7 @@ class MCCFIInstruction {
std::vector<char> Values;
std::string Comment;

MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R, int O, SMLoc Loc,
MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R, int64_t O, SMLoc Loc,
StringRef V = "", StringRef Comment = "")
: Label(L), Operation(Op), Loc(Loc), Values(V.begin(), V.end()),
Comment(Comment) {
Expand All @@ -539,7 +539,7 @@ class MCCFIInstruction {
assert(Op == OpRegister);
U.RR = {R1, R2};
}
MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R, int O, unsigned AS,
MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R, int64_t O, unsigned AS,
SMLoc Loc)
: Label(L), Operation(Op), Loc(Loc) {
assert(Op == OpLLVMDefAspaceCfa);
Expand All @@ -555,30 +555,30 @@ class MCCFIInstruction {
public:
/// .cfi_def_cfa defines a rule for computing CFA as: take address from
/// Register and add Offset to it.
static MCCFIInstruction cfiDefCfa(MCSymbol *L, unsigned Register, int Offset,
SMLoc Loc = {}) {
static MCCFIInstruction cfiDefCfa(MCSymbol *L, unsigned Register,
int64_t Offset, SMLoc Loc = {}) {
return MCCFIInstruction(OpDefCfa, L, Register, Offset, Loc);
}

/// .cfi_def_cfa_register modifies a rule for computing CFA. From now
/// on Register will be used instead of the old one. Offset remains the same.
static MCCFIInstruction createDefCfaRegister(MCSymbol *L, unsigned Register,
SMLoc Loc = {}) {
return MCCFIInstruction(OpDefCfaRegister, L, Register, 0, Loc);
return MCCFIInstruction(OpDefCfaRegister, L, Register, INT64_C(0), Loc);
}

/// .cfi_def_cfa_offset modifies a rule for computing CFA. Register
/// remains the same, but offset is new. Note that it is the absolute offset
/// that will be added to a defined register to the compute CFA address.
static MCCFIInstruction cfiDefCfaOffset(MCSymbol *L, int Offset,
static MCCFIInstruction cfiDefCfaOffset(MCSymbol *L, int64_t Offset,
SMLoc Loc = {}) {
return MCCFIInstruction(OpDefCfaOffset, L, 0, Offset, Loc);
}

/// .cfi_adjust_cfa_offset Same as .cfi_def_cfa_offset, but
/// Offset is a relative value that is added/subtracted from the previous
/// offset.
static MCCFIInstruction createAdjustCfaOffset(MCSymbol *L, int Adjustment,
static MCCFIInstruction createAdjustCfaOffset(MCSymbol *L, int64_t Adjustment,
SMLoc Loc = {}) {
return MCCFIInstruction(OpAdjustCfaOffset, L, 0, Adjustment, Loc);
}
Expand All @@ -588,7 +588,7 @@ class MCCFIInstruction {
/// be the result of evaluating the DWARF operation expression
/// `DW_OP_constu AS; DW_OP_aspace_bregx R, B` as a location description.
static MCCFIInstruction createLLVMDefAspaceCfa(MCSymbol *L, unsigned Register,
int Offset,
int64_t Offset,
unsigned AddressSpace,
SMLoc Loc) {
return MCCFIInstruction(OpLLVMDefAspaceCfa, L, Register, Offset,
Expand All @@ -598,15 +598,15 @@ class MCCFIInstruction {
/// .cfi_offset Previous value of Register is saved at offset Offset
/// from CFA.
static MCCFIInstruction createOffset(MCSymbol *L, unsigned Register,
int Offset, SMLoc Loc = {}) {
int64_t Offset, SMLoc Loc = {}) {
return MCCFIInstruction(OpOffset, L, Register, Offset, Loc);
}

/// .cfi_rel_offset Previous value of Register is saved at offset
/// Offset from the current CFA register. This is transformed to .cfi_offset
/// using the known displacement of the CFA register from the CFA.
static MCCFIInstruction createRelOffset(MCSymbol *L, unsigned Register,
int Offset, SMLoc Loc = {}) {
int64_t Offset, SMLoc Loc = {}) {
return MCCFIInstruction(OpRelOffset, L, Register, Offset, Loc);
}

Expand All @@ -619,44 +619,44 @@ class MCCFIInstruction {

/// .cfi_window_save SPARC register window is saved.
static MCCFIInstruction createWindowSave(MCSymbol *L, SMLoc Loc = {}) {
return MCCFIInstruction(OpWindowSave, L, 0, 0, Loc);
return MCCFIInstruction(OpWindowSave, L, 0, INT64_C(0), Loc);
}

/// .cfi_negate_ra_state AArch64 negate RA state.
static MCCFIInstruction createNegateRAState(MCSymbol *L, SMLoc Loc = {}) {
return MCCFIInstruction(OpNegateRAState, L, 0, 0, Loc);
return MCCFIInstruction(OpNegateRAState, L, 0, INT64_C(0), Loc);
}

/// .cfi_restore says that the rule for Register is now the same as it
/// was at the beginning of the function, after all initial instructions added
/// by .cfi_startproc were executed.
static MCCFIInstruction createRestore(MCSymbol *L, unsigned Register,
SMLoc Loc = {}) {
return MCCFIInstruction(OpRestore, L, Register, 0, Loc);
return MCCFIInstruction(OpRestore, L, Register, INT64_C(0), Loc);
}

/// .cfi_undefined From now on the previous value of Register can't be
/// restored anymore.
static MCCFIInstruction createUndefined(MCSymbol *L, unsigned Register,
SMLoc Loc = {}) {
return MCCFIInstruction(OpUndefined, L, Register, 0, Loc);
return MCCFIInstruction(OpUndefined, L, Register, INT64_C(0), Loc);
}

/// .cfi_same_value Current value of Register is the same as in the
/// previous frame. I.e., no restoration is needed.
static MCCFIInstruction createSameValue(MCSymbol *L, unsigned Register,
SMLoc Loc = {}) {
return MCCFIInstruction(OpSameValue, L, Register, 0, Loc);
return MCCFIInstruction(OpSameValue, L, Register, INT64_C(0), Loc);
}

/// .cfi_remember_state Save all current rules for all registers.
static MCCFIInstruction createRememberState(MCSymbol *L, SMLoc Loc = {}) {
return MCCFIInstruction(OpRememberState, L, 0, 0, Loc);
return MCCFIInstruction(OpRememberState, L, 0, INT64_C(0), Loc);
}

/// .cfi_restore_state Restore the previously saved state.
static MCCFIInstruction createRestoreState(MCSymbol *L, SMLoc Loc = {}) {
return MCCFIInstruction(OpRestoreState, L, 0, 0, Loc);
return MCCFIInstruction(OpRestoreState, L, 0, INT64_C(0), Loc);
}

/// .cfi_escape Allows the user to add arbitrary bytes to the unwind
Expand All @@ -667,7 +667,7 @@ class MCCFIInstruction {
}

/// A special wrapper for .cfi_escape that indicates GNU_ARGS_SIZE
static MCCFIInstruction createGnuArgsSize(MCSymbol *L, int Size,
static MCCFIInstruction createGnuArgsSize(MCSymbol *L, int64_t Size,
SMLoc Loc = {}) {
return MCCFIInstruction(OpGnuArgsSize, L, 0, Size, Loc);
}
Expand Down Expand Up @@ -702,7 +702,7 @@ class MCCFIInstruction {
return U.RIA.AddressSpace;
}

int getOffset() const {
int64_t getOffset() const {
if (Operation == OpLLVMDefAspaceCfa)
return U.RIA.Offset;
assert(Operation == OpDefCfa || Operation == OpOffset ||
Expand Down Expand Up @@ -736,7 +736,7 @@ struct MCDwarfFrameInfo {
unsigned CurrentCfaRegister = 0;
unsigned PersonalityEncoding = 0;
unsigned LsdaEncoding = 0;
uint32_t CompactUnwindEncoding = 0;
uint64_t CompactUnwindEncoding = 0;
bool IsSignalFrame = false;
bool IsSimple = false;
unsigned RAReg = static_cast<unsigned>(INT_MAX);
Expand Down
10 changes: 5 additions & 5 deletions llvm/lib/CodeGen/CFIInstrInserter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ class CFIInstrInserter : public MachineFunctionPass {
struct MBBCFAInfo {
MachineBasicBlock *MBB;
/// Value of cfa offset valid at basic block entry.
int IncomingCFAOffset = -1;
int64_t IncomingCFAOffset = -1;
/// Value of cfa offset valid at basic block exit.
int OutgoingCFAOffset = -1;
int64_t OutgoingCFAOffset = -1;
/// Value of cfa register valid at basic block entry.
unsigned IncomingCFARegister = 0;
/// Value of cfa register valid at basic block exit.
Expand Down Expand Up @@ -120,7 +120,7 @@ class CFIInstrInserter : public MachineFunctionPass {
/// Return the cfa offset value that should be set at the beginning of a MBB
/// if needed. The negated value is needed when creating CFI instructions that
/// set absolute offset.
int getCorrectCFAOffset(MachineBasicBlock *MBB) {
int64_t getCorrectCFAOffset(MachineBasicBlock *MBB) {
return MBBVector[MBB->getNumber()].IncomingCFAOffset;
}

Expand Down Expand Up @@ -175,7 +175,7 @@ void CFIInstrInserter::calculateCFAInfo(MachineFunction &MF) {

void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) {
// Outgoing cfa offset set by the block.
int SetOffset = MBBInfo.IncomingCFAOffset;
int64_t SetOffset = MBBInfo.IncomingCFAOffset;
// Outgoing cfa register set by the block.
unsigned SetRegister = MBBInfo.IncomingCFARegister;
MachineFunction *MF = MBBInfo.MBB->getParent();
Expand All @@ -188,7 +188,7 @@ void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) {
for (MachineInstr &MI : *MBBInfo.MBB) {
if (MI.isCFIInstruction()) {
std::optional<unsigned> CSRReg;
std::optional<int> CSROffset;
std::optional<int64_t> CSROffset;
unsigned CFIIndex = MI.getOperand(0).getCFIIndex();
const MCCFIInstruction &CFI = Instrs[CFIIndex];
switch (CFI.getOperation()) {
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/CodeGen/MachineFrameInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ void MachineFrameInfo::computeMaxCallFrameSize(
for (MachineInstr &MI : MBB) {
unsigned Opcode = MI.getOpcode();
if (Opcode == FrameSetupOpcode || Opcode == FrameDestroyOpcode) {
unsigned Size = TII.getFrameSize(MI);
uint64_t Size = TII.getFrameSize(MI);
MaxCallFrameSize = std::max(MaxCallFrameSize, Size);
if (FrameSDOps != nullptr)
FrameSDOps->push_back(&MI);
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/CodeGen/PrologEpilogInserter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -366,8 +366,8 @@ void PEI::calculateCallFrameInfo(MachineFunction &MF) {
return;

// (Re-)Compute the MaxCallFrameSize.
[[maybe_unused]] uint32_t MaxCFSIn =
MFI.isMaxCallFrameSizeComputed() ? MFI.getMaxCallFrameSize() : UINT32_MAX;
[[maybe_unused]] uint64_t MaxCFSIn =
MFI.isMaxCallFrameSizeComputed() ? MFI.getMaxCallFrameSize() : UINT64_MAX;
std::vector<MachineBasicBlock::iterator> FrameSDOps;
MFI.computeMaxCallFrameSize(MF, &FrameSDOps);
assert(MFI.getMaxCallFrameSize() <= MaxCFSIn &&
Expand Down
6 changes: 3 additions & 3 deletions llvm/lib/MC/MCDwarf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1299,8 +1299,8 @@ static void EmitPersonality(MCStreamer &streamer, const MCSymbol &symbol,
namespace {

class FrameEmitterImpl {
int CFAOffset = 0;
int InitialCFAOffset = 0;
int64_t CFAOffset = 0;
int64_t InitialCFAOffset = 0;
bool IsEH;
MCObjectStreamer &Streamer;

Expand Down Expand Up @@ -1414,7 +1414,7 @@ void FrameEmitterImpl::emitCFIInstruction(const MCCFIInstruction &Instr) {
if (!IsEH)
Reg = MRI->getDwarfRegNumFromDwarfEHRegNum(Reg);

int Offset = Instr.getOffset();
int64_t Offset = Instr.getOffset();
if (IsRelative)
Offset -= CFAOffset;
Offset = Offset / dataAlignmentFactor;
Expand Down
8 changes: 4 additions & 4 deletions llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,7 @@ class DarwinAArch64AsmBackend : public AArch64AsmBackend {
}

/// Generate the compact unwind encoding from the CFI directives.
uint32_t generateCompactUnwindEncoding(const MCDwarfFrameInfo *FI,
uint64_t generateCompactUnwindEncoding(const MCDwarfFrameInfo *FI,
const MCContext *Ctxt) const override {
ArrayRef<MCCFIInstruction> Instrs = FI->Instructions;
if (Instrs.empty())
Expand All @@ -609,10 +609,10 @@ class DarwinAArch64AsmBackend : public AArch64AsmBackend {
return CU::UNWIND_ARM64_MODE_DWARF;

bool HasFP = false;
unsigned StackSize = 0;
uint64_t StackSize = 0;

uint32_t CompactUnwindEncoding = 0;
int CurOffset = 0;
uint64_t CompactUnwindEncoding = 0;
int64_t CurOffset = 0;
for (size_t i = 0, e = Instrs.size(); i != e; ++i) {
const MCCFIInstruction &Inst = Instrs[i];

Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/Target/ARM/ARMFrameLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1167,7 +1167,7 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
if (STI.splitFramePushPop(MF)) {
unsigned DwarfReg = MRI->getDwarfRegNum(
Reg == ARM::R12 ? ARM::RA_AUTH_CODE : Reg, true);
unsigned Offset = MFI.getObjectOffset(FI);
int64_t Offset = MFI.getObjectOffset(FI);
unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::createOffset(nullptr, DwarfReg, Offset));
BuildMI(MBB, Pos, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
Expand All @@ -1189,7 +1189,7 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
if ((Reg >= ARM::D0 && Reg <= ARM::D31) &&
(Reg < ARM::D8 || Reg >= ARM::D8 + AFI->getNumAlignedDPRCS2Regs())) {
unsigned DwarfReg = MRI->getDwarfRegNum(Reg, true);
unsigned Offset = MFI.getObjectOffset(FI);
int64_t Offset = MFI.getObjectOffset(FI);
unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::createOffset(nullptr, DwarfReg, Offset));
BuildMI(MBB, Pos, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1146,7 +1146,7 @@ enum CompactUnwindEncodings {
/// instructions. If the CFI instructions describe a frame that cannot be
/// encoded in compact unwind, the method returns UNWIND_ARM_MODE_DWARF which
/// tells the runtime to fallback and unwind using dwarf.
uint32_t ARMAsmBackendDarwin::generateCompactUnwindEncoding(
uint64_t ARMAsmBackendDarwin::generateCompactUnwindEncoding(
const MCDwarfFrameInfo *FI, const MCContext *Ctxt) const {
DEBUG_WITH_TYPE("compact-unwind", llvm::dbgs() << "generateCU()\n");
// Only armv7k uses CFI based unwinding.
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackendDarwin.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class ARMAsmBackendDarwin : public ARMAsmBackend {
/*Is64Bit=*/false, cantFail(MachO::getCPUType(TT)), Subtype);
}

uint32_t generateCompactUnwindEncoding(const MCDwarfFrameInfo *FI,
uint64_t generateCompactUnwindEncoding(const MCDwarfFrameInfo *FI,
const MCContext *Ctxt) const override;
};
} // end namespace llvm
Expand Down
Loading

0 comments on commit 461eed4

Please sign in to comment.