diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -2468,6 +2468,12 @@ /// 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 whether this is an implicit location description. bool isImplicit() const; diff --git a/llvm/include/llvm/IR/IntrinsicInst.h b/llvm/include/llvm/IR/IntrinsicInst.h --- a/llvm/include/llvm/IR/IntrinsicInst.h +++ b/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" @@ -122,6 +123,11 @@ /// is described. Optional getFragmentSizeInBits() const; + /// Returns true if it has an implicit pointer expression + bool isImplicitPointer() const { + return getExpression()->isImplicitPointer(); + } + /// \name Casting methods /// @{ static bool classof(const IntrinsicInst *I) { diff --git a/llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h b/llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h --- a/llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h +++ b/llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h @@ -26,19 +26,28 @@ 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_ImplicitPtr + }; enum EntryType EntryKind; - /// Either a constant, + /// a constant, union { int64_t Int; const ConstantFP *CFP; const ConstantInt *CIP; } Constant; - /// Or a location in the machine frame. + /// Or a location in the machine frame, MachineLocation Loc; + /// Or an implicit pointer variable target. + const DIVariable *ImpPtr; + public: DbgValueLoc(const DIExpression *Expr, int64_t i) : Expression(Expr), EntryKind(E_Integer) { @@ -56,15 +65,21 @@ : Expression(Expr), EntryKind(E_Location), Loc(Loc) { assert(cast(Expr)->isValid()); } + 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 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; } + const DIVariable *getImplicitPointer() const { return ImpPtr; } bool isFragment() const { return getExpression()->isFragment(); } bool isEntryVal() const { return getExpression()->isEntryValue(); } const DIExpression *getExpression() const { return Expression; } @@ -168,6 +183,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"); } diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -74,6 +74,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 index of dereferenced object's at first operand of + // DW_OP_implicit_pointer operation temporarily. This temporary value is + // later replaced by 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; @@ -120,6 +129,20 @@ void initStmtList(); + unsigned findOrInsertImplicitVar(const DINode *Var) { + SmallVector::iterator It = + std::find(ImplicitVars.begin(), ImplicitVars.end(), Var); + if (It == ImplicitVars.end()) { + ImplicitVars.push_back(Var); + return ImplicitVars.size() - 1; + } + + return std::distance(ImplicitVars.begin(), It); + } + + const DINode *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); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -1010,7 +1010,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()); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -767,7 +767,8 @@ static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT, const DbgValueLoc &Value, - DwarfExpression &DwarfExpr); + DwarfExpression &DwarfExpr, + DwarfCompileUnit &TheCU); }; } // end namespace llvm diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -192,6 +192,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, unsigned MachineReg) { // This information is not available while emitting .debug_loc entries. @@ -247,6 +267,12 @@ return DbgValueLoc(Expr, MI->getOperand(0).getFPImm()); if (MI->getOperand(0).isCImm()) return DbgValueLoc(Expr, MI->getOperand(0).getCImm()); + if (Expr->isImplicitPointer()) { + uint64_t FirstDIEOperand = Expr->getElement(1); + unsigned DerefVarNum = FirstDIEOperand - dwarf::DW_OP_LLVM_arg0; + const DIVariable *DVI = cast(MI->getOperand(DerefVarNum).getMetadata()); + return DbgValueLoc(Expr, DVI); + } llvm_unreachable("Unexpected 4-operand DBG_VALUE instruction!"); } @@ -1574,10 +1600,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)) { @@ -1600,7 +1629,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; } @@ -2203,6 +2235,27 @@ for (unsigned J = 0; J < ULEB128PadSize; ++J) if (Comment != End) Comment++; + } else if ((Op.getCode() == dwarf::DW_OP_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 DINode *ImpVar = CU->findImplicitVarAtIndex(ValOffset); + DIE *Die = CU->getDIE(ImpVar); + if (Die) + 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++) : ""); @@ -2215,7 +2268,8 @@ 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); @@ -2244,6 +2298,13 @@ } else if (Value.isConstantFP()) { APInt RawBytes = Value.getConstantFP()->getValueAPF().bitcastToAPInt(); DwarfExpr.addUnsignedConstant(RawBytes); + } else if (Value.isImplicitPtr()) { + const llvm::DIVariable *ImpVar = Value.getImplicitPointer(); + unsigned 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)); } @@ -2268,11 +2329,11 @@ "fragments are expected to be sorted"); for (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) diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h --- a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h @@ -188,6 +188,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(). @@ -337,6 +339,7 @@ void emitLegacySExt(unsigned FromBits); void emitLegacyZExt(unsigned FromBits); + void emitImplicitPointer(DIExpressionCursor &&Expr, unsigned ValOffset); }; /// DwarfExpression implementation for .debug_loc entries. @@ -362,6 +365,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; @@ -391,6 +395,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; diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -572,3 +572,17 @@ emitUnsigned((1ULL << FromBits) - 1); emitOp(dwarf::DW_OP_and); } + +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(dwarf::DW_OP_implicit_pointer); + // This is a dummy offset which will be replaced with actual offset in + // function DwarfDebug::emitDebugLocEntry. + emitAddressRef(ValOffset); + emitSigned(Op->getArg(1)); + return; +} diff --git a/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp b/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp @@ -101,6 +101,8 @@ Descriptions[DW_OP_convert] = Desc(Op::Dwarf5, Op::BaseTypeRef); Descriptions[DW_OP_entry_value] = Desc(Op::Dwarf5, Op::SizeLEB); + Descriptions[DW_OP_implicit_pointer] = + Desc(Op::Dwarf5, Op::SizeRefAddr, Op::SignedSizeLEB); return Descriptions; } diff --git a/llvm/lib/IR/IntrinsicInst.cpp b/llvm/lib/IR/IntrinsicInst.cpp --- a/llvm/lib/IR/IntrinsicInst.cpp +++ b/llvm/lib/IR/IntrinsicInst.cpp @@ -41,6 +41,9 @@ if (AllowNullOp && !Op) return nullptr; + if (isImplicitPointer()) + return Op; + auto *MD = cast(Op)->getMetadata(); if (auto *V = dyn_cast(MD)) return V->getValue(); diff --git a/llvm/test/DebugInfo/implicit_pointer_fast.ll b/llvm/test/DebugInfo/implicit_pointer_fast.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/implicit_pointer_fast.ll @@ -0,0 +1,99 @@ +; RUN: llc %s -fast-isel -O2 -filetype=obj -o %t.o +; RUN: llvm-dwarfdump %t.o | FileCheck %s + +; CHECK-LABEL: DW_TAG_inlined_subroutine + +; Test if More than 2 member location list is printed (for pointer pointing to aggregate) +; CHECK-LABEL: DW_TAG_formal_parameter +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: : DW_OP_implicit_pointer [[DIE:0x.+]] +0 +; CHECK-NEXT: : DW_OP_implicit_pointer [[DIE]] +4) +; 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 !20 + %inc = add nsw i32 %0, 1, !dbg !20 + store volatile i32 %inc, i32* @v, align 4, !dbg !20 + call void @llvm.dbg.derefval(metadata !16, metadata !25, metadata !DIExpression(DW_OP_LLVM_implicit_pointer, DW_OP_LLVM_arg0, 0)), !dbg !31 + %1 = load volatile i32, i32* @v, align 4, !dbg !33 + %inc1.i = add nsw i32 %1, 1, !dbg !33 + store volatile i32 %inc1.i, i32* @v, align 4, !dbg !33 + call void @llvm.dbg.derefval(metadata !16, metadata !25, metadata !DIExpression(DW_OP_LLVM_implicit_pointer, DW_OP_LLVM_arg0, 4)), !dbg !31 + %2 = load volatile i32, i32* @v, align 4, !dbg !34 + %inc3.i = add nsw i32 %2, 1, !dbg !34 + store volatile i32 %inc3.i, i32* @v, align 4, !dbg !34 + ret i32 0, !dbg !35 +} + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.derefval(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 10.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 10.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: 25, column: 4, scope: !12) +!21 = !{!22, !22, i64 0} +!22 = !{!"int", !23, i64 0} +!23 = !{!"omnipotent char", !24, i64 0} +!24 = !{!"Simple C/C++ TBAA"} +!25 = !DILocalVariable(name: "ptr", arg: 1, scope: !26, file: !3, line: 15, type: !29) +!26 = distinct !DISubprogram(name: "foo", scope: !3, file: !3, line: 15, type: !27, scopeLine: 15, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !30) +!27 = !DISubroutineType(types: !28) +!28 = !{null, !29} +!29 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!30 = !{!25} +!31 = !DILocation(line: 0, scope: !26, inlinedAt: !32) +!32 = distinct !DILocation(line: 26, column: 3, scope: !12) +!33 = !DILocation(line: 17, column: 4, scope: !26, inlinedAt: !32) +!34 = !DILocation(line: 20, column: 4, scope: !26, inlinedAt: !32) +!35 = !DILocation(line: 27, column: 3, scope: !12) diff --git a/llvm/test/DebugInfo/implicit_pointer_global.ll b/llvm/test/DebugInfo/implicit_pointer_global.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/implicit_pointer_global.ll @@ -0,0 +1,99 @@ +; RUN: llc %s -global-isel -O2 -filetype=obj -o %t.o +; RUN: llvm-dwarfdump %t.o | FileCheck %s + +; CHECK-LABEL: DW_TAG_inlined_subroutine + +; Test if More than 2 member location list is printed (for pointer pointing to aggregate) +; CHECK-LABEL: DW_TAG_formal_parameter +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: : DW_OP_implicit_pointer [[DIE:0x.+]] +0 +; CHECK-NEXT: : DW_OP_implicit_pointer [[DIE]] +4) +; 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 !20 + %inc = add nsw i32 %0, 1, !dbg !20 + store volatile i32 %inc, i32* @v, align 4, !dbg !20 + call void @llvm.dbg.derefval(metadata !16, metadata !25, metadata !DIExpression(DW_OP_LLVM_implicit_pointer, DW_OP_LLVM_arg0, 0)), !dbg !31 + %1 = load volatile i32, i32* @v, align 4, !dbg !33 + %inc1.i = add nsw i32 %1, 1, !dbg !33 + store volatile i32 %inc1.i, i32* @v, align 4, !dbg !33 + call void @llvm.dbg.derefval(metadata !16, metadata !25, metadata !DIExpression(DW_OP_LLVM_implicit_pointer, DW_OP_LLVM_arg0, 4)), !dbg !31 + %2 = load volatile i32, i32* @v, align 4, !dbg !34 + %inc3.i = add nsw i32 %2, 1, !dbg !34 + store volatile i32 %inc3.i, i32* @v, align 4, !dbg !34 + ret i32 0, !dbg !35 +} + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.derefval(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 10.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 10.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: 25, column: 4, scope: !12) +!21 = !{!22, !22, i64 0} +!22 = !{!"int", !23, i64 0} +!23 = !{!"omnipotent char", !24, i64 0} +!24 = !{!"Simple C/C++ TBAA"} +!25 = !DILocalVariable(name: "ptr", arg: 1, scope: !26, file: !3, line: 15, type: !29) +!26 = distinct !DISubprogram(name: "foo", scope: !3, file: !3, line: 15, type: !27, scopeLine: 15, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !30) +!27 = !DISubroutineType(types: !28) +!28 = !{null, !29} +!29 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!30 = !{!25} +!31 = !DILocation(line: 0, scope: !26, inlinedAt: !32) +!32 = distinct !DILocation(line: 26, column: 3, scope: !12) +!33 = !DILocation(line: 17, column: 4, scope: !26, inlinedAt: !32) +!34 = !DILocation(line: 20, column: 4, scope: !26, inlinedAt: !32) +!35 = !DILocation(line: 27, column: 3, scope: !12)