diff options
| author | Reid Kleckner <rnk@google.com> | 2018-10-02 16:43:52 +0000 |
|---|---|---|
| committer | Reid Kleckner <rnk@google.com> | 2018-10-02 16:43:52 +0000 |
| commit | d5e4ec74e3daa50dc6f174d9b6f8951be09694a5 (patch) | |
| tree | ae4b16ec4884b3f7f850c1db183cdb0586d10704 | |
| parent | 6f40e21a1601aa1b83a13282918ddae47e58b7d5 (diff) | |
| download | bcm5719-llvm-d5e4ec74e3daa50dc6f174d9b6f8951be09694a5.tar.gz bcm5719-llvm-d5e4ec74e3daa50dc6f174d9b6f8951be09694a5.zip | |
[codeview] Fix 32-bit x86 variable locations in realigned stack frames
Add the .cv_fpo_stackalign directive so that we can define $T0, or the
VFRAME virtual register, with it. This was overlooked in the initial
implementation because unlike MSVC, we push CSRs before allocating stack
space, so this value is only needed to describe local variable
locations. Variables that the compiler now addresses via ESP are instead
described as being stored at offsets from VFRAME, which for us is ESP
after alignment in the prologue.
This adds tests that show that we use the VFRAME register properly in
our S_DEFRANGE records, and that we emit the correct FPO data to define
it.
Fixes PR38857
llvm-svn: 343603
| -rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp | 14 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h | 2 | ||||
| -rw-r--r-- | llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp | 13 | ||||
| -rw-r--r-- | llvm/lib/Target/X86/MCTargetDesc/X86TargetStreamer.h | 1 | ||||
| -rw-r--r-- | llvm/lib/Target/X86/MCTargetDesc/X86WinCOFFTargetStreamer.cpp | 55 | ||||
| -rw-r--r-- | llvm/lib/Target/X86/X86FrameLowering.cpp | 7 | ||||
| -rw-r--r-- | llvm/lib/Target/X86/X86InstrCompiler.td | 2 | ||||
| -rw-r--r-- | llvm/lib/Target/X86/X86MCInstLower.cpp | 4 | ||||
| -rw-r--r-- | llvm/test/DebugInfo/COFF/fpo-realign-alloca.ll | 3 | ||||
| -rw-r--r-- | llvm/test/DebugInfo/COFF/fpo-realign-vframe.ll | 230 | ||||
| -rw-r--r-- | llvm/test/MC/COFF/cv-fpo-realign.s | 199 |
11 files changed, 520 insertions, 10 deletions
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp index aaa1dc95757..707ee410d76 100644 --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -1255,6 +1255,7 @@ void CodeViewDebug::beginFunctionImpl(const MachineFunction *MF) { // instruction (AArch64), this will be zero. CurFn->CSRSize = MFI.getCVBytesOfCalleeSavedRegisters(); CurFn->FrameSize = MFI.getStackSize(); + CurFn->HasStackRealignment = TRI->needsStackRealignment(*MF); // For this function S_FRAMEPROC record, figure out which codeview register // will be the frame pointer. @@ -1267,7 +1268,7 @@ void CodeViewDebug::beginFunctionImpl(const MachineFunction *MF) { } else { // If there is an FP, parameters are always relative to it. CurFn->EncodedParamFramePtrReg = EncodedFramePtrReg::FramePtr; - if (TRI->needsStackRealignment(*MF)) { + if (CurFn->HasStackRealignment) { // If the stack needs realignment, locals are relative to SP or VFRAME. CurFn->EncodedLocalFramePtrReg = EncodedFramePtrReg::StackPtr; } else { @@ -2502,13 +2503,18 @@ void CodeViewDebug::emitLocalVariable(const FunctionInfo &FI, int Offset = DefRange.DataOffset; unsigned Reg = DefRange.CVRegister; - // x86 call sequences often use PUSH instructions, which disrupt + // 32-bit x86 call sequences often use PUSH instructions, which disrupt // ESP-relative offsets. Use the virtual frame pointer, VFRAME or $T0, - // instead. In simple cases, $T0 will be the CFA. If the frame required - // re-alignment, it will be the CFA aligned downwards. + // instead. In simple cases, $T0 will be the CFA. if (RegisterId(Reg) == RegisterId::ESP) { Reg = unsigned(RegisterId::VFRAME); Offset -= FI.FrameSize; + + // If the frame requires realignment, VFRAME will be ESP after it is + // aligned. We have to remove the ESP adjustments made to push CSRs and + // EBP. EBP is not included in CSRSize. + if (FI.HasStackRealignment) + Offset += FI.CSRSize + 4; } // If we can use the chosen frame pointer for the frame and this isn't a diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h index 3836862f0a8..b2864306e50 100644 --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h @@ -165,6 +165,8 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { codeview::FrameProcedureOptions FrameProcOpts; + bool HasStackRealignment = false; + bool HaveLineInfo = false; }; FunctionInfo *CurFn = nullptr; diff --git a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp index 8b7b250e1a0..e67daa5d857 100644 --- a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp +++ b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -852,6 +852,7 @@ private: bool parseDirectiveFPOSetFrame(SMLoc L); bool parseDirectiveFPOPushReg(SMLoc L); bool parseDirectiveFPOStackAlloc(SMLoc L); + bool parseDirectiveFPOStackAlign(SMLoc L); bool parseDirectiveFPOEndPrologue(SMLoc L); bool parseDirectiveFPOEndProc(SMLoc L); bool parseDirectiveFPOData(SMLoc L); @@ -3315,6 +3316,8 @@ bool X86AsmParser::ParseDirective(AsmToken DirectiveID) { return parseDirectiveFPOPushReg(DirectiveID.getLoc()); else if (IDVal == ".cv_fpo_stackalloc") return parseDirectiveFPOStackAlloc(DirectiveID.getLoc()); + else if (IDVal == ".cv_fpo_stackalign") + return parseDirectiveFPOStackAlign(DirectiveID.getLoc()); else if (IDVal == ".cv_fpo_endprologue") return parseDirectiveFPOEndPrologue(DirectiveID.getLoc()); else if (IDVal == ".cv_fpo_endproc") @@ -3429,6 +3432,16 @@ bool X86AsmParser::parseDirectiveFPOStackAlloc(SMLoc L) { return getTargetStreamer().emitFPOStackAlloc(Offset, L); } +// .cv_fpo_stackalign 8 +bool X86AsmParser::parseDirectiveFPOStackAlign(SMLoc L) { + MCAsmParser &Parser = getParser(); + int64_t Offset; + if (Parser.parseIntToken(Offset, "expected offset") || + Parser.parseEOL("unexpected tokens")) + return addErrorSuffix(" in '.cv_fpo_stackalign' directive"); + return getTargetStreamer().emitFPOStackAlign(Offset, L); +} + // .cv_fpo_endprologue bool X86AsmParser::parseDirectiveFPOEndPrologue(SMLoc L) { MCAsmParser &Parser = getParser(); diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86TargetStreamer.h b/llvm/lib/Target/X86/MCTargetDesc/X86TargetStreamer.h index 8d38cd32b82..10a282dd296 100644 --- a/llvm/lib/Target/X86/MCTargetDesc/X86TargetStreamer.h +++ b/llvm/lib/Target/X86/MCTargetDesc/X86TargetStreamer.h @@ -26,6 +26,7 @@ public: virtual bool emitFPOData(const MCSymbol *ProcSym, SMLoc L = {}) = 0; virtual bool emitFPOPushReg(unsigned Reg, SMLoc L = {}) = 0; virtual bool emitFPOStackAlloc(unsigned StackAlloc, SMLoc L = {}) = 0; + virtual bool emitFPOStackAlign(unsigned Align, SMLoc L = {}) = 0; virtual bool emitFPOSetFrame(unsigned Reg, SMLoc L = {}) = 0; }; diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86WinCOFFTargetStreamer.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86WinCOFFTargetStreamer.cpp index 093dab4f2f9..bee9b704633 100644 --- a/llvm/lib/Target/X86/MCTargetDesc/X86WinCOFFTargetStreamer.cpp +++ b/llvm/lib/Target/X86/MCTargetDesc/X86WinCOFFTargetStreamer.cpp @@ -38,6 +38,7 @@ public: bool emitFPOData(const MCSymbol *ProcSym, SMLoc L) override; bool emitFPOPushReg(unsigned Reg, SMLoc L) override; bool emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) override; + bool emitFPOStackAlign(unsigned Align, SMLoc L) override; bool emitFPOSetFrame(unsigned Reg, SMLoc L) override; }; @@ -47,6 +48,7 @@ struct FPOInstruction { enum Operation { PushReg, StackAlloc, + StackAlign, SetFrame, } Op; unsigned RegOrOffset; @@ -90,6 +92,7 @@ public: bool emitFPOData(const MCSymbol *ProcSym, SMLoc L) override; bool emitFPOPushReg(unsigned Reg, SMLoc L) override; bool emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) override; + bool emitFPOStackAlign(unsigned Align, SMLoc L) override; bool emitFPOSetFrame(unsigned Reg, SMLoc L) override; }; } // end namespace @@ -133,6 +136,11 @@ bool X86WinCOFFAsmTargetStreamer::emitFPOStackAlloc(unsigned StackAlloc, return false; } +bool X86WinCOFFAsmTargetStreamer::emitFPOStackAlign(unsigned Align, SMLoc L) { + OS << "\t.cv_fpo_stackalign\t" << Align << '\n'; + return false; +} + bool X86WinCOFFAsmTargetStreamer::emitFPOSetFrame(unsigned Reg, SMLoc L) { OS << "\t.cv_fpo_setframe\t"; InstPrinter.printRegName(OS, Reg); @@ -226,6 +234,24 @@ bool X86WinCOFFTargetStreamer::emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) { return false; } +bool X86WinCOFFTargetStreamer::emitFPOStackAlign(unsigned Align, SMLoc L) { + if (checkInFPOPrologue(L)) + return true; + if (!llvm::any_of(CurFPOData->Instructions, [](const FPOInstruction &Inst) { + return Inst.Op == FPOInstruction::SetFrame; + })) { + getContext().reportError( + L, "a frame register must be established before aligning the stack"); + return true; + } + FPOInstruction Inst; + Inst.Label = emitFPOLabel(); + Inst.Op = FPOInstruction::StackAlign; + Inst.RegOrOffset = Align; + CurFPOData->Instructions.push_back(Inst); + return false; +} + bool X86WinCOFFTargetStreamer::emitFPOEndPrologue(SMLoc L) { if (checkInFPOPrologue(L)) return true; @@ -250,6 +276,8 @@ struct FPOStateMachine { unsigned CurOffset = 0; unsigned LocalSize = 0; unsigned SavedRegSize = 0; + unsigned StackOffsetBeforeAlign = 0; + unsigned StackAlign = 0; unsigned Flags = 0; // FIXME: Set HasSEH / HasEH. SmallString<128> FrameFunc; @@ -291,24 +319,39 @@ void FPOStateMachine::emitFrameDataRecord(MCStreamer &OS, MCSymbol *Label) { FrameFunc.clear(); raw_svector_ostream FuncOS(FrameFunc); const MCRegisterInfo *MRI = OS.getContext().getRegisterInfo(); + assert((StackAlign == 0 || FrameReg != 0) && + "cannot align stack without frame reg"); + StringRef CFAVar = StackAlign == 0 ? "$T0" : "$T1"; + if (FrameReg) { // CFA is FrameReg + FrameRegOff. - FuncOS << "$T0 " << printFPOReg(MRI, FrameReg) << " " << FrameRegOff + FuncOS << CFAVar << ' ' << printFPOReg(MRI, FrameReg) << ' ' << FrameRegOff << " + = "; + + // Assign $T0, the VFRAME register, the value of ESP after it is aligned. + // Starting from the CFA, we subtract the size of all pushed registers, and + // align the result. While we don't store any CSRs in this area, $T0 is used + // by S_DEFRANGE_FRAMEPOINTER_REL records to find local variables. + if (StackAlign) { + FuncOS << "$T0 " << CFAVar << ' ' << StackOffsetBeforeAlign << " - " + << StackAlign << " @ = "; + } } else { // The address of return address is ESP + CurOffset, but we use .raSearch to // match MSVC. This seems to ask the debugger to subtract some combination // of LocalSize and SavedRegSize from ESP and grovel around in that memory // to find the address of a plausible return address. - FuncOS << "$T0 .raSearch = "; + FuncOS << CFAVar << " .raSearch = "; } // Caller's $eip should be dereferenced CFA, and $esp should be CFA plus 4. - FuncOS << "$eip $T0 ^ = $esp $T0 4 + = "; + FuncOS << "$eip " << CFAVar << " ^ = "; + FuncOS << "$esp " << CFAVar << " 4 + = "; // Each saved register is stored at an unchanging negative CFA offset. for (RegSaveOffset RO : RegSaveOffsets) - FuncOS << printFPOReg(MRI, RO.Reg) << " $T0 " << RO.Offset << " - ^ = "; + FuncOS << printFPOReg(MRI, RO.Reg) << ' ' << CFAVar << ' ' << RO.Offset + << " - ^ = "; // Add it to the CV string table. CodeViewContext &CVCtx = OS.getContext().getCVContext(); @@ -380,6 +423,10 @@ bool X86WinCOFFTargetStreamer::emitFPOData(const MCSymbol *ProcSym, SMLoc L) { FSM.FrameReg = Inst.RegOrOffset; FSM.FrameRegOff = FSM.CurOffset; break; + case FPOInstruction::StackAlign: + FSM.StackOffsetBeforeAlign = FSM.CurOffset; + FSM.StackAlign = Inst.RegOrOffset; + break; case FPOInstruction::StackAlloc: FSM.CurOffset += Inst.RegOrOffset; FSM.LocalSize += Inst.RegOrOffset; diff --git a/llvm/lib/Target/X86/X86FrameLowering.cpp b/llvm/lib/Target/X86/X86FrameLowering.cpp index 2d660ac8826..1eb9fa0bc1e 100644 --- a/llvm/lib/Target/X86/X86FrameLowering.cpp +++ b/llvm/lib/Target/X86/X86FrameLowering.cpp @@ -1208,6 +1208,13 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF, if (!IsWin64Prologue && !IsFunclet && TRI->needsStackRealignment(MF)) { assert(HasFP && "There should be a frame pointer if stack is realigned."); BuildStackAlignAND(MBB, MBBI, DL, StackPtr, MaxAlign); + + if (NeedsWinCFI) { + HasWinCFI = true; + BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_StackAlign)) + .addImm(MaxAlign) + .setMIFlag(MachineInstr::FrameSetup); + } } // If there is an SUB32ri of ESP immediately before this instruction, merge diff --git a/llvm/lib/Target/X86/X86InstrCompiler.td b/llvm/lib/Target/X86/X86InstrCompiler.td index 111dc28f2eb..ca354fae833 100644 --- a/llvm/lib/Target/X86/X86InstrCompiler.td +++ b/llvm/lib/Target/X86/X86InstrCompiler.td @@ -240,6 +240,8 @@ let isPseudo = 1, SchedRW = [WriteSystem] in { "#SEH_SaveXMM $reg, $dst", []>; def SEH_StackAlloc : I<0, Pseudo, (outs), (ins i32imm:$size), "#SEH_StackAlloc $size", []>; + def SEH_StackAlign : I<0, Pseudo, (outs), (ins i32imm:$align), + "#SEH_StackAlign $align", []>; def SEH_SetFrame : I<0, Pseudo, (outs), (ins i32imm:$reg, i32imm:$offset), "#SEH_SetFrame $reg, $offset", []>; def SEH_PushFrame : I<0, Pseudo, (outs), (ins i1imm:$mode), diff --git a/llvm/lib/Target/X86/X86MCInstLower.cpp b/llvm/lib/Target/X86/X86MCInstLower.cpp index a6251ffb2e1..acb2bc20858 100644 --- a/llvm/lib/Target/X86/X86MCInstLower.cpp +++ b/llvm/lib/Target/X86/X86MCInstLower.cpp @@ -1532,6 +1532,9 @@ void X86AsmPrinter::EmitSEHInstruction(const MachineInstr *MI) { case X86::SEH_StackAlloc: XTS->emitFPOStackAlloc(MI->getOperand(0).getImm()); break; + case X86::SEH_StackAlign: + XTS->emitFPOStackAlign(MI->getOperand(0).getImm()); + break; case X86::SEH_SetFrame: assert(MI->getOperand(1).getImm() == 0 && ".cv_fpo_setframe takes no offset"); @@ -1809,6 +1812,7 @@ void X86AsmPrinter::EmitInstruction(const MachineInstr *MI) { case X86::SEH_SaveReg: case X86::SEH_SaveXMM: case X86::SEH_StackAlloc: + case X86::SEH_StackAlign: case X86::SEH_SetFrame: case X86::SEH_PushFrame: case X86::SEH_EndPrologue: diff --git a/llvm/test/DebugInfo/COFF/fpo-realign-alloca.ll b/llvm/test/DebugInfo/COFF/fpo-realign-alloca.ll index 84e112200cb..6046e2f5262 100644 --- a/llvm/test/DebugInfo/COFF/fpo-realign-alloca.ll +++ b/llvm/test/DebugInfo/COFF/fpo-realign-alloca.ll @@ -17,9 +17,8 @@ ; CHECK: .cv_fpo_setframe %ebp ; CHECK: pushl %esi ; CHECK: .cv_fpo_pushreg %esi -; We don't seem to need to describe this AND because at this point CSRs -; are stored relative to EBP, but it's suspicious. ; CHECK: andl $-16, %esp +; CHECK: .cv_fpo_stackalign 16 ; CHECK: subl $32, %esp ; CHECK: .cv_fpo_stackalloc 32 ; CHECK: .cv_fpo_endprologue diff --git a/llvm/test/DebugInfo/COFF/fpo-realign-vframe.ll b/llvm/test/DebugInfo/COFF/fpo-realign-vframe.ll new file mode 100644 index 00000000000..fded804a531 --- /dev/null +++ b/llvm/test/DebugInfo/COFF/fpo-realign-vframe.ll @@ -0,0 +1,230 @@ +; RUN: llc < %s | FileCheck %s --check-prefix=ASM +; RUN: llc -filetype=obj < %s | llvm-readobj -codeview | FileCheck %s --check-prefix=OBJ + +; PR38857 + +; When stack realignment is required by dynamic allocas are not used, the +; compiler will address locals with the ESP register. However, if call argument +; set up uses PUSH instructions, ESP may vary over the course of the function. +; This means it's not useful as a base register for describing the locations of +; variables. Instead, our CodeView output prefers to use the VFRAME virtual +; register, which is defined in the FPO data as $T0. Make sure we define it. + +; Original C++ test case, which uses __thiscall to encourage PUSH conversion: +; struct Foo { +; int x = 42; +; int __declspec(noinline) foo(); +; void __declspec(noinline) bar(int *a, int *b, double *c); +; }; +; int Foo::foo() { +; int a = 1; +; int b = 2; +; double __declspec(align(8)) force_alignment = 0.42; +; bar(&a, &b, &force_alignment); +; x += (int)force_alignment; +; return x; +; } +; void Foo::bar(int *a, int *b, double *c) { +; __debugbreak(); +; *c += *a + *b; +; } +; int main() { +; Foo o; +; o.foo(); +; } +; This stops the debugger in bar, and locals in Foo::foo would be corrupt. + +; More reduced C code to generate this IR: +; int getval(void); +; void usevals(int *, int *, double *); +; int realign_with_csrs(int x) { +; int a = getval(); +; double __declspec(align(8)) force_alignment = 0.42; +; usevals(&a, &x, &force_alignment); +; return x; +; } + +; Match the prologue for the .cv_fpo* directives. +; ASM-LABEL: _realign_with_csrs: +; ASM: .cv_fpo_proc _realign_with_csrs 4 +; ASM: # %bb.0: # %entry +; ASM: pushl %ebp +; ASM: .cv_fpo_pushreg %ebp +; ASM: movl %esp, %ebp +; ASM: .cv_fpo_setframe %ebp +; ASM: andl $-8, %esp +; ASM: .cv_fpo_stackalign 8 +; ASM: subl $16, %esp +; ASM: .cv_fpo_stackalloc 16 +; ASM: .cv_fpo_endprologue + +; 'x' should be EBP-relative, 'a' and 'force_alignment' ESP relative. +; ASM: calll _getval +; ASM-DAG: leal 8(%esp), %[[LEA_DBL:[^ ]*]] +; ASM-DAG: leal 8(%ebp), %[[LEA_X:[^ ]*]] +; ASM-DAG: leal 4(%esp), %[[LEA_A:[^ ]*]] +; ASM: pushl %[[LEA_DBL]] +; ASM: pushl %[[LEA_X]] +; ASM: pushl %[[LEA_A]] +; ASM: calll _usevals +; ASM: addl $12, %esp + +; OBJ: Subsection [ +; OBJ: SubSectionType: Symbols (0xF1) +; OBJ: ] +; OBJ: Subsection [ +; OBJ: SubSectionType: FrameData (0xF5) +; Really, the only important FrameFunc is the last one. +; OBJ: FrameData { +; OBJ: } +; OBJ: FrameData { +; OBJ: } +; OBJ: FrameData { +; OBJ: } +; OBJ: FrameData { +; OBJ: FrameFunc [ +; OBJ: $T1 $ebp 4 + = +; OBJ: $T0 $T1 4 - 8 @ = +; OBJ: $eip $T1 ^ = +; OBJ: $esp $T1 4 + = +; OBJ: $ebp $T1 4 - ^ = +; OBJ: ] +; OBJ: } +; OBJ: ] +; OBJ: Subsection [ +; OBJ: SubSectionType: Symbols (0xF1) +; OBJ: GlobalProcIdSym { +; OBJ: Kind: S_GPROC32_ID (0x1147) +; OBJ: DisplayName: realign_with_csrs +; OBJ: LinkageName: _realign_with_csrs +; OBJ: } +; The frame register for locals should be VFRAME, and EBP for parameters. +; OBJ: FrameProcSym { +; OBJ: Kind: S_FRAMEPROC (0x1012) +; OBJ: TotalFrameBytes: 0x14 +; OBJ: LocalFramePtrReg: VFRAME (0x7536) +; OBJ: ParamFramePtrReg: EBP (0x16) +; OBJ: } +; As seen in ASM, offset of x is 8. +; OBJ: LocalSym { +; OBJ: Kind: S_LOCAL (0x113E) +; OBJ: Type: int (0x74) +; OBJ: Flags [ (0x1) +; OBJ: IsParameter (0x1) +; OBJ: ] +; OBJ: VarName: x +; OBJ: } +; OBJ: DefRangeFramePointerRelSym { +; OBJ: Kind: S_DEFRANGE_FRAMEPOINTER_REL (0x1142) +; OBJ: Offset: 8 +; OBJ: } +; ESP is VFRAME - 16, ESP offset of 'a' is 4, so -12. +; OBJ: LocalSym { +; OBJ: Kind: S_LOCAL (0x113E) +; OBJ: Type: int (0x74) +; OBJ: Flags [ (0x0) +; OBJ: ] +; OBJ: VarName: a +; OBJ: } +; OBJ: DefRangeFramePointerRelSym { +; OBJ: Kind: S_DEFRANGE_FRAMEPOINTER_REL (0x1142) +; OBJ: Offset: -12 +; OBJ: } +; ESP is VFRAME - 16, ESP offset of 'force_alignment' is 8, so -8. +; OBJ: LocalSym { +; OBJ: Kind: S_LOCAL (0x113E) +; OBJ: Type: double (0x41) +; OBJ: Flags [ (0x0) +; OBJ: ] +; OBJ: VarName: force_alignment +; OBJ: } +; OBJ: DefRangeFramePointerRelSym { +; OBJ: Kind: S_DEFRANGE_FRAMEPOINTER_REL (0x1142) +; OBJ: Offset: -8 +; OBJ: } +; OBJ: ProcEnd { +; OBJ: Kind: S_PROC_ID_END (0x114F) +; OBJ: } +; OBJ: ] + +; ModuleID = 't.c' +source_filename = "t.c" +target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" +target triple = "i386-pc-windows-msvc19.14.26433" + +; Function Attrs: nounwind +define dso_local i32 @realign_with_csrs(i32 %x) local_unnamed_addr #0 !dbg !8 { +entry: + %x.addr = alloca i32, align 4 + %a = alloca i32, align 4 + %force_alignment = alloca double, align 8 + store i32 %x, i32* %x.addr, align 4, !tbaa !17 + call void @llvm.dbg.declare(metadata i32* %x.addr, metadata !13, metadata !DIExpression()), !dbg !21 + %0 = bitcast i32* %a to i8*, !dbg !22 + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %0) #4, !dbg !22 + call void @llvm.dbg.declare(metadata i32* %a, metadata !14, metadata !DIExpression()), !dbg !22 + %call = tail call i32 @getval() #4, !dbg !22 + store i32 %call, i32* %a, align 4, !dbg !22, !tbaa !17 + %1 = bitcast double* %force_alignment to i8*, !dbg !23 + call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %1) #4, !dbg !23 + call void @llvm.dbg.declare(metadata double* %force_alignment, metadata !15, metadata !DIExpression()), !dbg !23 + store double 4.200000e-01, double* %force_alignment, align 8, !dbg !23, !tbaa !24 + call void @usevals(i32* nonnull %a, i32* nonnull %x.addr, double* nonnull %force_alignment) #4, !dbg !26 + %2 = load i32, i32* %x.addr, align 4, !dbg !27, !tbaa !17 + call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %1) #4, !dbg !28 + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %0) #4, !dbg !28 + ret i32 %2, !dbg !27 +} + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #2 + +declare dso_local i32 @getval() local_unnamed_addr #3 + +declare dso_local void @usevals(i32*, i32*, double*) local_unnamed_addr #3 + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #2 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone speculatable } +attributes #2 = { argmemonly nounwind } +attributes #3 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5, !6} +!llvm.ident = !{!7} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 8.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "t.c", directory: "C:\5Csrc\5Cllvm-project\5Cbuild", checksumkind: CSK_MD5, checksum: "a646950309d5d01d8087fc10fea33941") +!2 = !{} +!3 = !{i32 1, !"NumRegisterParameters", i32 0} +!4 = !{i32 2, !"CodeView", i32 1} +!5 = !{i32 2, !"Debug Info Version", i32 3} +!6 = !{i32 1, !"wchar_size", i32 2} +!7 = !{!"clang version 8.0.0 "} +!8 = distinct !DISubprogram(name: "realign_with_csrs", scope: !1, file: !1, line: 3, type: !9, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !12) +!9 = !DISubroutineType(types: !10) +!10 = !{!11, !11} +!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!12 = !{!13, !14, !15} +!13 = !DILocalVariable(name: "x", arg: 1, scope: !8, file: !1, line: 3, type: !11) +!14 = !DILocalVariable(name: "a", scope: !8, file: !1, line: 4, type: !11) +!15 = !DILocalVariable(name: "force_alignment", scope: !8, file: !1, line: 5, type: !16, align: 64) +!16 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float) +!17 = !{!18, !18, i64 0} +!18 = !{!"int", !19, i64 0} +!19 = !{!"omnipotent char", !20, i64 0} +!20 = !{!"Simple C/C++ TBAA"} +!21 = !DILocation(line: 3, scope: !8) +!22 = !DILocation(line: 4, scope: !8) +!23 = !DILocation(line: 5, scope: !8) +!24 = !{!25, !25, i64 0} +!25 = !{!"double", !19, i64 0} +!26 = !DILocation(line: 6, scope: !8) +!27 = !DILocation(line: 7, scope: !8) +!28 = !DILocation(line: 8, scope: !8) diff --git a/llvm/test/MC/COFF/cv-fpo-realign.s b/llvm/test/MC/COFF/cv-fpo-realign.s new file mode 100644 index 00000000000..247cad9334b --- /dev/null +++ b/llvm/test/MC/COFF/cv-fpo-realign.s @@ -0,0 +1,199 @@ +# RUN: llvm-mc -triple=i686-windows-msvc -filetype=obj < %s | llvm-readobj -codeview | FileCheck %s + +# Test for .cv_fpo_stackalign. We should generate FPO data that restores CSRs +# at each instruction, and in the last FrameData we should use the '@' +# alignment operator to define $T0, the vframe value. + +# Based on this C code: +# void usevals(int, int, double*); +# int realign_with_csrs() { +# int a = getval(); +# int b = getval(); +# double __declspec(align(8)) force_alignment = 0.42; +# usevals(a, b, &force_alignment); +# return a + b; +# } + +# CHECK: Subsection [ +# CHECK: SubSectionType: Symbols (0xF1) +# CHECK: Compile3Sym { +# CHECK: Kind: S_COMPILE3 (0x113C) +# CHECK: } +# CHECK: ] +# CHECK: Subsection [ +# CHECK: SubSectionType: FrameData (0xF5) +# CHECK: FrameData { +# CHECK: FrameFunc [ +# CHECK: $T0 .raSearch = +# CHECK: $eip $T0 ^ = +# CHECK: $esp $T0 4 + = +# CHECK: ] +# CHECK: } +# CHECK: FrameData { +# CHECK: FrameFunc [ +# CHECK: $T0 .raSearch = +# CHECK: $eip $T0 ^ = +# CHECK: $esp $T0 4 + = +# CHECK: $ebp $T0 4 - ^ = +# CHECK: ] +# CHECK: } +# CHECK: FrameData { +# CHECK: FrameFunc [ +# CHECK: $T0 $ebp 4 + = +# CHECK: $eip $T0 ^ = +# CHECK: $esp $T0 4 + = +# CHECK: $ebp $T0 4 - ^ = +# CHECK: ] +# CHECK: } +# CHECK: FrameData { +# CHECK: FrameFunc [ +# CHECK: $T0 $ebp 4 + = +# CHECK: $eip $T0 ^ = +# CHECK: $esp $T0 4 + = +# CHECK: $ebp $T0 4 - ^ = +# CHECK: $edi $T0 8 - ^ = +# CHECK: ] +# CHECK: } +# CHECK: FrameData { +# CHECK: FrameFunc [ +# CHECK: $T0 $ebp 4 + = +# CHECK: $eip $T0 ^ = +# CHECK: $esp $T0 4 + = +# CHECK: $ebp $T0 4 - ^ = +# CHECK: $edi $T0 8 - ^ = +# CHECK: $esi $T0 12 - ^ = +# CHECK: ] +# CHECK: } +# CHECK: FrameData { +# CHECK: FrameFunc [ +# CHECK: $T1 $ebp 4 + = +# CHECK: $T0 $T1 12 - 8 @ = +# CHECK: $eip $T1 ^ = +# CHECK: $esp $T1 4 + = +# CHECK: $ebp $T1 4 - ^ = +# CHECK: $edi $T1 8 - ^ = +# CHECK: $esi $T1 12 - ^ = +# CHECK: ] +# CHECK: } +# CHECK: ] +# CHECK: Subsection [ +# CHECK: SubSectionType: Symbols (0xF1) +# CHECK: ] +# CHECK: Subsection [ +# CHECK: SubSectionType: FileChecksums (0xF4) +# CHECK: ] +# CHECK: Subsection [ +# CHECK: SubSectionType: StringTable (0xF3) +# CHECK: ] + + .text + .def _realign_with_csrs; .scl 2; .type 32; .endef + .globl _realign_with_csrs # -- Begin function realign_with_csrs +_realign_with_csrs: # @realign_with_csrs +Lfunc_begin0: + .cv_func_id 0 + .cv_file 1 "C:\\src\\llvm-project\\build\\t.c" "2A4F9B6BBBF7845521201755D1B14ACC" 1 + .cv_loc 0 1 4 0 # t.c:4:0 + .cv_fpo_proc _realign_with_csrs 0 +# %bb.0: # %entry + pushl %ebp + .cv_fpo_pushreg %ebp + movl %esp, %ebp + .cv_fpo_setframe %ebp +Ltmp0: + pushl %edi + .cv_fpo_pushreg %edi + pushl %esi + .cv_fpo_pushreg %esi + andl $-8, %esp + .cv_fpo_stackalign 8 + subl $8, %esp + .cv_fpo_stackalloc 8 + .cv_fpo_endprologue + .cv_loc 0 1 5 0 # t.c:5:0 + calll _getval + movl %eax, %esi + .cv_loc 0 1 6 0 # t.c:6:0 + calll _getval + movl %eax, %edi + movl %esp, %eax + .cv_loc 0 1 7 0 # t.c:7:0 + movl $1071309127, 4(%esp) # imm = 0x3FDAE147 + movl $-1374389535, (%esp) # imm = 0xAE147AE1 + .cv_loc 0 1 8 0 # t.c:8:0 + pushl %eax + pushl %edi + pushl %esi + calll _usevals + addl $12, %esp + .cv_loc 0 1 9 0 # t.c:9:0 + addl %esi, %edi + movl %edi, %eax + leal -8(%ebp), %esp + popl %esi + popl %edi + popl %ebp + retl +Ltmp1: + .cv_fpo_endproc +Lfunc_end0: + # -- End function + .section .debug$S,"dr" + .p2align 2 + .long 4 # Debug section magic + .long 241 + .long Ltmp3-Ltmp2 # Subsection size +Ltmp2: + .short Ltmp5-Ltmp4 # Record length +Ltmp4: + .short 4412 # Record kind: S_COMPILE3 + .long 0 # Flags and language + .short 7 # CPUType + .short 8 # Frontend version + .short 0 + .short 0 + .short 0 + .short 8000 # Backend version + .short 0 + .short 0 + .short 0 + .asciz "clang version 8.0.0 " # Null-terminated compiler version string +Ltmp5: +Ltmp3: + .p2align 2 + .cv_fpo_data _realign_with_csrs + .long 241 # Symbol subsection for realign_with_csrs + .long Ltmp7-Ltmp6 # Subsection size +Ltmp6: + .short Ltmp9-Ltmp8 # Record length +Ltmp8: + .short 4423 # Record kind: S_GPROC32_ID + .long 0 # PtrParent + .long 0 # PtrEnd + .long 0 # PtrNext + .long Lfunc_end0-_realign_with_csrs # Code size + .long 0 # Offset after prologue + .long 0 # Offset before epilogue + .long 0 # Function type index + .secrel32 _realign_with_csrs # Function section relative address + .secidx _realign_with_csrs # Function section index + .byte 0 # Flags + .asciz "realign_with_csrs" # Function name +Ltmp9: + .short Ltmp11-Ltmp10 # Record length +Ltmp10: + .short 4114 # Record kind: S_FRAMEPROC + .long 12 # FrameSize + .long 0 # Padding + .long 0 # Offset of padding + .long 8 # Bytes of callee saved registers + .long 0 # Exception handler offset + .short 0 # Exception handler section + .long 1196032 # Flags (defines frame register) +Ltmp11: + .short 2 # Record length + .short 4431 # Record kind: S_PROC_ID_END +Ltmp7: + .p2align 2 + .cv_filechecksums # File index to string table offset subsection + .cv_stringtable # String table |

