summaryrefslogtreecommitdiffstats
path: root/llvm/lib/CodeGen/AsmPrinter
diff options
context:
space:
mode:
authorReid Kleckner <rnk@google.com>2018-10-01 21:59:45 +0000
committerReid Kleckner <rnk@google.com>2018-10-01 21:59:45 +0000
commit9ea2c01264eac590bf149cbb882a1f1bd1c2bc1b (patch)
treeb19c87e9c7ee5cb156a3d33e3632eabff4102235 /llvm/lib/CodeGen/AsmPrinter
parent8e57b07f668528fa4ed893093342ba8d899a1556 (diff)
downloadbcm5719-llvm-9ea2c01264eac590bf149cbb882a1f1bd1c2bc1b.tar.gz
bcm5719-llvm-9ea2c01264eac590bf149cbb882a1f1bd1c2bc1b.zip
[codeview] Emit S_FRAMEPROC and use S_DEFRANGE_FRAMEPOINTER_REL
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 llvm-svn: 343543
Diffstat (limited to 'llvm/lib/CodeGen/AsmPrinter')
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp196
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h30
2 files changed, 184 insertions, 42 deletions
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
index f99b5c20e1c..1c67d765dad 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
@@ -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);
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h
index 6d7b97c5dd6..3836862f0a8 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h
@@ -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,
OpenPOWER on IntegriCloud