summaryrefslogtreecommitdiffstats
path: root/llvm/lib
diff options
context:
space:
mode:
authorDjordje Todorovic <djordje.todorovic@rt-rk.com>2019-07-09 11:33:56 +0000
committerDjordje Todorovic <djordje.todorovic@rt-rk.com>2019-07-09 11:33:56 +0000
commit01eaae6dd12862cda6b42d565a215b07a178aba6 (patch)
tree1100521e1eb7dce0a791709349f96a9efa16e432 /llvm/lib
parent9b3f38f99085e2bbf9db01bb00d4c6d837f0fc00 (diff)
downloadbcm5719-llvm-01eaae6dd12862cda6b42d565a215b07a178aba6.tar.gz
bcm5719-llvm-01eaae6dd12862cda6b42d565a215b07a178aba6.zip
[DwarfDebug] Dump call site debug info
Dump the DWARF information about call sites and call site parameters into debug info sections. The patch also provides an interface for the interpretation of instructions that could load values of a call site parameters in order to generate DWARF about the call site parameters. ([13/13] Introduce the debug entry values.) Co-authored-by: Ananth Sowda <asowda@cisco.com> Co-authored-by: Nikola Prica <nikola.prica@rt-rk.com> Co-authored-by: Ivan Baev <ibaev@cisco.com> Differential Revision: https://reviews.llvm.org/D60716 llvm-svn: 365467
Diffstat (limited to 'llvm/lib')
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp100
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h18
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp187
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h16
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp36
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h11
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp4
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h2
-rw-r--r--llvm/lib/CodeGen/TargetInstrInfo.cpp40
-rw-r--r--llvm/lib/CodeGen/TargetRegisterInfo.cpp14
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFDie.cpp1
-rw-r--r--llvm/lib/IR/DebugInfoMetadata.cpp9
-rw-r--r--llvm/lib/Target/X86/X86InstrInfo.cpp94
-rw-r--r--llvm/lib/Target/X86/X86InstrInfo.h3
14 files changed, 495 insertions, 40 deletions
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
index 4163fdbb177..09780cc350e 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
@@ -890,32 +890,106 @@ void DwarfCompileUnit::constructAbstractSubprogramScopeDIE(
ContextCU->addDIEEntry(*AbsDef, dwarf::DW_AT_object_pointer, *ObjectPointer);
}
+dwarf::Tag DwarfCompileUnit::getDwarf5OrGNUCallSiteTag(dwarf::Tag Tag) {
+ bool ApplyGNUExtensions = DD->getDwarfVersion() == 4 && DD->tuneForGDB();
+ if (!ApplyGNUExtensions)
+ return Tag;
+ switch(Tag) {
+ case dwarf::DW_TAG_call_site:
+ return dwarf::DW_TAG_GNU_call_site;
+ case dwarf::DW_TAG_call_site_parameter:
+ return dwarf::DW_TAG_GNU_call_site_parameter;
+ default:
+ llvm_unreachable("unhandled call site tag");
+ }
+}
+
+dwarf::Attribute DwarfCompileUnit::getDwarf5OrGNUCallSiteAttr(dwarf::Attribute Attr) {
+ bool ApplyGNUExtensions = DD->getDwarfVersion() == 4 && DD->tuneForGDB();
+ if (!ApplyGNUExtensions)
+ return Attr;
+ switch(Attr) {
+ case dwarf::DW_AT_call_all_calls:
+ return dwarf::DW_AT_GNU_all_call_sites;
+ case dwarf::DW_AT_call_target:
+ return dwarf::DW_AT_GNU_call_site_target;
+ case dwarf::DW_AT_call_origin:
+ return dwarf::DW_AT_abstract_origin;
+ case dwarf::DW_AT_call_pc:
+ return dwarf::DW_AT_low_pc;
+ case dwarf::DW_AT_call_value:
+ return dwarf::DW_AT_GNU_call_site_value;
+ case dwarf::DW_AT_call_tail_call:
+ return dwarf::DW_AT_GNU_tail_call;
+ default:
+ llvm_unreachable("unhandled call site attribute");
+ }
+}
+
DIE &DwarfCompileUnit::constructCallSiteEntryDIE(DIE &ScopeDIE,
- const DISubprogram &CalleeSP,
+ const DISubprogram *CalleeSP,
bool IsTail,
- const MCExpr *PCOffset) {
+ const MCSymbol *PCAddr,
+ const MCExpr *PCOffset,
+ unsigned CallReg) {
// Insert a call site entry DIE within ScopeDIE.
DIE &CallSiteDIE =
- createAndAddDIE(dwarf::DW_TAG_call_site, ScopeDIE, nullptr);
+ createAndAddDIE(getDwarf5OrGNUCallSiteTag(dwarf::DW_TAG_call_site),
+ ScopeDIE, nullptr);
- // For the purposes of showing tail call frames in backtraces, a key piece of
- // information is DW_AT_call_origin, a pointer to the callee DIE.
- DIE *CalleeDIE = getOrCreateSubprogramDIE(&CalleeSP);
- assert(CalleeDIE && "Could not create DIE for call site entry origin");
- addDIEEntry(CallSiteDIE, dwarf::DW_AT_call_origin, *CalleeDIE);
+ if (CallReg) {
+ // Indirect call.
+ addAddress(CallSiteDIE, getDwarf5OrGNUCallSiteAttr(dwarf::DW_AT_call_target),
+ MachineLocation(CallReg));
+ } else {
+ DIE *CalleeDIE = getOrCreateSubprogramDIE(CalleeSP);
+ assert(CalleeDIE && "Could not create DIE for call site entry origin");
+ addDIEEntry(CallSiteDIE, getDwarf5OrGNUCallSiteAttr(dwarf::DW_AT_call_origin),
+ *CalleeDIE);
+ }
- if (IsTail) {
+ if (IsTail)
// Attach DW_AT_call_tail_call to tail calls for standards compliance.
- addFlag(CallSiteDIE, dwarf::DW_AT_call_tail_call);
- } else {
- // Attach the return PC to allow the debugger to disambiguate call paths
- // from one function to another.
+ addFlag(CallSiteDIE, getDwarf5OrGNUCallSiteAttr(dwarf::DW_AT_call_tail_call));
+
+ // Attach the return PC to allow the debugger to disambiguate call paths
+ // from one function to another.
+ if (DD->getDwarfVersion() == 4 && DD->tuneForGDB()) {
+ assert(PCAddr && "Missing PC information for a call");
+ addLabelAddress(CallSiteDIE, dwarf::DW_AT_low_pc, PCAddr);
+ } else if (!IsTail || DD->tuneForGDB()) {
assert(PCOffset && "Missing return PC information for a call");
addAddressExpr(CallSiteDIE, dwarf::DW_AT_call_return_pc, PCOffset);
}
+
return CallSiteDIE;
}
+void DwarfCompileUnit::constructCallSiteParmEntryDIEs(
+ DIE &CallSiteDIE, SmallVector<DbgCallSiteParam, 4> &Params) {
+ for (auto &Param : Params) {
+ unsigned Register = Param.getRegister();
+ auto CallSiteDieParam =
+ DIE::get(DIEValueAllocator,
+ getDwarf5OrGNUCallSiteTag(dwarf::DW_TAG_call_site_parameter));
+ insertDIE(CallSiteDieParam);
+ addAddress(*CallSiteDieParam, dwarf::DW_AT_location,
+ MachineLocation(Register));
+
+ DIELoc *Loc = new (DIEValueAllocator) DIELoc;
+ DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc);
+ DwarfExpr.setCallSiteParamValueFlag();
+
+ DwarfDebug::emitDebugLocValue(*Asm, nullptr, Param.getValue(), DwarfExpr);
+
+ addBlock(*CallSiteDieParam,
+ getDwarf5OrGNUCallSiteAttr(dwarf::DW_AT_call_value),
+ DwarfExpr.finalize());
+
+ CallSiteDIE.addChild(CallSiteDieParam);
+ }
+}
+
DIE *DwarfCompileUnit::constructImportedEntityDIE(
const DIImportedEntity *Module) {
DIE *IMDie = DIE::get(DIEValueAllocator, (dwarf::Tag)Module->getTag());
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
index ea980dfda17..0c2e66d3f09 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
@@ -227,12 +227,22 @@ public:
void constructAbstractSubprogramScopeDIE(LexicalScope *Scope);
+ dwarf::Tag getDwarf5OrGNUCallSiteTag(dwarf::Tag Tag);
+ dwarf::Attribute getDwarf5OrGNUCallSiteAttr(dwarf::Attribute Attr);
+
/// Construct a call site entry DIE describing a call within \p Scope to a
/// callee described by \p CalleeSP. \p IsTail specifies whether the call is
- /// a tail call. \p PCOffset must be non-zero for non-tail calls or be the
- /// function-local offset to PC value after the call instruction.
- DIE &constructCallSiteEntryDIE(DIE &ScopeDIE, const DISubprogram &CalleeSP,
- bool IsTail, const MCExpr *PCOffset);
+ /// a tail call. \p PCAddr (used for GDB + DWARF 4 tuning) points to
+ /// the PC value after the call instruction. \p PCOffset (used for
+ /// cases other than GDB + DWARF 4 tuning) must be non-zero for non-tail calls
+ /// (in the case of non-gdb tuning) or be the function-local offset to PC value
+ /// after the call instruction. \p CallReg is a register location
+ /// for an indirect call.
+ DIE &constructCallSiteEntryDIE(DIE &ScopeDIE, const DISubprogram *CalleeSP,
+ bool IsTail, const MCSymbol *PCAddr,
+ const MCExpr *PCOffset, unsigned CallReg);
+ void constructCallSiteParmEntryDIEs(DIE &CallSiteDIE,
+ SmallVector<DbgCallSiteParam, 4> &Params);
/// Construct import_module DIE.
DIE *constructImportedEntityDIE(const DIImportedEntity *Module);
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index 71bb2b0858c..6c6349d4987 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -26,6 +26,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/Triple.h"
#include "llvm/ADT/Twine.h"
#include "llvm/BinaryFormat/Dwarf.h"
@@ -39,6 +40,7 @@
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
+#include "llvm/CodeGen/TargetLowering.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
@@ -83,6 +85,8 @@ using namespace llvm;
#define DEBUG_TYPE "dwarfdebug"
+STATISTIC(NumCSParams, "Number of dbg call site params created");
+
static cl::opt<bool>
DisableDebugInfoPrinting("disable-debug-info-print", cl::Hidden,
cl::desc("Disable debug info printing"));
@@ -551,6 +555,123 @@ void DwarfDebug::constructAbstractSubprogramScopeDIE(DwarfCompileUnit &SrcCU,
}
}
+/// Try to interpret values loaded into registers that forward parameters
+/// for \p CallMI. Store parameters with interpreted value into \p Params.
+static void collectCallSiteParameters(const MachineInstr *CallMI,
+ ParamSet &Params) {
+ auto *MF = CallMI->getMF();
+ auto CalleesMap = MF->getCallSitesInfo();
+ auto CallFwdRegsInfo = CalleesMap.find(CallMI);
+
+ // There is no information for the call instruction.
+ if (CallFwdRegsInfo == CalleesMap.end())
+ return;
+
+ auto *MBB = CallMI->getParent();
+ const auto &TRI = MF->getSubtarget().getRegisterInfo();
+ const auto &TII = MF->getSubtarget().getInstrInfo();
+ const auto &TLI = MF->getSubtarget().getTargetLowering();
+
+ // Skip the call instruction.
+ auto I = std::next(CallMI->getReverseIterator());
+
+ DenseSet<unsigned> ArgsRegsForProcess;
+ for (auto ArgReg : CallFwdRegsInfo->second)
+ ArgsRegsForProcess.insert(ArgReg.Reg);
+
+ // If we did not find loading a value into forwarding registers
+ // that means we can try generating 'DW_OP_entry_value' for the argument
+ // if a call is within entry MBB.
+ DenseMap<unsigned, unsigned> RegsForEntryValues;
+ bool ShouldTryEmitEntryVals = MBB->getIterator() == MF->begin();
+
+ // Return true if it is an instruction over a parameter's forwarding
+ // register that clobbers it.
+ auto shouldInterpret = [&](const MachineInstr &MI) -> unsigned {
+ if (MI.isDebugInstr())
+ return 0;
+ // If a MI clobbers a forwarding reg try to interpret
+ // a value loaded into the reg.
+ for (const MachineOperand &MO : MI.operands()) {
+ if (MO.isReg() && MO.isDef() && MO.getReg() &&
+ TRI->isPhysicalRegister(MO.getReg())) {
+ for (auto FwdReg : ArgsRegsForProcess)
+ if (TRI->regsOverlap(FwdReg, MO.getReg()))
+ return FwdReg;
+ }
+ }
+
+ return 0;
+ };
+
+ auto finishCallSiteParam = [&](DbgValueLoc &DbgLocVal,
+ unsigned &Reg) {
+ unsigned FwdReg = Reg;
+ if (ShouldTryEmitEntryVals && RegsForEntryValues.count(Reg))
+ FwdReg = RegsForEntryValues[Reg];
+ DbgCallSiteParam CSParm(FwdReg, DbgLocVal);
+ Params.push_back(CSParm);
+ NumCSParams++;
+ };
+
+ // Search for a loading value in forwaring registers.
+ while (I != MBB->rend()) {
+ // If the next instruction is a call we can not
+ // interpret parameter's forwarding registers or
+ // we finished interpretation of all parameters.
+ if (I->isCall())
+ return;
+
+ if (ArgsRegsForProcess.empty())
+ return;
+
+ if (unsigned Reg = shouldInterpret(*I)) {
+ ArgsRegsForProcess.erase(Reg);
+ const MachineOperand *Op;
+ DIExpression *Expr;
+ if (auto ParamValue = TII->describeLoadedValue(*I)) {
+ Op = ParamValue->first;
+ Expr = ParamValue->second;
+ if (Op->isImm()) {
+ unsigned Val = Op->getImm();
+ DbgValueLoc DbgLocVal(Expr, Val);
+ finishCallSiteParam(DbgLocVal, Reg);
+ } else if (Op->isReg()) {
+ unsigned RegLoc = Op->getReg();
+ unsigned SP = TLI->getStackPointerRegisterToSaveRestore();
+ unsigned FP = TRI->getFrameRegister(*MF);
+ bool IsSPorFP = (RegLoc == SP) || (RegLoc == FP);
+ if (TRI->isCallerPreservedPhysReg(RegLoc, *MF) || IsSPorFP) {
+ DbgValueLoc DbgLocVal(
+ Expr, MachineLocation(RegLoc, IsSPorFP));
+ finishCallSiteParam(DbgLocVal, Reg);
+ } else if (ShouldTryEmitEntryVals) {
+ ArgsRegsForProcess.insert(RegLoc);
+ RegsForEntryValues[RegLoc] = Reg;
+ }
+ }
+ }
+ }
+
+ ++I;
+ }
+
+ // Emit call site parameter's value as entry value.
+ if (ShouldTryEmitEntryVals) {
+ DIExpression *EntryExpr = DIExpression::get(MF->getFunction().getContext(),
+ {dwarf::DW_OP_entry_value, 1});
+ for (auto RegEntry : ArgsRegsForProcess) {
+ unsigned FwdReg = RegsForEntryValues.count(RegEntry)
+ ? RegsForEntryValues[RegEntry]
+ : RegEntry;
+ DbgValueLoc DbgLocVal(EntryExpr, MachineLocation(RegEntry));
+ DbgCallSiteParam CSParm(FwdReg, DbgLocVal);
+ Params.push_back(CSParm);
+ NumCSParams++;
+ }
+ }
+}
+
void DwarfDebug::constructCallSiteEntryDIEs(const DISubprogram &SP,
DwarfCompileUnit &CU, DIE &ScopeDIE,
const MachineFunction &MF) {
@@ -563,10 +684,13 @@ void DwarfDebug::constructCallSiteEntryDIEs(const DISubprogram &SP,
// for both tail and non-tail calls. Don't use DW_AT_call_all_source_calls
// because one of its requirements is not met: call site entries for
// optimized-out calls are elided.
- CU.addFlag(ScopeDIE, dwarf::DW_AT_call_all_calls);
+ CU.addFlag(ScopeDIE,
+ CU.getDwarf5OrGNUCallSiteAttr(dwarf::DW_AT_call_all_calls));
const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
assert(TII && "TargetInstrInfo not found: cannot label tail calls");
+ const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
+ bool ApplyGNUExtensions = getDwarfVersion() == 4 && tuneForGDB();
// Emit call site entries for each call or tail call in the function.
for (const MachineBasicBlock &MBB : MF) {
@@ -581,30 +705,65 @@ void DwarfDebug::constructCallSiteEntryDIEs(const DISubprogram &SP,
return;
// If this is a direct call, find the callee's subprogram.
+ // In the case of an indirect call find the register that holds
+ // the callee.
const MachineOperand &CalleeOp = MI.getOperand(0);
- if (!CalleeOp.isGlobal())
- continue;
- const Function *CalleeDecl = dyn_cast<Function>(CalleeOp.getGlobal());
- if (!CalleeDecl || !CalleeDecl->getSubprogram())
+ if (!CalleeOp.isGlobal() && !CalleeOp.isReg())
continue;
+ unsigned CallReg = 0;
+ const DISubprogram *CalleeSP = nullptr;
+ const Function *CalleeDecl = nullptr;
+ if (CalleeOp.isReg()) {
+ CallReg = CalleeOp.getReg();
+ if (!CallReg)
+ continue;
+ } else {
+ CalleeDecl = dyn_cast<Function>(CalleeOp.getGlobal());
+ if (!CalleeDecl || !CalleeDecl->getSubprogram())
+ continue;
+ CalleeSP = CalleeDecl->getSubprogram();
+ }
+
// TODO: Omit call site entries for runtime calls (objc_msgSend, etc).
- // TODO: Add support for indirect calls.
bool IsTail = TII->isTailCall(MI);
- // For tail calls, no return PC information is needed. For regular calls,
- // the return PC is needed to disambiguate paths in the call graph which
- // could lead to some target function.
+ // For tail calls, for non-gdb tuning, no return PC information is needed.
+ // For regular calls (and tail calls in GDB tuning), the return PC
+ // is needed to disambiguate paths in the call graph which could lead to
+ // some target function.
const MCExpr *PCOffset =
- IsTail ? nullptr : getFunctionLocalOffsetAfterInsn(&MI);
+ (IsTail && !tuneForGDB()) ? nullptr
+ : getFunctionLocalOffsetAfterInsn(&MI);
+
+ // Address of a call-like instruction for a normal call or a jump-like
+ // instruction for a tail call. This is needed for GDB + DWARF 4 tuning.
+ const MCSymbol *PCAddr =
+ ApplyGNUExtensions ? const_cast<MCSymbol*>(getLabelAfterInsn(&MI))
+ : nullptr;
+
+ assert((IsTail || PCOffset || PCAddr) &&
+ "Call without return PC information");
- assert((IsTail || PCOffset) && "Call without return PC information");
LLVM_DEBUG(dbgs() << "CallSiteEntry: " << MF.getName() << " -> "
- << CalleeDecl->getName() << (IsTail ? " [tail]" : "")
+ << (CalleeDecl ? CalleeDecl->getName()
+ : StringRef(TRI->getName(CallReg)))
+ << (IsTail ? " [IsTail]" : "")
<< "\n");
- CU.constructCallSiteEntryDIE(ScopeDIE, *CalleeDecl->getSubprogram(),
- IsTail, PCOffset);
+
+ DIE &CallSiteDIE =
+ CU.constructCallSiteEntryDIE(ScopeDIE, CalleeSP, IsTail, PCAddr,
+ PCOffset, CallReg);
+
+ // For now only GDB supports call site parameter debug info.
+ if (Asm->TM.Options.EnableDebugEntryValues &&
+ tuneForGDB()) {
+ ParamSet Params;
+ // Try to interpret values of call site parameters.
+ collectCallSiteParameters(&MI, Params);
+ CU.constructCallSiteParmEntryDIEs(CallSiteDIE, Params);
+ }
}
}
}
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
index 3ac474e2bdd..1c9de983ea1 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
@@ -254,6 +254,22 @@ public:
}
};
+/// Used for tracking debug info about call site parameters.
+class DbgCallSiteParam {
+private:
+ unsigned Register;
+ DbgValueLoc Value;
+public:
+ DbgCallSiteParam(unsigned Reg, DbgValueLoc Val)
+ : Register(Reg), Value(Val) {}
+
+ unsigned getRegister() { return Register; }
+ DbgValueLoc getValue() { return Value; }
+};
+
+/// Collection used for storing debug call site parameters.
+using ParamSet = SmallVector<DbgCallSiteParam, 4>;
+
/// Helper used to pair up a symbol and its DWARF compile unit.
struct SymbolCU {
SymbolCU(DwarfCompileUnit *CU, const MCSymbol *Sym) : Sym(Sym), CU(CU) {}
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp
index 2858afaa1cf..436852bda92 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp
@@ -241,15 +241,20 @@ bool DwarfExpression::addMachineRegExpression(const TargetRegisterInfo &TRI,
return false;
}
- // Handle simple register locations.
- if (!isMemoryLocation() && !HasComplexExpression) {
+ // Handle simple register locations. If we are supposed to
+ // emit a call site parameter expression and if that expression
+ // is just a register location, emit it with addBReg and offset 0,
+ // because we should emit a DWARF expression representing a value,
+ // rather than a location.
+ if (!isMemoryLocation() && !HasComplexExpression &&
+ (!isParameterValue() || isEntryValue())) {
for (auto &Reg : DwarfRegs) {
if (Reg.DwarfRegNo >= 0)
addReg(Reg.DwarfRegNo, Reg.Comment);
addOpPiece(Reg.Size);
}
- if (isEntryValue() && DwarfVersion >= 4)
+ if (isEntryValue() && !isParameterValue() && DwarfVersion >= 4)
emitOp(dwarf::DW_OP_stack_value);
DwarfRegs.clear();
@@ -340,7 +345,16 @@ void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor,
while (ExprCursor) {
auto Op = ExprCursor.take();
- switch (Op->getOp()) {
+ uint64_t OpNum = Op->getOp();
+ if (OpNum >= dwarf::DW_OP_reg0 && OpNum <= dwarf::DW_OP_reg31) {
+ if (isParameterValue())
+ addBReg(OpNum - dwarf::DW_OP_reg0, 0);
+ else
+ emitOp(OpNum);
+ continue;
+ }
+
+ switch (OpNum) {
case dwarf::DW_OP_LLVM_fragment: {
unsigned SizeInBits = Op->getArg(1);
unsigned FragmentOffset = Op->getArg(0);
@@ -389,7 +403,7 @@ void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor,
case dwarf::DW_OP_lit0:
case dwarf::DW_OP_not:
case dwarf::DW_OP_dup:
- emitOp(Op->getOp());
+ emitOp(OpNum);
break;
case dwarf::DW_OP_deref:
assert(!isRegisterLocation());
@@ -458,12 +472,22 @@ void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor,
case dwarf::DW_OP_LLVM_tag_offset:
TagOffset = Op->getArg(0);
break;
+ case dwarf::DW_OP_regx:
+ if (isParameterValue()) {
+ emitOp(dwarf::DW_OP_bregx);
+ emitUnsigned(Op->getArg(0));
+ emitSigned(Op->getArg(1));
+ } else {
+ emitOp(dwarf::DW_OP_regx);
+ emitUnsigned(Op->getArg(0));
+ }
+ break;
default:
llvm_unreachable("unhandled opcode found in expression");
}
}
- if (isImplicitLocation())
+ if (isImplicitLocation() && !isParameterValue())
// Turn this into an implicit location description.
addStackValue();
}
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h
index ec2ef6e575f..9f9baf8c1a1 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h
@@ -120,7 +120,7 @@ protected:
enum { Unknown = 0, Register, Memory, Implicit };
/// The flags of location description being produced.
- enum { EntryValue = 1 };
+ enum { EntryValue = 1, CallSiteParamValue };
unsigned LocationKind : 3;
unsigned LocationFlags : 2;
@@ -147,6 +147,10 @@ public:
return LocationFlags & EntryValue;
}
+ bool isParameterValue() {
+ return LocationFlags & CallSiteParamValue;
+ }
+
Optional<uint8_t> TagOffset;
protected:
@@ -264,6 +268,11 @@ public:
LocationFlags |= EntryValue;
}
+ /// Lock this down to become a call site parameter location.
+ void setCallSiteParamValueFlag() {
+ LocationFlags |= CallSiteParamValue;
+ }
+
/// Emit a machine register location. As an optimization this may also consume
/// the prefix of a DwarfExpression if a more efficient representation for
/// combining the register location and the first operation exists.
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
index 991ab94b50a..4990ea66cc1 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
@@ -205,6 +205,10 @@ void DwarfUnit::insertDIE(const DINode *Desc, DIE *D) {
MDNodeToDieMap.insert(std::make_pair(Desc, D));
}
+void DwarfUnit::insertDIE(DIE *D) {
+ MDNodeToDieMap.insert(std::make_pair(nullptr, D));
+}
+
void DwarfUnit::addFlag(DIE &Die, dwarf::Attribute Attribute) {
if (DD->getDwarfVersion() >= 4)
Die.addValue(DIEValueAllocator, Attribute, dwarf::DW_FORM_flag_present,
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h
index 56c934a35ae..a376d5e75f6 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h
@@ -127,6 +127,8 @@ public:
/// the mappings are kept in DwarfDebug.
void insertDIE(const DINode *Desc, DIE *D);
+ void insertDIE(DIE *D);
+
/// Add a flag that is true to the DIE.
void addFlag(DIE &Die, dwarf::Attribute Attribute);
diff --git a/llvm/lib/CodeGen/TargetInstrInfo.cpp b/llvm/lib/CodeGen/TargetInstrInfo.cpp
index 868617ffe14..f7f3e11f18a 100644
--- a/llvm/lib/CodeGen/TargetInstrInfo.cpp
+++ b/llvm/lib/CodeGen/TargetInstrInfo.cpp
@@ -23,6 +23,7 @@
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/CodeGen/TargetSchedule.h"
#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCInstrItineraries.h"
#include "llvm/Support/CommandLine.h"
@@ -1120,6 +1121,45 @@ bool TargetInstrInfo::hasLowDefLatency(const TargetSchedModel &SchedModel,
return (DefCycle != -1 && DefCycle <= 1);
}
+Optional<ParamLoadedValue>
+TargetInstrInfo::describeLoadedValue(const MachineInstr &MI) const {
+ const MachineOperand *Op = nullptr;
+ DIExpression *Expr = nullptr;
+
+ const MachineOperand *SrcRegOp, *DestRegOp;
+ const MachineFunction *MF = MI.getMF();
+ if (isCopyInstr(MI, SrcRegOp, DestRegOp)) {
+ Expr = DIExpression::get(MF->getFunction().getContext(), {});
+ Op = SrcRegOp;
+ return ParamLoadedValue(Op, Expr);
+ } else if (MI.isMoveImmediate()) {
+ Expr = DIExpression::get(MF->getFunction().getContext(), {});
+ Op = &MI.getOperand(1);
+ return ParamLoadedValue(Op, Expr);
+ } else if (MI.hasOneMemOperand()) {
+ int64_t Offset;
+ const auto &TRI = MF->getSubtarget().getRegisterInfo();
+ const auto &TII = MF->getSubtarget().getInstrInfo();
+ const MachineOperand *BaseOp;
+ if (!TII->getMemOperandWithOffset(MI, BaseOp, Offset, TRI))
+ return None;
+ unsigned CastedOffset = static_cast<unsigned>(Offset);
+ if (Offset > 0)
+ Expr = DIExpression::get(
+ MF->getFunction().getContext(),
+ {dwarf::DW_OP_plus_uconst, CastedOffset, dwarf::DW_OP_deref});
+ else
+ Expr = DIExpression::get(MF->getFunction().getContext(),
+ {dwarf::DW_OP_constu, -CastedOffset,
+ dwarf::DW_OP_minus, dwarf::DW_OP_deref});
+
+ Op = BaseOp;
+ return ParamLoadedValue(Op, Expr);
+ }
+
+ return None;
+}
+
/// Both DefMI and UseMI must be valid. By default, call directly to the
/// itinerary. This may be overriden by the target.
int TargetInstrInfo::getOperandLatency(const InstrItineraryData *ItinData,
diff --git a/llvm/lib/CodeGen/TargetRegisterInfo.cpp b/llvm/lib/CodeGen/TargetRegisterInfo.cpp
index f1b2ecf3243..b5a4419e6b8 100644
--- a/llvm/lib/CodeGen/TargetRegisterInfo.cpp
+++ b/llvm/lib/CodeGen/TargetRegisterInfo.cpp
@@ -433,6 +433,20 @@ TargetRegisterInfo::getRegAllocationHints(unsigned VirtReg,
return false;
}
+bool
+TargetRegisterInfo::isCallerPreservedPhysReg(unsigned PhysReg,
+ const MachineFunction &MF) const {
+ if (PhysReg == 0)
+ return false;
+ const uint32_t *callerPreservedRegs =
+ getCallPreservedMask(MF, MF.getFunction().getCallingConv());
+ if (callerPreservedRegs) {
+ assert(isPhysicalRegister(PhysReg) && "Expected physical register");
+ return (callerPreservedRegs[PhysReg / 32] >> PhysReg % 32) & 1;
+ }
+ return false;
+}
+
bool TargetRegisterInfo::canRealignStack(const MachineFunction &MF) const {
return !MF.getFunction().hasFnAttribute("no-realign-stack");
}
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
index 62128429836..63afbeccb70 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
@@ -733,6 +733,7 @@ bool DWARFAttribute::mayHaveLocationDescription(dwarf::Attribute Attr) {
case DW_AT_call_data_value:
// Extensions.
case DW_AT_GNU_call_site_value:
+ case DW_AT_GNU_call_site_target:
return true;
default:
return false;
diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp
index 900df27d1d3..cdb95769ed7 100644
--- a/llvm/lib/IR/DebugInfoMetadata.cpp
+++ b/llvm/lib/IR/DebugInfoMetadata.cpp
@@ -833,10 +833,12 @@ unsigned DIExpression::ExprOperand::getSize() const {
case dwarf::DW_OP_LLVM_fragment:
return 3;
case dwarf::DW_OP_constu:
+ case dwarf::DW_OP_consts:
case dwarf::DW_OP_deref_size:
case dwarf::DW_OP_plus_uconst:
case dwarf::DW_OP_LLVM_tag_offset:
case dwarf::DW_OP_entry_value:
+ case dwarf::DW_OP_regx:
return 2;
default:
return 1;
@@ -849,8 +851,12 @@ bool DIExpression::isValid() const {
if (I->get() + I->getSize() > E->get())
return false;
+ uint64_t Op = I->getOp();
+ if (Op >= dwarf::DW_OP_reg0 && Op <= dwarf::DW_OP_reg31)
+ continue;
+
// Check that the operand is valid.
- switch (I->getOp()) {
+ switch (Op) {
default:
return false;
case dwarf::DW_OP_LLVM_fragment:
@@ -905,6 +911,7 @@ bool DIExpression::isValid() const {
case dwarf::DW_OP_lit0:
case dwarf::DW_OP_not:
case dwarf::DW_OP_dup:
+ case dwarf::DW_OP_regx:
break;
}
}
diff --git a/llvm/lib/Target/X86/X86InstrInfo.cpp b/llvm/lib/Target/X86/X86InstrInfo.cpp
index e5da23cf29d..6ecee41fd03 100644
--- a/llvm/lib/Target/X86/X86InstrInfo.cpp
+++ b/llvm/lib/Target/X86/X86InstrInfo.cpp
@@ -30,7 +30,7 @@
#include "llvm/CodeGen/StackMaps.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
-#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
@@ -7318,6 +7318,98 @@ bool X86InstrInfo::isAssociativeAndCommutative(const MachineInstr &Inst) const {
}
}
+Optional<ParamLoadedValue>
+X86InstrInfo::describeLoadedValue(const MachineInstr &MI) const {
+ const MachineOperand *Op = nullptr;
+ DIExpression *Expr = nullptr;
+
+ switch (MI.getOpcode()) {
+ case X86::LEA32r:
+ case X86::LEA64r:
+ case X86::LEA64_32r: {
+ // Operand 4 could be global address. For now we do not support
+ // such situation.
+ if (!MI.getOperand(4).isImm() || !MI.getOperand(2).isImm())
+ return None;
+
+ const MachineOperand &Op1 = MI.getOperand(1);
+ const MachineOperand &Op2 = MI.getOperand(3);
+ const TargetRegisterInfo *TRI = &getRegisterInfo();
+ assert(Op2.isReg() &&
+ (Op2.getReg() == X86::NoRegister ||
+ TargetRegisterInfo::isPhysicalRegister(Op2.getReg())));
+
+ // Omit situations like:
+ // %rsi = lea %rsi, 4, ...
+ if ((Op1.isReg() && Op1.getReg() == MI.getOperand(0).getReg()) ||
+ Op2.getReg() == MI.getOperand(0).getReg())
+ return None;
+ else if ((Op1.isReg() && Op1.getReg() != X86::NoRegister &&
+ TRI->regsOverlap(Op1.getReg(), MI.getOperand(0).getReg())) ||
+ (Op2.getReg() != X86::NoRegister &&
+ TRI->regsOverlap(Op2.getReg(), MI.getOperand(0).getReg())))
+ return None;
+
+ int64_t Coef = MI.getOperand(2).getImm();
+ int64_t Offset = MI.getOperand(4).getImm();
+ SmallVector<uint64_t, 8> Elements;
+
+ if ((Op1.isReg() && Op1.getReg() != X86::NoRegister)) {
+ Op = &Op1;
+ } else if (Op1.isFI())
+ Op = &Op1;
+
+ if (Op && Op->isReg() && Op->getReg() == Op2.getReg() && Coef > 0) {
+ Elements.push_back(dwarf::DW_OP_constu);
+ Elements.push_back(Coef + 1);
+ Elements.push_back(dwarf::DW_OP_mul);
+ } else {
+ if (Op && Op2.getReg() != X86::NoRegister) {
+ int dwarfReg = TRI->getDwarfRegNum(Op2.getReg(), false);
+ if (dwarfReg < 0)
+ return None;
+ else if (dwarfReg < 32)
+ Elements.push_back(dwarf::DW_OP_reg0 + dwarfReg);
+ else {
+ Elements.push_back(dwarf::DW_OP_regx);
+ Elements.push_back(dwarfReg);
+ }
+ } else if (!Op) {
+ assert(Op2.getReg() != X86::NoRegister);
+ Op = &Op2;
+ }
+
+ if (Coef > 1) {
+ assert(Op2.getReg() != X86::NoRegister);
+ Elements.push_back(dwarf::DW_OP_constu);
+ Elements.push_back(Coef);
+ Elements.push_back(dwarf::DW_OP_mul);
+ }
+
+ if (((Op1.isReg() && Op1.getReg() != X86::NoRegister) || Op1.isFI()) &&
+ Op2.getReg() != X86::NoRegister) {
+ Elements.push_back(dwarf::DW_OP_plus);
+ }
+ }
+
+ if (Offset < 0) {
+ Elements.push_back(dwarf::DW_OP_constu);
+ Elements.push_back(-Offset);
+ Elements.push_back(dwarf::DW_OP_minus);
+ } else if (Offset > 0) {
+ Elements.push_back(dwarf::DW_OP_constu);
+ Elements.push_back(Offset);
+ Elements.push_back(dwarf::DW_OP_plus);
+ }
+
+ Expr = DIExpression::get(MI.getMF()->getFunction().getContext(), Elements);
+ return ParamLoadedValue(Op, Expr);;
+ }
+ default:
+ return TargetInstrInfo::describeLoadedValue(MI);
+ }
+}
+
/// This is an architecture-specific helper function of reassociateOps.
/// Set special operand attributes for new instructions after reassociation.
void X86InstrInfo::setSpecialOperandAttr(MachineInstr &OldMI1,
diff --git a/llvm/lib/Target/X86/X86InstrInfo.h b/llvm/lib/Target/X86/X86InstrInfo.h
index 13ca1713949..b18c1da3c9f 100644
--- a/llvm/lib/Target/X86/X86InstrInfo.h
+++ b/llvm/lib/Target/X86/X86InstrInfo.h
@@ -527,6 +527,9 @@ public:
#define GET_INSTRINFO_HELPER_DECLS
#include "X86GenInstrInfo.inc"
+ Optional<ParamLoadedValue>
+ describeLoadedValue(const MachineInstr &MI) const override;
+
protected:
/// Commutes the operands in the given instruction by changing the operands
/// order and/or changing the instruction's opcode and/or the immediate value
OpenPOWER on IntegriCloud