Index: llvm/include/llvm/BinaryFormat/Dwarf.def =================================================================== --- llvm/include/llvm/BinaryFormat/Dwarf.def +++ llvm/include/llvm/BinaryFormat/Dwarf.def @@ -669,6 +669,8 @@ // Extensions for WebAssembly. HANDLE_DW_OP(0xed, WASM_location, 0, WASM) HANDLE_DW_OP(0xee, WASM_location_int, 0, WASM) +// The GNU implicit pointer extension. +HANDLE_DW_OP(0xf2, GNU_implicit_pointer, 0, GNU) // The GNU entry value extension. HANDLE_DW_OP(0xf3, GNU_entry_value, 0, GNU) // Extensions for Fission proposal. Index: llvm/include/llvm/CodeGen/MachineInstr.h =================================================================== --- llvm/include/llvm/CodeGen/MachineInstr.h +++ llvm/include/llvm/CodeGen/MachineInstr.h @@ -440,6 +440,10 @@ /// this DBG_VALUE instruction. MachineOperand &getDebugExpressionOp(); + /// Return the debug implicit variable referenced by + /// this DBG_VALUE instruction. + const DIVariable *getDebugImplicitVariable() const; + /// Return the complex address expression referenced by /// this DBG_VALUE instruction. const DIExpression *getDebugExpression() const; Index: llvm/include/llvm/CodeGen/MachineInstrBuilder.h =================================================================== --- llvm/include/llvm/CodeGen/MachineInstrBuilder.h +++ llvm/include/llvm/CodeGen/MachineInstrBuilder.h @@ -245,6 +245,16 @@ return *this; } + const MachineInstrBuilder &addImplicitPtrMetadata(const MDNode *MD) const { + MI->addOperand(*MF, MachineOperand::CreateMetadata(MD)); + assert((!MI->isDebugValue() || + static_cast(MI->getDebugImplicitVariable())) && + "first MDNode argument of a DBG_VALUE not a DIVariable"); + assert((!MI->isDebugLabel() || static_cast(MI->getDebugLabel())) && + "first MDNode argument of a DBG_LABEL not a label"); + return *this; + } + const MachineInstrBuilder &addCFIIndex(unsigned CFIIndex) const { MI->addOperand(*MF, MachineOperand::CreateCFIIndex(CFIIndex)); return *this; Index: llvm/include/llvm/CodeGen/SelectionDAG.h =================================================================== --- llvm/include/llvm/CodeGen/SelectionDAG.h +++ llvm/include/llvm/CodeGen/SelectionDAG.h @@ -1543,6 +1543,11 @@ unsigned VReg, bool IsIndirect, const DebugLoc &DL, unsigned O); + /// Creates an Implicit Pointer SDDbgValue node. + SDDbgValue *getImpPtrDbgValue(DIVariable *Var, DIExpression *Expr, + DIVariable *Val, const DebugLoc &DL, + unsigned O); + /// Creates a SDDbgLabel node. SDDbgLabel *getDbgLabel(DILabel *Label, const DebugLoc &DL, unsigned O); Index: llvm/include/llvm/IR/DIBuilder.h =================================================================== --- llvm/include/llvm/IR/DIBuilder.h +++ llvm/include/llvm/IR/DIBuilder.h @@ -645,6 +645,13 @@ DINode::DIFlags Flags = DINode::FlagZero, uint32_t AlignInBits = 0); + /// Create a temporary variable. + /// + /// \c Scope must be a \a DILocalScope, and thus its scope chain eventually + /// leads to a \a DISubprogram. + DILocalVariable *createImplicitTempVariable(DIScope *Scope, DIType *Ty, + uint32_t AlignInBits = 0); + /// Create a new descriptor for an label. /// /// \c Scope must be a \a DILocalScope, and thus its scope chain eventually Index: llvm/include/llvm/IR/DebugInfoMetadata.h =================================================================== --- llvm/include/llvm/IR/DebugInfoMetadata.h +++ llvm/include/llvm/IR/DebugInfoMetadata.h @@ -2702,6 +2702,24 @@ /// Return whether this is a piece of an aggregate variable. bool isFragment() const { return getFragmentInfo().hasValue(); } + /// Return whether this is an Implicit Pointer. + bool isImplicitPointer() const { + return getNumElements() > 0 && + (expr_op_begin()->getOp() == dwarf::DW_OP_LLVM_implicit_pointer); + } + + /// Return the number of indirection levels. + unsigned implicitPointerCount() const { + unsigned Count = 0; + for (unsigned i = 0; i < getNumElements(); ++i) { + if (Elements[i] != dwarf::DW_OP_LLVM_implicit_pointer) + continue; + + Count++; + } + return Count; + } + /// Return whether this is an implicit location description. bool isImplicit() const; Index: llvm/include/llvm/IR/IntrinsicInst.h =================================================================== --- llvm/include/llvm/IR/IntrinsicInst.h +++ llvm/include/llvm/IR/IntrinsicInst.h @@ -24,6 +24,7 @@ #define LLVM_IR_INTRINSICINST_H #include "llvm/IR/Constants.h" +#include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/FPEnv.h" #include "llvm/IR/Function.h" @@ -154,6 +155,19 @@ /// is described. Optional getFragmentSizeInBits() const; + /// Returns true if it has an implicit pointer expression. + bool isImplicitPointer() const { + return getExpression()->isImplicitPointer(); + } + + /// Returns number of levels of implicit pointer expression. + unsigned implicitPointerCount() const { + if (!isa(getRawExpression())) + return 0; + + return getExpression()->implicitPointerCount(); + } + /// \name Casting methods /// @{ static bool classof(const IntrinsicInst *I) { Index: llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -937,6 +937,8 @@ auto Op = MI->getDebugOperand(0); OS << "!target-index(" << Op.getIndex() << "," << Op.getOffset() << ")"; return true; + } else if (MI->getOperand(0).isMetadata()) { + OS << MI->getOperand(0).getMetadata(); } else { Register Reg; if (MI->getDebugOperand(0).isReg()) { Index: llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h +++ llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h @@ -45,7 +45,8 @@ E_Integer, E_ConstantFP, E_ConstantInt, - E_TargetIndexLocation + E_TargetIndexLocation, + E_ImplicitPtr }; enum EntryType EntryKind; @@ -61,6 +62,8 @@ MachineLocation Loc; /// Or a location from target specific location. TargetIndexLocation TIL; + /// Or an implicit pointer variable target. + const DIVariable *ImpPtr; }; public: @@ -82,6 +85,10 @@ } DbgValueLoc(const DIExpression *Expr, TargetIndexLocation Loc) : Expression(Expr), EntryKind(E_TargetIndexLocation), TIL(Loc) {} + DbgValueLoc(const DIExpression *Expr, const DIVariable *ImpPtr) + : Expression(Expr), EntryKind(E_ImplicitPtr), ImpPtr(ImpPtr) { + assert(cast(Expr)->isValid()); + } bool isLocation() const { return EntryKind == E_Location; } bool isTargetIndexLocation() const { @@ -90,11 +97,13 @@ bool isInt() const { return EntryKind == E_Integer; } bool isConstantFP() const { return EntryKind == E_ConstantFP; } bool isConstantInt() const { return EntryKind == E_ConstantInt; } + bool isImplicitPtr() const { return EntryKind == E_ImplicitPtr; } int64_t getInt() const { return Constant.Int; } const ConstantFP *getConstantFP() const { return Constant.CFP; } const ConstantInt *getConstantInt() const { return Constant.CIP; } MachineLocation getLoc() const { return Loc; } TargetIndexLocation getTargetIndexLocation() const { return TIL; } + const DIVariable *getImplicitPointer() const { return ImpPtr; } bool isFragment() const { return getExpression()->isFragment(); } bool isEntryVal() const { return getExpression()->isEntryValue(); } const DIExpression *getExpression() const { return Expression; } @@ -200,6 +209,8 @@ return A.Constant.CFP == B.Constant.CFP; case DbgValueLoc::E_ConstantInt: return A.Constant.CIP == B.Constant.CIP; + case DbgValueLoc::E_ImplicitPtr: + return A.ImpPtr == B.ImpPtr; } llvm_unreachable("unhandled EntryKind"); } Index: llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -76,6 +76,15 @@ // List of ranges for a given compile unit. SmallVector CURanges; + // First operand of DW_OP_implicit_pointer operation is a reference to a + // debugging information entry that describes the dereferenced object’s value. + // When this operation is created, the debugging information entry is not yet + // formed. To solve this problem, we maintain a vector of dereferenced + // objects. We keep the index of dereferenced object's at first operand of + // DW_OP_implicit_pointer operation temporarily. This temporary value is later + // replaced by the actual value in function DwarfDebug::emitDebugLocEntry. + SmallVector ImplicitVars; + // The base address of this unit, if any. Used for relative references in // ranges/locs. const MCSymbol *BaseAddress = nullptr; @@ -122,6 +131,20 @@ void initStmtList(); + auto findOrInsertImplicitVar(const DIVariable *Var) { + SmallVector::iterator It = + std::find(ImplicitVars.begin(), ImplicitVars.end(), Var); + if (It == ImplicitVars.end()) { + ImplicitVars.push_back(Var); + return ImplicitVars.size() - 1; + } + + return static_cast(std::distance(ImplicitVars.begin(), It)); + } + + const DIVariable *findImplicitVarAtIndex(unsigned Idx) const { + return ImplicitVars[Idx]; + } /// Apply the DW_AT_stmt_list from this compile unit to the specified DIE. void applyStmtList(DIE &D); Index: llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -1056,6 +1056,8 @@ switch (Loc) { case dwarf::DW_OP_entry_value: return dwarf::DW_OP_GNU_entry_value; + case dwarf::DW_OP_implicit_pointer: + return dwarf::DW_OP_GNU_implicit_pointer; default: llvm_unreachable("DWARF5 location atom with no GNU analog"); } @@ -1131,7 +1133,8 @@ DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); DwarfExpr.setCallSiteParamValueFlag(); - DwarfDebug::emitDebugLocValue(*Asm, nullptr, Param.getValue(), DwarfExpr); + DwarfDebug::emitDebugLocValue(*Asm, nullptr, Param.getValue(), DwarfExpr, + *this); addBlock(*CallSiteDieParam, getDwarf5OrGNUAttr(dwarf::DW_AT_call_value), DwarfExpr.finalize()); Index: llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -812,7 +812,8 @@ static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT, const DbgValueLoc &Value, - DwarfExpression &DwarfExpr); + DwarfExpression &DwarfExpr, + DwarfCompileUnit &TheCU); /// If the \p File has an MD5 checksum, return it as an MD5Result /// allocated in the MCContext. Index: llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -176,6 +176,26 @@ getActiveStreamer().emitULEB128(Idx, Twine(Idx), ULEB128PadSize); } +void DebugLocDwarfExpression::emitAddressRef(uint64_t Idx) { + uint8_t Val; + uint8_t NumBytes; + + switch (CU.getAsmPrinter()->OutStreamer->getContext().getDwarfFormat()) { + case dwarf::DWARF32: + NumBytes = 4; + break; + case dwarf::DWARF64: + NumBytes = 8; + break; + } + + while (NumBytes--) { + Val = Idx & 0xff; + Idx = Idx >> 8; + getActiveStreamer().emitInt8(Val, Twine(Idx)); + } +} + bool DebugLocDwarfExpression::isFrameRegister(const TargetRegisterInfo &TRI, llvm::Register MachineReg) { // This information is not available while emitting .debug_loc entries. @@ -236,6 +256,11 @@ return DbgValueLoc(Expr, MI->getDebugOperand(0).getFPImm()); if (MI->getDebugOperand(0).isCImm()) return DbgValueLoc(Expr, MI->getDebugOperand(0).getCImm()); + if (Expr->isImplicitPointer()) { + const DIVariable *DVI = + cast(MI->getDebugOperand(0).getMetadata()); + return DbgValueLoc(Expr, DVI); + } llvm_unreachable("Unexpected 4-operand DBG_VALUE instruction!"); } @@ -1772,10 +1797,13 @@ // Check if there is a single DBG_VALUE, valid throughout the var's scope. // If the history map contains a single debug value, there may be an // additional entry which clobbers the debug value. + // In case of implicit pointer, implicit target can not initialize + // variable so we need to create location list even in case of single value size_t HistSize = HistoryMapEntries.size(); bool SingleValueWithClobber = HistSize == 2 && HistoryMapEntries[1].isClobber(); - if (HistSize == 1 || SingleValueWithClobber) { + if (!MInsn->getDebugExpression()->isImplicitPointer() && + (HistSize == 1 || SingleValueWithClobber)) { const auto *End = SingleValueWithClobber ? HistoryMapEntries[1].getInstr() : nullptr; if (validThroughout(LScopes, MInsn, End, getInstOrdering())) { @@ -1798,7 +1826,10 @@ // Check whether buildLocationList managed to merge all locations to one // that is valid throughout the variable's scope. If so, produce single // value location. - if (isValidSingleLocation) { + // In case of implicit pointer, implicit target can not initialize + // variable so we need to create location list even in case of single value. + if (!MInsn->getDebugExpression()->isImplicitPointer() && + isValidSingleLocation) { RegVar->initializeDbgValue(Entries[0].getValues()[0]); continue; } @@ -2426,6 +2457,28 @@ for (unsigned J = 0; J < ULEB128PadSize; ++J) if (Comment != End) Comment++; + } else if ((Op.getCode() == dwarf::DW_OP_implicit_pointer || + Op.getCode() == dwarf::DW_OP_GNU_implicit_pointer) && + (Op.getDescription().Op[I] == Encoding::SizeRefAddr)) { + // Till now we do not have actual offset from debug_info section + // all we have is index in a list of variable, we can now compute + // actual offset. + unsigned ValOffset = 0; + // Read the dummy offset (index). + for (uint64_t J = Op.getOperandEndOffset(I) - 1; J >= Offset; --J) + ValOffset = (ValOffset << 8) + (uint8_t)Data.getData()[J]; + // Get the variable and compute the actual offset. + const DIVariable *ImpVar = CU->findImplicitVarAtIndex(ValOffset); + DIE *Die = CU->getDIE(ImpVar); + assert(Die && "Die can not be NULL"); + ValOffset = Die->getDebugSectionOffset(); + + // Emit the actual offset. + for (uint64_t J = Offset; J < Op.getOperandEndOffset(I); ++J) { + Streamer.emitInt8(ValOffset & 0xff, + Comment != End ? *(Comment++) : ""); + ValOffset = ValOffset >> 8; + } } else { for (uint64_t J = Offset; J < Op.getOperandEndOffset(I); ++J) Streamer.emitInt8(Data.getData()[J], Comment != End ? *(Comment++) : ""); @@ -2438,10 +2491,12 @@ void DwarfDebug::emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT, const DbgValueLoc &Value, - DwarfExpression &DwarfExpr) { + DwarfExpression &DwarfExpr, + DwarfCompileUnit &TheCU) { auto *DIExpr = Value.getExpression(); DIExpressionCursor ExprCursor(DIExpr); DwarfExpr.addFragmentOffset(DIExpr); + // Regular entry. if (Value.isInt()) { if (BT && (BT->getEncoding() == dwarf::DW_ATE_signed || @@ -2484,7 +2539,15 @@ << "Skipped DwarfExpression creation for ConstantFP of size" << Value.getConstantFP()->getValueAPF().bitcastToAPInt().getBitWidth() << " bits\n"); + } else if (Value.isImplicitPtr()) { + const llvm::DIVariable *ImpVar = Value.getImplicitPointer(); + unsigned long ValOffset = TheCU.findOrInsertImplicitVar(ImpVar); + // This works as dummy offset in first operand of DW_OP_implicit_pointer + // this will later be replace by actual offset of variable in .debug_info + DwarfExpr.emitImplicitPointer(std::move(ExprCursor), ValOffset); + return; } + DwarfExpr.addExpression(std::move(ExprCursor)); } @@ -2507,11 +2570,11 @@ assert(llvm::is_sorted(Values) && "fragments are expected to be sorted"); for (const auto &Fragment : Values) - DwarfDebug::emitDebugLocValue(AP, BT, Fragment, DwarfExpr); + DwarfDebug::emitDebugLocValue(AP, BT, Fragment, DwarfExpr, TheCU); } else { assert(Values.size() == 1 && "only fragments may have >1 value"); - DwarfDebug::emitDebugLocValue(AP, BT, Value, DwarfExpr); + DwarfDebug::emitDebugLocValue(AP, BT, Value, DwarfExpr, TheCU); } DwarfExpr.finalize(); if (DwarfExpr.TagOffset) Index: llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h +++ llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h @@ -196,6 +196,8 @@ virtual void emitBaseTypeRef(uint64_t Idx) = 0; + virtual void emitAddressRef(uint64_t Idx) = 0; + /// Start emitting data to the temporary buffer. The data stored in the /// temporary buffer can be committed to the main output using /// commitTemporaryBuffer(). @@ -357,6 +359,8 @@ /// Emit location information expressed via WebAssembly location + offset /// The Index is an identifier for locals, globals or operand stack. void addWasmLocation(unsigned Index, uint64_t Offset); + + void emitImplicitPointer(DIExpressionCursor &&Expr, unsigned ValOffset); }; /// DwarfExpression implementation for .debug_loc entries. @@ -382,6 +386,7 @@ void emitUnsigned(uint64_t Value) override; void emitData1(uint8_t Value) override; void emitBaseTypeRef(uint64_t Idx) override; + void emitAddressRef(uint64_t Idx) override; void enableTemporaryBuffer() override; void disableTemporaryBuffer() override; @@ -412,6 +417,7 @@ void emitUnsigned(uint64_t Value) override; void emitData1(uint8_t Value) override; void emitBaseTypeRef(uint64_t Idx) override; + void emitAddressRef(uint64_t Idx) override{}; void enableTemporaryBuffer() override; void disableTemporaryBuffer() override; Index: llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp +++ llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -670,3 +670,17 @@ emitUnsigned(Index); emitUnsigned(Offset); } + +void DwarfExpression::emitImplicitPointer(DIExpressionCursor &&ExprCursor, + unsigned ValOffset) { + auto Op = ExprCursor.take(); + assert(Op->getOp() == dwarf::DW_OP_LLVM_implicit_pointer && + "not dwarf::DW_OP_LLVM_implicit_pointer"); + + emitOp(CU.getDwarf5OrGNULocationAtom(dwarf::DW_OP_implicit_pointer)); + // This is a dummy offset which will be replaced with actual offset in + // function DwarfDebug::emitDebugLocEntry. + emitAddressRef(ValOffset); + emitSigned(0); + return; +} Index: llvm/lib/CodeGen/CodeGenPrepare.cpp =================================================================== --- llvm/lib/CodeGen/CodeGenPrepare.cpp +++ llvm/lib/CodeGen/CodeGenPrepare.cpp @@ -1220,7 +1220,6 @@ // If we removed all uses, nuke the cast. if (CI->use_empty()) { - salvageDebugInfo(*CI); CI->eraseFromParent(); MadeChange = true; } @@ -1883,7 +1882,6 @@ // If we removed all uses, or there are none, nuke the shift. if (ShiftI->use_empty()) { - salvageDebugInfo(*ShiftI); ShiftI->eraseFromParent(); MadeChange = true; } Index: llvm/lib/CodeGen/LiveDebugValues/VarLocBasedImpl.cpp =================================================================== --- llvm/lib/CodeGen/LiveDebugValues/VarLocBasedImpl.cpp +++ llvm/lib/CodeGen/LiveDebugValues/VarLocBasedImpl.cpp @@ -318,7 +318,8 @@ ImmediateKind, EntryValueKind, EntryValueBackupKind, - EntryValueCopyBackupKind + EntryValueCopyBackupKind, + ImplicitPtrKind } Kind = InvalidKind; /// The value location. Stored separately to avoid repeatedly @@ -330,6 +331,7 @@ int64_t Immediate; const ConstantFP *FPImm; const ConstantInt *CImm; + const DIVariable *ImplicitPtr; } Loc; VarLoc(const MachineInstr &MI, LexicalScopes &LS) @@ -352,6 +354,9 @@ } else if (MI.getDebugOperand(0).isCImm()) { Kind = ImmediateKind; Loc.CImm = MI.getDebugOperand(0).getCImm(); + } else if (MI.getDebugOperand(0).isMetadata()) { + Kind = ImplicitPtrKind; + Loc.ImplicitPtr = MI.getDebugImplicitVariable(); } // We create the debug entry values from the factory functions rather than @@ -459,6 +464,10 @@ MachineOperand MO = MI.getDebugOperand(0); return BuildMI(MF, DbgLoc, IID, Indirect, MO, Var, DIExpr); } + case ImplicitPtrKind: { + MachineOperand MO = MI.getOperand(0); + return BuildMI(MF, DbgLoc, IID, Indirect, MO, Var, DIExpr); + } case EntryValueBackupKind: case EntryValueCopyBackupKind: case InvalidKind: @@ -524,6 +533,9 @@ case ImmediateKind: Out << Loc.Immediate; break; + case ImplicitPtrKind: + dbgs() << Loc.ImplicitPtr->getName(); + break; case InvalidKind: llvm_unreachable("Invalid VarLoc in dump method"); } @@ -1073,7 +1085,8 @@ } if (isDbgValueDescribedByReg(MI) || MI.getDebugOperand(0).isImm() || - MI.getDebugOperand(0).isFPImm() || MI.getDebugOperand(0).isCImm()) { + MI.getDebugOperand(0).isFPImm() || MI.getDebugOperand(0).isCImm() || + MI.getOperand(0).isMetadata()) { // Use normal VarLoc constructor for registers and immediates. VarLoc VL(MI, LS); // End all previous ranges of VL.Var. Index: llvm/lib/CodeGen/MachineInstr.cpp =================================================================== --- llvm/lib/CodeGen/MachineInstr.cpp +++ llvm/lib/CodeGen/MachineInstr.cpp @@ -861,6 +861,11 @@ return getOperand(3); } +const DIVariable *MachineInstr::getDebugImplicitVariable() const { + assert(isDebugValue() && "not a DBG_VALUE"); + return cast(getOperand(0).getMetadata()); +} + const DIExpression *MachineInstr::getDebugExpression() const { assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE"); return cast(getOperand(3).getMetadata()); Index: llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp +++ llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp @@ -749,6 +749,10 @@ // dropped. MIB.addReg(0U); } + } else if (SD->getKind() == SDDbgValue::IMPPTR) { + const MDNode *DV = SD->getImplicitPointer(); + // insert implicit pointer + MIB.addImplicitPtrMetadata(DV); } else { // Insert an Undef so we can see what we dropped. MIB.addReg(0U); Index: llvm/lib/CodeGen/SelectionDAG/SDNodeDbgValue.h =================================================================== --- llvm/lib/CodeGen/SelectionDAG/SDNodeDbgValue.h +++ llvm/lib/CodeGen/SelectionDAG/SDNodeDbgValue.h @@ -30,11 +30,13 @@ class SDDbgValue { public: enum DbgValueKind { - SDNODE = 0, ///< Value is the result of an expression. - CONST = 1, ///< Value is a constant. - FRAMEIX = 2, ///< Value is contents of a stack location. - VREG = 3 ///< Value is a virtual register. + SDNODE = 0, ///< Value is the result of an expression. + CONST = 1, ///< Value is a constant. + FRAMEIX = 2, ///< Value is contents of a stack location. + VREG = 3, ///< Value is a virtual register. + IMPPTR = 4 ///< Value is an implicit pointer. }; + private: union { struct { @@ -44,6 +46,7 @@ const Value *Const; ///< Valid for constants. unsigned FrameIx; ///< Valid for stack objects. unsigned VReg; ///< Valid for registers. + DIVariable *ImpPtr; } u; DIVariable *Var; DIExpression *Expr; @@ -86,6 +89,14 @@ u.FrameIx = VRegOrFrameIdx; } + /// Constructor for Implicit Pointer. + SDDbgValue(DIVariable *Var, DIExpression *Expr, DIVariable *Val, DebugLoc dl, + unsigned O) + : Var(Var), Expr(Expr), DL(std::move(dl)), Order(O), IsIndirect(false) { + kind = IMPPTR; + u.ImpPtr = Val; + } + /// Returns the kind. DbgValueKind getKind() const { return kind; } @@ -110,6 +121,12 @@ /// Returns the Virtual Register for a VReg unsigned getVReg() const { assert (kind==VREG); return u.VReg; } + /// Returns the implicit pointer target + DIVariable *getImplicitPointer() const { + assert(kind == IMPPTR); + return u.ImpPtr; + } + /// Returns whether this is an indirect value. bool isIndirect() const { return IsIndirect; } Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -8384,6 +8384,15 @@ SDDbgValue(Var, Expr, VReg, IsIndirect, DL, O, SDDbgValue::VREG); } +/// Implicit pointer +SDDbgValue *SelectionDAG::getImpPtrDbgValue(DIVariable *Var, DIExpression *Expr, + DIVariable *Val, const DebugLoc &DL, + unsigned O) { + assert(cast(Var)->isValidLocationForIntrinsic(DL) && + "Expected inlined-at fields to agree"); + return new (DbgInfo->getAlloc()) SDDbgValue(Var, Expr, Val, DL, O); +} + void SelectionDAG::transferDbgValues(SDValue From, SDValue To, unsigned OffsetInBits, unsigned SizeInBits, bool InvalidateDbg) { Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h =================================================================== --- llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h @@ -507,6 +507,9 @@ /// this cannot be done, produce an Undef debug value record. void salvageUnresolvedDbgValue(DanglingDebugInfo &DDI); + bool handleDebugValueWrapper(const DbgValueInst &DI, DebugLoc dl, + unsigned Order); + /// For a given Value, attempt to create and record a SDDbgValue in the /// SelectionDAG. bool handleDebugValue(const Value *V, DILocalVariable *Var, Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -66,6 +66,7 @@ #include "llvm/IR/Constant.h" #include "llvm/IR/ConstantRange.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/DIBuilder.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DerivedTypes.h" @@ -1122,7 +1123,7 @@ void SelectionDAGBuilder::dropDanglingDebugInfo(const DILocalVariable *Variable, const DIExpression *Expr) { auto isMatchingDbgValue = [&](DanglingDebugInfo &DDI) { - const DbgValueInst *DI = DDI.getDI(); + const DbgVariableIntrinsic *DI = DDI.getDI(); DIVariable *DanglingVariable = DI->getVariable(); DIExpression *DanglingExpr = DI->getExpression(); if (DanglingVariable == Variable && Expr->fragmentsOverlap(DanglingExpr)) { @@ -1256,6 +1257,63 @@ << "\n"); } +bool SelectionDAGBuilder::handleDebugValueWrapper(const DbgValueInst &DI, + DebugLoc dl, unsigned Order) { + DILocalVariable *Variable = DI.getVariable(); + DIExpression *Expression = DI.getExpression(); + + const Value *V = DI.getValue(); + + unsigned Level = Expression->implicitPointerCount(); + if (Level == 0) { + return handleDebugValue(V, Variable, Expression, dl, DI.getDebugLoc(), + SDNodeOrder); + } + + DIScope *Scope = DI.getDebugLoc()->getScope(); + DIType *Type = DI.getVariable()->getType(); + Module *Mod = const_cast(DI.getModule()); + DIBuilder DIB(*Mod, /*AllowUnresolved*/ false); + SmallVector PtrVars; + + // Multi-level DW_OP_LLVM_implicit_pointer is broken into multiple statements + // of single DW_OP_LLVM_implicit_pointer. + + // Add the original pointer as first element in PtrVars + PtrVars.push_back(Variable); + + // Generate artificial variable for each level and append in PtrVars + unsigned Count = 0; + while (Count++ < Level) { + if (DIDerivedType *DT = dyn_cast(Type)) + Type = DT->getBaseType(); + uint32_t AlignInBits = DI.getVariable()->getAlignInBytes(); + + DILocalVariable *PteVar = + DIB.createImplicitTempVariable(Scope, Type, AlignInBits); + PtrVars.push_back(PteVar); + } + + SmallVector Ops; + DIExpression *DE = DIExpression::get(Expression->getContext(), Ops); + + if (!handleDebugValue(V, PtrVars[Level], DE, dl, DI.getDebugLoc(), + SDNodeOrder)) + return false; + + Count = Level; + while (Count-- > 0) { + DE = DIExpression::get(DE->getContext(), + {dwarf::DW_OP_LLVM_implicit_pointer}); + + SDDbgValue *SDV = DAG.getImpPtrDbgValue( + PtrVars[Count], DE, PtrVars[Count + 1], dl, SDNodeOrder); + DAG.AddDbgValue(SDV, nullptr, false); + } + + return true; +} + bool SelectionDAGBuilder::handleDebugValue(const Value *V, DILocalVariable *Var, DIExpression *Expr, DebugLoc dl, DebugLoc InstDL, unsigned Order) { @@ -5928,8 +5986,7 @@ if (!V) return; - if (handleDebugValue(V, Variable, Expression, dl, DI.getDebugLoc(), - SDNodeOrder)) + if (handleDebugValueWrapper(DI, dl, SDNodeOrder)) return; // TODO: Dangling debug info will eventually either be resolved or produce Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp @@ -818,6 +818,11 @@ case VREG: OS << "(VREG=" << getVReg() << ')'; break; + case IMPPTR: + // implicit pointer will be printed as + // DbgVal(Order=1)(IMPPTR=arr):"ptr"!DIExpression(DW_OP_implicit_pointer, 0) + OS << "(IMPPTR=" << u.ImpPtr->getName() << ')'; + break; } if (isIndirect()) OS << "(Indirect)"; OS << ":\"" << Var->getName() << '"'; Index: llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp @@ -111,11 +111,13 @@ unsigned AddressSize, const MCRegisterInfo *MRI, DWARFUnit *U) { DWARFDataExtractor Extractor(Data, IsLittleEndian, AddressSize); - // Note. We do not pass any format to DWARFExpression, even if the - // corresponding unit is known. For now, there is only one operation, - // DW_OP_call_ref, which depends on the format; it is rarely used, and - // is unexpected in location tables. - DWARFExpression(Extractor, AddressSize).print(OS, DumpOpts, MRI, U); + // In case (DWARFUnit) U is non NULL lets deduce the format and pass + // to DWARFExpression + if (U) + DWARFExpression(Extractor, AddressSize, U->getFormParams().Format) + .print(OS, DumpOpts, MRI, U); + else + DWARFExpression(Extractor, AddressSize).print(OS, DumpOpts, MRI, U); } bool DWARFLocationTable::dumpLocationList(uint64_t *Offset, raw_ostream &OS, Index: llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp @@ -99,11 +99,15 @@ 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); + Descriptions[DW_OP_GNU_implicit_pointer] = + Desc(Op::Dwarf4, Op::SizeRefAddr, Op::SignedSizeLEB); Descriptions[DW_OP_convert] = Desc(Op::Dwarf5, Op::BaseTypeRef); Descriptions[DW_OP_entry_value] = Desc(Op::Dwarf5, Op::SizeLEB); Descriptions[DW_OP_regval_type] = Desc(Op::Dwarf5, Op::SizeLEB, Op::BaseTypeRef); + Descriptions[DW_OP_implicit_pointer] = + Desc(Op::Dwarf5, Op::SizeRefAddr, Op::SignedSizeLEB); return Descriptions; } Index: llvm/lib/IR/DIBuilder.cpp =================================================================== --- llvm/lib/IR/DIBuilder.cpp +++ llvm/lib/IR/DIBuilder.cpp @@ -718,16 +718,20 @@ DenseMap> &PreservedVariables, DIScope *Scope, StringRef Name, unsigned ArgNo, DIFile *File, unsigned LineNo, DIType *Ty, bool AlwaysPreserve, DINode::DIFlags Flags, - uint32_t AlignInBits) { + uint32_t AlignInBits, bool IsDistinct = false) { // FIXME: Why getNonCompileUnitScope()? // FIXME: Why is "!Context" okay here? // FIXME: Why doesn't this check for a subprogram or lexical block (AFAICT // the only valid scopes)? DIScope *Context = getNonCompileUnitScope(Scope); - auto *Node = - DILocalVariable::get(VMContext, cast_or_null(Context), Name, - File, LineNo, Ty, ArgNo, Flags, AlignInBits); + auto *Node = IsDistinct + ? DILocalVariable::getDistinct( + VMContext, cast_or_null(Context), Name, + File, LineNo, Ty, ArgNo, Flags, AlignInBits) + : DILocalVariable::get( + VMContext, cast_or_null(Context), Name, + File, LineNo, Ty, ArgNo, Flags, AlignInBits); if (AlwaysPreserve) { // The optimizer may remove local variables. If there is an interest // to preserve variable info in such situation then stash it in a @@ -749,6 +753,16 @@ Flags, AlignInBits); } +DILocalVariable *DIBuilder::createImplicitTempVariable(DIScope *Scope, + DIType *Ty, + uint32_t AlignInBits) { + llvm::StringRef Name; + + return createLocalVariable(VMContext, PreservedVariables, Scope, Name, + /* ArgNo */ 0, nullptr, 0, Ty, false, + llvm::DINode::FlagArtificial, AlignInBits, true); +} + DILocalVariable *DIBuilder::createParameterVariable( DIScope *Scope, StringRef Name, unsigned ArgNo, DIFile *File, unsigned LineNo, DIType *Ty, bool AlwaysPreserve, DINode::DIFlags Flags) { Index: llvm/test/DebugInfo/X86/dwarfdump-implicit_pointer_dwarf4.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/dwarfdump-implicit_pointer_dwarf4.ll @@ -0,0 +1,196 @@ +; RUN: llc %s -filetype=obj -o - | llvm-dwarfdump - | FileCheck %s + +; CHECK-LABEL: DW_AT_name ("arr1") + +; CHECK-LABEL: DW_AT_location +; CHECK-NEXT: : DW_OP_lit0, DW_OP_stack_value +; CHECK-NEXT: : DW_OP_GNU_implicit_pointer 0x[[IP1:[0-9a-f]+]] +0 +; CHECK-NEXT: DW_AT_name ("ptr1") + +; CHECK-LABEL: DW_AT_location +; CHECK-NEXT: : DW_OP_lit0, DW_OP_stack_value +; CHECK-NEXT: : DW_OP_GNU_implicit_pointer 0x[[IP2:[0-9a-f]+]] +0 +; CHECK-NEXT: DW_AT_name ("ptr2") + +; CHECK-LABEL: DW_AT_location +; CHECK-NEXT: : DW_OP_lit0, DW_OP_stack_value +; CHECK-NEXT: : DW_OP_GNU_implicit_pointer 0x[[IP3:[0-9a-f]+]] +0 +; CHECK-NEXT: DW_AT_name ("ptr3") + +; CHECK-LABEL: DW_AT_location +; CHECK-NEXT: : DW_OP_lit0, DW_OP_stack_value +; CHECK-NEXT: : DW_OP_GNU_implicit_pointer 0x[[IP4:[0-9a-f]+]] +0 +; CHECK-NEXT: DW_AT_name ("ptrptr1") + +; CHECK-LABEL: DW_AT_location +; CHECK-NEXT: : DW_OP_lit0, DW_OP_stack_value +; CHECK-NEXT: : DW_OP_GNU_implicit_pointer 0x[[IP5:[0-9a-f]+]] +0 +; CHECK-NEXT: DW_AT_name ("ptrptr2") + +; CHECK-LABEL: DW_AT_location +; CHECK-NEXT: : DW_OP_lit0, DW_OP_stack_value +; CHECK-NEXT: : DW_OP_GNU_implicit_pointer 0x[[IP6:[0-9a-f]+]] +0 +; CHECK-NEXT: DW_AT_name ("ptrptr3") + +; CHECK: [[IP6]]: DW_TAG_variable +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: : DW_OP_GNU_implicit_pointer 0x[[IP61:[0-9a-f]+]] +0 +; CHECK-NEXT: DW_AT_type (0x{{[0-9a-f]+}} "int*") +; CHECK-NEXT: DW_AT_artificial (true) + +; CHECK: [[IP61]]: DW_TAG_variable +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: DW_OP_consts +2, DW_OP_stack_value +; CHECK-NEXT: DW_AT_type (0x{{[0-9a-f]+}} "int") +; CHECK-NEXT: DW_AT_artificial (true) + +; CHECK: [[IP5]]: DW_TAG_variable +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: : DW_OP_GNU_implicit_pointer 0x[[IP51:[0-9a-f]+]] +0 +; CHECK-NEXT: DW_AT_type (0x{{[0-9a-f]+}} "int*") +; CHECK-NEXT: DW_AT_artificial (true) + +; CHECK: [[IP51]]: DW_TAG_variable +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: DW_OP_consts +5, DW_OP_stack_value +; CHECK-NEXT: DW_AT_type (0x{{[0-9a-f]+}} "int") +; CHECK-NEXT: DW_AT_artificial (true) + +; CHECK: [[IP4]]: DW_TAG_variable +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: : DW_OP_GNU_implicit_pointer 0x[[IP41:[0-9a-f]+]] +0 +; CHECK-NEXT: DW_AT_type (0x{{[0-9a-f]+}} "int*") +; CHECK-NEXT: DW_AT_artificial (true) + +; CHECK: [[IP41]]: DW_TAG_variable +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: DW_OP_consts +4, DW_OP_stack_value +; CHECK-NEXT: DW_AT_type (0x{{[0-9a-f]+}} "int") +; CHECK-NEXT: DW_AT_artificial (true) + +; CHECK: [[IP3]]: DW_TAG_variable +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: DW_OP_consts +2, DW_OP_stack_value +; CHECK-NEXT: DW_AT_type (0x{{[0-9a-f]+}} "int") +; CHECK-NEXT: DW_AT_artificial (true) + +; CHECK: [[IP2]]: DW_TAG_variable +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: DW_OP_consts +5, DW_OP_stack_value +; CHECK-NEXT: DW_AT_type (0x{{[0-9a-f]+}} "int") +; CHECK-NEXT: DW_AT_artificial (true) + +; CHECK: [[IP1]]: DW_TAG_variable +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: DW_OP_consts +4, DW_OP_stack_value +; CHECK-NEXT: DW_AT_type (0x{{[0-9a-f]+}} "int") +; CHECK-NEXT: DW_AT_artificial (true) + +; Below is the original test case this IR is generated from +;--------------------------- +;static const char *b = "opq"; +;volatile int v; +;int main() { +; int var1 = 4; +; int var2 = 5; +; int arr1[2] = {2, 3}; +; int *ptr1 = 0; +; int *ptr2 = 0; +; int *ptr3 = 0; +; int **ptrptr1 = 0; +; int **ptrptr2 = 0; +; int **ptrptr3 = 0; +; +; v++; +; ptr1 = &var1; +; ptr2 = &var2; +; ptr3 = arr1; +; ptrptr1 = &ptr1; +; ptrptr2 = &ptr2; +; ptrptr3 = &ptr3; +; v++; +; +; return arr1[0] + arr1[1] + *ptr1 + *ptr2 + **ptrptr1 + **ptrptr2 - 5; +;} +;--------------------------- + +; ModuleID = 'dwarfdump-implicit_pointer_mem2reg.c' +source_filename = "dwarfdump-implicit_pointer_mem2reg.c" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@v = common dso_local global i32 0, align 4, !dbg !0 + +; Function Attrs: nofree norecurse nounwind uwtable +define dso_local i32 @main() local_unnamed_addr #0 !dbg !12 { +entry: + call void @llvm.dbg.value(metadata i32 4, metadata !16, metadata !DIExpression()), !dbg !30 + call void @llvm.dbg.value(metadata i32 5, metadata !17, metadata !DIExpression()), !dbg !30 + call void @llvm.dbg.value(metadata i32 2, metadata !18, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)), !dbg !30 + call void @llvm.dbg.value(metadata i32 3, metadata !18, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32)), !dbg !30 + call void @llvm.dbg.value(metadata i32* null, metadata !22, metadata !DIExpression()), !dbg !30 + call void @llvm.dbg.value(metadata i32* null, metadata !24, metadata !DIExpression()), !dbg !30 + call void @llvm.dbg.value(metadata i32* null, metadata !25, metadata !DIExpression()), !dbg !30 + call void @llvm.dbg.value(metadata i32** null, metadata !26, metadata !DIExpression()), !dbg !30 + call void @llvm.dbg.value(metadata i32** null, metadata !28, metadata !DIExpression()), !dbg !30 + call void @llvm.dbg.value(metadata i32** null, metadata !29, metadata !DIExpression()), !dbg !30 + %0 = load volatile i32, i32* @v, align 4, !dbg !31, !tbaa !32 + %inc = add nsw i32 %0, 1, !dbg !31 + store volatile i32 %inc, i32* @v, align 4, !dbg !31, !tbaa !32 + call void @llvm.dbg.value(metadata i32 4, metadata !22, metadata !DIExpression(DW_OP_LLVM_implicit_pointer)), !dbg !30 + call void @llvm.dbg.value(metadata i32 5, metadata !24, metadata !DIExpression(DW_OP_LLVM_implicit_pointer)), !dbg !30 + call void @llvm.dbg.value(metadata i32 2, metadata !25, metadata !DIExpression(DW_OP_LLVM_implicit_pointer)), !dbg !30 + call void @llvm.dbg.value(metadata i32 4, metadata !26, metadata !DIExpression(DW_OP_LLVM_implicit_pointer, DW_OP_LLVM_implicit_pointer)), !dbg !30 + call void @llvm.dbg.value(metadata i32 5, metadata !28, metadata !DIExpression(DW_OP_LLVM_implicit_pointer, DW_OP_LLVM_implicit_pointer)), !dbg !30 + call void @llvm.dbg.value(metadata i32 2, metadata !29, metadata !DIExpression(DW_OP_LLVM_implicit_pointer, DW_OP_LLVM_implicit_pointer)), !dbg !30 + %1 = load volatile i32, i32* @v, align 4, !dbg !36, !tbaa !32 + %inc1 = add nsw i32 %1, 1, !dbg !36 + store volatile i32 %inc1, i32* @v, align 4, !dbg !36, !tbaa !32 + ret i32 18, !dbg !37 +} + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!8, !9, !10} +!llvm.ident = !{!11} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "v", scope: !2, file: !3, line: 45, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 12.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "dwarfdump-implicit_pointer_mem2reg.c", directory: "/dir", checksumkind: CSK_MD5, checksum: "6ad1488ed7a007c3a33e08ec42847d87") +!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 = !{i32 1, !"wchar_size", i32 4} +!11 = !{!"clang version 10.0.0"} +!12 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 46, type: !13, scopeLine: 46, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !15) +!13 = !DISubroutineType(types: !14) +!14 = !{!7} +!15 = !{!16, !17, !18, !22, !24, !25, !26, !28, !29} +!16 = !DILocalVariable(name: "var1", scope: !12, file: !3, line: 47, type: !7) +!17 = !DILocalVariable(name: "var2", scope: !12, file: !3, line: 48, type: !7) +!18 = !DILocalVariable(name: "arr1", scope: !12, file: !3, line: 49, type: !19) +!19 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 64, elements: !20) +!20 = !{!21} +!21 = !DISubrange(count: 2) +!22 = !DILocalVariable(name: "ptr1", scope: !12, file: !3, line: 50, type: !23) +!23 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!24 = !DILocalVariable(name: "ptr2", scope: !12, file: !3, line: 51, type: !23) +!25 = !DILocalVariable(name: "ptr3", scope: !12, file: !3, line: 52, type: !23) +!26 = !DILocalVariable(name: "ptrptr1", scope: !12, file: !3, line: 53, type: !27) +!27 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !23, size: 64) +!28 = !DILocalVariable(name: "ptrptr2", scope: !12, file: !3, line: 54, type: !27) +!29 = !DILocalVariable(name: "ptrptr3", scope: !12, file: !3, line: 55, type: !27) +!30 = !DILocation(line: 0, scope: !12) +!31 = !DILocation(line: 57, column: 4, scope: !12) +!32 = !{!33, !33, i64 0} +!33 = !{!"int", !34, i64 0} +!34 = !{!"omnipotent char", !35, i64 0} +!35 = !{!"Simple C/C++ TBAA"} +!36 = !DILocation(line: 64, column: 4, scope: !12) +!37 = !DILocation(line: 66, column: 3, scope: !12) Index: llvm/test/DebugInfo/X86/dwarfdump-implicit_pointer_instcomb.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/dwarfdump-implicit_pointer_instcomb.ll @@ -0,0 +1,116 @@ +; RUN: llc %s -filetype=obj -o - | llvm-dwarfdump - | FileCheck %s + +; CHECK-LABEL: DW_AT_name ("func") +; CHECK-LABEL: DW_TAG_formal_parameter +; CHECK: 0x000000[[IMPLICITDIE2:[0-9a-f]+]]: DW_TAG_variable + +; CHECK-LABEL: DW_TAG_subprogram +; CHECK-LABEL: DW_AT_name ("main") +; CHECK: 0x000000[[IMPLICITDIE1:[0-9a-f]+]]: DW_TAG_variable +; CHECK: DW_AT_const_value (4) +; CHECK-LABEL: DW_AT_artificial +; CHECK: DW_AT_location +; CHECK-NEXT: DW_OP_implicit_pointer 0x[[IMPLICITDIE1]] +0 +; CHECK-NEXT: DW_AT_name ("ptrVar") + +; CHECK-LABEL: DW_TAG_inlined_subroutine +; CHECK: DW_TAG_formal_parameter +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: DW_OP_implicit_pointer 0x[[IMPLICITDIE2]] +0 +; CHECK-NEXT: "ptr" + +; Below is the original test case this IR is generated from +;--------------------------- +;volatile int gvar = 7; +; +;int func(int *ptr) { +; gvar = *ptr; +; return *ptr + 5; +;} +; +;int main() { +; int var = 4; +; int *ptrVar = &var; +; +; int res = func(ptrVar); +; +; return res; +;} +;--------------------------- + +; ModuleID = 'dwarfdump-implicit_pointer_instcomb.c' +source_filename = "dwarfdump-implicit_pointer_instcomb.c" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@gvar = dso_local global i32 7, align 4, !dbg !0 + +; Function Attrs: nofree norecurse nounwind uwtable +define dso_local i32 @func(i32* nocapture readonly %ptr) local_unnamed_addr #0 !dbg !12 { +entry: + call void @llvm.dbg.value(metadata i32* %ptr, metadata !17, metadata !DIExpression()), !dbg !18 + %0 = load i32, i32* %ptr, align 4, !dbg !19 + store volatile i32 %0, i32* @gvar, align 4, !dbg !24 + %1 = load i32, i32* %ptr, align 4, !dbg !25 + %add = add nsw i32 %1, 5, !dbg !26 + ret i32 %add, !dbg !27 +} + +; Function Attrs: nounwind uwtable +define dso_local i32 @main() local_unnamed_addr #1 !dbg !28 { +entry: + call void @llvm.dbg.value(metadata i32 4, metadata !33, metadata !DIExpression(DW_OP_LLVM_implicit_pointer)), !dbg !35 + call void @llvm.dbg.value(metadata i32 4, metadata !32, metadata !DIExpression()), !dbg !35 + call void @llvm.dbg.value(metadata i32 4, metadata !17, metadata !DIExpression(DW_OP_LLVM_implicit_pointer)), !dbg !36 + store volatile i32 4, i32* @gvar, align 4, !dbg !38 + call void @llvm.dbg.value(metadata i32 9, metadata !34, metadata !DIExpression()), !dbg !35 + ret i32 9, !dbg !39 +} + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!8, !9, !10} +!llvm.ident = !{!11} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "gvar", scope: !2, file: !3, line: 14, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 12.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "dwarfdump-implicit_pointer_instcomb.c", directory: "/dir", checksumkind: CSK_MD5, checksum: "1c991e568deb5a6321b60bc8bf8be8d6") +!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 5} +!9 = !{i32 2, !"Debug Info Version", i32 3} +!10 = !{i32 1, !"wchar_size", i32 4} +!11 = !{!"clang version 11.0.0"} +!12 = distinct !DISubprogram(name: "func", scope: !3, file: !3, line: 16, type: !13, scopeLine: 16, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !16) +!13 = !DISubroutineType(types: !14) +!14 = !{!7, !15} +!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!16 = !{!17} +!17 = !DILocalVariable(name: "ptr", arg: 1, scope: !12, file: !3, line: 16, type: !15) +!18 = !DILocation(line: 0, scope: !12) +!19 = !DILocation(line: 17, column: 10, scope: !12) +!20 = !{!21, !21, i64 0} +!21 = !{!"int", !22, i64 0} +!22 = !{!"omnipotent char", !23, i64 0} +!23 = !{!"Simple C/C++ TBAA"} +!24 = !DILocation(line: 17, column: 8, scope: !12) +!25 = !DILocation(line: 18, column: 10, scope: !12) +!26 = !DILocation(line: 18, column: 15, scope: !12) +!27 = !DILocation(line: 18, column: 3, scope: !12) +!28 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 21, type: !29, scopeLine: 21, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !31) +!29 = !DISubroutineType(types: !30) +!30 = !{!7} +!31 = !{!32, !33, !34} +!32 = !DILocalVariable(name: "var", scope: !28, file: !3, line: 22, type: !7) +!33 = !DILocalVariable(name: "ptrVar", scope: !28, file: !3, line: 23, type: !15) +!34 = !DILocalVariable(name: "res", scope: !28, file: !3, line: 25, type: !7) +!35 = !DILocation(line: 0, scope: !28) +!36 = !DILocation(line: 0, scope: !12, inlinedAt: !37) +!37 = distinct !DILocation(line: 25, column: 13, scope: !28) +!38 = !DILocation(line: 17, column: 8, scope: !12, inlinedAt: !37) +!39 = !DILocation(line: 27, column: 3, scope: !28) Index: llvm/test/DebugInfo/X86/dwarfdump-implicit_pointer_multilevel.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/dwarfdump-implicit_pointer_multilevel.ll @@ -0,0 +1,196 @@ +; RUN: llc %s -filetype=obj -o - | llvm-dwarfdump - | FileCheck %s + +; CHECK-LABEL: DW_AT_name ("arr1") + +; CHECK-LABEL: DW_AT_location +; CHECK-NEXT: : DW_OP_lit0, DW_OP_stack_value +; CHECK-NEXT: : DW_OP_implicit_pointer 0x[[IP1:[0-9a-f]+]] +0 +; CHECK-NEXT: DW_AT_name ("ptr1") + +; CHECK-LABEL: DW_AT_location +; CHECK-NEXT: : DW_OP_lit0, DW_OP_stack_value +; CHECK-NEXT: : DW_OP_implicit_pointer 0x[[IP2:[0-9a-f]+]] +0 +; CHECK-NEXT: DW_AT_name ("ptr2") + +; CHECK-LABEL: DW_AT_location +; CHECK-NEXT: : DW_OP_lit0, DW_OP_stack_value +; CHECK-NEXT: : DW_OP_implicit_pointer 0x[[IP3:[0-9a-f]+]] +0 +; CHECK-NEXT: DW_AT_name ("ptr3") + +; CHECK-LABEL: DW_AT_location +; CHECK-NEXT: : DW_OP_lit0, DW_OP_stack_value +; CHECK-NEXT: : DW_OP_implicit_pointer 0x[[IP4:[0-9a-f]+]] +0 +; CHECK-NEXT: DW_AT_name ("ptrptr1") + +; CHECK-LABEL: DW_AT_location +; CHECK-NEXT: : DW_OP_lit0, DW_OP_stack_value +; CHECK-NEXT: : DW_OP_implicit_pointer 0x[[IP5:[0-9a-f]+]] +0 +; CHECK-NEXT: DW_AT_name ("ptrptr2") + +; CHECK-LABEL: DW_AT_location +; CHECK-NEXT: : DW_OP_lit0, DW_OP_stack_value +; CHECK-NEXT: : DW_OP_implicit_pointer 0x[[IP6:[0-9a-f]+]] +0 +; CHECK-NEXT: DW_AT_name ("ptrptr3") + +; CHECK: [[IP6]]: DW_TAG_variable +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: : DW_OP_implicit_pointer 0x[[IP61:[0-9a-f]+]] +0 +; CHECK-NEXT: DW_AT_type (0x{{[0-9a-f]+}} "int*") +; CHECK-NEXT: DW_AT_artificial (true) + +; CHECK: [[IP61]]: DW_TAG_variable +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: DW_OP_consts +2, DW_OP_stack_value +; CHECK-NEXT: DW_AT_type (0x{{[0-9a-f]+}} "int") +; CHECK-NEXT: DW_AT_artificial (true) + +; CHECK: [[IP5]]: DW_TAG_variable +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: : DW_OP_implicit_pointer 0x[[IP51:[0-9a-f]+]] +0 +; CHECK-NEXT: DW_AT_type (0x{{[0-9a-f]+}} "int*") +; CHECK-NEXT: DW_AT_artificial (true) + +; CHECK: [[IP51]]: DW_TAG_variable +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: DW_OP_consts +5, DW_OP_stack_value +; CHECK-NEXT: DW_AT_type (0x{{[0-9a-f]+}} "int") +; CHECK-NEXT: DW_AT_artificial (true) + +; CHECK: [[IP4]]: DW_TAG_variable +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: : DW_OP_implicit_pointer 0x[[IP41:[0-9a-f]+]] +0 +; CHECK-NEXT: DW_AT_type (0x{{[0-9a-f]+}} "int*") +; CHECK-NEXT: DW_AT_artificial (true) + +; CHECK: [[IP41]]: DW_TAG_variable +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: DW_OP_consts +4, DW_OP_stack_value +; CHECK-NEXT: DW_AT_type (0x{{[0-9a-f]+}} "int") +; CHECK-NEXT: DW_AT_artificial (true) + +; CHECK: [[IP3]]: DW_TAG_variable +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: DW_OP_consts +2, DW_OP_stack_value +; CHECK-NEXT: DW_AT_type (0x{{[0-9a-f]+}} "int") +; CHECK-NEXT: DW_AT_artificial (true) + +; CHECK: [[IP2]]: DW_TAG_variable +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: DW_OP_consts +5, DW_OP_stack_value +; CHECK-NEXT: DW_AT_type (0x{{[0-9a-f]+}} "int") +; CHECK-NEXT: DW_AT_artificial (true) + +; CHECK: [[IP1]]: DW_TAG_variable +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: DW_OP_consts +4, DW_OP_stack_value +; CHECK-NEXT: DW_AT_type (0x{{[0-9a-f]+}} "int") +; CHECK-NEXT: DW_AT_artificial (true) + +; Below is the original test case this IR is generated from +;--------------------------- +;static const char *b = "opq"; +;volatile int v; +;int main() { +; int var1 = 4; +; int var2 = 5; +; int arr1[2] = {2, 3}; +; int *ptr1 = 0; +; int *ptr2 = 0; +; int *ptr3 = 0; +; int **ptrptr1 = 0; +; int **ptrptr2 = 0; +; int **ptrptr3 = 0; +; +; v++; +; ptr1 = &var1; +; ptr2 = &var2; +; ptr3 = arr1; +; ptrptr1 = &ptr1; +; ptrptr2 = &ptr2; +; ptrptr3 = &ptr3; +; v++; +; +; return arr1[0] + arr1[1] + *ptr1 + *ptr2 + **ptrptr1 + **ptrptr2 - 5; +;} +;--------------------------- + +; ModuleID = 'dwarfdump-implicit_pointer_mem2reg.c' +source_filename = "dwarfdump-implicit_pointer_mem2reg.c" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@v = common dso_local global i32 0, align 4, !dbg !0 + +; Function Attrs: nofree norecurse nounwind uwtable +define dso_local i32 @main() local_unnamed_addr #0 !dbg !12 { +entry: + call void @llvm.dbg.value(metadata i32 4, metadata !16, metadata !DIExpression()), !dbg !30 + call void @llvm.dbg.value(metadata i32 5, metadata !17, metadata !DIExpression()), !dbg !30 + call void @llvm.dbg.value(metadata i32 2, metadata !18, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)), !dbg !30 + call void @llvm.dbg.value(metadata i32 3, metadata !18, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32)), !dbg !30 + call void @llvm.dbg.value(metadata i32* null, metadata !22, metadata !DIExpression()), !dbg !30 + call void @llvm.dbg.value(metadata i32* null, metadata !24, metadata !DIExpression()), !dbg !30 + call void @llvm.dbg.value(metadata i32* null, metadata !25, metadata !DIExpression()), !dbg !30 + call void @llvm.dbg.value(metadata i32** null, metadata !26, metadata !DIExpression()), !dbg !30 + call void @llvm.dbg.value(metadata i32** null, metadata !28, metadata !DIExpression()), !dbg !30 + call void @llvm.dbg.value(metadata i32** null, metadata !29, metadata !DIExpression()), !dbg !30 + %0 = load volatile i32, i32* @v, align 4, !dbg !31, !tbaa !32 + %inc = add nsw i32 %0, 1, !dbg !31 + store volatile i32 %inc, i32* @v, align 4, !dbg !31, !tbaa !32 + call void @llvm.dbg.value(metadata i32 4, metadata !22, metadata !DIExpression(DW_OP_LLVM_implicit_pointer)), !dbg !30 + call void @llvm.dbg.value(metadata i32 5, metadata !24, metadata !DIExpression(DW_OP_LLVM_implicit_pointer)), !dbg !30 + call void @llvm.dbg.value(metadata i32 2, metadata !25, metadata !DIExpression(DW_OP_LLVM_implicit_pointer)), !dbg !30 + call void @llvm.dbg.value(metadata i32 4, metadata !26, metadata !DIExpression(DW_OP_LLVM_implicit_pointer, DW_OP_LLVM_implicit_pointer)), !dbg !30 + call void @llvm.dbg.value(metadata i32 5, metadata !28, metadata !DIExpression(DW_OP_LLVM_implicit_pointer, DW_OP_LLVM_implicit_pointer)), !dbg !30 + call void @llvm.dbg.value(metadata i32 2, metadata !29, metadata !DIExpression(DW_OP_LLVM_implicit_pointer, DW_OP_LLVM_implicit_pointer)), !dbg !30 + %1 = load volatile i32, i32* @v, align 4, !dbg !36, !tbaa !32 + %inc1 = add nsw i32 %1, 1, !dbg !36 + store volatile i32 %inc1, i32* @v, align 4, !dbg !36, !tbaa !32 + ret i32 18, !dbg !37 +} + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!8, !9, !10} +!llvm.ident = !{!11} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "v", scope: !2, file: !3, line: 45, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 12.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "dwarfdump-implicit_pointer_mem2reg.c", directory: "/dir", checksumkind: CSK_MD5, checksum: "6ad1488ed7a007c3a33e08ec42847d87") +!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 5} +!9 = !{i32 2, !"Debug Info Version", i32 3} +!10 = !{i32 1, !"wchar_size", i32 4} +!11 = !{!"clang version 10.0.0"} +!12 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 46, type: !13, scopeLine: 46, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !15) +!13 = !DISubroutineType(types: !14) +!14 = !{!7} +!15 = !{!16, !17, !18, !22, !24, !25, !26, !28, !29} +!16 = !DILocalVariable(name: "var1", scope: !12, file: !3, line: 47, type: !7) +!17 = !DILocalVariable(name: "var2", scope: !12, file: !3, line: 48, type: !7) +!18 = !DILocalVariable(name: "arr1", scope: !12, file: !3, line: 49, type: !19) +!19 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 64, elements: !20) +!20 = !{!21} +!21 = !DISubrange(count: 2) +!22 = !DILocalVariable(name: "ptr1", scope: !12, file: !3, line: 50, type: !23) +!23 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!24 = !DILocalVariable(name: "ptr2", scope: !12, file: !3, line: 51, type: !23) +!25 = !DILocalVariable(name: "ptr3", scope: !12, file: !3, line: 52, type: !23) +!26 = !DILocalVariable(name: "ptrptr1", scope: !12, file: !3, line: 53, type: !27) +!27 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !23, size: 64) +!28 = !DILocalVariable(name: "ptrptr2", scope: !12, file: !3, line: 54, type: !27) +!29 = !DILocalVariable(name: "ptrptr3", scope: !12, file: !3, line: 55, type: !27) +!30 = !DILocation(line: 0, scope: !12) +!31 = !DILocation(line: 57, column: 4, scope: !12) +!32 = !{!33, !33, i64 0} +!33 = !{!"int", !34, i64 0} +!34 = !{!"omnipotent char", !35, i64 0} +!35 = !{!"Simple C/C++ TBAA"} +!36 = !DILocation(line: 64, column: 4, scope: !12) +!37 = !DILocation(line: 66, column: 3, scope: !12) Index: llvm/test/DebugInfo/X86/dwarfdump-implicit_pointer_sroa.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/dwarfdump-implicit_pointer_sroa.ll @@ -0,0 +1,168 @@ +; RUN: llc %s -filetype=obj -o - | llvm-dwarfdump - | FileCheck %s + +; CHECK-LABEL: DW_AT_name ("arr2") + +; CHECK-LABEL: DW_AT_location +; CHECK-NEXT: : DW_OP_lit0, DW_OP_stack_value +; CHECK-NEXT: : DW_OP_implicit_pointer 0x[[IP11:[0-9a-f]+]] +0 +; CHECK-NEXT: : DW_OP_implicit_pointer 0x[[IP12:[0-9a-f]+]] +0) +; CHECK-NEXT: DW_AT_name ("ptr1") + + +; CHECK-LABEL: DW_AT_location +; CHECK-NEXT: : DW_OP_lit0, DW_OP_stack_value +; CHECK-NEXT: : DW_OP_implicit_pointer 0x[[IP21:[0-9a-f]+]] +0 +; CHECK-NEXT: : DW_OP_implicit_pointer 0x[[IP22:[0-9a-f]+]] +0) +; CHECK-NEXT: DW_AT_name ("ptr2") + +; CHECK-LABEL: DW_AT_location +; CHECK-NEXT: : DW_OP_lit0, DW_OP_stack_value +; CHECK-NEXT: : DW_OP_implicit_pointer 0x[[IP31:[0-9a-f]+]] +0 +; CHECK-NEXT: : DW_OP_implicit_pointer 0x[[IP32:[0-9a-f]+]] +0) +; CHECK-NEXT: DW_AT_name ("ptr3") + +; CHECK: [[IP31]]: DW_TAG_variable +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: DW_OP_consts +3, DW_OP_stack_value + +; CHECK: [[IP21]]: DW_TAG_variable +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: DW_OP_consts +7, DW_OP_stack_value + +; CHECK: [[IP11]]: DW_TAG_variable +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: DW_OP_consts +2, DW_OP_stack_value + +; CHECK: [[IP32]]: DW_TAG_variable +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: DW_OP_consts +4, DW_OP_stack_value + +; CHECK: [[IP22]]: DW_TAG_variable +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: DW_OP_consts +8, DW_OP_stack_value + +; CHECK: [[IP12]]: DW_TAG_variable +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: DW_OP_consts +3, DW_OP_stack_value + +; Below is the original test case this IR is generated from +;--------------------------- +;static const char *b = "opq"; +;volatile int v; +;int main() { +; int arr1[2] = {1, 2}; +; int arr2[2] = {6, 7}; +; int *ptr1 = 0; +; int *ptr2 = 0; +; int *ptr3 = 0; +; +; v++; +; ptr1 = arr1; +; ptr2 = arr2; +; ptr3 = arr1; +; (*ptr1)++; +; (*ptr2)++; +; (*ptr3)++; +; v++; +; ptr1++; +; (*ptr1)++; +; (*ptr2)++; +; (*ptr3)++; +; v++; +; return arr1[0] + arr1[1] + arr2[0] + arr2[1] - 5; +;} +;--------------------------- + +; ModuleID = 'dwarfdump-implicit_pointer_sroa.c' +source_filename = "dwarfdump-implicit_pointer_sroa.c" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@v = common dso_local global i32 0, align 4, !dbg !0 + +; Function Attrs: nofree norecurse nounwind uwtable +define dso_local i32 @main() local_unnamed_addr #0 !dbg !12 { +entry: + call void @llvm.dbg.value(metadata i32 1, metadata !16, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)), !dbg !25 + call void @llvm.dbg.value(metadata i32 2, metadata !16, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32)), !dbg !25 + call void @llvm.dbg.value(metadata i32 6, metadata !20, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)), !dbg !25 + call void @llvm.dbg.value(metadata i32 7, metadata !20, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32)), !dbg !25 + call void @llvm.dbg.value(metadata i32* null, metadata !21, metadata !DIExpression()), !dbg !25 + call void @llvm.dbg.value(metadata i32* null, metadata !23, metadata !DIExpression()), !dbg !25 + call void @llvm.dbg.value(metadata i32* null, metadata !24, metadata !DIExpression()), !dbg !25 + %0 = load volatile i32, i32* @v, align 4, !dbg !26, !tbaa !27 + %inc = add nsw i32 %0, 1, !dbg !26 + store volatile i32 %inc, i32* @v, align 4, !dbg !26, !tbaa !27 + call void @llvm.dbg.value(metadata i32 1, metadata !21, metadata !DIExpression(DW_OP_LLVM_implicit_pointer)), !dbg !25 + call void @llvm.dbg.value(metadata i32 6, metadata !23, metadata !DIExpression(DW_OP_LLVM_implicit_pointer)), !dbg !25 + call void @llvm.dbg.value(metadata i32 1, metadata !24, metadata !DIExpression(DW_OP_LLVM_implicit_pointer)), !dbg !25 + call void @llvm.dbg.value(metadata i32 2, metadata !21, metadata !DIExpression(DW_OP_LLVM_implicit_pointer)), !dbg !31 + call void @llvm.dbg.value(metadata i32 2, metadata !24, metadata !DIExpression(DW_OP_LLVM_implicit_pointer)), !dbg !31 + call void @llvm.dbg.value(metadata i32 2, metadata !16, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)), !dbg !25 + call void @llvm.dbg.value(metadata i32 7, metadata !23, metadata !DIExpression(DW_OP_LLVM_implicit_pointer)), !dbg !32 + call void @llvm.dbg.value(metadata i32 7, metadata !20, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)), !dbg !25 + call void @llvm.dbg.value(metadata i32 3, metadata !24, metadata !DIExpression(DW_OP_LLVM_implicit_pointer)), !dbg !33 + call void @llvm.dbg.value(metadata i32 3, metadata !16, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)), !dbg !25 + %1 = load volatile i32, i32* @v, align 4, !dbg !34, !tbaa !27 + %inc6 = add nsw i32 %1, 1, !dbg !34 + store volatile i32 %inc6, i32* @v, align 4, !dbg !34, !tbaa !27 + call void @llvm.dbg.value(metadata i32 2, metadata !21, metadata !DIExpression(DW_OP_LLVM_implicit_pointer)), !dbg !25 + call void @llvm.dbg.value(metadata i32 3, metadata !21, metadata !DIExpression(DW_OP_LLVM_implicit_pointer)), !dbg !35 + call void @llvm.dbg.value(metadata i32 3, metadata !16, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32)), !dbg !25 + call void @llvm.dbg.value(metadata i32 8, metadata !23, metadata !DIExpression(DW_OP_LLVM_implicit_pointer)), !dbg !36 + call void @llvm.dbg.value(metadata i32 8, metadata !20, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)), !dbg !25 + call void @llvm.dbg.value(metadata i32 4, metadata !24, metadata !DIExpression(DW_OP_LLVM_implicit_pointer)), !dbg !37 + call void @llvm.dbg.value(metadata i32 4, metadata !16, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)), !dbg !25 + %2 = load volatile i32, i32* @v, align 4, !dbg !38, !tbaa !27 + %inc10 = add nsw i32 %2, 1, !dbg !38 + store volatile i32 %inc10, i32* @v, align 4, !dbg !38, !tbaa !27 + ret i32 17, !dbg !39 +} + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!8, !9, !10} +!llvm.ident = !{!11} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "v", scope: !2, file: !3, line: 25, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 12.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "dwarfdump-implicit_pointer_sroa.c", directory: "/dir", checksumkind: CSK_MD5, checksum: "955d25ccee581cfd1dc4cfad0d994e8f") +!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 5} +!9 = !{i32 2, !"Debug Info Version", i32 3} +!10 = !{i32 1, !"wchar_size", i32 4} +!11 = !{!"clang version 12.0.0"} +!12 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 26, type: !13, scopeLine: 26, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !15) +!13 = !DISubroutineType(types: !14) +!14 = !{!7} +!15 = !{!16, !20, !21, !23, !24} +!16 = !DILocalVariable(name: "arr1", scope: !12, file: !3, line: 27, type: !17) +!17 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 64, elements: !18) +!18 = !{!19} +!19 = !DISubrange(count: 2) +!20 = !DILocalVariable(name: "arr2", scope: !12, file: !3, line: 28, type: !17) +!21 = !DILocalVariable(name: "ptr1", scope: !12, file: !3, line: 29, type: !22) +!22 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!23 = !DILocalVariable(name: "ptr2", scope: !12, file: !3, line: 30, type: !22) +!24 = !DILocalVariable(name: "ptr3", scope: !12, file: !3, line: 31, type: !22) +!25 = !DILocation(line: 0, scope: !12) +!26 = !DILocation(line: 33, column: 4, scope: !12) +!27 = !{!28, !28, i64 0} +!28 = !{!"int", !29, i64 0} +!29 = !{!"omnipotent char", !30, i64 0} +!30 = !{!"Simple C/C++ TBAA"} +!31 = !DILocation(line: 18, column: 10, scope: !12) +!32 = !DILocation(line: 19, column: 10, scope: !12) +!33 = !DILocation(line: 20, column: 10, scope: !12) +!34 = !DILocation(line: 24, column: 4, scope: !12) +!35 = !DILocation(line: 26, column: 10, scope: !12) +!36 = !DILocation(line: 27, column: 10, scope: !12) +!37 = !DILocation(line: 28, column: 10, scope: !12) +!38 = !DILocation(line: 32, column: 4, scope: !12) +!39 = !DILocation(line: 33, column: 3, scope: !12) Index: llvm/test/DebugInfo/X86/dwarfdump-implicit_pointer_sroa_inline.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/dwarfdump-implicit_pointer_sroa_inline.ll @@ -0,0 +1,99 @@ +; RUN: llc %s -filetype=obj -o - | llvm-dwarfdump - | FileCheck %s + +; CHECK: DW_TAG_inlined_subroutine + +; CHECK: DW_TAG_formal_parameter +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: : DW_OP_implicit_pointer {{0x.+}} +0 +; CHECK-NEXT: : DW_OP_implicit_pointer {{0x.+}} +0) +; CHECK-NEXT: DW_AT_abstract_origin ({{0x.+}} "ptr") + +; Below is the original test case this IR is generated from +;--------------------------- +;static const char *b = "opq"; +;volatile int v; +;static inline void foo(int *ptr) { +; (*ptr)++; +; v++; +; ptr++; +; (*ptr)++; +; v++; +;} +; +;int main() { +; int arr[2] = {1, 2}; +; v++; +; foo(arr); +; return arr[0] + arr[1] - 5; +;} +;--------------------------- + +; ModuleID = 'dwarfdump-implicit_pointer_sroa_inline.c' +source_filename = "dwarfdump-implicit_pointer_sroa_inline.c" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@v = common dso_local global i32 0, align 4, !dbg !0 + +; Function Attrs: nounwind uwtable +define dso_local i32 @main() local_unnamed_addr #0 !dbg !12 { +entry: + %0 = load volatile i32, i32* @v, align 4, !dbg !21, !tbaa !22 + %inc = add nsw i32 %0, 1, !dbg !21 + store volatile i32 %inc, i32* @v, align 4, !dbg !21, !tbaa !22 + call void @llvm.dbg.value(metadata i32 2, metadata !26, metadata !DIExpression(DW_OP_LLVM_implicit_pointer)), !dbg !32 + %1 = load volatile i32, i32* @v, align 4, !dbg !34, !tbaa !22 + %inc1.i = add nsw i32 %1, 1, !dbg !34 + store volatile i32 %inc1.i, i32* @v, align 4, !dbg !34, !tbaa !22 + call void @llvm.dbg.value(metadata i32 3, metadata !26, metadata !DIExpression(DW_OP_LLVM_implicit_pointer)), !dbg !35 + %2 = load volatile i32, i32* @v, align 4, !dbg !36, !tbaa !22 + %inc3.i = add nsw i32 %2, 1, !dbg !36 + store volatile i32 %inc3.i, i32* @v, align 4, !dbg !36, !tbaa !22 + ret i32 0, !dbg !37 +} + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!8, !9, !10} +!llvm.ident = !{!11} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "v", scope: !2, file: !3, line: 14, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 12.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "dwarfdump-implicit_pointer_sroa_inline.c", directory: "/dir", checksumkind: CSK_MD5, checksum: "f9bbaee6b152b3bc05125796b573408a") +!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 5} +!9 = !{i32 2, !"Debug Info Version", i32 3} +!10 = !{i32 1, !"wchar_size", i32 4} +!11 = !{!"clang version 11.0.0"} +!12 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 23, type: !13, scopeLine: 23, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !15) +!13 = !DISubroutineType(types: !14) +!14 = !{!7} +!15 = !{!16} +!16 = !DILocalVariable(name: "arr", scope: !12, file: !3, line: 24, type: !17) +!17 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 64, elements: !18) +!18 = !{!19} +!19 = !DISubrange(count: 2) +!20 = !DILocation(line: 24, column: 7, scope: !12) +!21 = !DILocation(line: 25, column: 4, scope: !12) +!22 = !{!23, !23, i64 0} +!23 = !{!"int", !24, i64 0} +!24 = !{!"omnipotent char", !25, i64 0} +!25 = !{!"Simple C/C++ TBAA"} +!26 = !DILocalVariable(name: "ptr", arg: 1, scope: !27, file: !3, line: 15, type: !30) +!27 = distinct !DISubprogram(name: "foo", scope: !3, file: !3, line: 15, type: !28, scopeLine: 15, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !31) +!28 = !DISubroutineType(types: !29) +!29 = !{null, !30} +!30 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!31 = !{!26} +!32 = !DILocation(line: 16, column: 9, scope: !27, inlinedAt: !33) +!33 = distinct !DILocation(line: 26, column: 3, scope: !12) +!34 = !DILocation(line: 17, column: 4, scope: !27, inlinedAt: !33) +!35 = !DILocation(line: 19, column: 9, scope: !27, inlinedAt: !33) +!36 = !DILocation(line: 20, column: 4, scope: !27, inlinedAt: !33) +!37 = !DILocation(line: 27, column: 3, scope: !12)