[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