OSDN Git Service

[codeview] Emit S_FRAMEPROC and use S_DEFRANGE_FRAMEPOINTER_REL
authorReid Kleckner <rnk@google.com>
Mon, 1 Oct 2018 21:59:45 +0000 (21:59 +0000)
committerReid Kleckner <rnk@google.com>
Mon, 1 Oct 2018 21:59:45 +0000 (21:59 +0000)
Summary:
Before this change, LLVM would always describe locals on the stack as
being relative to some specific register, RSP, ESP, EBP, ESI, etc.
Variables in stack memory are pretty common, so there is a special
S_DEFRANGE_FRAMEPOINTER_REL symbol for them. This change uses it to
reduce the size of our debug info.

On top of the size savings, there are cases on 32-bit x86 where local
variables are addressed from ESP, but ESP changes across the function.
Unlike in DWARF, there is no FPO data to describe the stack adjustments
made to push arguments onto the stack and pop them off after the call,
which makes it hard for the debugger to find the local variables in
frames further up the stack.

To handle this, CodeView has a special VFRAME register, which
corresponds to the $T0 variable set by our FPO data in 32-bit.  Offsets
to local variables are instead relative to this value.

This is part of PR38857.

Reviewers: hans, zturner, javed.absar

Subscribers: aprantl, hiraditya, JDevlieghere, llvm-commits

Differential Revision: https://reviews.llvm.org/D52217

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@343543 91177308-0d34-0410-b5e6-96231b3b80d8

23 files changed:
include/llvm/CodeGen/MIRYamlMapping.h
include/llvm/CodeGen/MachineFrameInfo.h
include/llvm/DebugInfo/CodeView/CodeView.h
include/llvm/DebugInfo/CodeView/SymbolRecord.h
lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
lib/CodeGen/AsmPrinter/CodeViewDebug.h
lib/CodeGen/MIRParser/MIRParser.cpp
lib/CodeGen/MIRPrinter.cpp
lib/DebugInfo/CodeView/SymbolRecordMapping.cpp
lib/Target/X86/X86FrameLowering.cpp
test/CodeGen/MIR/Generic/frame-info.mir
test/CodeGen/MIR/X86/diexpr-win32.mir
test/DebugInfo/COFF/asm.ll
test/DebugInfo/COFF/frameproc-flags.ll [new file with mode: 0644]
test/DebugInfo/COFF/local-variables.ll
test/DebugInfo/COFF/multifile.ll
test/DebugInfo/COFF/multifunction.ll
test/DebugInfo/COFF/pieces.ll
test/DebugInfo/COFF/simple.ll
test/DebugInfo/COFF/types-array.ll
test/DebugInfo/COFF/vframe-fpo.ll [new file with mode: 0644]
test/DebugInfo/X86/dbg-declare-inalloca.ll
test/MC/ARM/coff-debugging-secrel.ll

index 7f46406..dc90575 100644 (file)
@@ -425,6 +425,7 @@ struct MachineFrameInfo {
   StringValue StackProtector;
   // TODO: Serialize FunctionContextIdx
   unsigned MaxCallFrameSize = ~0u; ///< ~0u means: not computed yet.
+  unsigned CVBytesOfCalleeSavedRegisters = 0;
   bool HasOpaqueSPAdjustment = false;
   bool HasVAStart = false;
   bool HasMustTailInVarArgFunc = false;
@@ -443,6 +444,8 @@ struct MachineFrameInfo {
            AdjustsStack == Other.AdjustsStack && HasCalls == Other.HasCalls &&
            StackProtector == Other.StackProtector &&
            MaxCallFrameSize == Other.MaxCallFrameSize &&
+           CVBytesOfCalleeSavedRegisters ==
+               Other.CVBytesOfCalleeSavedRegisters &&
            HasOpaqueSPAdjustment == Other.HasOpaqueSPAdjustment &&
            HasVAStart == Other.HasVAStart &&
            HasMustTailInVarArgFunc == Other.HasMustTailInVarArgFunc &&
@@ -465,6 +468,8 @@ template <> struct MappingTraits<MachineFrameInfo> {
     YamlIO.mapOptional("stackProtector", MFI.StackProtector,
                        StringValue()); // Don't print it out when it's empty.
     YamlIO.mapOptional("maxCallFrameSize", MFI.MaxCallFrameSize, (unsigned)~0);
+    YamlIO.mapOptional("cvBytesOfCalleeSavedRegisters",
+                       MFI.CVBytesOfCalleeSavedRegisters, 0U);
     YamlIO.mapOptional("hasOpaqueSPAdjustment", MFI.HasOpaqueSPAdjustment,
                        false);
     YamlIO.mapOptional("hasVAStart", MFI.HasVAStart, false);
index 2d6081f..02b2f1b 100644 (file)
@@ -266,6 +266,10 @@ private:
   /// It is only valid during and after prolog/epilog code insertion.
   unsigned MaxCallFrameSize = ~0u;
 
+  /// The number of bytes of callee saved registers that the target wants to
+  /// report for the current function in the CodeView S_FRAMEPROC record.
+  unsigned CVBytesOfCalleeSavedRegisters = 0;
+
   /// The prolog/epilog code inserter fills in this vector with each
   /// callee saved register saved in the frame.  Beyond its use by the prolog/
   /// epilog code inserter, this data used for debug info and exception
@@ -603,6 +607,15 @@ public:
   }
   void setMaxCallFrameSize(unsigned S) { MaxCallFrameSize = S; }
 
+  /// Returns how many bytes of callee-saved registers the target pushed in the
+  /// prologue. Only used for debug info.
+  unsigned getCVBytesOfCalleeSavedRegisters() const {
+    return CVBytesOfCalleeSavedRegisters;
+  }
+  void setCVBytesOfCalleeSavedRegisters(unsigned S) {
+    CVBytesOfCalleeSavedRegisters = S;
+  }
+
   /// Create a new object at a fixed location on the stack.
   /// All fixed objects should be created before other objects are created for
   /// efficiency. By default, fixed objects are not pointed to by LLVM IR
index fd2a665..4b96bc1 100644 (file)
@@ -512,6 +512,19 @@ enum class RegisterId : uint16_t {
 #undef CV_REGISTER
 };
 
+/// Two-bit value indicating which register is the designated frame pointer
+/// register. Appears in the S_FRAMEPROC record flags.
+enum class EncodedFramePtrReg : uint8_t {
+  None = 0,
+  StackPtr = 1,
+  FramePtr = 2,
+  BasePtr = 3,
+};
+
+RegisterId decodeFramePtrReg(EncodedFramePtrReg EncodedReg, CPUType CPU);
+
+EncodedFramePtrReg encodeFramePtrReg(RegisterId Reg, CPUType CPU);
+
 /// These values correspond to the THUNK_ORDINAL enumeration.
 enum class ThunkOrdinal : uint8_t {
   Standard,
index 039d390..bc7571b 100644 (file)
@@ -763,49 +763,19 @@ public:
 
   /// Extract the register this frame uses to refer to local variables.
   RegisterId getLocalFramePtrReg(CPUType CPU) const {
-    return decodeFramePtrReg((uint32_t(Flags) >> 14U) & 0x3U, CPU);
+    return decodeFramePtrReg(
+        EncodedFramePtrReg((uint32_t(Flags) >> 14U) & 0x3U), CPU);
   }
 
   /// Extract the register this frame uses to refer to parameters.
   RegisterId getParamFramePtrReg(CPUType CPU) const {
-    return decodeFramePtrReg((uint32_t(Flags) >> 16U) & 0x3U, CPU);
+    return decodeFramePtrReg(
+        EncodedFramePtrReg((uint32_t(Flags) >> 16U) & 0x3U), CPU);
   }
 
   uint32_t RecordOffset;
 
 private:
-  static RegisterId decodeFramePtrReg(uint32_t EncodedReg, CPUType CPU) {
-    assert(EncodedReg < 4);
-    switch (CPU) {
-    // FIXME: Add ARM and AArch64 variants here.
-    default:
-      break;
-    case CPUType::Intel8080:
-    case CPUType::Intel8086:
-    case CPUType::Intel80286:
-    case CPUType::Intel80386:
-    case CPUType::Intel80486:
-    case CPUType::Pentium:
-    case CPUType::PentiumPro:
-    case CPUType::Pentium3:
-      switch (EncodedReg) {
-      case 0: return RegisterId::NONE;
-      case 1: return RegisterId::VFRAME;
-      case 2: return RegisterId::EBP;
-      case 3: return RegisterId::EBX;
-      }
-      llvm_unreachable("bad encoding");
-    case CPUType::X64:
-      switch (EncodedReg) {
-      case 0: return RegisterId::NONE;
-      case 1: return RegisterId::RSP;
-      case 2: return RegisterId::RBP;
-      case 3: return RegisterId::R13;
-      }
-      llvm_unreachable("bad encoding");
-    }
-    return RegisterId::NONE;
-  }
 };
 
 // S_CALLSITEINFO
index f99b5c2..1c67d76 100644 (file)
@@ -31,6 +31,7 @@
 #include "llvm/BinaryFormat/Dwarf.h"
 #include "llvm/CodeGen/AsmPrinter.h"
 #include "llvm/CodeGen/LexicalScopes.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineInstr.h"
 #include "llvm/CodeGen/MachineModuleInfo.h"
@@ -93,6 +94,21 @@ using namespace llvm::codeview;
 static cl::opt<bool> EmitDebugGlobalHashes("emit-codeview-ghash-section",
                                            cl::ReallyHidden, cl::init(false));
 
+static CPUType mapArchToCVCPUType(Triple::ArchType Type) {
+  switch (Type) {
+  case Triple::ArchType::x86:
+    return CPUType::Pentium3;
+  case Triple::ArchType::x86_64:
+    return CPUType::X64;
+  case Triple::ArchType::thumb:
+    return CPUType::Thumb;
+  case Triple::ArchType::aarch64:
+    return CPUType::ARM64;
+  default:
+    report_fatal_error("target architecture doesn't map to a CodeView CPUType");
+  }
+}
+
 CodeViewDebug::CodeViewDebug(AsmPrinter *AP)
     : DebugHandlerBase(AP), OS(*Asm->OutStreamer), TypeTable(Allocator) {
   // If module doesn't have named metadata anchors or COFF debug section
@@ -102,9 +118,11 @@ CodeViewDebug::CodeViewDebug(AsmPrinter *AP)
     Asm = nullptr;
     return;
   }
-
   // Tell MMI that we have debug info.
   MMI->setDebugInfoAvailability(true);
+
+  TheCPU =
+      mapArchToCVCPUType(Triple(MMI->getModule()->getTargetTriple()).getArch());
 }
 
 StringRef CodeViewDebug::getFullFilepath(const DIFile *File) {
@@ -669,21 +687,6 @@ static Version parseVersion(StringRef Name) {
   return V;
 }
 
-static CPUType mapArchToCVCPUType(Triple::ArchType Type) {
-  switch (Type) {
-  case Triple::ArchType::x86:
-    return CPUType::Pentium3;
-  case Triple::ArchType::x86_64:
-    return CPUType::X64;
-  case Triple::ArchType::thumb:
-    return CPUType::Thumb;
-  case Triple::ArchType::aarch64:
-    return CPUType::ARM64;
-  default:
-    report_fatal_error("target architecture doesn't map to a CodeView CPUType");
-  }
-}
-
 void CodeViewDebug::emitCompilerInformation() {
   MCContext &Context = MMI->getContext();
   MCSymbol *CompilerBegin = Context.createTempSymbol(),
@@ -707,9 +710,7 @@ void CodeViewDebug::emitCompilerInformation() {
   OS.EmitIntValue(Flags, 4);
 
   OS.AddComment("CPUType");
-  CPUType CPU =
-      mapArchToCVCPUType(Triple(MMI->getModule()->getTargetTriple()).getArch());
-  OS.EmitIntValue(static_cast<uint64_t>(CPU), 2);
+  OS.EmitIntValue(static_cast<uint64_t>(TheCPU), 2);
 
   StringRef CompilerVersion = CU->getProducer();
   Version FrontVer = parseVersion(CompilerVersion);
@@ -801,7 +802,7 @@ void CodeViewDebug::emitInlinedCallSite(const FunctionInfo &FI,
 
   OS.EmitLabel(InlineEnd);
 
-  emitLocalVariableList(Site.InlinedLocals);
+  emitLocalVariableList(FI, Site.InlinedLocals);
 
   // Recurse on child inlined call sites before closing the scope.
   for (const DILocation *ChildSite : Site.ChildSites) {
@@ -970,7 +971,31 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV,
     emitNullTerminatedSymbolName(OS, FuncName);
     OS.EmitLabel(ProcRecordEnd);
 
-    emitLocalVariableList(FI.Locals);
+    MCSymbol *FrameProcBegin = MMI->getContext().createTempSymbol(),
+             *FrameProcEnd = MMI->getContext().createTempSymbol();
+    OS.AddComment("Record length");
+    OS.emitAbsoluteSymbolDiff(FrameProcEnd, FrameProcBegin, 2);
+    OS.EmitLabel(FrameProcBegin);
+    OS.AddComment("Record kind: S_FRAMEPROC");
+    OS.EmitIntValue(unsigned(SymbolKind::S_FRAMEPROC), 2);
+    // Subtract out the CSR size since MSVC excludes that and we include it.
+    OS.AddComment("FrameSize");
+    OS.EmitIntValue(FI.FrameSize - FI.CSRSize, 4);
+    OS.AddComment("Padding");
+    OS.EmitIntValue(0, 4);
+    OS.AddComment("Offset of padding");
+    OS.EmitIntValue(0, 4);
+    OS.AddComment("Bytes of callee saved registers");
+    OS.EmitIntValue(FI.CSRSize, 4);
+    OS.AddComment("Exception handler offset");
+    OS.EmitIntValue(0, 4);
+    OS.AddComment("Exception handler section");
+    OS.EmitIntValue(0, 2);
+    OS.AddComment("Flags (defines frame register)");
+    OS.EmitIntValue(uint32_t(FI.FrameProcOpts), 4);
+    OS.EmitLabel(FrameProcEnd);
+
+    emitLocalVariableList(FI, FI.Locals);
     emitLexicalBlockList(FI.ChildBlocks, FI);
 
     // Emit inlined call site information. Only emit functions inlined directly
@@ -1215,6 +1240,9 @@ void CodeViewDebug::collectVariableInfo(const DISubprogram *SP) {
 }
 
 void CodeViewDebug::beginFunctionImpl(const MachineFunction *MF) {
+  const TargetSubtargetInfo &TSI = MF->getSubtarget();
+  const TargetRegisterInfo *TRI = TSI.getRegisterInfo();
+  const MachineFrameInfo &MFI = MF->getFrameInfo();
   const Function &GV = MF->getFunction();
   auto Insertion = FnDebugInfo.insert({&GV, llvm::make_unique<FunctionInfo>()});
   assert(Insertion.second && "function already has info");
@@ -1222,6 +1250,64 @@ void CodeViewDebug::beginFunctionImpl(const MachineFunction *MF) {
   CurFn->FuncId = NextFuncId++;
   CurFn->Begin = Asm->getFunctionBegin();
 
+  // The S_FRAMEPROC record reports the stack size, and how many bytes of
+  // callee-saved registers were used. For targets that don't use a PUSH
+  // instruction (AArch64), this will be zero.
+  CurFn->CSRSize = MFI.getCVBytesOfCalleeSavedRegisters();
+  CurFn->FrameSize = MFI.getStackSize();
+
+  // For this function S_FRAMEPROC record, figure out which codeview register
+  // will be the frame pointer.
+  CurFn->EncodedParamFramePtrReg = EncodedFramePtrReg::None; // None.
+  CurFn->EncodedLocalFramePtrReg = EncodedFramePtrReg::None; // None.
+  if (CurFn->FrameSize > 0) {
+    if (!TSI.getFrameLowering()->hasFP(*MF)) {
+      CurFn->EncodedLocalFramePtrReg = EncodedFramePtrReg::StackPtr;
+      CurFn->EncodedParamFramePtrReg = EncodedFramePtrReg::StackPtr;
+    } else {
+      // If there is an FP, parameters are always relative to it.
+      CurFn->EncodedParamFramePtrReg = EncodedFramePtrReg::FramePtr;
+      if (TRI->needsStackRealignment(*MF)) {
+        // If the stack needs realignment, locals are relative to SP or VFRAME.
+        CurFn->EncodedLocalFramePtrReg = EncodedFramePtrReg::StackPtr;
+      } else {
+        // Otherwise, locals are relative to EBP, and we probably have VLAs or
+        // other stack adjustments.
+        CurFn->EncodedLocalFramePtrReg = EncodedFramePtrReg::FramePtr;
+      }
+    }
+  }
+
+  // Compute other frame procedure options.
+  FrameProcedureOptions FPO = FrameProcedureOptions::None;
+  if (MFI.hasVarSizedObjects())
+    FPO |= FrameProcedureOptions::HasAlloca;
+  if (MF->exposesReturnsTwice())
+    FPO |= FrameProcedureOptions::HasSetJmp;
+  // FIXME: Set HasLongJmp if we ever track that info.
+  if (MF->hasInlineAsm())
+    FPO |= FrameProcedureOptions::HasInlineAssembly;
+  if (GV.hasPersonalityFn()) {
+    if (isAsynchronousEHPersonality(
+            classifyEHPersonality(GV.getPersonalityFn())))
+      FPO |= FrameProcedureOptions::HasStructuredExceptionHandling;
+    else
+      FPO |= FrameProcedureOptions::HasExceptionHandling;
+  }
+  if (GV.hasFnAttribute(Attribute::InlineHint))
+    FPO |= FrameProcedureOptions::MarkedInline;
+  if (GV.hasFnAttribute(Attribute::Naked))
+    FPO |= FrameProcedureOptions::Naked;
+  if (MFI.hasStackProtectorIndex())
+    FPO |= FrameProcedureOptions::SecurityChecks;
+  FPO |= FrameProcedureOptions(uint32_t(CurFn->EncodedLocalFramePtrReg) << 14U);
+  FPO |= FrameProcedureOptions(uint32_t(CurFn->EncodedParamFramePtrReg) << 16U);
+  if (Asm->TM.getOptLevel() != CodeGenOpt::None && !GV.optForSize() &&
+      !GV.hasFnAttribute(Attribute::OptimizeNone))
+    FPO |= FrameProcedureOptions::OptimizedForSpeed;
+  // FIXME: Set GuardCfg when it is implemented.
+  CurFn->FrameProcOpts = FPO;
+
   OS.EmitCVFuncIdDirective(CurFn->FuncId);
 
   // Find the end of the function prolog.  First known non-DBG_VALUE and
@@ -2347,7 +2433,8 @@ void CodeViewDebug::emitDeferredCompleteTypes() {
   }
 }
 
-void CodeViewDebug::emitLocalVariableList(ArrayRef<LocalVariable> Locals) {
+void CodeViewDebug::emitLocalVariableList(const FunctionInfo &FI,
+                                          ArrayRef<LocalVariable> Locals) {
   // Get the sorted list of parameters and emit them first.
   SmallVector<const LocalVariable *, 6> Params;
   for (const LocalVariable &L : Locals)
@@ -2357,15 +2444,16 @@ void CodeViewDebug::emitLocalVariableList(ArrayRef<LocalVariable> Locals) {
     return L->DIVar->getArg() < R->DIVar->getArg();
   });
   for (const LocalVariable *L : Params)
-    emitLocalVariable(*L);
+    emitLocalVariable(FI, *L);
 
   // Next emit all non-parameters in the order that we found them.
   for (const LocalVariable &L : Locals)
     if (!L.DIVar->isParameter())
-      emitLocalVariable(L);
+      emitLocalVariable(FI, L);
 }
 
-void CodeViewDebug::emitLocalVariable(const LocalVariable &Var) {
+void CodeViewDebug::emitLocalVariable(const FunctionInfo &FI,
+                                      const LocalVariable &Var) {
   // LocalSym record, see SymbolRecord.h for more info.
   MCSymbol *LocalBegin = MMI->getContext().createTempSymbol(),
            *LocalEnd = MMI->getContext().createTempSymbol();
@@ -2400,21 +2488,49 @@ void CodeViewDebug::emitLocalVariable(const LocalVariable &Var) {
   for (const LocalVarDefRange &DefRange : Var.DefRanges) {
     BytePrefix.clear();
     if (DefRange.InMemory) {
-      uint16_t RegRelFlags = 0;
-      if (DefRange.IsSubfield) {
-        RegRelFlags = DefRangeRegisterRelSym::IsSubfieldFlag |
-                      (DefRange.StructOffset
-                       << DefRangeRegisterRelSym::OffsetInParentShift);
+      int Offset = DefRange.DataOffset;
+      unsigned Reg = DefRange.CVRegister;
+
+      // 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.
+      if (RegisterId(Reg) == RegisterId::ESP) {
+        Reg = unsigned(RegisterId::VFRAME);
+        Offset -= FI.FrameSize;
+      }
+
+      // If we can use the chosen frame pointer for the frame and this isn't a
+      // sliced aggregate, use the smaller S_DEFRANGE_FRAMEPOINTER_REL record.
+      // Otherwise, use S_DEFRANGE_REGISTER_REL.
+      EncodedFramePtrReg EncFP = encodeFramePtrReg(RegisterId(Reg), TheCPU);
+      if (!DefRange.IsSubfield && EncFP != EncodedFramePtrReg::None &&
+          (bool(Flags & LocalSymFlags::IsParameter)
+               ? (EncFP == FI.EncodedParamFramePtrReg)
+               : (EncFP == FI.EncodedLocalFramePtrReg))) {
+        ulittle16_t SymKind = ulittle16_t(S_DEFRANGE_FRAMEPOINTER_REL);
+        little32_t FPOffset = little32_t(Offset);
+        BytePrefix += StringRef(reinterpret_cast<const char *>(&SymKind),
+                                sizeof(SymKind));
+        BytePrefix += StringRef(reinterpret_cast<const char *>(&FPOffset),
+                                sizeof(FPOffset));
+      } else {
+        uint16_t RegRelFlags = 0;
+        if (DefRange.IsSubfield) {
+          RegRelFlags = DefRangeRegisterRelSym::IsSubfieldFlag |
+                        (DefRange.StructOffset
+                         << DefRangeRegisterRelSym::OffsetInParentShift);
+        }
+        DefRangeRegisterRelSym::Header DRHdr;
+        DRHdr.Register = Reg;
+        DRHdr.Flags = RegRelFlags;
+        DRHdr.BasePointerOffset = Offset;
+        ulittle16_t SymKind = ulittle16_t(S_DEFRANGE_REGISTER_REL);
+        BytePrefix += StringRef(reinterpret_cast<const char *>(&SymKind),
+                                sizeof(SymKind));
+        BytePrefix += StringRef(reinterpret_cast<const char *>(&DRHdr),
+                                sizeof(DRHdr));
       }
-      DefRangeRegisterRelSym Sym(S_DEFRANGE_REGISTER_REL);
-      Sym.Hdr.Register = DefRange.CVRegister;
-      Sym.Hdr.Flags = RegRelFlags;
-      Sym.Hdr.BasePointerOffset = DefRange.DataOffset;
-      ulittle16_t SymKind = ulittle16_t(S_DEFRANGE_REGISTER_REL);
-      BytePrefix +=
-          StringRef(reinterpret_cast<const char *>(&SymKind), sizeof(SymKind));
-      BytePrefix +=
-          StringRef(reinterpret_cast<const char *>(&Sym.Hdr), sizeof(Sym.Hdr));
     } else {
       assert(DefRange.DataOffset == 0 && "unexpected offset into register");
       if (DefRange.IsSubfield) {
@@ -2479,7 +2595,7 @@ void CodeViewDebug::emitLexicalBlock(const LexicalBlock &Block,
   OS.EmitLabel(RecordEnd);
 
   // Emit variables local to this lexical block.
-  emitLocalVariableList(Block.Locals);
+  emitLocalVariableList(FI, Block.Locals);
 
   // Emit lexical blocks contained within this block.
   emitLexicalBlockList(Block.Children, FI);
index 6d7b97c..3836862 100644 (file)
@@ -54,6 +54,9 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
   BumpPtrAllocator Allocator;
   codeview::GlobalTypeTableBuilder TypeTable;
 
+  /// The codeview CPU type used by the translation unit.
+  codeview::CPUType TheCPU;
+
   /// Represents the most general definition range.
   struct LocalVarDefRange {
     /// Indicates that variable data is stored in memory relative to the
@@ -140,6 +143,28 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
     const MCSymbol *End = nullptr;
     unsigned FuncId = 0;
     unsigned LastFileId = 0;
+
+    /// Number of bytes allocated in the prologue for all local stack objects.
+    unsigned FrameSize = 0;
+
+    /// Number of bytes of parameters on the stack.
+    unsigned ParamSize = 0;
+
+    /// Number of bytes pushed to save CSRs.
+    unsigned CSRSize = 0;
+
+    /// Two-bit value indicating which register is the designated frame pointer
+    /// register for local variables. Included in S_FRAMEPROC.
+    codeview::EncodedFramePtrReg EncodedLocalFramePtrReg =
+        codeview::EncodedFramePtrReg::None;
+
+    /// Two-bit value indicating which register is the designated frame pointer
+    /// register for stack parameters. Included in S_FRAMEPROC.
+    codeview::EncodedFramePtrReg EncodedParamFramePtrReg =
+        codeview::EncodedFramePtrReg::None;
+
+    codeview::FrameProcedureOptions FrameProcOpts;
+
     bool HaveLineInfo = false;
   };
   FunctionInfo *CurFn = nullptr;
@@ -293,10 +318,11 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
   void recordLocalVariable(LocalVariable &&Var, const LexicalScope *LS);
 
   /// Emits local variables in the appropriate order.
-  void emitLocalVariableList(ArrayRef<LocalVariable> Locals);
+  void emitLocalVariableList(const FunctionInfo &FI,
+                             ArrayRef<LocalVariable> Locals);
 
   /// Emits an S_LOCAL record and its associated defined ranges.
-  void emitLocalVariable(const LocalVariable &Var);
+  void emitLocalVariable(const FunctionInfo &FI, const LocalVariable &Var);
 
   /// Emits a sequence of lexical block scopes and their children.
   void emitLexicalBlockList(ArrayRef<LexicalBlock *> Blocks,
index 3d2db97..0102f12 100644 (file)
@@ -580,6 +580,7 @@ bool MIRParserImpl::initializeFrameInfo(PerFunctionMIParsingState &PFS,
   MFI.setHasCalls(YamlMFI.HasCalls);
   if (YamlMFI.MaxCallFrameSize != ~0u)
     MFI.setMaxCallFrameSize(YamlMFI.MaxCallFrameSize);
+  MFI.setCVBytesOfCalleeSavedRegisters(YamlMFI.CVBytesOfCalleeSavedRegisters);
   MFI.setHasOpaqueSPAdjustment(YamlMFI.HasOpaqueSPAdjustment);
   MFI.setHasVAStart(YamlMFI.HasVAStart);
   MFI.setHasMustTailInVarArgFunc(YamlMFI.HasMustTailInVarArgFunc);
index 20533f9..88e2f16 100644 (file)
@@ -328,6 +328,8 @@ void MIRPrinter::convert(ModuleSlotTracker &MST,
   YamlMFI.HasCalls = MFI.hasCalls();
   YamlMFI.MaxCallFrameSize = MFI.isMaxCallFrameSizeComputed()
     ? MFI.getMaxCallFrameSize() : ~0u;
+  YamlMFI.CVBytesOfCalleeSavedRegisters =
+      MFI.getCVBytesOfCalleeSavedRegisters();
   YamlMFI.HasOpaqueSPAdjustment = MFI.hasOpaqueSPAdjustment();
   YamlMFI.HasVAStart = MFI.hasVAStart();
   YamlMFI.HasMustTailInVarArgFunc = MFI.hasMustTailInVarArgFunc();
index e77c8e8..e73c69f 100644 (file)
@@ -471,3 +471,75 @@ Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
 
   return Error::success();
 }
+
+RegisterId codeview::decodeFramePtrReg(EncodedFramePtrReg EncodedReg,
+                                       CPUType CPU) {
+  assert(unsigned(EncodedReg) < 4);
+  switch (CPU) {
+  // FIXME: Add ARM and AArch64 variants here.
+  default:
+    break;
+  case CPUType::Intel8080:
+  case CPUType::Intel8086:
+  case CPUType::Intel80286:
+  case CPUType::Intel80386:
+  case CPUType::Intel80486:
+  case CPUType::Pentium:
+  case CPUType::PentiumPro:
+  case CPUType::Pentium3:
+    switch (EncodedReg) {
+    case EncodedFramePtrReg::None:     return RegisterId::NONE;
+    case EncodedFramePtrReg::StackPtr: return RegisterId::VFRAME;
+    case EncodedFramePtrReg::FramePtr: return RegisterId::EBP;
+    case EncodedFramePtrReg::BasePtr:  return RegisterId::EBX;
+    }
+    llvm_unreachable("bad encoding");
+  case CPUType::X64:
+    switch (EncodedReg) {
+    case EncodedFramePtrReg::None:     return RegisterId::NONE;
+    case EncodedFramePtrReg::StackPtr: return RegisterId::RSP;
+    case EncodedFramePtrReg::FramePtr: return RegisterId::RBP;
+    case EncodedFramePtrReg::BasePtr:  return RegisterId::R13;
+    }
+    llvm_unreachable("bad encoding");
+  }
+  return RegisterId::NONE;
+}
+
+EncodedFramePtrReg codeview::encodeFramePtrReg(RegisterId Reg, CPUType CPU) {
+  switch (CPU) {
+  // FIXME: Add ARM and AArch64 variants here.
+  default:
+    break;
+  case CPUType::Intel8080:
+  case CPUType::Intel8086:
+  case CPUType::Intel80286:
+  case CPUType::Intel80386:
+  case CPUType::Intel80486:
+  case CPUType::Pentium:
+  case CPUType::PentiumPro:
+  case CPUType::Pentium3:
+    switch (Reg) {
+    case RegisterId::VFRAME:
+      return EncodedFramePtrReg::StackPtr;
+    case RegisterId::EBP:
+      return EncodedFramePtrReg::FramePtr;
+    case RegisterId::EBX:
+      return EncodedFramePtrReg::BasePtr;
+    default:
+      break;
+    }
+  case CPUType::X64:
+    switch (Reg) {
+    case RegisterId::RSP:
+      return EncodedFramePtrReg::StackPtr;
+    case RegisterId::RBP:
+      return EncodedFramePtrReg::FramePtr;
+    case RegisterId::R13:
+      return EncodedFramePtrReg::BasePtr;
+    default:
+      break;
+    }
+  }
+  return EncodedFramePtrReg::None;
+}
index 46e30d7..2d660ac 100644 (file)
@@ -1983,6 +1983,7 @@ bool X86FrameLowering::assignCalleeSavedSpillSlots(
   }
 
   X86FI->setCalleeSavedFrameSize(CalleeSavedFrameSize);
+  MFI.setCVBytesOfCalleeSavedRegisters(CalleeSavedFrameSize);
 
   // Assign slots for XMMs.
   for (unsigned i = CSI.size(); i != 0; --i) {
index 24c0ccd..e25bdcf 100644 (file)
@@ -38,6 +38,7 @@ tracksRegLiveness: true
 # CHECK-NEXT: hasCalls: false
 # CHECK-NEXT: stackProtector:  ''
 # CHECK-NEXT: maxCallFrameSize:
+# CHECK-NEXT: cvBytesOfCalleeSavedRegisters: 0
 # CHECK-NEXT: hasOpaqueSPAdjustment: false
 # CHECK-NEXT: hasVAStart: false
 # CHECK-NEXT: hasMustTailInVarArgFunc: false
@@ -68,6 +69,7 @@ tracksRegLiveness: true
 # CHECK-NEXT: hasCalls: true
 # CHECK-NEXT: stackProtector:  ''
 # CHECK-NEXT: maxCallFrameSize: 4
+# CHECK-NEXT: cvBytesOfCalleeSavedRegisters: 8
 # CHECK-NEXT: hasOpaqueSPAdjustment: true
 # CHECK-NEXT: hasVAStart: true
 # CHECK-NEXT: hasMustTailInVarArgFunc: true
@@ -83,6 +85,7 @@ frameInfo:
   adjustsStack:    true
   hasCalls:        true
   maxCallFrameSize: 4
+  cvBytesOfCalleeSavedRegisters: 8
   hasOpaqueSPAdjustment: true
   hasVAStart:      true
   hasMustTailInVarArgFunc: true
index f8612bb..3388ef7 100644 (file)
@@ -1,5 +1,10 @@
 # RUN: llc -start-after=prologepilog -filetype=obj -O0 %s -o - | llvm-readobj -codeview | FileCheck %s
-#
+
+# Offsets are now CFA, or VFRAME, relative. Both the NRVO sret pointer and the
+# string* parameter are on the stack, NRVO at offset 4 (after RA), and Str at
+# offset 8 (next slot). The stack size is 4, so the DW_OP_plus_uconst math
+# works out.
+
 # (DW_OP_plus_uconst 12)
 # CHECK: LocalSym {
 # CHECK-NEXT:   Kind: S_LOCAL (0x113E)
@@ -8,12 +13,9 @@
 # CHECK-NEXT:   ]
 # CHECK-NEXT:   VarName: Str
 # CHECK-NEXT: }
-# CHECK-NEXT: DefRangeRegisterRelSym {
-# CHECK-NEXT:   Kind: S_DEFRANGE_REGISTER_REL (0x1145)
-# CHECK-NEXT:   BaseRegister:
-# CHECK-NEXT:   HasSpilledUDTMember: No
-# CHECK-NEXT:   OffsetInParent: 0
-# CHECK-NEXT:   BasePointerOffset: 12
+# CHECK-NEXT: DefRangeFramePointerRelSym {
+# CHECK-NEXT:   Kind: S_DEFRANGE_FRAMEPOINTER_REL (0x1142)
+# CHECK-NEXT:   Offset: 8
 # CHECK-NEXT:   LocalVariableAddrRange {
 # CHECK-NEXT:     OffsetStart:
 # CHECK-NEXT:     ISectStart:
 # CHECK-NEXT:   ]
 # CHECK-NEXT:   VarName: Result
 # CHECK-NEXT: }
-# CHECK-NEXT: DefRangeRegisterRelSym {
-# CHECK-NEXT:   Kind: S_DEFRANGE_REGISTER_REL (0x1145)
-# CHECK-NEXT:   BaseRegister:
-# CHECK-NEXT:   HasSpilledUDTMember: No
-# CHECK-NEXT:   OffsetInParent: 0
-# CHECK-NEXT:   BasePointerOffset: 8
+# CHECK-NEXT: DefRangeFramePointerRelSym {
+# CHECK-NEXT:   Kind: S_DEFRANGE_FRAMEPOINTER_REL (0x1142)
+# CHECK-NEXT:   Offset: 4
 # CHECK-NEXT:   LocalVariableAddrRange {
-# CHECK-NEXT:     OffsetStart:
-# CHECK-NEXT:     ISectStart:
-# CHECK-NEXT:     Range:
+# CHECK-NEXT:     OffsetStart: .text+0x5
+# CHECK-NEXT:     ISectStart: 0x0
+# CHECK-NEXT:     Range: 0x18
 # CHECK-NEXT:   }
 # CHECK-NEXT: }
 # (DW_OP_constu, 4, DW_OP_minus)
index fa2a258..ed71b24 100644 (file)
@@ -99,7 +99,7 @@
 ; OBJ64:          DisplayName: f
 ; OBJ64:          LinkageName: f
 ; OBJ64:        }
-; OBJ64-NEXT:   ProcEnd {
+; OBJ64:        ProcEnd {
 ; OBJ64:        }
 ; OBJ64-NEXT: ]
 ; OBJ64:      FunctionLineTable [
diff --git a/test/DebugInfo/COFF/frameproc-flags.ll b/test/DebugInfo/COFF/frameproc-flags.ll
new file mode 100644 (file)
index 0000000..a9d0fe0
--- /dev/null
@@ -0,0 +1,379 @@
+; RUN: llc -filetype=obj %s -o %t.obj
+; RUN: llvm-pdbutil dump %t.obj -symbols | FileCheck %s
+
+; A fairly exhaustive test of S_FRAMEPROC flags. Use the source below to compare
+; the flags we set with MSVC.
+
+; extern "C" {
+;
+; void *_alloca(size_t);
+; struct __declspec(align(16)) _jmp_buf_str {
+;   unsigned __int64 Part[2];
+; };
+; typedef struct _jmp_buf_str jmp_buf[16];
+; int __cdecl _setjmp(jmp_buf _Buf);
+;
+; void may_throw(void);
+; void use_intptr(int *);
+;
+; void use_alloca(int n) {
+;   int *p = (int*)_alloca(n * sizeof(int));
+;   use_intptr(p);
+; }
+;
+; jmp_buf g_jbuf;
+; void call_setjmp(int n) {
+;   if (!_setjmp(g_jbuf))
+;     use_intptr(nullptr);
+; }
+;
+; void use_inlineasm() {
+;   __asm nop
+; }
+;
+; void cpp_eh() {
+;   try {
+;     may_throw();
+;   } catch (...) {
+;   }
+; }
+;
+; static inline int is_marked_inline(int x, int y) {
+;   return x + y;
+; }
+; int (*use_inline())(int x, int y) {
+;   return &is_marked_inline;
+; }
+;
+; void seh() {
+;   __try {
+;     may_throw();
+;   } __except (1) {
+;   }
+; }
+;
+; void __declspec(naked) use_naked() {
+;   __asm ret
+; }
+;
+; void stack_guard() {
+;   int arr[12] = {0};
+;   use_intptr(&arr[0]);
+; }
+; }
+
+; CHECK-LABEL: S_GPROC32_ID [size = 50] `use_alloca`
+; CHECK: S_FRAMEPROC [size = 30]
+; CHECK:   local fp reg = VFRAME, param fp reg = EBP
+; CHECK:   flags = has alloca | secure checks | opt speed
+; CHECK-LABEL: S_GPROC32_ID [size = 51] `call_setjmp`
+; CHECK: S_FRAMEPROC [size = 30]
+; CHECK:   local fp reg = NONE, param fp reg = NONE
+; CHECK:   flags = has setjmp | opt speed
+; CHECK-LABEL: S_GPROC32_ID [size = 53] `use_inlineasm`
+; CHECK: S_FRAMEPROC [size = 30]
+; CHECK:   local fp reg = NONE, param fp reg = NONE
+; CHECK:   flags = has inline asm | opt speed
+; CHECK-LABEL: S_GPROC32_ID [size = 46] `cpp_eh`
+; CHECK: S_FRAMEPROC [size = 30]
+; CHECK:   local fp reg = EBP, param fp reg = EBP
+; CHECK:   flags = has eh | opt speed
+; CHECK-LABEL: S_GPROC32_ID [size = 50] `use_inline`
+; CHECK: S_FRAMEPROC [size = 30]
+; CHECK:   local fp reg = NONE, param fp reg = NONE
+; CHECK:   flags = opt speed
+; CHECK-LABEL: S_LPROC32_ID [size = 56] `is_marked_inline`
+; CHECK: S_FRAMEPROC [size = 30]
+; CHECK:   local fp reg = NONE, param fp reg = NONE
+; CHECK:   flags = marked inline | opt speed
+; CHECK-LABEL: S_GPROC32_ID [size = 43] `seh`
+; CHECK: S_FRAMEPROC [size = 30]
+; CHECK:   local fp reg = EBP, param fp reg = EBP
+; CHECK:   flags = has seh | opt speed
+; CHECK-LABEL: S_LPROC32_ID [size = 55] `?filt$0@0@seh@@`
+; CHECK: S_FRAMEPROC [size = 30]
+; CHECK:   local fp reg = EBP, param fp reg = EBP
+; CHECK:   flags = opt speed
+; CHECK-LABEL: S_GPROC32_ID [size = 49] `use_naked`
+; CHECK: S_FRAMEPROC [size = 30]
+; CHECK:   local fp reg = NONE, param fp reg = NONE
+; CHECK:   flags = has inline asm | naked | opt speed
+; CHECK-LABEL: S_GPROC32_ID [size = 51] `stack_guard`
+; CHECK: S_FRAMEPROC [size = 30]
+; CHECK:   local fp reg = VFRAME, param fp reg = EBP
+; CHECK:   flags = secure checks | opt speed
+
+; ModuleID = 'frameproc-flags.cpp'
+source_filename = "frameproc-flags.cpp"
+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"
+
+%struct._jmp_buf_str = type { [2 x i64] }
+
+@g_jbuf = dso_local global [16 x %struct._jmp_buf_str] zeroinitializer, align 16, !dbg !0
+
+define dso_local void @use_alloca(i32 %n) local_unnamed_addr #0 !dbg !25 {
+entry:
+  call void @llvm.dbg.value(metadata i32 %n, metadata !29, metadata !DIExpression()), !dbg !31
+  %mul = shl i32 %n, 2, !dbg !32
+  %0 = alloca i8, i32 %mul, align 16, !dbg !32
+  %1 = bitcast i8* %0 to i32*, !dbg !32
+  call void @llvm.dbg.value(metadata i32* %1, metadata !30, metadata !DIExpression()), !dbg !32
+  call void @use_intptr(i32* nonnull %1), !dbg !33
+  ret void, !dbg !34
+}
+
+; 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 void @use_intptr(i32*) local_unnamed_addr #3
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #2
+
+define dso_local void @call_setjmp(i32 %n) local_unnamed_addr #0 !dbg !35 {
+entry:
+  call void @llvm.dbg.value(metadata i32 %n, metadata !37, metadata !DIExpression()), !dbg !38
+  %0 = call i32 (i8*, i32, ...) @_setjmp3(i8* bitcast ([16 x %struct._jmp_buf_str]* @g_jbuf to i8*), i32 0) #4, !dbg !39
+  %tobool = icmp eq i32 %0, 0, !dbg !39
+  br i1 %tobool, label %if.then, label %if.end, !dbg !39
+
+if.then:                                          ; preds = %entry
+  call void @use_intptr(i32* null), !dbg !40
+  br label %if.end, !dbg !40
+
+if.end:                                           ; preds = %entry, %if.then
+  ret void, !dbg !42
+}
+
+; Function Attrs: returns_twice
+declare dso_local i32 @_setjmp3(i8*, i32, ...) local_unnamed_addr #4
+
+; Function Attrs: nounwind
+define dso_local void @use_inlineasm() local_unnamed_addr #5 !dbg !43 {
+entry:
+  tail call void asm sideeffect inteldialect "nop", "~{dirflag},~{fpsr},~{flags}"() #10, !dbg !46, !srcloc !47
+  ret void, !dbg !48
+}
+
+define dso_local void @cpp_eh() local_unnamed_addr #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) !dbg !49 {
+entry:
+  invoke void @may_throw()
+          to label %try.cont unwind label %catch.dispatch, !dbg !50
+
+catch.dispatch:                                   ; preds = %entry
+  %0 = catchswitch within none [label %catch] unwind to caller, !dbg !52
+
+catch:                                            ; preds = %catch.dispatch
+  %1 = catchpad within %0 [i8* null, i32 64, i8* null], !dbg !52
+  catchret from %1 to label %try.cont, !dbg !53
+
+try.cont:                                         ; preds = %entry, %catch
+  ret void, !dbg !55
+}
+
+declare dso_local void @may_throw() local_unnamed_addr #3
+
+declare dso_local i32 @__CxxFrameHandler3(...)
+
+; Function Attrs: norecurse nounwind readnone
+define dso_local nonnull i32 (i32, i32)* @use_inline() local_unnamed_addr #6 !dbg !56 {
+entry:
+  ret i32 (i32, i32)* @"?is_marked_inline@@YAHHH@Z", !dbg !62
+}
+
+; Function Attrs: inlinehint nounwind readnone
+define internal i32 @"?is_marked_inline@@YAHHH@Z"(i32 %x, i32 %y) #7 !dbg !63 {
+entry:
+  call void @llvm.dbg.value(metadata i32 %y, metadata !65, metadata !DIExpression()), !dbg !67
+  call void @llvm.dbg.value(metadata i32 %x, metadata !66, metadata !DIExpression()), !dbg !67
+  %add = add nsw i32 %y, %x, !dbg !68
+  ret i32 %add, !dbg !68
+}
+
+define dso_local void @seh() #0 personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) !dbg !69 {
+entry:
+  %__exception_code = alloca i32, align 4
+  call void (...) @llvm.localescape(i32* nonnull %__exception_code)
+  invoke void @may_throw() #12
+          to label %__try.cont unwind label %catch.dispatch, !dbg !70
+
+catch.dispatch:                                   ; preds = %entry
+  %0 = catchswitch within none [label %__except.ret] unwind to caller, !dbg !72
+
+__except.ret:                                     ; preds = %catch.dispatch
+  %1 = catchpad within %0 [i8* bitcast (i32 ()* @"?filt$0@0@seh@@" to i8*)], !dbg !72
+  catchret from %1 to label %__try.cont, !dbg !72
+
+__try.cont:                                       ; preds = %entry, %__except.ret
+  ret void, !dbg !73
+}
+
+; Function Attrs: nounwind
+define internal i32 @"?filt$0@0@seh@@"() #8 !dbg !74 {
+entry:
+  %0 = tail call i8* @llvm.frameaddress(i32 1)
+  %1 = tail call i8* @llvm.x86.seh.recoverfp(i8* bitcast (void ()* @seh to i8*), i8* %0)
+  %2 = tail call i8* @llvm.localrecover(i8* bitcast (void ()* @seh to i8*), i8* %1, i32 0)
+  %__exception_code = bitcast i8* %2 to i32*
+  %3 = getelementptr inbounds i8, i8* %0, i32 -20, !dbg !76
+  %4 = bitcast i8* %3 to { i32*, i8* }**, !dbg !76
+  %5 = load { i32*, i8* }*, { i32*, i8* }** %4, align 4, !dbg !76
+  %6 = getelementptr inbounds { i32*, i8* }, { i32*, i8* }* %5, i32 0, i32 0, !dbg !76
+  %7 = load i32*, i32** %6, align 4, !dbg !76
+  %8 = load i32, i32* %7, align 4, !dbg !76
+  store i32 %8, i32* %__exception_code, align 4, !dbg !76
+  ret i32 1, !dbg !76
+}
+
+; Function Attrs: nounwind readnone
+declare i8* @llvm.frameaddress(i32) #9
+
+; Function Attrs: nounwind readnone
+declare i8* @llvm.x86.seh.recoverfp(i8*, i8*) #9
+
+; Function Attrs: nounwind readnone
+declare i8* @llvm.localrecover(i8*, i8*, i32) #9
+
+declare dso_local i32 @_except_handler3(...)
+
+; Function Attrs: nounwind
+declare void @llvm.localescape(...) #10
+
+; Function Attrs: naked noinline nounwind
+define dso_local void @use_naked() #11 !dbg !77 {
+entry:
+  tail call void asm sideeffect inteldialect "ret", "~{dirflag},~{fpsr},~{flags}"() #10, !dbg !78, !srcloc !79
+  unreachable, !dbg !80
+}
+
+define dso_local void @stack_guard() local_unnamed_addr #0 !dbg !81 {
+entry:
+  %arr = alloca [12 x i32], align 4
+  %0 = bitcast [12 x i32]* %arr to i8*, !dbg !87
+  call void @llvm.lifetime.start.p0i8(i64 48, i8* nonnull %0) #10, !dbg !87
+  call void @llvm.dbg.declare(metadata [12 x i32]* %arr, metadata !83, metadata !DIExpression()), !dbg !87
+  call void @llvm.memset.p0i8.i32(i8* nonnull align 4 %0, i8 0, i32 48, i1 false), !dbg !87
+  %arrayidx = getelementptr inbounds [12 x i32], [12 x i32]* %arr, i32 0, i32 0, !dbg !88
+  call void @use_intptr(i32* nonnull %arrayidx), !dbg !88
+  call void @llvm.lifetime.end.p0i8(i64 48, i8* nonnull %0) #10, !dbg !89
+  ret void, !dbg !89
+}
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.memset.p0i8.i32(i8* nocapture writeonly, i8, i32, i1) #2
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.value(metadata, metadata, metadata) #1
+
+attributes #0 = { sspstrong "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 = { returns_twice }
+attributes #5 = { 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 #6 = { norecurse nounwind readnone "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 #7 = { inlinehint nounwind readnone "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 #8 = { 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-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 #9 = { nounwind readnone }
+attributes #10 = { nounwind }
+attributes #11 = { naked noinline 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 #12 = { noinline }
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!20, !21, !22, !23}
+!llvm.ident = !{!24}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "g_jbuf", scope: !2, file: !3, line: 18, type: !9, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 8.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !8, nameTableKind: None)
+!3 = !DIFile(filename: "frameproc-flags.cpp", directory: "C:\5Csrc\5Cllvm-project\5Cbuild", checksumkind: CSK_MD5, checksum: "1dd66a71668512c95552767c3a35300a")
+!4 = !{}
+!5 = !{!6}
+!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 32)
+!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!8 = !{!0}
+!9 = !DIDerivedType(tag: DW_TAG_typedef, name: "jmp_buf", file: !3, line: 7, baseType: !10)
+!10 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 2048, elements: !18)
+!11 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "_jmp_buf_str", file: !3, line: 4, size: 128, align: 128, flags: DIFlagTypePassByValue | DIFlagTrivial, elements: !12, identifier: ".?AU_jmp_buf_str@@")
+!12 = !{!13}
+!13 = !DIDerivedType(tag: DW_TAG_member, name: "Part", scope: !11, file: !3, line: 5, baseType: !14, size: 128)
+!14 = !DICompositeType(tag: DW_TAG_array_type, baseType: !15, size: 128, elements: !16)
+!15 = !DIBasicType(name: "long long unsigned int", size: 64, encoding: DW_ATE_unsigned)
+!16 = !{!17}
+!17 = !DISubrange(count: 2)
+!18 = !{!19}
+!19 = !DISubrange(count: 16)
+!20 = !{i32 1, !"NumRegisterParameters", i32 0}
+!21 = !{i32 2, !"CodeView", i32 1}
+!22 = !{i32 2, !"Debug Info Version", i32 3}
+!23 = !{i32 1, !"wchar_size", i32 2}
+!24 = !{!"clang version 8.0.0 "}
+!25 = distinct !DISubprogram(name: "use_alloca", scope: !3, file: !3, line: 13, type: !26, isLocal: false, isDefinition: true, scopeLine: 13, flags: DIFlagPrototyped, isOptimized: true, unit: !2, retainedNodes: !28)
+!26 = !DISubroutineType(types: !27)
+!27 = !{null, !7}
+!28 = !{!29, !30}
+!29 = !DILocalVariable(name: "n", arg: 1, scope: !25, file: !3, line: 13, type: !7)
+!30 = !DILocalVariable(name: "p", scope: !25, file: !3, line: 14, type: !6)
+!31 = !DILocation(line: 13, scope: !25)
+!32 = !DILocation(line: 14, scope: !25)
+!33 = !DILocation(line: 15, scope: !25)
+!34 = !DILocation(line: 16, scope: !25)
+!35 = distinct !DISubprogram(name: "call_setjmp", scope: !3, file: !3, line: 19, type: !26, isLocal: false, isDefinition: true, scopeLine: 19, flags: DIFlagPrototyped, isOptimized: true, unit: !2, retainedNodes: !36)
+!36 = !{!37}
+!37 = !DILocalVariable(name: "n", arg: 1, scope: !35, file: !3, line: 19, type: !7)
+!38 = !DILocation(line: 19, scope: !35)
+!39 = !DILocation(line: 20, scope: !35)
+!40 = !DILocation(line: 21, scope: !41)
+!41 = distinct !DILexicalBlock(scope: !35, file: !3, line: 20)
+!42 = !DILocation(line: 22, scope: !35)
+!43 = distinct !DISubprogram(name: "use_inlineasm", scope: !3, file: !3, line: 24, type: !44, isLocal: false, isDefinition: true, scopeLine: 24, flags: DIFlagPrototyped, isOptimized: true, unit: !2, retainedNodes: !4)
+!44 = !DISubroutineType(types: !45)
+!45 = !{null}
+!46 = !DILocation(line: 25, scope: !43)
+!47 = !{i32 445}
+!48 = !DILocation(line: 26, scope: !43)
+!49 = distinct !DISubprogram(name: "cpp_eh", scope: !3, file: !3, line: 28, type: !44, isLocal: false, isDefinition: true, scopeLine: 28, flags: DIFlagPrototyped, isOptimized: true, unit: !2, retainedNodes: !4)
+!50 = !DILocation(line: 30, scope: !51)
+!51 = distinct !DILexicalBlock(scope: !49, file: !3, line: 29)
+!52 = !DILocation(line: 31, scope: !51)
+!53 = !DILocation(line: 32, scope: !54)
+!54 = distinct !DILexicalBlock(scope: !49, file: !3, line: 31)
+!55 = !DILocation(line: 33, scope: !49)
+!56 = distinct !DISubprogram(name: "use_inline", scope: !3, file: !3, line: 38, type: !57, isLocal: false, isDefinition: true, scopeLine: 38, flags: DIFlagPrototyped, isOptimized: true, unit: !2, retainedNodes: !4)
+!57 = !DISubroutineType(types: !58)
+!58 = !{!59}
+!59 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !60, size: 32)
+!60 = !DISubroutineType(types: !61)
+!61 = !{!7, !7, !7}
+!62 = !DILocation(line: 39, scope: !56)
+!63 = distinct !DISubprogram(name: "is_marked_inline", linkageName: "?is_marked_inline@@YAHHH@Z", scope: !3, file: !3, line: 35, type: !60, isLocal: true, isDefinition: true, scopeLine: 35, flags: DIFlagPrototyped, isOptimized: true, unit: !2, retainedNodes: !64)
+!64 = !{!65, !66}
+!65 = !DILocalVariable(name: "y", arg: 2, scope: !63, file: !3, line: 35, type: !7)
+!66 = !DILocalVariable(name: "x", arg: 1, scope: !63, file: !3, line: 35, type: !7)
+!67 = !DILocation(line: 35, scope: !63)
+!68 = !DILocation(line: 36, scope: !63)
+!69 = distinct !DISubprogram(name: "seh", scope: !3, file: !3, line: 42, type: !44, isLocal: false, isDefinition: true, scopeLine: 42, flags: DIFlagPrototyped, isOptimized: true, unit: !2, retainedNodes: !4)
+!70 = !DILocation(line: 44, scope: !71)
+!71 = distinct !DILexicalBlock(scope: !69, file: !3, line: 43)
+!72 = !DILocation(line: 45, scope: !71)
+!73 = !DILocation(line: 47, scope: !69)
+!74 = distinct !DISubprogram(linkageName: "?filt$0@0@seh@@", scope: !3, file: !3, line: 45, type: !75, isLocal: true, isDefinition: true, scopeLine: 45, flags: DIFlagArtificial, isOptimized: true, unit: !2, retainedNodes: !4)
+!75 = !DISubroutineType(types: !4)
+!76 = !DILocation(line: 45, scope: !74)
+!77 = distinct !DISubprogram(name: "use_naked", scope: !3, file: !3, line: 49, type: !44, isLocal: false, isDefinition: true, scopeLine: 49, flags: DIFlagPrototyped, isOptimized: true, unit: !2, retainedNodes: !4)
+!78 = !DILocation(line: 50, scope: !77)
+!79 = !{i32 765}
+!80 = !DILocation(line: 51, scope: !77)
+!81 = distinct !DISubprogram(name: "stack_guard", scope: !3, file: !3, line: 53, type: !44, isLocal: false, isDefinition: true, scopeLine: 53, flags: DIFlagPrototyped, isOptimized: true, unit: !2, retainedNodes: !82)
+!82 = !{!83}
+!83 = !DILocalVariable(name: "arr", scope: !81, file: !3, line: 54, type: !84)
+!84 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 384, elements: !85)
+!85 = !{!86}
+!86 = !DISubrange(count: 12)
+!87 = !DILocation(line: 54, scope: !81)
+!88 = !DILocation(line: 55, scope: !81)
+!89 = !DILocation(line: 56, scope: !81)
index 683b438..085ced1 100644 (file)
 ; ASM: .long   116                     # TypeIndex
 ; ASM: .short  1                       # Flags
 ; ASM: .asciz  "param"
-; ASM: .cv_def_range    [[prologue_end]] [[param_end]], "E\021O\001\000\0004\000\000\000"
+; ASM: .cv_def_range    [[prologue_end]] [[param_end]], "B\0214\000\000\000"
 ; ASM: .short  4414                    # Record kind: S_LOCAL
 ; ASM: .long   116                     # TypeIndex
 ; ASM: .short  0                       # Flags
 ; ASM: .asciz  "a"
-; ASM: .cv_def_range    [[if_start]] [[else_start]], "E\021O\001\000\000(\000\000\000"
+; ASM: .cv_def_range    [[if_start]] [[else_start]], "B\021(\000\000\000"
 ; ASM: .short  4414                    # Record kind: S_LOCAL
 ; ASM: .long   116                     # TypeIndex
 ; ASM: .short  0                       # Flags
 ; ASM: .asciz  "b"
-; ASM: .cv_def_range    [[else_start]] [[else_end]], "E\021O\001\000\000$\000\000\000"
+; ASM: .cv_def_range    [[else_start]] [[else_end]], "B\021$\000\000\000"
 ; ASM: .short  4429                    # Record kind: S_INLINESITE
 ; ASM: .short  4414                    # Record kind: S_LOCAL
 ; ASM: .long   116                     # TypeIndex
 ; ASM: .short  0                       # Flags
 ; ASM: .asciz  "v"
-; ASM: .cv_def_range    [[inline_site1]] [[else_start]], "E\021O\001\000\000,\000\000\000"
+; ASM: .cv_def_range    [[inline_site1]] [[else_start]], "B\021,\000\000\000"
 ; ASM: .short  4430                    # Record kind: S_INLINESITE_END
 ; ASM: .short  4429                    # Record kind: S_INLINESITE
 ; ASM: .short  4414                    # Record kind: S_LOCAL
 ; ASM: .long   116                     # TypeIndex
 ; ASM: .short  0                       # Flags
 ; ASM: .asciz  "v"
-; ASM: .cv_def_range    [[inline_site2]] [[else_end]], "E\021O\001\000\0000\000\000\000"
+; ASM: .cv_def_range    [[inline_site2]] [[else_end]], "B\0210\000\000\000"
 ; ASM: .short  4430                    # Record kind: S_INLINESITE_END
 
 ; OBJ:  Subsection [
 ; OBJ:      ]
 ; OBJ:      VarName: param
 ; OBJ:    }
-; OBJ:    DefRangeRegisterRelSym {
-; OBJ:      BaseRegister: RSP (0x14F)
-; OBJ:      HasSpilledUDTMember: No
-; OBJ:      OffsetInParent: 0
-; OBJ:      BasePointerOffset: 52
+; OBJ:    DefRangeFramePointerRelSym {
+; OBJ:      Offset: 52
 ; OBJ:      LocalVariableAddrRange {
 ; OBJ:        OffsetStart: .text+0x8
 ; OBJ:        ISectStart: 0x0
 ; OBJ:      ]
 ; OBJ:      VarName: a
 ; OBJ:    }
-; OBJ:    DefRangeRegisterRelSym {
-; OBJ:      BaseRegister: RSP (0x14F)
-; OBJ:      HasSpilledUDTMember: No
-; OBJ:      OffsetInParent: 0
-; OBJ:      BasePointerOffset: 40
+; OBJ:    DefRangeFramePointerRelSym {
+; OBJ:      Offset: 40
 ; OBJ:      LocalVariableAddrRange {
 ; OBJ:        OffsetStart: .text+0xC
 ; OBJ:        ISectStart: 0x0
 ; OBJ:      ]
 ; OBJ:      VarName: b
 ; OBJ:    }
-; OBJ:    DefRangeRegisterRelSym {
-; OBJ:      BaseRegister: RSP (0x14F)
-; OBJ:      HasSpilledUDTMember: No
-; OBJ:      OffsetInParent: 0
-; OBJ:      BasePointerOffset: 36
+; OBJ:    DefRangeFramePointerRelSym {
+; OBJ:      Offset: 36
 ; OBJ:      LocalVariableAddrRange {
 ; OBJ:        OffsetStart: .text+0x2D
 ; OBJ:        ISectStart: 0x0
 ; OBJ:      ]
 ; OBJ:      VarName: v
 ; OBJ:    }
-; OBJ:    DefRangeRegisterRelSym {
-; OBJ:      BaseRegister: RSP (0x14F)
-; OBJ:      HasSpilledUDTMember: No
-; OBJ:      OffsetInParent: 0
-; OBJ:      BasePointerOffset: 44
+; OBJ:    DefRangeFramePointerRelSym {
+; OBJ:      Offset: 44
 ; OBJ:      LocalVariableAddrRange {
 ; OBJ:        OffsetStart: .text+0x14
 ; OBJ:        ISectStart: 0x0
 ; OBJ:      ]
 ; OBJ:      VarName: v
 ; OBJ:    }
-; OBJ:    DefRangeRegisterRelSym {
-; OBJ:      BaseRegister: RSP (0x14F)
-; OBJ:      HasSpilledUDTMember: No
-; OBJ:      OffsetInParent: 0
-; OBJ:      BasePointerOffset: 48
+; OBJ:    DefRangeFramePointerRelSym {
+; OBJ:      Offset: 48
 ; OBJ:      LocalVariableAddrRange {
 ; OBJ:        OffsetStart: .text+0x35
 ; OBJ:        ISectStart: 0x0
index ea6e758..cb281ea 100644 (file)
@@ -48,7 +48,7 @@
 ; OBJ32:          DisplayName: f
 ; OBJ32:          LinkageName: _f
 ; OBJ32:        }
-; OBJ32-NEXT:   ProcEnd {
+; OBJ32:        ProcEnd {
 ; OBJ32:        }
 ; OBJ32-NEXT: ]
 ; OBJ32:         Subsection [
 ; OBJ64:          DisplayName: f
 ; OBJ64:          LinkageName: f
 ; OBJ64:        }
-; OBJ64-NEXT:   ProcEnd {
+; OBJ64:        ProcEnd {
 ; OBJ64:        }
 ; OBJ64-NEXT: ]
 ; OBJ64:         Subsection [
index c675eda..c74b332 100644 (file)
 ; X86-NEXT: .byte   0
 ; X86-NEXT: .asciz "x"
 ; X86-NEXT: [[PROC_SEGMENT_END]]:
+; X86-NEXT: .short  [[FPROC_END:[^ ]*]]-[[FPROC_BEG:[^ ]*]]           # Record length
+; X86-NEXT: [[FPROC_BEG]]:
+; X86-NEXT: .short  4114                    # Record kind: S_FRAMEPROC
+; X86-NEXT: .long   0                       # FrameSize
+; X86-NEXT: .long   0                       # Padding
+; X86-NEXT: .long   0                       # Offset of padding
+; X86-NEXT: .long   0                       # Bytes of callee saved registers
+; X86-NEXT: .long   0                       # Exception handler offset
+; X86-NEXT: .short  0                       # Exception handler section
+; X86-NEXT: .long   0                       # Flags (defines frame register)
+; X86-NEXT: [[FPROC_END]]:
 ; X86-NEXT: .short  2
 ; X86-NEXT: .short  4431
 ; X86-NEXT: [[F1_END]]:
 ; X86-NEXT: .byte   0
 ; X86-NEXT: .asciz "y"
 ; X86-NEXT: [[PROC_SEGMENT_END]]:
+; X86-NEXT: .short  [[FPROC_END:[^ ]*]]-[[FPROC_BEG:[^ ]*]]           # Record length
+; X86-NEXT: [[FPROC_BEG]]:
+; X86-NEXT: .short  4114                    # Record kind: S_FRAMEPROC
+; X86-NEXT: .long   0                       # FrameSize
+; X86-NEXT: .long   0                       # Padding
+; X86-NEXT: .long   0                       # Offset of padding
+; X86-NEXT: .long   0                       # Bytes of callee saved registers
+; X86-NEXT: .long   0                       # Exception handler offset
+; X86-NEXT: .short  0                       # Exception handler section
+; X86-NEXT: .long   0                       # Flags (defines frame register)
+; X86-NEXT: [[FPROC_END]]:
 ; X86-NEXT: .short  2
 ; X86-NEXT: .short  4431
 ; X86-NEXT: [[COMPILE_END]]:
 ; X86-NEXT: .byte   0
 ; X86-NEXT: .asciz "f"
 ; X86-NEXT: [[PROC_SEGMENT_END]]:
+; X86-NEXT: .short  [[FPROC_END:[^ ]*]]-[[FPROC_BEG:[^ ]*]]           # Record length
+; X86-NEXT: [[FPROC_BEG]]:
+; X86-NEXT: .short  4114                    # Record kind: S_FRAMEPROC
+; X86-NEXT: .long   0                       # FrameSize
+; X86-NEXT: .long   0                       # Padding
+; X86-NEXT: .long   0                       # Offset of padding
+; X86-NEXT: .long   0                       # Bytes of callee saved registers
+; X86-NEXT: .long   0                       # Exception handler offset
+; X86-NEXT: .short  0                       # Exception handler section
+; X86-NEXT: .long   0                       # Flags (defines frame register)
+; X86-NEXT: [[FPROC_END]]:
 ; X86-NEXT: .short  2
 ; X86-NEXT: .short  4431
 ; X86-NEXT: [[COMPILE_END]]:
 ; X64-NEXT: .byte   0
 ; X64-NEXT: .asciz "x"
 ; X64-NEXT: [[PROC_SEGMENT_END]]:
+; X64-NEXT: .short  [[FPROC_END:[^ ]*]]-[[FPROC_BEG:[^ ]*]]           # Record length
+; X64-NEXT: [[FPROC_BEG]]:
+; X64-NEXT: .short  4114                    # Record kind: S_FRAMEPROC
+; X64-NEXT: .long   40                       # FrameSize
+; X64-NEXT: .long   0                       # Padding
+; X64-NEXT: .long   0                       # Offset of padding
+; X64-NEXT: .long   0                       # Bytes of callee saved registers
+; X64-NEXT: .long   0                       # Exception handler offset
+; X64-NEXT: .short  0                       # Exception handler section
+; X64-NEXT: .long   81920                       # Flags (defines frame register)
+; X64-NEXT: [[FPROC_END]]:
 ; X64-NEXT: .short  2
 ; X64-NEXT: .short  4431
 ; X64-NEXT: [[F1_END]]:
 ; X64-NEXT: .byte   0
 ; X64-NEXT: .asciz "y"
 ; X64-NEXT: [[PROC_SEGMENT_END]]:
+; X64-NEXT: .short  [[FPROC_END:[^ ]*]]-[[FPROC_BEG:[^ ]*]]           # Record length
+; X64-NEXT: [[FPROC_BEG]]:
+; X64-NEXT: .short  4114                    # Record kind: S_FRAMEPROC
+; X64-NEXT: .long   40                       # FrameSize
+; X64-NEXT: .long   0                       # Padding
+; X64-NEXT: .long   0                       # Offset of padding
+; X64-NEXT: .long   0                       # Bytes of callee saved registers
+; X64-NEXT: .long   0                       # Exception handler offset
+; X64-NEXT: .short  0                       # Exception handler section
+; X64-NEXT: .long   81920                       # Flags (defines frame register)
+; X64-NEXT: [[FPROC_END]]:
 ; X64-NEXT: .short  2
 ; X64-NEXT: .short  4431
 ; X64-NEXT: [[COMPILE_END]]:
 ; X64-NEXT: .byte   0
 ; X64-NEXT: .asciz "f"
 ; X64-NEXT: [[PROC_SEGMENT_END]]:
+; X64-NEXT: .short  [[FPROC_END:[^ ]*]]-[[FPROC_BEG:[^ ]*]]           # Record length
+; X64-NEXT: [[FPROC_BEG]]:
+; X64-NEXT: .short  4114                    # Record kind: S_FRAMEPROC
+; X64-NEXT: .long   40                       # FrameSize
+; X64-NEXT: .long   0                       # Padding
+; X64-NEXT: .long   0                       # Offset of padding
+; X64-NEXT: .long   0                       # Bytes of callee saved registers
+; X64-NEXT: .long   0                       # Exception handler offset
+; X64-NEXT: .short  0                       # Exception handler section
+; X64-NEXT: .long   81920                       # Flags (defines frame register)
+; X64-NEXT: [[FPROC_END]]:
 ; X64-NEXT: .short  2
 ; X64-NEXT: .short  4431
 ; X64-NEXT: [[COMPILE_END]]:
 ; OBJ64:      Relocations [
 ; OBJ64-NEXT:   0x64 IMAGE_REL_AMD64_SECREL x
 ; OBJ64-NEXT:   0x68 IMAGE_REL_AMD64_SECTION x
-; OBJ64-NEXT:   0x7C IMAGE_REL_AMD64_SECREL x
-; OBJ64-NEXT:   0x80 IMAGE_REL_AMD64_SECTION x
-; OBJ64-NEXT:   0xE0 IMAGE_REL_AMD64_SECREL y
-; OBJ64-NEXT:   0xE4 IMAGE_REL_AMD64_SECTION y
-; OBJ64-NEXT:   0xF8 IMAGE_REL_AMD64_SECREL y
-; OBJ64-NEXT:   0xFC IMAGE_REL_AMD64_SECTION y
-; OBJ64-NEXT:   0x15C IMAGE_REL_AMD64_SECREL f
-; OBJ64-NEXT:   0x160 IMAGE_REL_AMD64_SECTION f
-; OBJ64-NEXT:   0x174 IMAGE_REL_AMD64_SECREL f
-; OBJ64-NEXT:   0x178 IMAGE_REL_AMD64_SECTION f
+; OBJ64-NEXT:   0x98 IMAGE_REL_AMD64_SECREL x
+; OBJ64-NEXT:   0x9C IMAGE_REL_AMD64_SECTION x
+; OBJ64-NEXT:   0xFC IMAGE_REL_AMD64_SECREL y
+; OBJ64-NEXT:   0x100 IMAGE_REL_AMD64_SECTION y
+; OBJ64-NEXT:   0x130 IMAGE_REL_AMD64_SECREL y
+; OBJ64-NEXT:   0x134 IMAGE_REL_AMD64_SECTION y
+; OBJ64-NEXT:   0x194 IMAGE_REL_AMD64_SECREL f
+; OBJ64-NEXT:   0x198 IMAGE_REL_AMD64_SECTION f
+; OBJ64-NEXT:   0x1C8 IMAGE_REL_AMD64_SECREL f
+; OBJ64-NEXT:   0x1CC IMAGE_REL_AMD64_SECTION f
 ; OBJ64-NEXT: ]
 ; OBJ64:      Subsection [
 ; OBJ64-NEXT:   SubSectionType: Symbols (0xF1)
index ab3794d..10a81e1 100644 (file)
 ; ASM:        .cv_def_range    [[oy_start]] [[oy_end]], "C\021\027\000\000\000\004\000\000\000"
 
 
-; OBJ-LABEL: {{.*}}Proc{{.*}}Sym {
+; OBJ-LABEL: GlobalProcIdSym {
 ; OBJ:         Kind: S_GPROC32_ID (0x1147)
 ; OBJ:         DisplayName: loop_csr
 ; OBJ:       }
 ; ASM:        .asciz  "o"
 ; ASM:        .cv_def_range    .Lfunc_begin1 .Ltmp8, "C\021\021\000\000\000\004\000\000\000"
 
-; OBJ-LABEL: {{.*}}Proc{{.*}}Sym {
+; OBJ-LABEL: GlobalProcIdSym {
 ; OBJ:         Kind: S_GPROC32_ID (0x1147)
 ; OBJ:         DisplayName: pad_right
 ; OBJ:       }
 ; ASM:        .asciz  "o"
 ; ASM:        .cv_def_range    .Lfunc_begin2 .Ltmp10, "C\021\021\000\000\000\000\000\000\000"
 
-; OBJ-LABEL: {{.*}}Proc{{.*}}Sym {
+; OBJ-LABEL: GlobalProcIdSym {
 ; OBJ:         Kind: S_GPROC32_ID (0x1147)
 ; OBJ:         DisplayName: pad_left
 ; OBJ:       }
 ; ASM:        .asciz  "p"
 ; ASM:        .cv_def_range    [[p_start]] .Lfunc_end3, "C\021\021\000\000\000\004\000\000\000"
 
-; OBJ-LABEL: {{.*}}Proc{{.*}}Sym {
+; OBJ-LABEL: GlobalProcIdSym {
 ; OBJ:         Kind: S_GPROC32_ID (0x1147)
 ; OBJ:         DisplayName: nested
 ; OBJ:       }
 ; ASM:        .asciz  "o"
 ; ASM:        .cv_def_range    [[spill_o_x_start]] [[spill_o_x_end]], "E\021O\001A\000$\000\000\000"
 
-; OBJ-LABEL: {{.*}}Proc{{.*}}Sym {
+; OBJ-LABEL: GlobalProcIdSym {
 ; OBJ:         Kind: S_GPROC32_ID (0x1147)
 ; OBJ:         DisplayName: bitpiece_spill
 ; OBJ:       }
index 175be1a..3c495a3 100644 (file)
 ; X86-NEXT: .byte   0
 ; X86-NEXT: .asciz "f"
 ; X86-NEXT: [[PROC_SEGMENT_END]]:
+; X86-NEXT: .short  [[FPROC_END:[^ ]*]]-[[FPROC_BEG:[^ ]*]]           # Record length
+; X86-NEXT: [[FPROC_BEG]]:
+; X86-NEXT: .short  4114                    # Record kind: S_FRAMEPROC
+; X86-NEXT: .long   0                       # FrameSize
+; X86-NEXT: .long   0                       # Padding
+; X86-NEXT: .long   0                       # Offset of padding
+; X86-NEXT: .long   0                       # Bytes of callee saved registers
+; X86-NEXT: .long   0                       # Exception handler offset
+; X86-NEXT: .short  0                       # Exception handler section
+; X86-NEXT: .long   0                       # Flags (defines frame register)
+; X86-NEXT: [[FPROC_END]]:
 ; X86-NEXT: .short  2
 ; X86-NEXT: .short  4431
 ; X86-NEXT: [[F1_END]]:
@@ -78,8 +89,8 @@
 ; OBJ32-NEXT:   0x44 IMAGE_REL_I386_DIR32NB _f
 ; OBJ32-NEXT:   0x90 IMAGE_REL_I386_SECREL _f
 ; OBJ32-NEXT:   0x94 IMAGE_REL_I386_SECTION _f
-; OBJ32-NEXT:   0xA8 IMAGE_REL_I386_SECREL _f
-; OBJ32-NEXT:   0xAC IMAGE_REL_I386_SECTION _f
+; OBJ32-NEXT:   0xC4 IMAGE_REL_I386_SECREL _f
+; OBJ32-NEXT:   0xC8 IMAGE_REL_I386_SECTION _f
 ; OBJ32-NEXT: ]
 ; OBJ32:      Subsection [
 ; OBJ32-NEXT:   SubSectionType: Symbols (0xF1)
 ; OBJ32:          DisplayName: f
 ; OBJ32:          LinkageName: _f
 ; OBJ32:        }
-; OBJ32-NEXT:   ProcEnd {
+; OBJ32:        ProcEnd {
 ; OBJ32:        }
 ; OBJ32-NEXT: ]
 ; OBJ32:       Subsection [
 ; X64-NEXT: .byte   0
 ; X64-NEXT: .asciz "f"
 ; X64-NEXT: [[PROC_SEGMENT_END]]:
+; X64-NEXT: .short  [[FPROC_END:[^ ]*]]-[[FPROC_BEG:[^ ]*]]           # Record length
+; X64-NEXT: [[FPROC_BEG]]:
+; X64-NEXT: .short  4114                    # Record kind: S_FRAMEPROC
+; X64-NEXT: .long   40                       # FrameSize
+; X64-NEXT: .long   0                       # Padding
+; X64-NEXT: .long   0                       # Offset of padding
+; X64-NEXT: .long   0                       # Bytes of callee saved registers
+; X64-NEXT: .long   0                       # Exception handler offset
+; X64-NEXT: .short  0                       # Exception handler section
+; X64-NEXT: .long   81920                       # Flags (defines frame register)
+; X64-NEXT: [[FPROC_END]]:
 ; X64-NEXT: .short  2
 ; X64-NEXT: .short  4431
 ; X64-NEXT: [[F1_END]]:
 ; OBJ64:      Relocations [
 ; OBJ64-NEXT:   0x64 IMAGE_REL_AMD64_SECREL f
 ; OBJ64-NEXT:   0x68 IMAGE_REL_AMD64_SECTION f
-; OBJ64-NEXT:   0x7C IMAGE_REL_AMD64_SECREL f
-; OBJ64-NEXT:   0x80 IMAGE_REL_AMD64_SECTION f
+; OBJ64-NEXT:   0x98 IMAGE_REL_AMD64_SECREL f
+; OBJ64-NEXT:   0x9C IMAGE_REL_AMD64_SECTION f
 ; OBJ64-NEXT: ]
 ; OBJ64:      Subsection [
 ; OBJ64-NEXT:   SubSectionType: Symbols (0xF1)
 ; OBJ64:          DisplayName: f
 ; OBJ64:          LinkageName: f
 ; OBJ64:        }
-; OBJ64-NEXT:   ProcEnd {
+; OBJ64:        ProcEnd {
 ; OBJ64:        }
 ; OBJ64-NEXT: ]
 ; OBJ64:       Subsection [
index 10ae426..16298da 100644 (file)
 ; CHECK:       ]
 ; CHECK:       VarName: a
 ; CHECK:     }
-; CHECK:     DefRangeRegisterRelSym {
-; CHECK:       BaseRegister: EBP (0x16)
-; CHECK:       HasSpilledUDTMember: No
-; CHECK:       OffsetInParent: 0
-; CHECK:       BasePointerOffset: -20
+; CHECK:     DefRangeFramePointerRelSym {
+; CHECK:       Offset: -20
 ; CHECK:       LocalVariableAddrRange {
 ; CHECK:         OffsetStart: .text+0x6
 ; CHECK:         ISectStart: 0x0
diff --git a/test/DebugInfo/COFF/vframe-fpo.ll b/test/DebugInfo/COFF/vframe-fpo.ll
new file mode 100644 (file)
index 0000000..b3b7153
--- /dev/null
@@ -0,0 +1,264 @@
+; RUN: llc < %s | FileCheck %s --check-prefix=ASM
+; RUN: llc < %s -filetype=obj | llvm-readobj -codeview | FileCheck %s --check-prefix=CODEVIEW
+
+; This test checks that for 32-bit x86 we use VFRAME and
+; S_DEFRANGE_FRAMEPOINTER_REL with the right offsets. The test has two function
+; calls with different stack depths, which makes it impossible to correctly
+; describe locals in memory as being ESP-relative.
+
+; The following source can be used with a debugger to check that locals are
+; displayed correctly:
+; $ cat fpo.cpp
+; #if 0
+; void __attribute__((optnone)) __declspec(noinline) f(int &a, int &b) {
+;   __debugbreak();
+;   a += b;
+; }
+; void __attribute__((optnone)) __declspec(noinline) g(int &a, int &b, int &c) {
+;   __debugbreak();
+;   a += b;
+;   a += c;
+; }
+; #endif
+; void f(int &a, int &b);
+; void g(int &a, int &b, int &c);
+; int main() {
+;   int a = 1;
+;   int b = 2;
+;   int c = 3;
+;   f(a, b);
+;   g(a, b, c);
+;   return a + b + c;
+; }
+; $ clang -S -g -gcodeview t.cpp -emit-llvm -o vframe-fpo.ll -Os
+
+; ASM-LABEL: _main:
+; ASM:      # %bb.0:                                # %entry
+; ASM-NEXT:         pushl   %ebx
+; ASM-NEXT:         .cv_fpo_pushreg %ebx
+; ASM-NEXT:         pushl   %edi
+; ASM-NEXT:         .cv_fpo_pushreg %edi
+; ASM-NEXT:         pushl   %esi
+; ASM-NEXT:         .cv_fpo_pushreg %esi
+; ASM-NEXT:         subl    $12, %esp
+; ASM-NEXT:         .cv_fpo_stackalloc      12
+; ASM-NEXT:         .cv_fpo_endprologue
+
+; Store locals.
+; ASM:         movl    $1, {{.*}}
+; ASM:         movl    $2, {{.*}}
+; ASM:         movl    $3, {{.*}}
+
+; ASM that store-to-push conversion fires.
+; ASM:         pushl
+; ASM-NEXT:    pushl
+; ASM-NEXT:    calll   "?f@@YAXAAH0@Z"
+; ASM-NEXT:    addl    $8, %esp
+; ASM:         pushl
+; ASM-NEXT:    pushl
+; ASM-NEXT:    pushl
+; ASM-NEXT:    calll   "?g@@YAXAAH00@Z"
+
+; CODEVIEW:      CodeViewDebugInfo [
+; CODEVIEW-NEXT:   Section: .debug$S (4)
+; CODEVIEW-NEXT:   Magic: 0x4
+; CODEVIEW-NEXT:   Subsection [
+; CODEVIEW-NEXT:     SubSectionType: Symbols (0xF1)
+; CODEVIEW-NEXT:     SubSectionSize: 0x2F
+; CODEVIEW-NEXT:     Compile3Sym {
+; CODEVIEW-NEXT:       Kind: S_COMPILE3 (0x113C)
+; CODEVIEW:          }
+; CODEVIEW:        ]
+; CODEVIEW:        Subsection [
+; CODEVIEW-NEXT:     SubSectionType: FrameData (0xF5)
+; CODEVIEW-NEXT:     SubSectionSize: 0xA4
+; CODEVIEW-NEXT:     LinkageName: _main
+; CODEVIEW:          FrameData {
+; CODEVIEW:          }
+; CODEVIEW:          FrameData {
+; CODEVIEW:          }
+; CODEVIEW:          FrameData {
+; CODEVIEW:          }
+; CODEVIEW:          FrameData {
+; CODEVIEW:          }
+; CODEVIEW:          FrameData {
+; CODEVIEW-NEXT:       RvaStart:
+; CODEVIEW-NEXT:       CodeSize:
+; CODEVIEW-NEXT:       LocalSize: 0xC
+; CODEVIEW-NEXT:       ParamsSize: 0x0
+; CODEVIEW-NEXT:       MaxStackSize: 0x0
+; CODEVIEW-NEXT:       PrologSize:
+; CODEVIEW-NEXT:       SavedRegsSize: 0xC
+; CODEVIEW-NEXT:       Flags [ (0x0)
+; CODEVIEW-NEXT:       ]
+
+; $T0 is the CFA, the address of the return address, and our defranges are
+; relative to it.
+; CODEVIEW-NEXT:       FrameFunc [
+; CODEVIEW-NEXT:         $T0 .raSearch =
+; CODEVIEW-NEXT:         $eip $T0 ^ =
+; CODEVIEW-NEXT:         $esp $T0 4 + =
+; CODEVIEW-NEXT:         $ebx $T0 4 - ^ =
+; CODEVIEW-NEXT:         $edi $T0 8 - ^ =
+; CODEVIEW-NEXT:         $esi $T0 12 - ^ =
+; CODEVIEW-NEXT:       ]
+; CODEVIEW-NEXT:     }
+
+; We push 16 bytes in the prologue, so our local variables are at offsets -16,
+; -20, and -24.
+
+; CODEVIEW:      Subsection [
+; CODEVIEW-NEXT:   SubSectionType: Symbols (0xF1)
+; CODEVIEW-NEXT:   SubSectionSize: 0xA2
+; CODEVIEW-NEXT:   GlobalProcIdSym {
+; CODEVIEW-NEXT:     Kind: S_GPROC32_ID (0x1147)
+; CODEVIEW:          DisplayName: main
+; CODEVIEW:          LinkageName: _main
+; CODEVIEW-NEXT:   }
+; CODEVIEW-NEXT:   FrameProcSym {
+; CODEVIEW-NEXT:     Kind: S_FRAMEPROC (0x1012)
+; CODEVIEW-NEXT:     TotalFrameBytes: 0xC
+; CODEVIEW-NEXT:     PaddingFrameBytes: 0x0
+; CODEVIEW-NEXT:     OffsetToPadding: 0x0
+; CODEVIEW-NEXT:     BytesOfCalleeSavedRegisters: 0xC
+; CODEVIEW-NEXT:     OffsetOfExceptionHandler: 0x0
+; CODEVIEW-NEXT:     SectionIdOfExceptionHandler: 0x0
+; CODEVIEW-NEXT:     Flags [ (0x14000)
+; CODEVIEW-NEXT:     ]
+; CODEVIEW-NEXT:     LocalFramePtrReg: VFRAME (0x7536)
+; CODEVIEW-NEXT:     ParamFramePtrReg: VFRAME (0x7536)
+; CODEVIEW-NEXT:   }
+; CODEVIEW-NEXT:   LocalSym {
+; CODEVIEW-NEXT:     Kind: S_LOCAL (0x113E)
+; CODEVIEW:          VarName: a
+; CODEVIEW-NEXT:   }
+; CODEVIEW-NEXT:   DefRangeFramePointerRelSym {
+; CODEVIEW-NEXT:     Kind: S_DEFRANGE_FRAMEPOINTER_REL (0x1142)
+; CODEVIEW-NEXT:     Offset: -16
+; CODEVIEW-NEXT:     LocalVariableAddrRange {
+; CODEVIEW-NEXT:       OffsetStart:
+; CODEVIEW-NEXT:       ISectStart:
+; CODEVIEW-NEXT:       Range:
+; CODEVIEW-NEXT:     }
+; CODEVIEW-NEXT:   }
+; CODEVIEW-NEXT:   LocalSym {
+; CODEVIEW-NEXT:     Kind: S_LOCAL (0x113E)
+; CODEVIEW:          VarName: b
+; CODEVIEW-NEXT:   }
+; CODEVIEW-NEXT:   DefRangeFramePointerRelSym {
+; CODEVIEW-NEXT:     Kind: S_DEFRANGE_FRAMEPOINTER_REL (0x1142)
+; CODEVIEW-NEXT:     Offset: -20
+; CODEVIEW-NEXT:     LocalVariableAddrRange {
+; CODEVIEW-NEXT:       OffsetStart:
+; CODEVIEW-NEXT:       ISectStart:
+; CODEVIEW-NEXT:       Range:
+; CODEVIEW-NEXT:     }
+; CODEVIEW-NEXT:   }
+; CODEVIEW-NEXT:   LocalSym {
+; CODEVIEW-NEXT:     Kind: S_LOCAL (0x113E)
+; CODEVIEW:          VarName: c
+; CODEVIEW-NEXT:   }
+; CODEVIEW-NEXT:   DefRangeFramePointerRelSym {
+; CODEVIEW-NEXT:     Kind: S_DEFRANGE_FRAMEPOINTER_REL (0x1142)
+; CODEVIEW-NEXT:     Offset: -24
+; CODEVIEW-NEXT:     LocalVariableAddrRange {
+; CODEVIEW-NEXT:       OffsetStart:
+; CODEVIEW-NEXT:       ISectStart:
+; CODEVIEW-NEXT:       Range:
+; CODEVIEW-NEXT:     }
+; CODEVIEW-NEXT:   }
+; CODEVIEW-NEXT:   ProcEnd {
+; CODEVIEW-NEXT:     Kind: S_PROC_ID_END (0x114F)
+; CODEVIEW-NEXT:   }
+; CODEVIEW-NEXT: ]
+
+
+; ModuleID = 'fpo.cpp'
+source_filename = "fpo.cpp"
+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: norecurse optsize
+define dso_local i32 @main() local_unnamed_addr #0 !dbg !8 {
+entry:
+  %a = alloca i32, align 4
+  %b = alloca i32, align 4
+  %c = alloca i32, align 4
+  %0 = bitcast i32* %a to i8*, !dbg !16
+  call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %0) #4, !dbg !16
+  call void @llvm.dbg.declare(metadata i32* %a, metadata !13, metadata !DIExpression()), !dbg !16
+  store i32 1, i32* %a, align 4, !dbg !16, !tbaa !17
+  %1 = bitcast i32* %b to i8*, !dbg !21
+  call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %1) #4, !dbg !21
+  call void @llvm.dbg.declare(metadata i32* %b, metadata !14, metadata !DIExpression()), !dbg !21
+  store i32 2, i32* %b, align 4, !dbg !21, !tbaa !17
+  %2 = bitcast i32* %c to i8*, !dbg !22
+  call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %2) #4, !dbg !22
+  call void @llvm.dbg.declare(metadata i32* %c, metadata !15, metadata !DIExpression()), !dbg !22
+  store i32 3, i32* %c, align 4, !dbg !22, !tbaa !17
+  call void @"?f@@YAXAAH0@Z"(i32* nonnull dereferenceable(4) %a, i32* nonnull dereferenceable(4) %b) #5, !dbg !23
+  call void @"?g@@YAXAAH00@Z"(i32* nonnull dereferenceable(4) %a, i32* nonnull dereferenceable(4) %b, i32* nonnull dereferenceable(4) %c) #5, !dbg !24
+  %3 = load i32, i32* %a, align 4, !dbg !25, !tbaa !17
+  %4 = load i32, i32* %b, align 4, !dbg !25, !tbaa !17
+  %add = add nsw i32 %4, %3, !dbg !25
+  %5 = load i32, i32* %c, align 4, !dbg !25, !tbaa !17
+  %add1 = add nsw i32 %add, %5, !dbg !25
+  call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %2) #4, !dbg !26
+  call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %1) #4, !dbg !26
+  call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %0) #4, !dbg !26
+  ret i32 %add1, !dbg !25
+}
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #1
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #2
+
+; Function Attrs: optsize
+declare dso_local void @"?f@@YAXAAH0@Z"(i32* dereferenceable(4), i32* dereferenceable(4)) local_unnamed_addr #3
+
+; Function Attrs: optsize
+declare dso_local void @"?g@@YAXAAH00@Z"(i32* dereferenceable(4), i32* dereferenceable(4), i32* dereferenceable(4)) local_unnamed_addr #3
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #1
+
+attributes #0 = { norecurse optsize "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 = { argmemonly nounwind }
+attributes #2 = { nounwind readnone speculatable }
+attributes #3 = { optsize "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 }
+attributes #5 = { optsize }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5, !6}
+!llvm.ident = !{!7}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 8.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "fpo.cpp", directory: "C:\5Csrc\5Cllvm-project\5Cbuild", checksumkind: CSK_MD5, checksum: "d0bb7e43f4e54936a94da008319a7de3")
+!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: "main", scope: !1, file: !1, line: 14, type: !9, isLocal: false, isDefinition: true, scopeLine: 14, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !12)
+!9 = !DISubroutineType(types: !10)
+!10 = !{!11}
+!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!12 = !{!13, !14, !15}
+!13 = !DILocalVariable(name: "a", scope: !8, file: !1, line: 15, type: !11)
+!14 = !DILocalVariable(name: "b", scope: !8, file: !1, line: 16, type: !11)
+!15 = !DILocalVariable(name: "c", scope: !8, file: !1, line: 17, type: !11)
+!16 = !DILocation(line: 15, scope: !8)
+!17 = !{!18, !18, i64 0}
+!18 = !{!"int", !19, i64 0}
+!19 = !{!"omnipotent char", !20, i64 0}
+!20 = !{!"Simple C++ TBAA"}
+!21 = !DILocation(line: 16, scope: !8)
+!22 = !DILocation(line: 17, scope: !8)
+!23 = !DILocation(line: 18, scope: !8)
+!24 = !DILocation(line: 19, scope: !8)
+!25 = !DILocation(line: 20, scope: !8)
+!26 = !DILocation(line: 21, scope: !8)
index 53ceeb1..c28485c 100644 (file)
 ; OBJ:   Kind: S_GPROC32_ID (0x1147)
 ; OBJ:   DisplayName: f
 ; OBJ: }
+; OBJ: FrameProcSym {
+; OBJ:   Kind: S_FRAMEPROC (0x1012)
+; OBJ:   TotalFrameBytes: 0x8
+; OBJ:   LocalFramePtrReg: VFRAME (0x7536)
+; OBJ:   ParamFramePtrReg: VFRAME (0x7536)
+; OBJ: }
 ; OBJ: LocalSym {
 ; OBJ:   Type: NonTrivial (0x1007)
 ; OBJ:   Flags [ (0x1)
@@ -66,9 +72,8 @@
 ; OBJ:   ]
 ; OBJ:   VarName: a
 ; OBJ: }
-; OBJ: DefRangeRegisterRelSym {
-; OBJ:   BaseRegister: ESP (0x15)
-; OBJ:   BasePointerOffset: 12
+; OBJ: DefRangeFramePointerRelSym {
+; OBJ:   Offset: 4
 ; OBJ: }
 ; OBJ: LocalSym {
 ; OBJ:   Type: int (0x74)
@@ -77,9 +82,8 @@
 ; OBJ:   ]
 ; OBJ:   VarName: b
 ; OBJ: }
-; OBJ: DefRangeRegisterRelSym {
-; OBJ:   BaseRegister: ESP (0x15)
-; OBJ:   BasePointerOffset: 16
+; OBJ: DefRangeFramePointerRelSym {
+; OBJ:   Offset: 8
 ; OBJ: }
 ; FIXME: Retain unused.
 ; OBJ: LocalSym {
@@ -89,9 +93,8 @@
 ; OBJ:   ]
 ; OBJ:   VarName: c
 ; OBJ: }
-; OBJ: DefRangeRegisterRelSym {
-; OBJ:   BaseRegister: ESP (0x15)
-; OBJ:   BasePointerOffset: 24
+; OBJ: DefRangeFramePointerRelSym {
+; OBJ:   Offset: 16
 ; OBJ: }
 ; OBJ-LABEL: ProcEnd {
 ; OBJ: }
index 0cfd510..dbd251a 100644 (file)
@@ -44,8 +44,8 @@ entry:
 ; CHECK-MSVC:   Section {{.*}} .debug$S {
 ; CHECK-MSVC:     0x64 IMAGE_REL_ARM_SECREL function
 ; CHECK-MSVC:     0x68 IMAGE_REL_ARM_SECTION function
-; CHECK-MSVC:     0x80 IMAGE_REL_ARM_SECREL function
-; CHECK-MSVC:     0x84 IMAGE_REL_ARM_SECTION function
+; CHECK-MSVC:     0xA0 IMAGE_REL_ARM_SECREL function
+; CHECK-MSVC:     0xA4 IMAGE_REL_ARM_SECTION function
 ; CHECK-MSVC:   }
 ; CHECK-MSVC: ]