Index: include/llvm/CodeGen/DbgEntityHistoryCalculator.h =================================================================== --- include/llvm/CodeGen/DbgEntityHistoryCalculator.h +++ include/llvm/CodeGen/DbgEntityHistoryCalculator.h @@ -76,10 +76,28 @@ InstrMap::const_iterator end() const { return LabelInstr.end(); } }; +class DbgCallSiteInstrMap { +public: + using InlinedCallSite = std::pair; + using InstrMap = MapVector; + +private: + InstrMap CSInstr; + +public: + void addInstr(InlinedCallSite CallSite, const MachineInstr &MI); + + bool empty() const { return CSInstr.empty(); } + void clear() { CSInstr.clear(); } + InstrMap::const_iterator begin() const { return CSInstr.begin(); } + InstrMap::const_iterator end() const { return CSInstr.end(); } +}; + void calculateDbgEntityHistory(const MachineFunction *MF, const TargetRegisterInfo *TRI, DbgValueHistoryMap &DbgValues, - DbgLabelInstrMap &DbgLabels); + DbgLabelInstrMap &DbgLabels, + DbgCallSiteInstrMap &DbgCallSites); } // end namespace llvm Index: include/llvm/CodeGen/DebugHandlerBase.h =================================================================== --- include/llvm/CodeGen/DebugHandlerBase.h +++ include/llvm/CodeGen/DebugHandlerBase.h @@ -84,6 +84,9 @@ /// Mapping of inlined labels and DBG_LABEL machine instruction. DbgLabelInstrMap DbgLabels; + /// Mapping DBG callsites + DbgCallSiteInstrMap DbgCallSites; + /// Maps instruction with label emitted before instruction. /// FIXME: Make this private from DwarfDebug, we have the necessary accessors /// for it. Index: include/llvm/CodeGen/MachineInstr.h =================================================================== --- include/llvm/CodeGen/MachineInstr.h +++ include/llvm/CodeGen/MachineInstr.h @@ -401,6 +401,10 @@ /// this DBG_LABEL instruction. const DILabel *getDebugLabel() const; + bool isTailCall() const; + + uint64_t getRegCS() const; + /// Emit an error referring to the source location of this instruction. /// This should only be used for inline assembly that is somehow /// impossible to compile. Other errors should have been handled much Index: include/llvm/IR/DebugInfoMetadata.h =================================================================== --- include/llvm/IR/DebugInfoMetadata.h +++ include/llvm/IR/DebugInfoMetadata.h @@ -1863,8 +1863,8 @@ return cast_or_null(getRawThrownTypes()); } - void replaceElements(DINodeArray Elements) { - replaceOperandWith(10, Elements.get()); + void replaceRetainedNodes(DINodeArray RetainedNodes) { + replaceOperandWith(7, RetainedNodes.get()); } Metadata *getRawScope() const { return getOperand(1); } Index: lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp +++ lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp @@ -30,17 +30,26 @@ #define DEBUG_TYPE "dwarfdebug" -// If @MI is a DBG_VALUE with debug value described by a +// If @MI is a (non-entry) DBG_VALUE with debug value described by a // defined register, returns the number of this register. // In the other case, returns 0. static unsigned isDescribedByReg(const MachineInstr &MI) { assert(MI.isDebugValue()); assert(MI.getNumOperands() == 4); + // If location of variable is entry value (DW_OP_entry_value). + if (MI.getDebugExpression()->isEntryValue()) + return 0; // If location of variable is described using a register (directly or // indirectly), this register is always a first operand. return MI.getOperand(0).isReg() ? MI.getOperand(0).getReg() : 0; } +void DbgCallSiteInstrMap::addInstr(InlinedCallSite CallSite, + const MachineInstr &MI) { + assert(MI.isDebugCallSite() && "Not a DBG_CALLSITE"); + CSInstr[CallSite] = &MI; +} + void DbgValueHistoryMap::startInstrRange(InlinedEntity Var, const MachineInstr &MI) { // Instruction range should start with a DBG_VALUE instruction for the @@ -87,7 +96,7 @@ // Maps physreg numbers to the variables they describe. using InlinedEntity = DbgValueHistoryMap::InlinedEntity; using RegDescribedVarsMap = std::map>; - +using InlinedCallSite = DbgCallSiteInstrMap::InlinedCallSite; } // end anonymous namespace // Claim that @Var is not described by @RegNo anymore. @@ -194,7 +203,8 @@ void llvm::calculateDbgEntityHistory(const MachineFunction *MF, const TargetRegisterInfo *TRI, DbgValueHistoryMap &DbgValues, - DbgLabelInstrMap &DbgLabels) { + DbgLabelInstrMap &DbgLabels, + DbgCallSiteInstrMap &DbgCallSites) { BitVector ChangingRegs(TRI->getNumRegs()); collectChangingRegs(MF, TRI, ChangingRegs); @@ -266,6 +276,13 @@ // to query MCSymbol afterward. InlinedEntity L(RawLabel, MI.getDebugLoc()->getInlinedAt()); DbgLabels.addInstr(L, MI); + } else if (MI.isDebugCallSite()) { + assert(MI.getNumOperands() < 4 && "Invalid DBG_CALLSITE instruction!"); + const DICallSite *RawCS = MI.getDebugCallSite(); + assert(RawCS->isValidLocationForIntrinsic(MI.getDebugLoc()) && + "Expected inlined-at fields to agree"); + InlinedCallSite CS(RawCS, MI.getDebugLoc()->getInlinedAt()); + DbgCallSites.addInstr(CS, MI); } } Index: lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp +++ lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp @@ -206,7 +206,7 @@ assert(DbgValues.empty() && "DbgValues map wasn't cleaned!"); assert(DbgLabels.empty() && "DbgLabels map wasn't cleaned!"); calculateDbgEntityHistory(MF, Asm->MF->getSubtarget().getRegisterInfo(), - DbgValues, DbgLabels); + DbgValues, DbgLabels, DbgCallSites); LLVM_DEBUG(DbgValues.dump()); // Request labels for the full history. @@ -250,6 +250,12 @@ requestLabelBeforeInsn(MI); } + // Ensure there is a symbol before DBG_CALLSITE. + for (const auto &I : DbgCallSites) { + const MachineInstr *MI = I.second; + requestLabelBeforeInsn(MI); + } + PrevInstLoc = DebugLoc(); PrevLabel = Asm->getFunctionBegin(); beginFunctionImpl(MF); @@ -318,6 +324,7 @@ endFunctionImpl(MF); DbgValues.clear(); DbgLabels.clear(); + DbgCallSites.clear(); LabelsBeforeInsn.clear(); LabelsAfterInsn.clear(); } Index: lib/CodeGen/AsmPrinter/DebugLocEntry.h =================================================================== --- lib/CodeGen/AsmPrinter/DebugLocEntry.h +++ lib/CodeGen/AsmPrinter/DebugLocEntry.h @@ -47,11 +47,22 @@ assert(cast(Expr)->isValid()); } + Value(const DIExpression *Expr, const GlobalValue *Global) + : Expression(Expr), EntryKind(E_Global) { + Constant.Global = Global; + } + + Value(const DIExpression *Expr) + : Expression(Expr), EntryKind(E_Expression){ + assert(Expr->isConstant()); + } + /// Any complex address location expression for this Value. const DIExpression *Expression; /// Type of entry that this represents. - enum EntryType { E_Location, E_Integer, E_ConstantFP, E_ConstantInt }; + enum EntryType { E_Location, E_Integer, E_ConstantFP, E_ConstantInt, + E_Expression, E_Global }; enum EntryType EntryKind; /// Either a constant, @@ -59,6 +70,7 @@ int64_t Int; const ConstantFP *CFP; const ConstantInt *CIP; + const GlobalValue *Global; } Constant; // Or a location in the machine frame. @@ -68,11 +80,15 @@ bool isInt() const { return EntryKind == E_Integer; } bool isConstantFP() const { return EntryKind == E_ConstantFP; } bool isConstantInt() const { return EntryKind == E_ConstantInt; } + bool isGlobal() const { return EntryKind == E_Global; } + bool isConstExpression() const { return EntryKind == E_Expression; } int64_t getInt() const { return Constant.Int; } const ConstantFP *getConstantFP() const { return Constant.CFP; } const ConstantInt *getConstantInt() const { return Constant.CIP; } + const GlobalValue *getGlobal() const { return Constant.Global; } MachineLocation getLoc() const { return Loc; } bool isFragment() const { return getExpression()->isFragment(); } + bool isEntryVal() const { return getExpression()->isEntryValue(); } const DIExpression *getExpression() const { return Expression; } friend bool operator==(const Value &, const Value &); friend bool operator<(const Value &, const Value &); @@ -88,6 +104,8 @@ Constant.CIP->dump(); else if (isConstantFP()) Constant.CFP->dump(); + else if (isGlobal()) + Constant.Global->dump(); if (Expression) Expression->dump(); } @@ -170,6 +188,10 @@ return A.Constant.CFP == B.Constant.CFP; case DebugLocEntry::Value::E_ConstantInt: return A.Constant.CIP == B.Constant.CIP; + case DebugLocEntry::Value::E_Global: + return A.Constant.Global == B.Constant.Global; + case DebugLocEntry::Value::E_Expression: + return true; } llvm_unreachable("unhandled EntryKind"); } Index: lib/CodeGen/AsmPrinter/DwarfCompileUnit.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -86,6 +86,8 @@ /// DbgVariable's DIE reference. DIE *constructVariableDIEImpl(const DbgVariable &DV, bool Abstract); + DIE *constructCallSiteDIE(DbgCallSite &DCS, const LexicalScope &Scope); + bool isDwoUnit() const override; DenseMap &getAbstractSPDies() { @@ -302,6 +304,8 @@ void applyLabelAttributes(const DbgLabel &Label, DIE &LabelDie); + void applyCallSiteAttributes(const DbgCallSite &CS, DIE &CSDie); + /// getRanges - Get the list of ranges for this unit. const SmallVectorImpl &getRanges() const { return CURanges; } SmallVector takeRanges() { return std::move(CURanges); } Index: lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -259,8 +259,8 @@ // It would be better if this were unconditional, but malformed input that // mixes non-fragments and fragments for the same variable is too expensive // to detect in the verifier. - if (DwarfExpr->isUnknownLocation()) - DwarfExpr->setMemoryLocationKind(); + if (DwarfExpr->isLocationUnknown()) + DwarfExpr->setMemoryLocationFlag(); DwarfExpr->addExpression(Expr); } if (Asm->TM.getTargetTriple().isNVPTX() && DD->tuneForGDB()) { @@ -561,6 +561,17 @@ return LabelDie; } +DIE *DwarfCompileUnit::constructCallSiteDIE(DbgCallSite &DCS, + const LexicalScope &Scope) { + auto CallSiteDie = DIE::get(DIEValueAllocator, DCS.getTag()); + insertDIE(DCS.getCallSite(), CallSiteDie); + DCS.setDIE(*CallSiteDie); + + applyCallSiteAttributes(DCS, *CallSiteDie); + + return CallSiteDie; +} + DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV, bool Abstract) { // Define variable debug information entry. @@ -647,7 +658,7 @@ if (Expr) Ops.append(Expr->elements_begin(), Expr->elements_end()); DIExpressionCursor Cursor(Ops); - DwarfExpr.setMemoryLocationKind(); + DwarfExpr.setMemoryLocationFlag(); if (const MCSymbol *FrameSymbol = Asm->getFunctionFrameSymbol()) addOpAddress(*Loc, FrameSymbol); else @@ -769,6 +780,9 @@ for (DbgVariable *DV : Locals) Children.push_back(constructVariableDIE(*DV, *Scope, ObjectPointer)); + for (DbgCallSite *DCS : DU->getScopeCallSites().lookup(Scope)) + Children.push_back(constructCallSiteDIE(*DCS, *Scope)); + // Skip imported directives in gmlt-like data. if (!includeMinimalInlineScopes()) { // There is no need to emit empty lexical block DIE. @@ -858,6 +872,8 @@ ContextCU = DD->lookupCU(ContextDIE->getUnitDie()); } + SP->setIsDesribedByCallSites(); + // Passing null as the associated node because the abstract definition // shouldn't be found by lookup. AbsDef = &ContextCU->createAndAddDIE(dwarf::DW_TAG_subprogram, *ContextDIE, nullptr); @@ -939,8 +955,12 @@ void DwarfCompileUnit::finishEntityDefinition(const DbgEntity *Entity) { DbgEntity *AbsEntity = getExistingAbstractEntity(Entity->getEntity()); - auto *Die = Entity->getDIE(); + + /// Call sites are already finished. + if (Die->getTag() == dwarf::DW_TAG_GNU_call_site) + return; + /// Label may be used to generate DW_AT_low_pc, so put it outside /// if/else block. const DbgLabel *Label = nullptr; @@ -1078,7 +1098,7 @@ DIELoc *Loc = new (DIEValueAllocator) DIELoc; DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); if (Location.isIndirect()) - DwarfExpr.setMemoryLocationKind(); + DwarfExpr.setMemoryLocationFlag(); DIExpressionCursor Cursor({}); const TargetRegisterInfo &TRI = *Asm->MF->getSubtarget().getRegisterInfo(); @@ -1102,7 +1122,7 @@ const DIExpression *DIExpr = DV.getSingleExpression(); DwarfExpr.addFragmentOffset(DIExpr); if (Location.isIndirect()) - DwarfExpr.setMemoryLocationKind(); + DwarfExpr.setMemoryLocationFlag(); DIExpressionCursor Cursor(DIExpr); const TargetRegisterInfo &TRI = *Asm->MF->getSubtarget().getRegisterInfo(); @@ -1139,6 +1159,66 @@ addFlag(VariableDie, dwarf::DW_AT_artificial); } +void DwarfCompileUnit::applyCallSiteAttributes(const DbgCallSite &CS, + DIE &CSDie) { + const auto *DICallSite = CS.getCallSite(); + + bool isTailCall = CS.isTail(); + uint64_t regCS; + if (isTailCall) + addFlag(CSDie, dwarf::DW_AT_call_tail_call); + + const MCSymbol *Sym = CS.getSymbol(); + addLabelAddress(CSDie, dwarf::DW_AT_low_pc, Sym); + // TODO: DW_AT_call_pc should be instead low_pc + for (auto Param : CS.getParameters()) { + uint64_t Register = Param.Register; + const DICallSiteParam *CSP = Param.DCSP; + auto CallSiteDieParam = + DIE::get(DIEValueAllocator, dwarf::DW_TAG_GNU_call_site_parameter); + insertDIE(CSP, CallSiteDieParam); + addAddress(*CallSiteDieParam, dwarf::DW_AT_location, + MachineLocation(Register)); + + DIELoc *Loc = new (DIEValueAllocator) DIELoc; + DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); + DwarfExpr.setCallParamLocation(); + const DIExpression *ValueExpr = Param.Value.Expression; + + if (Param.isFromLocation()) { + if (Param.Value.isGlobal()) + // TODO: Handle global symbols as func arguments. + continue; + else + DwarfDebug::emitDebugLocValue(*Asm, nullptr, Param.Value, DwarfExpr); + } else { + const DIBasicType *BT = nullptr; + if (CSP->getVar()) + BT = dyn_cast( + static_cast(CSP->getVar()->getType())); + if (ValueExpr && ValueExpr->isEntryValue()) + DwarfDebug::emitDebugLocEntryValue(*Asm, BT, Param.Value, DwarfExpr); + else + DwarfDebug::emitDebugLocValue(*Asm, BT, Param.Value, DwarfExpr); + } + addBlock(*CallSiteDieParam, dwarf::DW_AT_GNU_call_site_value, + DwarfExpr.finalize()); + + CSDie.addChild(CallSiteDieParam); + } + + if (auto *CalledSP = DICallSite->getCalledSubprogram()) { + DIE *CalledDIE = getOrCreateSubprogramDIE(CalledSP); + if (CalledDIE && CalledDIE->getTag() == dwarf::DW_TAG_subprogram) + addDIEEntry(CSDie, dwarf::DW_AT_abstract_origin, *CalledDIE); + // TODO: DW_AT_call_origin is DWARF5 replacement of abstract_origin + } else { + regCS = CS.getRegCS(); + addAddress(CSDie, dwarf::DW_AT_GNU_call_site_target, + MachineLocation(regCS)); + } +} + void DwarfCompileUnit::applyLabelAttributes(const DbgLabel &Label, DIE &LabelDie) { StringRef Name = Label.getName(); Index: lib/CodeGen/AsmPrinter/DwarfDebug.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.h +++ lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -14,6 +14,7 @@ #define LLVM_LIB_CODEGEN_ASMPRINTER_DWARFDEBUG_H #include "AddressPool.h" +#include "DebugLocEntry.h" #include "DebugLocStream.h" #include "DwarfFile.h" #include "llvm/ADT/ArrayRef.h" @@ -51,6 +52,7 @@ class DebugLocEntry; class DIE; class DwarfCompileUnit; +class DwarfExpression; class DwarfTypeUnit; class DwarfUnit; class LexicalScope; @@ -73,7 +75,8 @@ public: enum DbgEntityKind { DbgVariableKind, - DbgLabelKind + DbgLabelKind, + DbgCallSiteKind }; DbgEntity(const DINode *N, const DILocation *IA, unsigned ID) @@ -96,6 +99,7 @@ return false; case DbgVariableKind: case DbgLabelKind: + case DbgCallSiteKind: return true; } } @@ -260,6 +264,93 @@ } }; +//===----------------------------------------------------------------------===// +/// This class is used to track call site information. +/// +/// CallSites are collected from \c DBG_CallSite instructions. +class DbgCallSite : public DbgEntity { + bool isTailCall = false; + const MCSymbol *Sym; /// Symbol before DBG_CALLSITE instruction. + + // Register that holds an indirect call. + uint64_t RegCS = 0; + + struct DbgCallSiteParam { + enum ParamKind { Normal, FromLocation }; + uint64_t Register; + const DICallSiteParam *DCSP; + DebugLocEntry::Value Value; + ParamKind Kind; + DbgCallSiteParam(uint64_t Reg, const DICallSiteParam *CSP, + DebugLocEntry::Value Val) + : Register(Reg), DCSP(CSP), Value(Val), Kind(Normal) {} + DbgCallSiteParam(uint64_t Reg, const DICallSiteParam *CSP, + DebugLocEntry::Value Val, bool Location) + : Register(Reg), DCSP(CSP), Value(Val), Kind(FromLocation) {} + DbgCallSiteParam(uint64_t Reg, const DICallSiteParam *DCSP) + : Register(Reg), DCSP(DCSP), Value(DCSP->getExpression()), + Kind(Normal) {} + bool isFromLocation() { return Kind == FromLocation; } + }; + + SmallVector Params; + +public: + /// We need MCSymbol information to generate DW_AT_low_pc. + DbgCallSite(const DICallSite *CS, const DILocation *IA, + const MCSymbol *Sym = nullptr) + : DbgEntity(CS, IA, DbgCallSiteKind), Sym(Sym) {} + + /// @{ + /// Accessors. + const DICallSite *getCallSite() const { + return cast(getEntity()); + } + const MCSymbol *getSymbol() const { return Sym; } + + void setIsTail(bool isTail) { isTailCall = isTail; } + bool isTail() const { return isTailCall; } + + void setRegCS(uint64_t reg) { RegCS = reg; } + uint64_t getRegCS() const { return RegCS; } + + /// @} + + /// Translate tag to proper Dwarf tag. + dwarf::Tag getTag() const { return dwarf::DW_TAG_GNU_call_site; } + + void addParam(uint64_t RegLoc, const DICallSiteParam *DCSP, + DebugLocEntry::Value Val, bool FromLocation) { + Params.push_back({RegLoc, DCSP, Val, FromLocation}); + } + + void addParam(uint64_t RegLoc, const DICallSiteParam *DCSP, + DebugLocEntry::Value Val) { + Params.push_back({RegLoc, DCSP, Val}); + } + + void addParam(uint64_t Reg, const DICallSiteParam *DCSP) { + Params.push_back({Reg, DCSP}); + } + + const SmallVector getParameters() const { + return Params; + } + + dwarf::Tag getParamTag() const { + return dwarf::DW_TAG_GNU_call_site_parameter; + } + + static bool classof(const DbgEntity *N) { + return N->getDbgEntityID() == DbgCallSiteKind; + } + +private: + template T *resolve(TypedDINodeRef Ref) const { + return Ref.resolve(); + } +}; + /// Helper used to pair up a symbol and its DWARF compile unit. struct SymbolCU { SymbolCU(DwarfCompileUnit *CU, const MCSymbol *Sym) : Sym(Sym), CU(CU) {} @@ -408,6 +499,7 @@ } using InlinedEntity = DbgValueHistoryMap::InlinedEntity; + using InlinedCallSite = DbgCallSiteInstrMap::InlinedCallSite; void ensureAbstractEntityIsCreated(DwarfCompileUnit &CU, const DINode *Node, @@ -420,7 +512,9 @@ LexicalScope &Scope, const DINode *Node, const DILocation *Location, - const MCSymbol *Sym = nullptr); + const MCSymbol *Sym = nullptr, + bool isTailCall = false, + uint64_t regCS = 0); /// Construct a DIE for this abstract scope. void constructAbstractSubprogramScopeDIE(DwarfCompileUnit &SrcCU, LexicalScope *Scope); @@ -730,6 +824,15 @@ void addSectionLabel(const MCSymbol *Sym); const MCSymbol *getSectionLabel(const MCSection *S); + + static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT, + const DebugLocEntry::Value &Value, + DwarfExpression &DwarfExpr); + + static void emitDebugLocEntryValue(const AsmPrinter &AP, + const DIBasicType *BT, + const DebugLocEntry::Value &Value, + DwarfExpression &DwarfExpr); }; } // end namespace llvm Index: lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -35,12 +35,14 @@ #include "llvm/CodeGen/LexicalScopes.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" +#include "llvm/CodeGen/TargetLowering.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DebugLoc.h" @@ -1058,27 +1060,47 @@ } } -// Get .debug_loc entry for the instruction range starting at MI. -static DebugLocEntry::Value getDebugLocValue(const MachineInstr *MI) { - const DIExpression *Expr = MI->getDebugExpression(); - assert(MI->getNumOperands() == 4); - if (MI->getOperand(0).isReg()) { - auto RegOp = MI->getOperand(0); - auto Op1 = MI->getOperand(1); +static DebugLocEntry::Value +getDebugValue(const MachineInstr *MI, const DIExpression *Expr, short OpIndex) { + bool callSiteParamValue = OpIndex; + assert((!callSiteParamValue && MI->isDebugValue() && + MI->getNumOperands() == 4) || + (callSiteParamValue && MI->isDebugCallSiteParam())); + if (MI->getOperand(OpIndex).isReg()) { + auto RegOp = MI->getOperand(OpIndex); + auto Op1 = MI->getOperand(OpIndex + 1); // If the second operand is an immediate, this is a // register-indirect address. - assert((!Op1.isImm() || (Op1.getImm() == 0)) && "unexpected offset"); + assert((callSiteParamValue || (!Op1.isImm() || (Op1.getImm() == 0))) && + "unexpected offset"); MachineLocation MLoc(RegOp.getReg(), Op1.isImm()); return DebugLocEntry::Value(Expr, MLoc); } - if (MI->getOperand(0).isImm()) - return DebugLocEntry::Value(Expr, MI->getOperand(0).getImm()); - if (MI->getOperand(0).isFPImm()) - return DebugLocEntry::Value(Expr, MI->getOperand(0).getFPImm()); - if (MI->getOperand(0).isCImm()) - return DebugLocEntry::Value(Expr, MI->getOperand(0).getCImm()); + if (MI->getOperand(OpIndex).isImm()) + return DebugLocEntry::Value(Expr, MI->getOperand(OpIndex).getImm()); + if (MI->getOperand(OpIndex).isFPImm()) + return DebugLocEntry::Value(Expr, MI->getOperand(OpIndex).getFPImm()); + if (MI->getOperand(OpIndex).isCImm()) + return DebugLocEntry::Value(Expr, MI->getOperand(OpIndex).getCImm()); + if (MI->getOperand(OpIndex).isGlobal()) + return DebugLocEntry::Value(Expr, MI->getOperand(OpIndex).getGlobal()); + + llvm_unreachable("Unexpected debug instruction!"); +} + +// Get .debug_loc entry for the instruction range starting at MI. +static DebugLocEntry::Value getDebugLocValue(const MachineInstr *MI) { + return getDebugValue(MI, MI->getDebugExpression(), 0); +} - llvm_unreachable("Unexpected 4-operand DBG_VALUE instruction!"); +static DebugLocEntry::Value getDebugCallSiteLocValue(const MachineInstr *MI, + const DIExpression *Expr) { + if (MI->isDebugCallSiteParam()) + return getDebugValue(MI, Expr, 2); + else { + assert(MI->isDebugValue()); + return getDebugValue(MI, Expr, 0); + } } /// If this and Next are describing different fragments of the same @@ -1234,7 +1256,9 @@ LexicalScope &Scope, const DINode *Node, const DILocation *Location, - const MCSymbol *Sym) { + const MCSymbol *Sym, + bool isTailCall, + uint64_t regCS) { ensureAbstractEntityIsCreatedIfScoped(TheCU, Node, Scope.getScopeNode()); if (isa(Node)) { ConcreteEntities.push_back( @@ -1248,6 +1272,14 @@ Location, Sym)); InfoHolder.addScopeLabel(&Scope, cast(ConcreteEntities.back().get())); + } else if (isa(Node)) { + ConcreteEntities.push_back( + llvm::make_unique(cast(Node), + Location, Sym)); + cast(ConcreteEntities.back().get())->setIsTail(isTailCall); + cast(ConcreteEntities.back().get())->setRegCS(regCS); + InfoHolder.addScopeCallSite(&Scope, + cast(ConcreteEntities.back().get())); } return ConcreteEntities.back().get(); } @@ -1310,6 +1342,27 @@ return false; } +// Debug loc will use DIExpression fom variable plus call site expression +// over that variable. +static const DIExpression *getExprOverDbgValue(const MachineInstr *DbgValMI, + const DIExpression *CSExpr) { + const DIExpression *DbgValueExpr = DbgValMI->getDebugExpression(); + if (CSExpr->getNumElements()) { + SmallVector Ops; + Ops.append(CSExpr->getElements().begin(), CSExpr->getElements().end()); + bool isConst = CSExpr->isConstant(); + if (Ops.size() && Ops.back() == dwarf::DW_OP_push_object_address) + Ops.pop_back(); + + if (isConst && DbgValueExpr->isEntryValue()) + return CSExpr; + else + return DIExpression::prependOpcodes(DbgValueExpr, Ops); + } + + return DbgValueExpr; +} + // Find variables for each lexical scope. void DwarfDebug::collectEntityInfo(DwarfCompileUnit &TheCU, const DISubprogram *SP, @@ -1399,6 +1452,95 @@ createConcreteEntity(TheCU, *Scope, Label, IL.second, Sym); } + // For each call site collected from DBG_CALLSIte instructions, convert to + // DWARF-related DbgCallSite. + for (const auto &I : DbgCallSites) { + InlinedCallSite ICS = I.first; + const MachineInstr *MI = I.second; + if (MI == nullptr) + continue; + + LexicalScope *Scope = nullptr; + // Get inlined DILocation if it is inlined cs. + if (const DILocation *IA = ICS.second) + Scope = LScopes.findInlinedScope(ICS.first->getScope(), IA); + else + Scope = LScopes.findLexicalScope(ICS.first->getScope()); + // If cs scope is not found then skip this cs. + if (!Scope) + continue; + + MCSymbol *Sym = getLabelBeforeInsn(MI); + bool isTailCall = MI->isTailCall(); + uint64_t regCS = MI->getRegCS(); + + DbgEntity *Entity = createConcreteEntity( + TheCU, *Scope, ICS.first, ICS.second, Sym, isTailCall, regCS); + DbgCallSite *DbgCS = cast(Entity); + auto LookForCSParamIT = (MI->getIterator()); + while (LookForCSParamIT->isBundledWithSucc()) { + LookForCSParamIT++; + assert(LookForCSParamIT->getOperand(0).isReg() && + "Add support for memory locations"); + uint64_t paramForwardingReg = LookForCSParamIT->getOperand(0).getReg(); + const DICallSiteParam *DCSP = LookForCSParamIT->getDebugCallSiteParam(); + const DIExpression *Expr; + + if (LookForCSParamIT->getNumOperands() == 5 && + LookForCSParamIT->getOperand(4).isMetadata()) + Expr = + cast(LookForCSParamIT->getOperand(4).getMetadata()); + else + Expr = DIExpression::get(DCSP->getExpression()->getContext(), {}); + + const MachineOperand &ParamLocation = LookForCSParamIT->getOperand(2); + + if (LookForCSParamIT->getOperand(3).isImm()) + if (int64_t Offset = LookForCSParamIT->getOperand(3).getImm()) + Expr = DIExpression::prepend(Expr, false, Offset); + + bool isRegisterLocation = ParamLocation.isReg(); + bool isNoReg = isRegisterLocation ? !ParamLocation.getReg() : false; + if (!isNoReg) { + auto Value = getDebugCallSiteLocValue(&*LookForCSParamIT, Expr); + DbgCS->addParam(paramForwardingReg, DCSP, Value, true); + continue; + } + + // Try to use backup location generated from frontend. We try to + // use expression generated in the frontend. Use expression + // over some variable or use some constant expression. + + // This is constant expression. + if (DCSP->getVar() == nullptr) { + assert(DCSP->getExpression()->isConstant()); + DbgCS->addParam(paramForwardingReg, DCSP); + continue; + } + // Else it is expression over variable. + auto LookForDbgValueIT = (MI->getReverseIterator()); + LookForDbgValueIT++; + + for (; LookForDbgValueIT != MI->getParent()->rend(); + LookForDbgValueIT++) { + if (!LookForDbgValueIT->isDebugValue()) + continue; + + const DILocalVariable *DLV = LookForDbgValueIT->getDebugVariable(); + if (DCSP->getVar() == DLV) { + Expr = + getExprOverDbgValue(&*LookForDbgValueIT, DCSP->getExpression()); + auto Value = getDebugCallSiteLocValue(&*LookForDbgValueIT, Expr); + DbgCS->addParam(paramForwardingReg, DCSP, Value); + break; + } + } + assert(LookForDbgValueIT != MI->getParent()->rend() && + "We must find DBG_VALUE that matches DCSP->getVar(). " && + "Otherwise it should have been deleted in LiveDebugValues."); + } + } + // Collect info for variables/labels that were optimized out. for (const DINode *DN : SP->getRetainedNodes()) { if (!Processed.insert(InlinedEntity(DN, nullptr)).second) @@ -1646,6 +1788,8 @@ Scope = DV->getScope(); else if (auto *DL = dyn_cast(DN)) Scope = DL->getScope(); + else if (auto *DCS = dyn_cast(DN)) + Scope = DCS->getScope(); else llvm_unreachable("Unexpected DI type!"); @@ -1673,6 +1817,7 @@ // can be used cross-function) InfoHolder.getScopeVariables().clear(); InfoHolder.getScopeLabels().clear(); + InfoHolder.getScopeCallSites().clear(); PrevLabel = nullptr; CurFn = nullptr; } @@ -1920,9 +2065,9 @@ Streamer.EmitInt8(Byte, Comment != End ? *(Comment++) : ""); } -static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT, - const DebugLocEntry::Value &Value, - DwarfExpression &DwarfExpr) { +void DwarfDebug::emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT, + const DebugLocEntry::Value &Value, + DwarfExpression &DwarfExpr) { auto *DIExpr = Value.getExpression(); DIExpressionCursor ExprCursor(DIExpr); DwarfExpr.addFragmentOffset(DIExpr); @@ -1936,7 +2081,7 @@ } else if (Value.isLocation()) { MachineLocation Location = Value.getLoc(); if (Location.isIndirect()) - DwarfExpr.setMemoryLocationKind(); + DwarfExpr.setMemoryLocationFlag(); DIExpressionCursor Cursor(DIExpr); const TargetRegisterInfo &TRI = *AP.MF->getSubtarget().getRegisterInfo(); if (!DwarfExpr.addMachineRegExpression(TRI, Cursor, Location.getReg())) @@ -1949,6 +2094,22 @@ DwarfExpr.addExpression(std::move(ExprCursor)); } +void DwarfDebug::emitDebugLocEntryValue(const AsmPrinter &AP, + const DIBasicType *BT, + const DebugLocEntry::Value &Value, + DwarfExpression &DwarfExpr) { + auto *DIExpr = Value.getExpression(); + DIExpressionCursor ExprCursor(DIExpr); + DwarfExpr.addFragmentOffset(DIExpr); + DwarfExpr.setEntryValueLocationFlag(); + + if (Value.isLocation()) { + MachineLocation Location = Value.getLoc(); + const TargetRegisterInfo &TRI = *AP.MF->getSubtarget().getRegisterInfo(); + DwarfExpr.addMachineRegExpression(TRI, ExprCursor, Location.getReg()); + } +} + void DebugLocEntry::finalize(const AsmPrinter &AP, DebugLocStream::ListBuilder &List, const DIBasicType *BT) { @@ -1965,12 +2126,19 @@ assert(std::is_sorted(Values.begin(), Values.end()) && "fragments are expected to be sorted"); - for (auto Fragment : Values) - emitDebugLocValue(AP, BT, Fragment, DwarfExpr); + if (!Value.isEntryVal()) { + for (auto Fragment : Values) + DwarfDebug::emitDebugLocValue(AP, BT, Fragment, DwarfExpr); + } else { + for (auto Fragment : Values) + DwarfDebug::emitDebugLocEntryValue(AP, BT, Fragment, DwarfExpr); + } + } else if (Value.isEntryVal()) { + DwarfDebug::emitDebugLocEntryValue(AP, BT, Value, DwarfExpr); } else { assert(Values.size() == 1 && "only fragments may have >1 value"); - emitDebugLocValue(AP, BT, Value, DwarfExpr); + DwarfDebug::emitDebugLocValue(AP, BT, Value, DwarfExpr); } DwarfExpr.finalize(); } Index: lib/CodeGen/AsmPrinter/DwarfExpression.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfExpression.h +++ lib/CodeGen/AsmPrinter/DwarfExpression.h @@ -115,9 +115,43 @@ unsigned SubRegisterSizeInBits = 0; unsigned SubRegisterOffsetInBits = 0; - /// The kind of location description being produced. - enum { Unknown = 0, Register, Memory, Implicit } LocationKind = Unknown; + /// The flags of location description being produced. + enum LocationFlags { + Unknown = 0, + Register = 1 << 0, + Memory = 1 << 1, + Implicit = 1 << 2, + ParamExpr = 1 << 3, + EntryValueExpr = 1 << 4 + }; + + uint8_t LocationFlags = 0; + +public: + bool isLocationUnknown() { + return LocationFlags == Unknown; + } + + bool isLocationRegister() { + return LocationFlags & Register; + } + + bool isLocationMemory() { + return LocationFlags & Memory; + } + + bool isLocationImplicit() { + return LocationFlags & Implicit; + } + + bool isLocationParamExpr() { + return LocationFlags & ParamExpr; + } + bool isLocationEntryValueExpr() { + return LocationFlags & EntryValueExpr; + } +protected: /// Push a DW_OP_piece / DW_OP_bit_piece for emitting later, if one is needed /// to represent a subregister. void setSubRegisterPiece(unsigned SizeInBits, unsigned OffsetInBits) { @@ -213,13 +247,21 @@ /// Emit an unsigned constant. void addUnsignedConstant(const APInt &Value); - bool isMemoryLocation() const { return LocationKind == Memory; } - bool isUnknownLocation() const { return LocationKind == Unknown; } - /// Lock this down to become a memory location description. - void setMemoryLocationKind() { - assert(LocationKind == Unknown); - LocationKind = Memory; + void setMemoryLocationFlag() { + assert(isLocationUnknown() || isLocationParamExpr() || + isLocationEntryValueExpr()); + LocationFlags |= Memory; + } + + /// Set this to become a entry value location + void setEntryValueLocationFlag() { + LocationFlags |= EntryValueExpr; + } + + /// Set this down to become a call site parameter location + void setCallParamLocation() { + LocationFlags |= ParamExpr; } /// Emit a machine register location. As an optimization this may also consume Index: lib/CodeGen/AsmPrinter/DwarfExpression.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfExpression.cpp +++ lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -39,9 +39,10 @@ void DwarfExpression::addReg(int DwarfReg, const char *Comment) { assert(DwarfReg >= 0 && "invalid negative dwarf register number"); - assert((LocationKind == Unknown || LocationKind == Register) && + assert((isLocationUnknown() || isLocationRegister() || + isLocationEntryValueExpr() || isLocationParamExpr()) && "location description already locked down"); - LocationKind = Register; + LocationFlags |= Register; if (DwarfReg < 32) { emitOp(dwarf::DW_OP_reg0 + DwarfReg, Comment); } else { @@ -52,7 +53,7 @@ void DwarfExpression::addBReg(int DwarfReg, int Offset) { assert(DwarfReg >= 0 && "invalid negative dwarf register number"); - assert(LocationKind != Register && "location description already locked down"); + assert(!isLocationRegister() && "location description already locked down"); if (DwarfReg < 32) { emitOp(dwarf::DW_OP_breg0 + DwarfReg); } else { @@ -183,21 +184,24 @@ } void DwarfExpression::addSignedConstant(int64_t Value) { - assert(LocationKind == Implicit || LocationKind == Unknown); - LocationKind = Implicit; + assert(isLocationImplicit() || isLocationUnknown() || + isLocationEntryValueExpr() || isLocationParamExpr()); + LocationFlags |= Implicit; emitOp(dwarf::DW_OP_consts); emitSigned(Value); } void DwarfExpression::addUnsignedConstant(uint64_t Value) { - assert(LocationKind == Implicit || LocationKind == Unknown); - LocationKind = Implicit; + assert(isLocationImplicit() || isLocationUnknown() || + isLocationEntryValueExpr() || isLocationParamExpr()); + LocationFlags |= Implicit; emitConstu(Value); } void DwarfExpression::addUnsignedConstant(const APInt &Value) { - assert(LocationKind == Implicit || LocationKind == Unknown); - LocationKind = Implicit; + assert(isLocationImplicit() || isLocationUnknown() || + isLocationEntryValueExpr() || isLocationParamExpr()); + LocationFlags |= Implicit; unsigned Size = Value.getBitWidth(); const uint64_t *Data = Value.getRawData(); @@ -221,7 +225,7 @@ unsigned FragmentOffsetInBits) { auto Fragment = ExprCursor.getFragmentInfo(); if (!addMachineReg(TRI, MachineReg, Fragment ? Fragment->SizeInBits : ~1U)) { - LocationKind = Unknown; + LocationFlags = Unknown; return false; } @@ -236,17 +240,45 @@ // operation to multiple DW_OP_pieces. if (HasComplexExpression && DwarfRegs.size() > 1) { DwarfRegs.clear(); - LocationKind = Unknown; + LocationFlags = Unknown; return false; } - // Handle simple register locations. - if (LocationKind != Memory && !HasComplexExpression) { + // Handle simple register locations. If we are supposed to + // emit call site parameter expression and if that expression + // is just register location emit it with addBReg and offset 0 + // because we should emitt DWARF expression not a location. + if ((!isLocationMemory() && !isLocationParamExpr() && + !HasComplexExpression) || + isLocationEntryValueExpr()) { + + if (isLocationEntryValueExpr()) { + unsigned size = 0; + for (auto &Reg : DwarfRegs) { + if (Reg.DwarfRegNo >= 0) + ++size; + if (Reg.Size != 0) { + const unsigned SizeOfByte = 8; + if (Reg.Size % SizeOfByte) + size += 3; + else + size += 2; + } + } + emitOp(dwarf::DW_OP_GNU_entry_value); + emitUnsigned(size); + } + for (auto &Reg : DwarfRegs) { if (Reg.DwarfRegNo >= 0) addReg(Reg.DwarfRegNo, Reg.Comment); addOpPiece(Reg.Size); } + + if (isLocationEntryValueExpr() && !isLocationParamExpr() && + DwarfVersion >= 4) + emitOp(dwarf::DW_OP_stack_value); + DwarfRegs.clear(); return true; } @@ -257,7 +289,7 @@ return Op.getOp() == dwarf::DW_OP_stack_value; })) { DwarfRegs.clear(); - LocationKind = Unknown; + LocationFlags = Unknown; return false; } @@ -272,6 +304,7 @@ if (Op && (Op->getOp() == dwarf::DW_OP_plus_uconst)) { SignedOffset = Op->getArg(0); ExprCursor.take(); + Op = ExprCursor.peek(); } // [Reg, DW_OP_constu, Offset, DW_OP_plus] --> [DW_OP_breg, Offset] @@ -282,7 +315,7 @@ if (N && (N->getOp() == dwarf::DW_OP_plus || (N->getOp() == dwarf::DW_OP_minus && !SubRegisterSizeInBits))) { int Offset = Op->getArg(0); - SignedOffset = (N->getOp() == dwarf::DW_OP_minus) ? -Offset : Offset; + SignedOffset =+ (N->getOp() == dwarf::DW_OP_minus) ? -Offset : Offset; ExprCursor.consume(2); } } @@ -320,7 +353,12 @@ while (ExprCursor) { auto Op = ExprCursor.take(); - switch (Op->getOp()) { + uint64_t OpNum = Op->getOp(); + if (OpNum >= dwarf::DW_OP_lit0 && OpNum <= dwarf::DW_OP_lit31) { + emitOp(OpNum); + continue; + } + switch (OpNum) { case dwarf::DW_OP_LLVM_fragment: { unsigned SizeInBits = Op->getArg(1); unsigned FragmentOffset = Op->getArg(0); @@ -340,18 +378,18 @@ SizeInBits = std::min(SizeInBits, SubRegisterSizeInBits); // Emit a DW_OP_stack_value for implicit location descriptions. - if (LocationKind == Implicit) + if (isLocationImplicit()) addStackValue(); // Emit the DW_OP_piece. addOpPiece(SizeInBits, SubRegisterOffsetInBits); setSubRegisterPiece(0, 0); // Reset the location description kind. - LocationKind = Unknown; + LocationFlags = Unknown; return; } case dwarf::DW_OP_plus_uconst: - assert(LocationKind != Register); + assert(!isLocationRegister()); emitOp(dwarf::DW_OP_plus_uconst); emitUnsigned(Op->getArg(0)); break; @@ -369,38 +407,52 @@ 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(LocationKind != Register); - if (LocationKind != Memory && ::isMemoryLocation(ExprCursor)) + assert(!isLocationRegister()); + if (!isLocationMemory() && isMemoryLocation(ExprCursor)) // Turning this into a memory location description makes the deref // implicit. - LocationKind = Memory; + LocationFlags |= Memory; else emitOp(dwarf::DW_OP_deref); break; case dwarf::DW_OP_constu: - assert(LocationKind != Register); + assert(!isLocationRegister()); emitConstu(Op->getArg(0)); break; + case dwarf::DW_OP_consts: + assert(!isLocationRegister()); + emitOp(dwarf::DW_OP_consts); + emitUnsigned(Op->getArg(0)); + break; case dwarf::DW_OP_stack_value: - LocationKind = Implicit; + LocationFlags |= Implicit; break; case dwarf::DW_OP_swap: - assert(LocationKind != Register); + assert(!isLocationRegister()); emitOp(dwarf::DW_OP_swap); break; case dwarf::DW_OP_xderef: - assert(LocationKind != Register); + assert(!isLocationRegister()); emitOp(dwarf::DW_OP_xderef); break; + case dwarf::DW_OP_neg: + emitOp(dwarf::DW_OP_neg); + break; + case dwarf::DW_OP_push_object_address: + emitOp(dwarf::DW_OP_push_object_address); + break; + case dwarf::DW_OP_GNU_entry_value: + emitOp(dwarf::DW_OP_GNU_entry_value); + break; default: llvm_unreachable("unhandled opcode found in expression"); } } - if (LocationKind == Implicit) + if (isLocationImplicit() && !isLocationParamExpr()) // Turn this into an implicit location description. addStackValue(); } Index: lib/CodeGen/AsmPrinter/DwarfFile.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfFile.h +++ lib/CodeGen/AsmPrinter/DwarfFile.h @@ -26,6 +26,7 @@ class DbgEntity; class DbgVariable; class DbgLabel; +class DbgCallSite; class DwarfCompileUnit; class DwarfUnit; class LexicalScope; @@ -101,6 +102,10 @@ /// Collection of DbgVariables of each lexical scope. DenseMap ScopeVariables; + // Collection of dbg callsites of a scope + using CallSiteList = SmallVector; + DenseMap ScopeCallSites; + /// Collection of DbgLabels of each lexical scope. using LabelList = SmallVector; DenseMap ScopeLabels; @@ -180,6 +185,12 @@ return ScopeVariables; } + void addScopeCallSite(LexicalScope *LS, DbgCallSite *CS); + + DenseMap &getScopeCallSites() { + return ScopeCallSites; + } + DenseMap &getScopeLabels() { return ScopeLabels; } Index: lib/CodeGen/AsmPrinter/DwarfFile.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfFile.cpp +++ lib/CodeGen/AsmPrinter/DwarfFile.cpp @@ -108,6 +108,11 @@ return true; } +void DwarfFile::addScopeCallSite(LexicalScope *LS, DbgCallSite *CS) { + SmallVectorImpl &CallSites = ScopeCallSites[LS]; + CallSites.push_back(CS); +} + void DwarfFile::addScopeLabel(LexicalScope *LS, DbgLabel *Label) { SmallVectorImpl &Labels = ScopeLabels[LS]; Labels.push_back(Label); Index: lib/CodeGen/AsmPrinter/DwarfUnit.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfUnit.h +++ lib/CodeGen/AsmPrinter/DwarfUnit.h @@ -193,6 +193,9 @@ void addSourceLine(DIE &Die, const DIType *Ty); void addSourceLine(DIE &Die, const DIObjCProperty *Ty); + /// Add location information for a call site. + void addSourceCallLine(DIE &Die, const DICallSite *CS); + /// Add constant value entry in variable DIE. void addConstantValue(DIE &Die, const MachineOperand &MO, const DIType *Ty); void addConstantValue(DIE &Die, const ConstantInt *CI, const DIType *Ty); Index: lib/CodeGen/AsmPrinter/DwarfUnit.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -1103,7 +1103,7 @@ // Stop here and fill this in later, depending on whether or not this // subprogram turns out to have inlined instances or not. - if (SP->isDefinition()) + if (SP->isDefinition() && !SP->getIsDeclForCallSite()) return &SPDie; applySubprogramAttributes(SP, SPDie); @@ -1225,6 +1225,9 @@ if (SP->isArtificial()) addFlag(SPDie, dwarf::DW_AT_artificial); + if (SP->getIsDesribedByCallSites()) + addFlag(SPDie, dwarf::DW_AT_GNU_all_call_sites); + if (!SP->isLocalToUnit()) addFlag(SPDie, dwarf::DW_AT_external); Index: lib/CodeGen/MachineInstr.cpp =================================================================== --- lib/CodeGen/MachineInstr.cpp +++ lib/CodeGen/MachineInstr.cpp @@ -809,6 +809,16 @@ return cast(getOperand(0).getMetadata()); } +bool MachineInstr::isTailCall() const { + assert(isDebugCallSite() && "not a DBG_CALLSITE"); + return (bool)(getOperand(0).getImm()); +} + +uint64_t MachineInstr::getRegCS() const { + assert(isDebugCallSite() && "not a DBG_CALLSITE"); + return (uint64_t)(getOperand(1).getReg()); +} + const DICallSite *MachineInstr::getDebugCallSite() const { assert(isDebugCallSite() && "not a DBG_CALLSITE"); return cast(getOperand(2).getMetadata()); Index: lib/DebugInfo/DWARF/DWARFDie.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFDie.cpp +++ lib/DebugInfo/DWARF/DWARFDie.cpp @@ -318,7 +318,8 @@ } } else if (Attr == DW_AT_location || Attr == DW_AT_frame_base || Attr == DW_AT_data_member_location || - Attr == DW_AT_GNU_call_site_value) + Attr == DW_AT_GNU_call_site_value || + Attr == DW_AT_GNU_call_site_target) dumpLocation(OS, formValue, U, sizeof(BaseIndent) + Indent + 4, DumpOpts); else formValue.dump(OS, DumpOpts); Index: lib/DebugInfo/DWARF/DWARFExpression.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFExpression.cpp +++ lib/DebugInfo/DWARF/DWARFExpression.cpp @@ -96,6 +96,7 @@ Descriptions[DW_OP_addrx] = Desc(Op::Dwarf4, Op::SizeLEB); Descriptions[DW_OP_GNU_addr_index] = Desc(Op::Dwarf4, Op::SizeLEB); Descriptions[DW_OP_GNU_const_index] = Desc(Op::Dwarf4, Op::SizeLEB); + Descriptions[DW_OP_GNU_entry_value] = Desc(Op::Dwarf4, Op::SizeLEB); return Descriptions; } @@ -251,7 +252,7 @@ } else { if (Signed) OS << format(" %+" PRId64, (int64_t)Operands[Operand]); - else + else if (Opcode != DW_OP_GNU_entry_value) OS << format(" 0x%" PRIx64, Operands[Operand]); } } @@ -260,6 +261,7 @@ void DWARFExpression::print(raw_ostream &OS, const MCRegisterInfo *RegInfo, bool IsEH) const { + uint32_t EntryValExprSize = 0; for (auto &Op : *this) { if (!Op.print(OS, this, RegInfo, IsEH)) { uint32_t FailOffset = Op.getEndOffset(); @@ -267,6 +269,19 @@ OS << format(" %02x", Data.getU8(&FailOffset)); return; } + + if (Op.getCode() == DW_OP_GNU_entry_value) { + OS << "("; + EntryValExprSize = Op.getRawOperand(0); + continue; + } + + if (EntryValExprSize) { + EntryValExprSize--; + if (EntryValExprSize == 0) + OS << ")"; + } + if (Op.getEndOffset() < Data.getData().size()) OS << ", "; } Index: lib/IR/DIBuilder.cpp =================================================================== --- lib/IR/DIBuilder.cpp +++ lib/IR/DIBuilder.cpp @@ -847,7 +847,7 @@ } DINodeArray AV = getOrCreateArray(Elements); - Fn->replaceElements(AV); + Fn->replaceRetainedNodes(AV); } DICallSite *DIBuilder::createSimpleCallSite(DICallSite *DCS, @@ -864,7 +864,7 @@ NewElements.push_back(DCS); DINodeArray AV = getOrCreateArray(NewElements); - Fn->replaceElements(AV); + Fn->replaceRetainedNodes(AV); return Node; } Index: lib/IR/DebugInfoMetadata.cpp =================================================================== --- lib/IR/DebugInfoMetadata.cpp +++ lib/IR/DebugInfoMetadata.cpp @@ -852,6 +852,7 @@ case dwarf::DW_OP_LLVM_fragment: return 3; case dwarf::DW_OP_constu: + case dwarf::DW_OP_consts: case dwarf::DW_OP_plus_uconst: return 2; default: @@ -1122,6 +1123,28 @@ } bool DIExpression::isConstant() const { + auto isLiteral = [this]() { + return dwarf::DW_OP_lit0 <= getElement(0) && + dwarf::DW_OP_lit31 >= getElement(0); + }; + auto isNegation = [this](unsigned Index) { + return dwarf::DW_OP_neg == getElement(Index); + }; + auto isConstuOrConsts = [this]() { + return getElement(0) == dwarf::DW_OP_consts || + getElement(0) == dwarf::DW_OP_constu; + }; + + if (getNumElements() == 1) + return isLiteral(); + else if (getNumElements() == 2) { + if (isConstuOrConsts()) + return true; + else + return isLiteral() && isNegation(1); + } else if (getNumElements() == 3 && isNegation(2)) + return isConstuOrConsts(); + // Recognize DW_OP_constu C DW_OP_stack_value (DW_OP_LLVM_fragment Len Ofs)?. if (getNumElements() != 3 && getNumElements() != 6) return false; Index: test/DebugInfo/MIR/X86/call-site-param-expr.mir =================================================================== --- /dev/null +++ test/DebugInfo/MIR/X86/call-site-param-expr.mir @@ -0,0 +1,202 @@ +# RUN: llc -filetype=obj -mtriple=x86_64-unknown-unknown -start-after=machineverifier -o - %s| llvm-dwarfdump - | FileCheck %s +# +#extern void foo(int *a, int b, int c, int d, int e, int f); +#extern int getVal(); +# +#void baa(int arg1, int arg2, int arg3) { +# int local1 = getVal(); +# foo(&local1, arg2, 10, 15, arg3 + 3, arg1 + arg2); +#} +# +# Test MIR is slightly changed in order to cover more code. +# CHECK: DW_TAG_GNU_call_site +# CHECK: DW_AT_abstract_origin {{.*}} "foo" +# CHECK: DW_TAG_GNU_call_site_parameter +# CHECK-NEXT: DW_AT_location (DW_OP_reg2 RCX) +# CHECK-NEXT: DW_AT_GNU_call_site_value (DW_OP_lit15) +# CHECK: DW_TAG_GNU_call_site_parameter +# CHECK-NEXT: DW_AT_location (DW_OP_reg1 RDX) +# CHECK-NEXT: DW_AT_GNU_call_site_value (DW_OP_lit10) +# CHECK: DW_TAG_GNU_call_site_parameter +# CHECK-NEXT: DW_AT_location (DW_OP_reg4 RSI) +# CHECK-NEXT: DW_AT_GNU_call_site_value (DW_OP_breg3 RBX+0) +# CHECK: DW_TAG_GNU_call_site_parameter +# CHECK-NEXT: DW_AT_location (DW_OP_reg5 RDI) +# CHECK-NEXT: DW_AT_GNU_call_site_value (DW_OP_fbreg +12) +# CHECK: DW_TAG_GNU_call_site_parameter +# CHECK-NEXT: DW_AT_location (DW_OP_reg8 R8) +# CHECK-NEXT: DW_AT_GNU_call_site_value (DW_OP_breg14 R14+0, DW_OP_constu 0xffffffff, DW_OP_and, DW_OP_lit3, DW_OP_plus) + +--- | + ; ModuleID = 'call-site-param-expr.ll' + source_filename = "call-site-param-expr.c" + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + target triple = "x86_64-unknown-linux-gnu" + + define void @baa(i32 %arg1, i32 %arg2, i32 %arg3) local_unnamed_addr !dbg !6 { + entry: + %local1 = alloca i32, align 4 + tail call void @llvm.dbg.value(metadata i32 %arg1, i64 0, metadata !14, metadata !DIExpression()), !dbg !26 + tail call void @llvm.dbg.value(metadata i32 %arg2, i64 0, metadata !11, metadata !DIExpression()), !dbg !26 + tail call void @llvm.dbg.value(metadata i32 %arg3, i64 0, metadata !12, metadata !DIExpression()), !dbg !26 + %0 = bitcast i32* %local1 to i8*, !dbg !26 + call void @llvm.lifetime.start(i64 4, i8* nonnull %0), !dbg !26 + %call = tail call i32 (...) @getVal(), !dbg !26, !CallSite !15 + tail call void @llvm.dbg.value(metadata i32 %call, i64 0, metadata !13, metadata !DIExpression()), !dbg !26 + store i32 %call, i32* %local1, align 4, !dbg !26, !tbaa !27 + %add = add nsw i32 %arg3, 3, !dbg !26 + %add1 = add nsw i32 %arg2, %arg1, !dbg !26 + tail call void @llvm.dbg.value(metadata i32* %local1, i64 0, metadata !13, metadata !DIExpression()), !dbg !26 + call void @foo(i32* nonnull %local1, i32 %arg2, i32 10, i32 15, i32 %add, i32 %add1), !dbg !26, !CallSite !17 + call void @llvm.lifetime.end(i64 4, i8* nonnull %0), !dbg !26 + ret void, !dbg !26 + } + + ; Function Attrs: argmemonly nounwind + declare void @llvm.lifetime.start(i64, i8* nocapture) #0 + + declare i32 @getVal(...) local_unnamed_addr + + declare void @foo(i32*, i32, i32, i32, i32, i32) local_unnamed_addr + + ; Function Attrs: argmemonly nounwind + declare void @llvm.lifetime.end(i64, i8* nocapture) #0 + + ; Function Attrs: nounwind readnone + declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #1 + + ; Function Attrs: nounwind + declare void @llvm.stackprotector(i8*, i8**) #2 + + attributes #0 = { argmemonly nounwind } + attributes #1 = { nounwind readnone } + attributes #2 = { nounwind } + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!3, !4} + !llvm.ident = !{!5} + + !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 4.0.0 (tags/RELEASE_400/final)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) + !1 = !DIFile(filename: "call-site-param-expr.c", directory: "/") + !2 = !{} + !3 = !{i32 2, !"Dwarf Version", i32 4} + !4 = !{i32 2, !"Debug Info Version", i32 3} + !5 = !{!"clang version 4.0.0 (tags/RELEASE_400/final)"} + !6 = distinct !DISubprogram(name: "baa", scope: !1, file: !1, line: 11, type: !7, isLocal: false, isDefinition: true, scopeLine: 11, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !10) + !7 = !DISubroutineType(types: !8) + !8 = !{null, !9, !9, !9} + !9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !10 = !{!11, !12, !13, !14, !15, !17} + !11 = !DILocalVariable(name: "arg2", arg: 2, scope: !6, file: !1, line: 11, type: !9, flags: DIFlagArgumentNotModified) + !12 = !DILocalVariable(name: "arg3", arg: 3, scope: !6, file: !1, line: 11, type: !9, flags: DIFlagArgumentNotModified) + !13 = !DILocalVariable(name: "local1", scope: !6, file: !1, line: 12, type: !9, flags: DIFlagArgumentNotModified) + !14 = !DILocalVariable(name: "arg1", arg: 1, scope: !6, file: !1, line: 11, type: !9, flags: DIFlagArgumentNotModified) + !15 = !DICallSite(scope: !6, file: !1, parameters: !2, line: 12, calledSubprogram: !16) + !16 = !DISubprogram(name: "getVal", scope: !1, file: !1, line: 9, isLocal: false, isDefinition: false, isOptimized: true, retainedNodes: !2) + !17 = !DICallSite(scope: !6, file: !1, parameters: !18, line: 13, calledSubprogram: !25) + !18 = !{!19, !20, !21, !22, !23, !24} + !19 = !DICallSiteParam(argno: 1, variable: !13, expr: !DIExpression(DW_OP_push_object_address)) + !20 = !DICallSiteParam(argno: 2, variable: !11, expr: !DIExpression()) + !21 = !DICallSiteParam(argno: 3, expr: !DIExpression(DW_OP_lit10)) + !22 = !DICallSiteParam(argno: 4, expr: !DIExpression(DW_OP_lit15)) + !23 = !DICallSiteParam(argno: 5, variable: !12, expr: !DIExpression(DW_OP_lit3, DW_OP_plus)) + !24 = !DICallSiteParam(argno: 6, expr: !DIExpression()) + !25 = !DISubprogram(name: "foo", scope: !1, file: !1, line: 8, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true, retainedNodes: !2) + !26 = !DILocation(line: 11, column: 14, scope: !6) + !27 = !{!28, !28, i64 0} + !28 = !{!"int", !29, i64 0} + !29 = !{!"omnipotent char", !30, i64 0} + !30 = !{!"Simple C/C++ TBAA"} + +... +--- +name: baa +alignment: 4 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +tracksRegLiveness: true +liveins: + - { reg: '$edi' } + - { reg: '$esi' } + - { reg: '$edx' } +calleeSavedRegisters: [ '$bh', '$bl', '$bp', '$bpl', '$bx', '$ebp', '$ebx', + '$rbp', '$rbx', '$r12', '$r13', '$r14', '$r15', + '$r12b', '$r13b', '$r14b', '$r15b', '$r12d', '$r13d', + '$r14d', '$r15d', '$r12w', '$r13w', '$r14w', '$r15w' ] +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 40 + offsetAdjustment: 0 + maxAlignment: 4 + adjustsStack: true + hasCalls: true + maxCallFrameSize: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false +fixedStack: + - { id: 0, type: spill-slot, offset: -32, size: 8, alignment: 16, callee-saved-register: '$rbx' } + - { id: 1, type: spill-slot, offset: -24, size: 8, alignment: 8, callee-saved-register: '$r14' } + - { id: 2, type: spill-slot, offset: -16, size: 8, alignment: 16, callee-saved-register: '$r15' } +stack: + - { id: 0, name: local1, offset: -36, size: 4, alignment: 4 } +body: | + bb.0.entry: + liveins: $edi, $edx, $esi, $r15, $r14, $rbx + + frame-setup PUSH64r killed $r15, implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION def_cfa_offset 16 + frame-setup PUSH64r killed $r14, implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION def_cfa_offset 24 + frame-setup PUSH64r killed $rbx, implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION def_cfa_offset 32 + $rsp = frame-setup SUB64ri8 $rsp, 16, implicit-def dead $eflags + CFI_INSTRUCTION def_cfa_offset 48 + CFI_INSTRUCTION offset $rbx, -32 + CFI_INSTRUCTION offset $r14, -24 + CFI_INSTRUCTION offset $r15, -16 + DBG_VALUE debug-use $edi, debug-use $noreg, !14, !DIExpression(), debug-location !26 + DBG_VALUE debug-use $esi, debug-use $noreg, !11, !DIExpression(), debug-location !26 + DBG_VALUE debug-use $edx, debug-use $noreg, !12, !DIExpression(), debug-location !26 + $r14d = MOV32rr $edx, implicit-def $r14 + DBG_VALUE debug-use $r14d, debug-use $noreg, !12, !DIExpression(), debug-location !26 + $ebx = MOV32rr $esi, implicit-def $rbx + DBG_VALUE debug-use $ebx, debug-use $noreg, !11, !DIExpression(), debug-location !26 + $r15d = MOV32rr $edi, implicit-def $r15 + DBG_VALUE debug-use $r15d, debug-use $noreg, !14, !DIExpression(), debug-location !26 + dead $eax = XOR32rr undef $eax, undef $eax, implicit-def dead $eflags, implicit-def $al, debug-location !26 + CALL64pcrel32 @getVal, csr_64, implicit $rsp, implicit $al, implicit-def $rsp, implicit-def $eax, debug-location !26 + DBG_CALLSITE 0, $noreg, !15, debug-location !26 + DBG_VALUE debug-use $eax, debug-use $noreg, !13, !DIExpression(), debug-location !26 + MOV32mr $rsp, 1, $noreg, 12, $noreg, killed $eax, debug-location !26 :: (store 4 into %ir.local1, !tbaa !27) + $r8d = LEA64_32r killed $r14, 1, $noreg, 3, $noreg, debug-location !26 + $r9d = LEA64_32r killed $r15, 1, $rbx, 0, $noreg, debug-location !26 + $rdi = LEA64r $rsp, 1, $noreg, 12, $noreg + DBG_VALUE debug-use $rdi, debug-use $noreg, !13, !DIExpression(), debug-location !26 + $edx = MOV32ri 10, debug-location !26 + $ecx = MOV32ri 15, debug-location !26 + $esi = MOV32rr $ebx, implicit killed $rbx, debug-location !26 + CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $rdi, implicit $esi, implicit $edx, implicit killed $ecx, implicit $r8d, implicit $r9d, implicit-def $rsp, debug-location !26 + DBG_CALLSITE 0, $noreg, !17, debug-location !26 { + DBG_CALLSITEPARAM debug-use $ecx, !22, 15, debug-use $noreg, debug-location !26 + DBG_CALLSITEPARAM debug-use $edx, !21, $noreg, debug-use $noreg, debug-location !26 + DBG_CALLSITEPARAM debug-use $esi, !20, $ebx, debug-use $noreg, debug-location !26 + DBG_CALLSITEPARAM debug-use $rdi, !19, $rsp, 12, debug-location !26 + DBG_CALLSITEPARAM debug-use $r8d, !23, $noreg, debug-use $noreg, debug-location !26 + } + $rsp = ADD64ri8 $rsp, 16, implicit-def dead $eflags, debug-location !26 + CFI_INSTRUCTION def_cfa_offset 32, debug-location !26 + $rbx = POP64r implicit-def $rsp, implicit $rsp, debug-location !26 + CFI_INSTRUCTION def_cfa_offset 24, debug-location !26 + $r14 = POP64r implicit-def $rsp, implicit $rsp, debug-location !26 + CFI_INSTRUCTION def_cfa_offset 16, debug-location !26 + $r15 = POP64r implicit-def $rsp, implicit $rsp, debug-location !26 + CFI_INSTRUCTION def_cfa_offset 8, debug-location !26 + RETQ debug-location !26 + +... Index: test/DebugInfo/MIR/X86/dbginfo-callsite-entryvals.mir =================================================================== --- /dev/null +++ test/DebugInfo/MIR/X86/dbginfo-callsite-entryvals.mir @@ -0,0 +1,347 @@ +# RUN: llc -filetype=obj -mtriple=x86_64-unknown-unknown -start-after=livedebugvalues -o - %s| llvm-dwarfdump - | FileCheck %s +# +# CHECK: DW_TAG_subprogram +# CHECK: DW_AT_name ("fn2") +# CHECK: DW_TAG_formal_parameter +# CHECK: DW_AT_location (0x00000023 +# CHECK-NEXT: [0x0000000000000000, 0x000000000000000b): DW_OP_reg4 RSI +# CHECK-NEXT: [0x000000000000000b, 0x0000000000000019): DW_OP_GNU_entry_value(DW_OP_reg4 RSI), DW_OP_stack_value) +# CHECK-NEXT: DW_AT_name ("b") +# +# CHECK: DW_TAG_GNU_call_site +# CHECK: DW_AT_low_pc +# CHECK: DW_AT_abstract_origin {{.*}} "fn1") +# +# CHECK: DW_TAG_GNU_call_site_parameter +# CHECK: DW_AT_location (DW_OP_reg4 RSI) +# CHECK-NEXT: DW_AT_GNU_call_site_value (DW_OP_GNU_entry_value(DW_OP_reg4 RSI)) +# +# CHECK: DW_TAG_GNU_call_site +# CHECK: DW_AT_low_pc +# CHECK: DW_AT_GNU_call_site_target (DW_OP_reg3 RBX) +# CHECK: DW_TAG_GNU_call_site +# CHECK: DW_AT_low_pc (0x000000000000003e) +# CHECK: DW_AT_GNU_call_site_target (DW_OP_reg3 RBX) +# CHECK: DW_TAG_GNU_call_site +# CHECK: DW_AT_low_pc +# CHECK: DW_AT_abstract_origin ({{.*}} "fn2") +# CHECK: DW_TAG_GNU_call_site_parameter +# CHECK: DW_AT_location (DW_OP_reg1 RDX) +# CHECK: DW_AT_GNU_call_site_value (DW_OP_breg15 R15+0) +# CHECK: DW_TAG_lexical_block +# CHECK: DW_TAG_GNU_call_site +# CHECK: DW_AT_low_pc +# CHECK: DW_AT_abstract_origin ({{.*}} "fn2") +# +--- | + ; ModuleID = 'test.ll' + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + ; Function Attrs: noinline nounwind uwtable + define i64 @fn2(i64 %a, i64 %b, i64 %c) local_unnamed_addr !dbg !6 { + entry: + tail call void @llvm.dbg.value(metadata i64 %a, i64 0, metadata !13, metadata !DIExpression()), !dbg !21 + tail call void @llvm.dbg.value(metadata i64 %b, i64 0, metadata !11, metadata !DIExpression()), !dbg !22 + tail call void @llvm.dbg.value(metadata i64 %c, i64 0, metadata !12, metadata !DIExpression()), !dbg !23 + tail call void @fn1(i64 5, i64 6, i64 7) #5, !dbg !24, !CallSite !15 + ret i64 0, !dbg !25 + } + + ; Function Attrs: argmemonly nounwind + declare void @llvm.lifetime.start(i64, i8* nocapture) + + declare void @fn1(i64, i64, i64) local_unnamed_addr + + ; Function Attrs: argmemonly nounwind + declare void @llvm.lifetime.end(i64, i8* nocapture) + + ; Function Attrs: nounwind uwtable + define i64 @fn3(i64 %x, i64 (i64*)* nocapture %fn4) local_unnamed_addr !dbg !26 { + entry: + %w2 = alloca i64, align 8 + tail call void @llvm.dbg.value(metadata i64 %x, i64 0, metadata !36, metadata !DIExpression()), !dbg !66 + tail call void @llvm.dbg.value(metadata i64 (i64*)* %fn4, i64 0, metadata !34, metadata !DIExpression()), !dbg !67 + %0 = bitcast i64* %w2 to i8*, !dbg !68 + call void @llvm.lifetime.start(i64 8, i8* nonnull %0) #5, !dbg !68 + tail call void @llvm.dbg.value(metadata i64* %w2, i64 0, metadata !41, metadata !DIExpression()), !dbg !69 + %call = call i64 %fn4(i64* nonnull %w2) #5, !dbg !70, !CallSite !46 + call void @llvm.dbg.value(metadata i64 %call, i64 0, metadata !42, metadata !DIExpression()), !dbg !71 + call void @llvm.dbg.value(metadata i64* %w2, i64 0, metadata !41, metadata !DIExpression()), !dbg !69 + %call1 = call i64 %fn4(i64* nonnull %w2) #5, !dbg !72, !CallSite !49 + call void @llvm.dbg.value(metadata i64 %call1, i64 0, metadata !43, metadata !DIExpression()), !dbg !73 + %add = add nsw i64 %call1, 1, !dbg !74 + %call2 = call i64 @fn2(i64 1, i64 %add, i64 %call), !dbg !75, !CallSite !50 + call void @llvm.dbg.value(metadata i64 0, i64 0, metadata !35, metadata !DIExpression()), !dbg !76 + %mul = shl nsw i64 %call1, 1, !dbg !77 + %add3 = shl i64 %call1, 32, !dbg !78 + %sext = add i64 %add3, 17179869184, !dbg !78 + %conv4 = ashr exact i64 %sext, 32, !dbg !78 + %call5 = call i64 @fn2(i64 %call, i64 %mul, i64 %conv4), !dbg !79, !CallSite !55 + call void @llvm.dbg.value(metadata i64 0, i64 0, metadata !35, metadata !DIExpression()), !dbg !76 + call void @llvm.dbg.value(metadata i64 0, i64 0, metadata !35, metadata !DIExpression()), !dbg !76 + call void @llvm.lifetime.end(i64 8, i8* nonnull %0) #5, !dbg !80 + ret i64 0, !dbg !81 + } + + ; Function Attrs: nounwind readnone + declare void @llvm.dbg.value(metadata, i64, metadata, metadata) + + ; Function Attrs: nounwind + declare void @llvm.stackprotector(i8*, i8**) + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!3, !4} + !llvm.ident = !{!5} + + !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 4.0.0 (tags/RELEASE_400/final)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) + !1 = !DIFile(filename: "test.c", directory: "/dir") + !2 = !{} + !3 = !{i32 2, !"Dwarf Version", i32 4} + !4 = !{i32 2, !"Debug Info Version", i32 3} + !5 = !{!"clang version 4.0.0 (tags/RELEASE_400/final)"} + !6 = distinct !DISubprogram(name: "fn2", scope: !1, file: !1, line: 6, type: !7, isLocal: false, isDefinition: true, scopeLine: 7, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !10) + !7 = !DISubroutineType(types: !8) + !8 = !{!9, !9, !9, !9} + !9 = !DIBasicType(name: "long int", size: 64, encoding: DW_ATE_signed) + !10 = !{!11, !12, !13, !14, !15} + !11 = !DILocalVariable(name: "b", arg: 2, scope: !6, file: !1, line: 6, type: !9, flags: DIFlagArgumentNotModified) + !12 = !DILocalVariable(name: "c", arg: 3, scope: !6, file: !1, line: 6, type: !9, flags: DIFlagArgumentNotModified) + !13 = !DILocalVariable(name: "a", arg: 1, scope: !6, file: !1, line: 6, type: !9) + !14 = !DILocalVariable(name: "q", scope: !6, file: !1, line: 8, type: !9, flags: DIFlagArgumentNotModified) + !15 = !DICallSite(scope: !6, file: !1, parameters: !16, line: 9, calledSubprogram: !20) + !16 = !{!17, !18, !19} + !17 = !DICallSiteParam(argno: 1, expr: !DIExpression(DW_OP_lit5)) + !18 = !DICallSiteParam(argno: 2, variable: !11, expr: !DIExpression()) + !19 = !DICallSiteParam(argno: 3, expr: !DIExpression(DW_OP_lit7)) + !20 = !DISubprogram(name: "fn1", scope: !1, file: !1, line: 3, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true, retainedNodes: !2) + !21 = !DILocation(line: 6, column: 15, scope: !6) + !22 = !DILocation(line: 6, column: 27, scope: !6) + !23 = !DILocation(line: 6, column: 39, scope: !6) + !24 = !DILocation(line: 9, column: 2, scope: !6) + !25 = !DILocation(line: 11, column: 2, scope: !6) + !26 = distinct !DISubprogram(name: "fn3", scope: !1, file: !1, line: 15, type: !27, isLocal: false, isDefinition: true, scopeLine: 16, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !33) + !27 = !DISubroutineType(types: !28) + !28 = !{!9, !9, !29} + !29 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !30, size: 64) + !30 = !DISubroutineType(types: !31) + !31 = !{!9, !32} + !32 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !9, size: 64) + !33 = !{!34, !35, !36, !37, !41, !42, !43, !44, !46, !49, !50, !55, !60} + !34 = !DILocalVariable(name: "fn4", arg: 2, scope: !26, file: !1, line: 15, type: !29, flags: DIFlagArgumentNotModified) + !35 = !DILocalVariable(name: "z", scope: !26, file: !1, line: 17, type: !9) + !36 = !DILocalVariable(name: "x", arg: 1, scope: !26, file: !1, line: 15, type: !9, flags: DIFlagArgumentNotModified) + !37 = !DILocalVariable(name: "v1", scope: !38, file: !1, line: 22, type: !40, flags: DIFlagArgumentNotModified) + !38 = distinct !DILexicalBlock(scope: !39, file: !1, line: 21, column: 15) + !39 = distinct !DILexicalBlock(scope: !26, file: !1, line: 21, column: 7) + !40 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !41 = !DILocalVariable(name: "w2", scope: !26, file: !1, line: 17, type: !9, flags: DIFlagArgumentNotModified) + !42 = !DILocalVariable(name: "w", scope: !26, file: !1, line: 17, type: !9) + !43 = !DILocalVariable(name: "v", scope: !26, file: !1, line: 17, type: !9) + !44 = !DILocalVariable(name: "v2", scope: !45, file: !1, line: 26, type: !40, flags: DIFlagArgumentNotModified) + !45 = distinct !DILexicalBlock(scope: !39, file: !1, line: 25, column: 7) + !46 = !DICallSite(scope: !26, file: !1, parameters: !47, line: 18) + !47 = !{!48} + !48 = !DICallSiteParam(argno: 1, variable: !41, expr: !DIExpression(DW_OP_push_object_address)) + !49 = !DICallSite(scope: !26, file: !1, parameters: !47, line: 19) + !50 = !DICallSite(scope: !26, file: !1, parameters: !51, line: 20, calledSubprogram: !6) + !51 = !{!52, !53, !54} + !52 = !DICallSiteParam(argno: 1, expr: !DIExpression(DW_OP_lit1)) + !53 = !DICallSiteParam(argno: 2, variable: !43, expr: !DIExpression(DW_OP_lit1, DW_OP_plus)) + !54 = !DICallSiteParam(argno: 3, variable: !42, expr: !DIExpression()) + !55 = !DICallSite(scope: !38, file: !1, parameters: !56, line: 23, calledSubprogram: !6) + !56 = !{!57, !58, !59} + !57 = !DICallSiteParam(argno: 1, variable: !42, expr: !DIExpression()) + !58 = !DICallSiteParam(argno: 2, variable: !43, expr: !DIExpression(DW_OP_lit2, DW_OP_mul)) + !59 = !DICallSiteParam(argno: 3, variable: !37, expr: !DIExpression()) + !60 = !DICallSite(scope: !61, file: !1, parameters: !62, line: 29, calledSubprogram: !6) + !61 = distinct !DILexicalBlock(scope: !45, file: !1, line: 27, column: 16) + !62 = !{!63, !64, !65} + !63 = !DICallSiteParam(argno: 1, variable: !36, expr: !DIExpression()) + !64 = !DICallSiteParam(argno: 2, variable: !43, expr: !DIExpression(DW_OP_lit3, DW_OP_plus)) + !65 = !DICallSiteParam(argno: 3, variable: !44, expr: !DIExpression()) + !66 = !DILocation(line: 15, column: 15, scope: !26) + !67 = !DILocation(line: 15, column: 29, scope: !26) + !68 = !DILocation(line: 17, column: 2, scope: !26) + !69 = !DILocation(line: 17, column: 17, scope: !26) + !70 = !DILocation(line: 18, column: 6, scope: !26) + !71 = !DILocation(line: 17, column: 14, scope: !26) + !72 = !DILocation(line: 19, column: 6, scope: !26) + !73 = !DILocation(line: 17, column: 11, scope: !26) + !74 = !DILocation(line: 20, column: 16, scope: !26) + !75 = !DILocation(line: 20, column: 6, scope: !26) + !76 = !DILocation(line: 17, column: 21, scope: !26) + !77 = !DILocation(line: 23, column: 19, scope: !38) + !78 = !DILocation(line: 23, column: 24, scope: !38) + !79 = !DILocation(line: 23, column: 9, scope: !38) + !80 = !DILocation(line: 33, column: 1, scope: !26) + !81 = !DILocation(line: 32, column: 2, scope: !26) + +... +--- +name: fn2 +alignment: 4 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +tracksRegLiveness: true +calleeSavedRegisters: [ '$bh', '$bl', '$bp', '$bpl', '$bx', '$ebp', '$ebx', + '$rbp', '$rbx', '$r12', '$r13', '$r14', '$r15', + '$r12b', '$r13b', '$r14b', '$r15b', '$r12d', '$r13d', + '$r14d', '$r15d', '$r12w', '$r13w', '$r14w', '$r15w' ] +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 8 + offsetAdjustment: 0 + maxAlignment: 0 + adjustsStack: true + hasCalls: true + maxCallFrameSize: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false +body: | + bb.0.entry: + frame-setup PUSH64r undef $rax, implicit-def $rsp, implicit $rsp, debug-location !24 + CFI_INSTRUCTION def_cfa_offset 16 + DBG_VALUE debug-use $rdi, debug-use $noreg, !13, !DIExpression(), debug-location !21 + DBG_VALUE debug-use $rsi, debug-use $noreg, !11, !DIExpression(), debug-location !22 + DBG_VALUE debug-use $rdx, debug-use $noreg, !12, !DIExpression(), debug-location !23 + dead $edi = MOV32ri 5, implicit-def $rdi, debug-location !24 + dead $esi = MOV32ri 6, implicit-def $rsi, debug-location !24 + DBG_VALUE debug-use $rsi, debug-use $noreg, !11, !DIExpression(DW_OP_GNU_entry_value), debug-location !22 + dead $edx = MOV32ri 7, implicit-def $rdx, debug-location !24 + DBG_VALUE debug-use $rdx, debug-use $noreg, !12, !DIExpression(DW_OP_GNU_entry_value), debug-location !23 + CALL64pcrel32 @fn1, csr_64, implicit $rsp, implicit $rdi, implicit $rsi, implicit $rdx, implicit-def $rsp, debug-location !24 + DBG_VALUE debug-use $rdx, debug-use $noreg, !12, !DIExpression(DW_OP_GNU_entry_value), debug-location !23 + DBG_VALUE debug-use $rsi, debug-use $noreg, !11, !DIExpression(DW_OP_GNU_entry_value), debug-location !22 + DBG_CALLSITE 0, $noreg, !15, debug-location !24 { + DBG_CALLSITEPARAM debug-use $rdx, !19, 7, debug-use $noreg, debug-location !24 + DBG_CALLSITEPARAM debug-use $rsi, !18, $noreg, debug-use $noreg, debug-location !24 + DBG_CALLSITEPARAM debug-use $rdi, !17, 5, debug-use $noreg, debug-location !24 + } + dead $eax = XOR32rr undef $eax, undef $eax, implicit-def dead $eflags, implicit-def $rax, debug-location !25 + $rcx = POP64r implicit-def $rsp, implicit $rsp, debug-location !25 + CFI_INSTRUCTION def_cfa_offset 8, debug-location !25 + RETQ killed $rax, debug-location !25 + +... +--- +name: fn3 +alignment: 4 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +tracksRegLiveness: true +liveins: + - { reg: '$rsi' } +calleeSavedRegisters: [ '$bh', '$bl', '$bp', '$bpl', '$bx', '$ebp', '$ebx', + '$rbp', '$rbx', '$r12', '$r13', '$r14', '$r15', + '$r12b', '$r13b', '$r14b', '$r15b', '$r12d', '$r13d', + '$r14d', '$r15d', '$r12w', '$r13w', '$r14w', '$r15w' ] +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 40 + offsetAdjustment: 0 + maxAlignment: 8 + adjustsStack: true + hasCalls: true + maxCallFrameSize: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false +fixedStack: + - { id: 0, type: spill-slot, offset: -32, size: 8, alignment: 16, callee-saved-register: '$rbx' } + - { id: 1, type: spill-slot, offset: -24, size: 8, alignment: 8, callee-saved-register: '$r14' } + - { id: 2, type: spill-slot, offset: -16, size: 8, alignment: 16, callee-saved-register: '$r15' } +stack: + - { id: 0, name: w2, offset: -40, size: 8, alignment: 8 } +body: | + bb.0.entry: + liveins: $rsi, $r15, $r14, $rbx + + frame-setup PUSH64r killed $r15, implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION def_cfa_offset 16 + frame-setup PUSH64r killed $r14, implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION def_cfa_offset 24 + frame-setup PUSH64r killed $rbx, implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION def_cfa_offset 32 + $rsp = frame-setup SUB64ri8 $rsp, 16, implicit-def dead $eflags + CFI_INSTRUCTION def_cfa_offset 48 + CFI_INSTRUCTION offset $rbx, -32 + CFI_INSTRUCTION offset $r14, -24 + CFI_INSTRUCTION offset $r15, -16 + DBG_VALUE debug-use $rdi, debug-use $noreg, !36, !DIExpression(), debug-location !66 + DBG_VALUE debug-use $rsi, debug-use $noreg, !34, !DIExpression(), debug-location !67 + $rbx = MOV64rr $rsi + DBG_VALUE debug-use $rbx, debug-use $noreg, !34, !DIExpression(), debug-location !67 + $r14 = LEA64r $rsp, 1, $noreg, 8, $noreg + DBG_VALUE debug-use $r14, debug-use $noreg, !41, !DIExpression(), debug-location !69 + $rdi = MOV64rr $r14, debug-location !70 + DBG_VALUE debug-use $rdi, debug-use $noreg, !36, !DIExpression(DW_OP_GNU_entry_value), debug-location !66 + CALL64r $rbx, csr_64, implicit $rsp, implicit $rdi, implicit-def $rsp, implicit-def $rax, debug-location !70 + DBG_VALUE debug-use $rdi, debug-use $noreg, !36, !DIExpression(DW_OP_GNU_entry_value), debug-location !66 + DBG_CALLSITE 0, debug-use $rbx, !46, debug-location !70 { + DBG_CALLSITEPARAM debug-use $rdi, !48, $rsp, 8, debug-location !70 + } + $r15 = MOV64rr $rax, debug-location !70 + DBG_VALUE debug-use $r15, debug-use $noreg, !42, !DIExpression(), debug-location !71 + $rdi = MOV64rr killed $r14, debug-location !72 + DBG_VALUE debug-use $rdi, debug-use $noreg, !36, !DIExpression(DW_OP_GNU_entry_value), debug-location !66 + CALL64r killed $rbx, csr_64, implicit $rsp, implicit $rdi, implicit-def $rsp, implicit-def $rax, debug-location !72 + DBG_VALUE debug-use $rdi, debug-use $noreg, !36, !DIExpression(DW_OP_GNU_entry_value), debug-location !66 + DBG_CALLSITE 0, debug-use $rbx, !49, debug-location !72 { + DBG_CALLSITEPARAM debug-use $rdi, !48, $rsp, 8, debug-location !72 + } + $rbx = MOV64rr $rax, debug-location !72 + DBG_VALUE debug-use $rsi, debug-use $noreg, !34, !DIExpression(DW_OP_GNU_entry_value), debug-location !67 + DBG_VALUE debug-use $rbx, debug-use $noreg, !43, !DIExpression(), debug-location !73 + $rsi = LEA64r $rbx, 1, $noreg, 1, $noreg, debug-location !74 + DBG_VALUE debug-use $rsi, debug-use $noreg, !34, !DIExpression(DW_OP_GNU_entry_value), debug-location !67 + dead $edi = MOV32ri 1, implicit-def $rdi, debug-location !75 + DBG_VALUE debug-use $rdi, debug-use $noreg, !36, !DIExpression(DW_OP_GNU_entry_value), debug-location !66 + $rdx = MOV64rr $r15, debug-location !75 + CALL64pcrel32 @fn2, csr_64, implicit $rsp, implicit $rdi, implicit $rsi, implicit $rdx, implicit-def $rsp, implicit-def dead $rax, debug-location !75 + DBG_VALUE debug-use $rsi, debug-use $noreg, !34, !DIExpression(DW_OP_GNU_entry_value), debug-location !67 + DBG_VALUE debug-use $rdi, debug-use $noreg, !36, !DIExpression(DW_OP_GNU_entry_value), debug-location !66 + DBG_CALLSITE 0, $noreg, !50, debug-location !75 { + DBG_CALLSITEPARAM debug-use $rdx, !54, debug-use $r15, debug-use $noreg, debug-location !75 + DBG_CALLSITEPARAM debug-use $rdi, !52, 1, debug-use $noreg, debug-location !75 + DBG_CALLSITEPARAM debug-use $rsi, !53, $rbx, 5, !DIExpression(DW_OP_constu, 1, DW_OP_plus), debug-location !75 + } + DBG_VALUE 0, 0, !35, !DIExpression(), debug-location !76 + $rax = MOV64rr $rbx, debug-location !78 + $rax = SHL64ri killed $rax, 32, implicit-def dead $eflags, debug-location !78 + $rsi = LEA64r killed $rbx, 1, $rbx, 0, $noreg, debug-location !77 + DBG_VALUE debug-use $rsi, debug-use $noreg, !34, !DIExpression(DW_OP_GNU_entry_value), debug-location !67 + $rdx = MOV64ri 17179869184, debug-location !78 + $rdx = ADD64rr killed $rdx, killed $rax, implicit-def dead $eflags, debug-location !78 + $rdx = SAR64ri killed $rdx, 32, implicit-def dead $eflags, debug-location !78 + $rdi = MOV64rr killed $r15, debug-location !79 + DBG_VALUE debug-use $rdi, debug-use $noreg, !36, !DIExpression(DW_OP_GNU_entry_value), debug-location !66 + CALL64pcrel32 @fn2, csr_64, implicit $rsp, implicit $rdi, implicit $rsi, implicit $rdx, implicit-def $rsp, implicit-def dead $rax, debug-location !79 + DBG_VALUE debug-use $rsi, debug-use $noreg, !34, !DIExpression(DW_OP_GNU_entry_value), debug-location !67 + DBG_VALUE debug-use $rdi, debug-use $noreg, !36, !DIExpression(DW_OP_GNU_entry_value), debug-location !66 + DBG_CALLSITE 0, $noreg, !55, debug-location !79 { + DBG_CALLSITEPARAM debug-use $rdi, !57, debug-use $r15, debug-use $noreg, debug-location !79 + DBG_CALLSITEPARAM debug-use $rsi, !58, $rbx, 0, !DIExpression(DW_OP_constu, 2, DW_OP_mul), debug-location !79 + } + dead $eax = XOR32rr undef $eax, undef $eax, implicit-def dead $eflags, implicit-def $rax, debug-location !81 + $rsp = ADD64ri8 $rsp, 16, implicit-def dead $eflags, debug-location !81 + CFI_INSTRUCTION def_cfa_offset 32, debug-location !81 + $rbx = POP64r implicit-def $rsp, implicit $rsp, debug-location !81 + CFI_INSTRUCTION def_cfa_offset 24, debug-location !81 + $r14 = POP64r implicit-def $rsp, implicit $rsp, debug-location !81 + CFI_INSTRUCTION def_cfa_offset 16, debug-location !81 + $r15 = POP64r implicit-def $rsp, implicit $rsp, debug-location !81 + CFI_INSTRUCTION def_cfa_offset 8, debug-location !81 + RETQ $rax, debug-location !81 + +... Index: test/DebugInfo/MIR/X86/dbginfo-unknown-tailcall.mir =================================================================== --- /dev/null +++ test/DebugInfo/MIR/X86/dbginfo-unknown-tailcall.mir @@ -0,0 +1,283 @@ +# RUN: llc -filetype=obj -mtriple=x86_64-unknown-unknown -start-after=machineverifier -o - %s| llvm-dwarfdump - | FileCheck %s +# +# +#test.c +# +#volatile int a; +# +#void bar(int k) __attribute__((noinline)) { +# a++; +# k++; +#} +# +#void foo(void (*fn_extern) ()) __attribute__((noinline)) { +# (*fn_extern)(); // tail call. +#} +# +#void quux() __attribute__((noinline)) { +# bar(3); +#} +# +#int main() __attribute__((disable_tail_calls)) { +# foo(&bar); +# return 0; +#} +# +# CHECK: DW_TAG_GNU_call_site +# CHECK-NEXT: DW_AT_call_tail_call (true) +# CHECK-NEXT: DW_AT_low_pc {{.*}} +# CHECK-NEXT: DW_AT_GNU_call_site_target {{.*}} +# CHECK: DW_TAG_GNU_call_site +# CHECK-NEXT: DW_AT_call_tail_call (true) +# CHECK-NEXT: DW_AT_low_pc {{.*}} +# CHECK-NEXT: DW_AT_abstract_origin {{.*}}"bar" +# CHECK: DW_TAG_GNU_call_site_param +# CHECK: DW_TAG_GNU_call_site +# CHECK-NEXT: DW_AT_low_pc {{.*}} +# CHECK-NEXT: DW_AT_abstract_origin {{.*}}"foo" +--- | + ; ModuleID = 'test.ll' + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @sink = common global i32 0, align 4, !dbg !0 + + ; Function Attrs: noinline nounwind uwtable + define void @bar(i32 %k) !dbg !11 { + entry: + tail call void @llvm.dbg.value(metadata i32 %k, i64 0, metadata !15, metadata !DIExpression()), !dbg !16 + %0 = load volatile i32, i32* @sink, align 4, !dbg !17, !tbaa !18 + %inc = add nsw i32 %0, 1, !dbg !17 + store volatile i32 %inc, i32* @sink, align 4, !dbg !17, !tbaa !18 + ret void, !dbg !22 + } + + ; Function Attrs: noinline nounwind uwtable + define void @foo(void (...)* nocapture %fn_extern) local_unnamed_addr !dbg !23 { + entry: + tail call void @llvm.dbg.value(metadata void (...)* %fn_extern, i64 0, metadata !30, metadata !DIExpression()), !dbg !32 + tail call void (...) %fn_extern(), !dbg !33, !CallSite !31 + ret void, !dbg !34 + } + + ; Function Attrs: noinline nounwind uwtable + define void @quux() local_unnamed_addr !dbg !35 { + entry: + tail call void @bar(i32 3), !dbg !42, !CallSite !39 + ret void, !dbg !43 + } + + ; Function Attrs: nounwind uwtable + define i32 @main() local_unnamed_addr !dbg !44 { + entry: + call void @foo(void (...)* bitcast (void (i32)* @bar to void (...)*)), !dbg !51, !CallSite !48 + ret i32 0, !dbg !52 + } + + ; Function Attrs: nounwind readnone + declare void @llvm.dbg.value(metadata, i64, metadata, metadata) + + ; Function Attrs: nounwind + declare void @llvm.stackprotector(i8*, i8**) + + !llvm.dbg.cu = !{!2} + !llvm.module.flags = !{!8, !9} + !llvm.ident = !{!10} + + !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) + !1 = distinct !DIGlobalVariable(name: "sink", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) + !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 4.0.0 (tags/RELEASE_400/final)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5) + !3 = !DIFile(filename: "test.c", directory: "/dir") + !4 = !{} + !5 = !{!0} + !6 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !7) + !7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !8 = !{i32 2, !"Dwarf Version", i32 4} + !9 = !{i32 2, !"Debug Info Version", i32 3} + !10 = !{!"clang version 4.0.0 (tags/RELEASE_400/final)"} + !11 = distinct !DISubprogram(name: "bar", scope: !3, file: !3, line: 3, type: !12, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !2, retainedNodes: !14) + !12 = !DISubroutineType(types: !13) + !13 = !{null, !7} + !14 = !{!15} + !15 = !DILocalVariable(name: "k", arg: 1, scope: !11, file: !3, line: 3, type: !7) + !16 = !DILocation(line: 3, column: 14, scope: !11) + !17 = !DILocation(line: 4, column: 6, scope: !11) + !18 = !{!19, !19, i64 0} + !19 = !{!"int", !20, i64 0} + !20 = !{!"omnipotent char", !21, i64 0} + !21 = !{!"Simple C/C++ TBAA"} + !22 = !DILocation(line: 6, column: 1, scope: !11) + !23 = distinct !DISubprogram(name: "foo", scope: !3, file: !3, line: 8, type: !24, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: true, unit: !2, retainedNodes: !29) + !24 = !DISubroutineType(types: !25) + !25 = !{null, !26} + !26 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !27, size: 64) + !27 = !DISubroutineType(types: !28) + !28 = !{null, null} + !29 = !{!30, !31} + !30 = !DILocalVariable(name: "fn_extern", arg: 1, scope: !23, file: !3, line: 8, type: !26, flags: DIFlagArgumentNotModified) + !31 = !DICallSite(scope: !23, file: !3, parameters: !4, line: 9) + !32 = !DILocation(line: 8, column: 17, scope: !23) + !33 = !DILocation(line: 9, column: 2, scope: !23) + !34 = !DILocation(line: 10, column: 1, scope: !23) + !35 = distinct !DISubprogram(name: "quux", scope: !3, file: !3, line: 12, type: !36, isLocal: false, isDefinition: true, scopeLine: 12, isOptimized: true, unit: !2, retainedNodes: !38) + !36 = !DISubroutineType(types: !37) + !37 = !{null} + !38 = !{!39} + !39 = !DICallSite(scope: !35, file: !3, parameters: !40, line: 13, calledSubprogram: !11) + !40 = !{!41} + !41 = !DICallSiteParam(argno: 1, expr: !DIExpression(DW_OP_lit3)) + !42 = !DILocation(line: 13, column: 2, scope: !35) + !43 = !DILocation(line: 14, column: 1, scope: !35) + !44 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 16, type: !45, isLocal: false, isDefinition: true, scopeLine: 16, isOptimized: true, unit: !2, retainedNodes: !47) + !45 = !DISubroutineType(types: !46) + !46 = !{!7} + !47 = !{!48} + !48 = !DICallSite(scope: !44, file: !3, parameters: !49, line: 17, calledSubprogram: !23) + !49 = !{!50} + !50 = !DICallSiteParam(argno: 1, expr: !DIExpression(DW_OP_push_object_address)) + !51 = !DILocation(line: 17, column: 2, scope: !44) + !52 = !DILocation(line: 18, column: 2, scope: !44) + +... +--- +name: bar +alignment: 4 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +tracksRegLiveness: true +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 0 + offsetAdjustment: 0 + maxAlignment: 0 + adjustsStack: false + hasCalls: false + maxCallFrameSize: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false +body: | + bb.0.entry: + DBG_VALUE debug-use $edi, debug-use $noreg, !15, !DIExpression(), debug-location !16 + INC32m $rip, 1, $noreg, @sink, $noreg, implicit-def dead $eflags, debug-location !17 :: (volatile store 4 into @sink, !tbaa !18), (volatile dereferenceable load 4 from @sink, !tbaa !18) + RETQ debug-location !22 + +... +--- +name: foo +alignment: 4 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +tracksRegLiveness: true +liveins: + - { reg: '$rdi' } +calleeSavedRegisters: [ '$bh', '$bl', '$bp', '$bpl', '$bx', '$ebp', '$ebx', + '$rbp', '$rbx', '$r12', '$r13', '$r14', '$r15', + '$r12b', '$r13b', '$r14b', '$r15b', '$r12d', '$r13d', + '$r14d', '$r15d', '$r12w', '$r13w', '$r14w', '$r15w' ] +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 0 + offsetAdjustment: 0 + maxAlignment: 0 + adjustsStack: false + hasCalls: false + maxCallFrameSize: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false +body: | + bb.0.entry: + liveins: $rdi + + DBG_VALUE debug-use $rdi, debug-use $noreg, !30, !DIExpression(), debug-location !32 + dead $eax = XOR32rr undef $eax, undef $eax, implicit-def dead $eflags, implicit-def $al, debug-location !33 + TAILJMPr64 killed $rdi, csr_64, implicit $rsp, implicit $rsp, implicit killed $al, debug-location !33 + DBG_CALLSITE 1, debug-use $rdi, !31, debug-location !33 + +... +--- +name: quux +alignment: 4 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +tracksRegLiveness: true +calleeSavedRegisters: [ '$bh', '$bl', '$bp', '$bpl', '$bx', '$ebp', '$ebx', + '$rbp', '$rbx', '$r12', '$r13', '$r14', '$r15', + '$r12b', '$r13b', '$r14b', '$r15b', '$r12d', '$r13d', + '$r14d', '$r15d', '$r12w', '$r13w', '$r14w', '$r15w' ] +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 0 + offsetAdjustment: 0 + maxAlignment: 0 + adjustsStack: false + hasCalls: false + maxCallFrameSize: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false +body: | + bb.0.entry: + $edi = MOV32ri 3, debug-location !42 + TAILJMPd64 @bar, csr_64, implicit $rsp, implicit $rsp, implicit killed $edi, debug-location !42 + DBG_CALLSITE 1, debug-use $noreg, !39, debug-location !42 { + DBG_CALLSITEPARAM debug-use $edi, !41, 3, debug-use $noreg, debug-location !42 + } + +... +--- +name: main +alignment: 4 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +tracksRegLiveness: true +calleeSavedRegisters: [ '$bh', '$bl', '$bp', '$bpl', '$bx', '$ebp', '$ebx', + '$rbp', '$rbx', '$r12', '$r13', '$r14', '$r15', + '$r12b', '$r13b', '$r14b', '$r15b', '$r12d', '$r13d', + '$r14d', '$r15d', '$r12w', '$r13w', '$r14w', '$r15w' ] +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 8 + offsetAdjustment: 0 + maxAlignment: 0 + adjustsStack: true + hasCalls: true + maxCallFrameSize: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false +body: | + bb.0.entry: + frame-setup PUSH64r undef $rax, implicit-def $rsp, implicit $rsp, debug-location !51 + CFI_INSTRUCTION def_cfa_offset 16 + dead $edi = MOV32ri @bar, implicit-def $rdi, debug-location !51 + CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit killed $rdi, implicit-def $rsp, debug-location !51 + DBG_CALLSITE 0, debug-use $noreg, !48, debug-location !51 { + DBG_CALLSITEPARAM debug-use $rdi, !50, @bar, debug-use $noreg, debug-location !51 + } + $eax = XOR32rr undef $eax, undef $eax, implicit-def dead $eflags, debug-location !52 + $rcx = POP64r implicit-def $rsp, implicit $rsp, debug-location !52 + CFI_INSTRUCTION def_cfa_offset 8, debug-location !52 + RETQ killed $eax, debug-location !52 + +... Index: test/DebugInfo/X86/dbginfo-call-fram-optimization.ll =================================================================== --- /dev/null +++ test/DebugInfo/X86/dbginfo-call-fram-optimization.ll @@ -0,0 +1,111 @@ +; RUN: llc -filetype=asm %s -o -|FileCheck %s +; This test verifies that X86 call frame optimization is performed. Call site +; debug info was part of X86 frame destruction and it caused unexpected +; behaviour that led different behaviour between object compiled with and +; without debug information for call sites. +; Test case: +; extern int foo(int *, int *, int, const char *, +; int , int ,int *, struct re_reg*, +; int); +; +; +; int baa(int *p, const char *string, int size, +; int startpos, int *data, struct re_reg* reg, +; int num) { +; return foo(p, 0, 0, string, size, startpos, data, reg, num); +; } +; +; CHECK: baa: +; CHECK: pushq %rax +; CHECK: movq %r9, %rax +; CHECK: movq %r8, %r10 +; CHECK: movl %ecx, %r9d +; CHECK: movl %edx, %r8d +; CHECK: movq %rsi, %rcx +; CHECK: movl 16(%rsp), %r11d +; CHECK: subq $8, %rsp +; CHECK: xorl %esi, %esi +; CHECK: xorl %edx, %edx +; CHECK: pushq %r11 +; CHECK: pushq %rax +; CHECK: pushq %r10 +; CHECK: callq foo +; CHECK: addq $32, %rsp +; CHECK: popq %rcx +; CHECK: retq + +; ModuleID = 'dbginfo-call-fram-optimization.ll' +source_filename = "dbginfo-call-fram-optimization.c" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +%struct.re_reg = type opaque + +; Function Attrs: nounwind uwtable +define i32 @baa(i32* %p, i8* %string, i32 %size, i32 %startpos, i32* %data, %struct.re_reg* %reg, i32 %num) local_unnamed_addr !dbg !6 { +entry: + tail call void @llvm.dbg.value(metadata i32* %p, i64 0, metadata !21, metadata !DIExpression()), !dbg !36 + tail call void @llvm.dbg.value(metadata i8* %string, i64 0, metadata !20, metadata !DIExpression()), !dbg !37 + tail call void @llvm.dbg.value(metadata i32 %size, i64 0, metadata !22, metadata !DIExpression()), !dbg !38 + tail call void @llvm.dbg.value(metadata i32 %startpos, i64 0, metadata !23, metadata !DIExpression()), !dbg !39 + tail call void @llvm.dbg.value(metadata i32* %data, i64 0, metadata !17, metadata !DIExpression()), !dbg !40 + tail call void @llvm.dbg.value(metadata %struct.re_reg* %reg, i64 0, metadata !18, metadata !DIExpression()), !dbg !41 + tail call void @llvm.dbg.value(metadata i32 %num, i64 0, metadata !19, metadata !DIExpression()), !dbg !42 + %call = tail call i32 @foo(i32* %p, i32* null, i32 0, i8* %string, i32 %size, i32 %startpos, i32* %data, %struct.re_reg* %reg, i32 %num), !dbg !43, !call_site !24 + ret i32 %call, !dbg !44 +} + +declare i32 @foo(i32*, i32*, i32, i8*, i32, i32, i32*, %struct.re_reg*, i32) local_unnamed_addr + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.value(metadata, i64, metadata, metadata) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4} +!llvm.ident = !{!5} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 4.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "dbginfo-call-fram-optimization.c", directory: "/") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{!"clang version 4.0.0"} +!6 = distinct !DISubprogram(name: "baa", scope: !1, file: !1, line: 17, type: !7, isLocal: false, isDefinition: true, scopeLine: 19, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !16) +!7 = !DISubroutineType(types: !8) +!8 = !{!9, !10, !11, !9, !9, !10, !14, !9} +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !9, size: 64) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!12 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !13) +!13 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!14 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !15, size: 64) +!15 = !DICompositeType(tag: DW_TAG_structure_type, name: "re_reg", file: !1, line: 10, flags: DIFlagFwdDecl) +!16 = !{!17, !18, !19, !20, !21, !22, !23, !24} +!17 = !DILocalVariable(name: "data", arg: 5, scope: !6, file: !1, line: 18, type: !10) +!18 = !DILocalVariable(name: "reg", arg: 6, scope: !6, file: !1, line: 18, type: !14) +!19 = !DILocalVariable(name: "num", arg: 7, scope: !6, file: !1, line: 19, type: !9) +!20 = !DILocalVariable(name: "string", arg: 2, scope: !6, file: !1, line: 17, type: !11) +!21 = !DILocalVariable(name: "p", arg: 1, scope: !6, file: !1, line: 17, type: !10) +!22 = !DILocalVariable(name: "size", arg: 3, scope: !6, file: !1, line: 17, type: !9) +!23 = !DILocalVariable(name: "startpos", arg: 4, scope: !6, file: !1, line: 18, type: !9) +!24 = !DICallSite(scope: !6, file: !1, parameters: !25, line: 20, calledSubprogram: !35) +!25 = !{!26, !27, !28, !29, !30, !31, !32, !33, !34} +!26 = !DICallSiteParam(argno: 1, variable: !21, expr: !DIExpression()) +!27 = !DICallSiteParam(argno: 2, expr: !DIExpression(DW_OP_lit0)) +!28 = !DICallSiteParam(argno: 3, expr: !DIExpression(DW_OP_lit0)) +!29 = !DICallSiteParam(argno: 4, variable: !20, expr: !DIExpression()) +!30 = !DICallSiteParam(argno: 5, variable: !22, expr: !DIExpression()) +!31 = !DICallSiteParam(argno: 6, variable: !23, expr: !DIExpression()) +!32 = !DICallSiteParam(argno: 7, variable: !17, expr: !DIExpression()) +!33 = !DICallSiteParam(argno: 8, variable: !18, expr: !DIExpression()) +!34 = !DICallSiteParam(argno: 9, variable: !19, expr: !DIExpression()) +!35 = !DISubprogram(name: "foo", scope: !1, file: !1, line: 12, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true, retainedNodes: !2) +!36 = !DILocation(line: 17, column: 14, scope: !6) +!37 = !DILocation(line: 17, column: 29, scope: !6) +!38 = !DILocation(line: 17, column: 41, scope: !6) +!39 = !DILocation(line: 18, column: 13, scope: !6) +!40 = !DILocation(line: 18, column: 28, scope: !6) +!41 = !DILocation(line: 18, column: 49, scope: !6) +!42 = !DILocation(line: 19, column: 13, scope: !6) +!43 = !DILocation(line: 20, column: 10, scope: !6) +!44 = !DILocation(line: 20, column: 3, scope: !6) Index: test/DebugInfo/X86/unprototyped-call-site.ll =================================================================== --- /dev/null +++ test/DebugInfo/X86/unprototyped-call-site.ll @@ -0,0 +1,48 @@ +; RUN: llc -mtriple=x86_64-linux-gnu -filetype=asm %s -o - | FileCheck %s +; +; CHECK: movl $2, %edi +; CHECK-NEXT: movl $7, %esi +; CHECK-NEXT: movb $1, %al +; CHECK-NEXT: jmp func1 +; CHECK-NEXT: .Ltmp1: +; CHECK-NEXT: #DEBUG_CALLSITE: func2: isTailCall: 1, register: %noreg +; CHECK-NEXT: # DBG_PARAM: arg1: $edi <- 2 +; CHECK-NEXT: # DBG_PARAM: arg3: $esi <- 7 + + +; ModuleID = 'unprototyped-call-site.c' +source_filename = "unprototyped-call-site.c" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: nounwind uwtable +define void @func2() local_unnamed_addr !dbg !6 { +entry: + %call = tail call i32 (i32, double, i32, ...) bitcast (i32 (...)* @func1 to i32 (i32, double, i32, ...)*)(i32 2, double 1.000000e+00, i32 7), !dbg !16, !call_site !10 + ret void, !dbg !17 +} + +declare i32 @func1(...) local_unnamed_addr + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4} +!llvm.ident = !{!5} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 8.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "unprototyped-call-site.c", directory: "/") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{!"clang version 8.0.0"} +!6 = distinct !DISubprogram(name: "func2", scope: !1, file: !1, line: 9, type: !7, isLocal: false, isDefinition: true, scopeLine: 9, isOptimized: true, unit: !0, retainedNodes: !9) +!7 = !DISubroutineType(types: !8) +!8 = !{null} +!9 = !{!10} +!10 = !DICallSite(scope: !6, file: !1, parameters: !11, line: 10, calledSubprogram: !15) +!11 = !{!12, !13, !14} +!12 = !DICallSiteParam(argno: 1, expr: !DIExpression(DW_OP_lit2)) +!13 = !DICallSiteParam(argno: 2, expr: !DIExpression()) +!14 = !DICallSiteParam(argno: 3, expr: !DIExpression(DW_OP_lit7)) +!15 = !DISubprogram(name: "func1", scope: !1, file: !1, line: 8, isLocal: false, isDefinition: false, isOptimized: true, retainedNodes: !2) +!16 = !DILocation(line: 10, column: 4, scope: !6) +!17 = !DILocation(line: 11, column: 1, scope: !6)