[llvm] r343603 - [codeview] Fix 32-bit x86 variable locations in realigned stack frames
Reid Kleckner via llvm-commits
llvm-commits at lists.llvm.org
Tue Oct 2 09:43:53 PDT 2018
Author: rnk
Date: Tue Oct 2 09:43:52 2018
New Revision: 343603
URL: http://llvm.org/viewvc/llvm-project?rev=343603&view=rev
Log:
[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
Added:
llvm/trunk/test/DebugInfo/COFF/fpo-realign-vframe.ll
llvm/trunk/test/MC/COFF/cv-fpo-realign.s
Modified:
llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.h
llvm/trunk/lib/Target/X86/AsmParser/X86AsmParser.cpp
llvm/trunk/lib/Target/X86/MCTargetDesc/X86TargetStreamer.h
llvm/trunk/lib/Target/X86/MCTargetDesc/X86WinCOFFTargetStreamer.cpp
llvm/trunk/lib/Target/X86/X86FrameLowering.cpp
llvm/trunk/lib/Target/X86/X86InstrCompiler.td
llvm/trunk/lib/Target/X86/X86MCInstLower.cpp
llvm/trunk/test/DebugInfo/COFF/fpo-realign-alloca.ll
Modified: llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp?rev=343603&r1=343602&r2=343603&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp Tue Oct 2 09:43:52 2018
@@ -1255,6 +1255,7 @@ void CodeViewDebug::beginFunctionImpl(co
// 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(co
} 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(co
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
Modified: llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.h?rev=343603&r1=343602&r2=343603&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.h (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.h Tue Oct 2 09:43:52 2018
@@ -165,6 +165,8 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDe
codeview::FrameProcedureOptions FrameProcOpts;
+ bool HasStackRealignment = false;
+
bool HaveLineInfo = false;
};
FunctionInfo *CurFn = nullptr;
Modified: llvm/trunk/lib/Target/X86/AsmParser/X86AsmParser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/AsmParser/X86AsmParser.cpp?rev=343603&r1=343602&r2=343603&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/AsmParser/X86AsmParser.cpp (original)
+++ llvm/trunk/lib/Target/X86/AsmParser/X86AsmParser.cpp Tue Oct 2 09:43:52 2018
@@ -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(AsmTok
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::parseDirectiveFPOStac
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();
Modified: llvm/trunk/lib/Target/X86/MCTargetDesc/X86TargetStreamer.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/MCTargetDesc/X86TargetStreamer.h?rev=343603&r1=343602&r2=343603&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/MCTargetDesc/X86TargetStreamer.h (original)
+++ llvm/trunk/lib/Target/X86/MCTargetDesc/X86TargetStreamer.h Tue Oct 2 09:43:52 2018
@@ -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;
};
Modified: llvm/trunk/lib/Target/X86/MCTargetDesc/X86WinCOFFTargetStreamer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/MCTargetDesc/X86WinCOFFTargetStreamer.cpp?rev=343603&r1=343602&r2=343603&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/MCTargetDesc/X86WinCOFFTargetStreamer.cpp (original)
+++ llvm/trunk/lib/Target/X86/MCTargetDesc/X86WinCOFFTargetStreamer.cpp Tue Oct 2 09:43:52 2018
@@ -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::emitFP
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::emitFPOSt
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::emitFrameDataRecor
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::emitFPODa
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;
Modified: llvm/trunk/lib/Target/X86/X86FrameLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86FrameLowering.cpp?rev=343603&r1=343602&r2=343603&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/X86FrameLowering.cpp (original)
+++ llvm/trunk/lib/Target/X86/X86FrameLowering.cpp Tue Oct 2 09:43:52 2018
@@ -1208,6 +1208,13 @@ void X86FrameLowering::emitPrologue(Mach
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
Modified: llvm/trunk/lib/Target/X86/X86InstrCompiler.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86InstrCompiler.td?rev=343603&r1=343602&r2=343603&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/X86InstrCompiler.td (original)
+++ llvm/trunk/lib/Target/X86/X86InstrCompiler.td Tue Oct 2 09:43:52 2018
@@ -240,6 +240,8 @@ let isPseudo = 1, SchedRW = [WriteSystem
"#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),
Modified: llvm/trunk/lib/Target/X86/X86MCInstLower.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86MCInstLower.cpp?rev=343603&r1=343602&r2=343603&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/X86MCInstLower.cpp (original)
+++ llvm/trunk/lib/Target/X86/X86MCInstLower.cpp Tue Oct 2 09:43:52 2018
@@ -1532,6 +1532,9 @@ void X86AsmPrinter::EmitSEHInstruction(c
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(cons
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:
Modified: llvm/trunk/test/DebugInfo/COFF/fpo-realign-alloca.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/COFF/fpo-realign-alloca.ll?rev=343603&r1=343602&r2=343603&view=diff
==============================================================================
--- llvm/trunk/test/DebugInfo/COFF/fpo-realign-alloca.ll (original)
+++ llvm/trunk/test/DebugInfo/COFF/fpo-realign-alloca.ll Tue Oct 2 09:43:52 2018
@@ -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
Added: llvm/trunk/test/DebugInfo/COFF/fpo-realign-vframe.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/COFF/fpo-realign-vframe.ll?rev=343603&view=auto
==============================================================================
--- llvm/trunk/test/DebugInfo/COFF/fpo-realign-vframe.ll (added)
+++ llvm/trunk/test/DebugInfo/COFF/fpo-realign-vframe.ll Tue Oct 2 09:43:52 2018
@@ -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)
Added: llvm/trunk/test/MC/COFF/cv-fpo-realign.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/COFF/cv-fpo-realign.s?rev=343603&view=auto
==============================================================================
--- llvm/trunk/test/MC/COFF/cv-fpo-realign.s (added)
+++ llvm/trunk/test/MC/COFF/cv-fpo-realign.s Tue Oct 2 09:43:52 2018
@@ -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
More information about the llvm-commits
mailing list