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;
AdjustsStack == Other.AdjustsStack && HasCalls == Other.HasCalls &&
StackProtector == Other.StackProtector &&
MaxCallFrameSize == Other.MaxCallFrameSize &&
+ CVBytesOfCalleeSavedRegisters ==
+ Other.CVBytesOfCalleeSavedRegisters &&
HasOpaqueSPAdjustment == Other.HasOpaqueSPAdjustment &&
HasVAStart == Other.HasVAStart &&
HasMustTailInVarArgFunc == Other.HasMustTailInVarArgFunc &&
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);
/// 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
}
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
#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,
/// 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
#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"
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
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) {
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(),
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);
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) {
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
}
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");
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
}
}
-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)
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();
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) {
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);
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
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;
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,
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);
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();
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;
+}
}
X86FI->setCalleeSavedFrameSize(CalleeSavedFrameSize);
+ MFI.setCVBytesOfCalleeSavedRegisters(CalleeSavedFrameSize);
// Assign slots for XMMs.
for (unsigned i = CSI.size(); i != 0; --i) {
# 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
# 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
adjustsStack: true
hasCalls: true
maxCallFrameSize: 4
+ cvBytesOfCalleeSavedRegisters: 8
hasOpaqueSPAdjustment: true
hasVAStart: true
hasMustTailInVarArgFunc: true
# 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)
# 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)
; OBJ64: DisplayName: f
; OBJ64: LinkageName: f
; OBJ64: }
-; OBJ64-NEXT: ProcEnd {
+; OBJ64: ProcEnd {
; OBJ64: }
; OBJ64-NEXT: ]
; OBJ64: FunctionLineTable [
--- /dev/null
+; 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)
; 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
; 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 [
; 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)
; 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: }
; 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]]:
; 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 [
; 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
--- /dev/null
+; 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)
; 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)
; 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)
; 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 {
; OBJ: ]
; OBJ: VarName: c
; OBJ: }
-; OBJ: DefRangeRegisterRelSym {
-; OBJ: BaseRegister: ESP (0x15)
-; OBJ: BasePointerOffset: 24
+; OBJ: DefRangeFramePointerRelSym {
+; OBJ: Offset: 16
; OBJ: }
; OBJ-LABEL: ProcEnd {
; OBJ: }
; 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: ]