diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-02-23 19:02:03 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-02-23 19:02:03 +0000 |
commit | e49737eb046479c0610f1254ef311a91036a5144 (patch) | |
tree | 0329bf538c7f7b280e5c880aeccd90070e8a3040 | |
parent | c60b95818e4f6c00c872114318d01109f97a7fa3 (diff) |
Vendor import of llvm release_40 branch r295910:vendor/llvm/llvm-release_40-r295910
Notes
Notes:
svn path=/vendor/llvm/dist/; revision=314159
svn path=/vendor/llvm/llvm-release_40-r295910/; revision=314160; tag=vendor/llvm/llvm-release_40-r295910
-rw-r--r-- | docs/ReleaseNotes.rst | 7 | ||||
-rw-r--r-- | lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp | 13 | ||||
-rw-r--r-- | lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 9 | ||||
-rw-r--r-- | lib/CodeGen/AsmPrinter/DwarfDebug.h | 58 | ||||
-rw-r--r-- | lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp | 6 | ||||
-rw-r--r-- | lib/Target/ARM/ARMExpandPseudoInsts.cpp | 34 | ||||
-rw-r--r-- | lib/Transforms/Scalar/LICM.cpp | 3 | ||||
-rw-r--r-- | test/CodeGen/AArch64/ldst-opt.mir | 26 | ||||
-rw-r--r-- | test/CodeGen/ARM/aeabi-read-tp.ll | 26 | ||||
-rw-r--r-- | test/DebugInfo/X86/FrameIndexExprs.ll | 85 |
10 files changed, 213 insertions, 54 deletions
diff --git a/docs/ReleaseNotes.rst b/docs/ReleaseNotes.rst index da86be3f96ff..6efa4813d770 100644 --- a/docs/ReleaseNotes.rst +++ b/docs/ReleaseNotes.rst @@ -61,6 +61,13 @@ Non-comprehensive list of changes in this release with LLVM option -adce-remove-loops when the loop body otherwise has no live operations. +* The GVNHoist pass is now enabled by default. The new pass based on Global + Value Numbering detects similar computations in branch code and replaces + multiple instances of the same computation with a unique expression. The + transform benefits code size and generates better schedules. GVNHoist is + more aggressive at -Os and -Oz, hoisting more expressions at the expense of + execution time degradations. + * The llvm-cov tool can now export coverage data as json. Its html output mode has also improved. diff --git a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp index 0db623bbc29a..d904372af589 100644 --- a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -522,22 +522,19 @@ DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV, } // .. else use frame index. - if (DV.getFrameIndex().empty()) + if (!DV.hasFrameIndexExprs()) return VariableDie; - auto Expr = DV.getExpression().begin(); DIELoc *Loc = new (DIEValueAllocator) DIELoc; DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); - for (auto FI : DV.getFrameIndex()) { + for (auto &Fragment : DV.getFrameIndexExprs()) { unsigned FrameReg = 0; const TargetFrameLowering *TFI = Asm->MF->getSubtarget().getFrameLowering(); - int Offset = TFI->getFrameIndexReference(*Asm->MF, FI, FrameReg); - assert(Expr != DV.getExpression().end() && "Wrong number of expressions"); - DwarfExpr.addFragmentOffset(*Expr); + int Offset = TFI->getFrameIndexReference(*Asm->MF, Fragment.FI, FrameReg); + DwarfExpr.addFragmentOffset(Fragment.Expr); DwarfExpr.AddMachineRegIndirect(*Asm->MF->getSubtarget().getRegisterInfo(), FrameReg, Offset); - DwarfExpr.AddExpression(*Expr); - ++Expr; + DwarfExpr.AddExpression(Fragment.Expr); } addBlock(*VariableDie, dwarf::DW_AT_location, DwarfExpr.finalize()); diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index b465b98f368a..91a3d0989cc5 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -199,6 +199,15 @@ const DIType *DbgVariable::getType() const { return Ty; } +ArrayRef<DbgVariable::FrameIndexExpr> DbgVariable::getFrameIndexExprs() const { + std::sort(FrameIndexExprs.begin(), FrameIndexExprs.end(), + [](const FrameIndexExpr &A, const FrameIndexExpr &B) -> bool { + return A.Expr->getFragmentInfo()->OffsetInBits < + B.Expr->getFragmentInfo()->OffsetInBits; + }); + return FrameIndexExprs; +} + static const DwarfAccelTable::Atom TypeAtoms[] = { DwarfAccelTable::Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4), DwarfAccelTable::Atom(dwarf::DW_ATOM_die_tag, dwarf::DW_FORM_data2), diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.h b/lib/CodeGen/AsmPrinter/DwarfDebug.h index e5bf33db81fb..253e3f06200e 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -54,7 +54,7 @@ class MachineModuleInfo; /// /// Variables can be created from allocas, in which case they're generated from /// the MMI table. Such variables can have multiple expressions and frame -/// indices. The \a Expr and \a FrameIndices array must match. +/// indices. /// /// Variables can be created from \c DBG_VALUE instructions. Those whose /// location changes over time use \a DebugLocListIndex, while those with a @@ -64,11 +64,16 @@ class MachineModuleInfo; class DbgVariable { const DILocalVariable *Var; /// Variable Descriptor. const DILocation *IA; /// Inlined at location. - SmallVector<const DIExpression *, 1> Expr; /// Complex address. DIE *TheDIE = nullptr; /// Variable DIE. unsigned DebugLocListIndex = ~0u; /// Offset in DebugLocs. const MachineInstr *MInsn = nullptr; /// DBG_VALUE instruction. - SmallVector<int, 1> FrameIndex; /// Frame index. + + struct FrameIndexExpr { + int FI; + const DIExpression *Expr; + }; + mutable SmallVector<FrameIndexExpr, 1> + FrameIndexExprs; /// Frame index + expression. public: /// Construct a DbgVariable. @@ -80,21 +85,18 @@ public: /// Initialize from the MMI table. void initializeMMI(const DIExpression *E, int FI) { - assert(Expr.empty() && "Already initialized?"); - assert(FrameIndex.empty() && "Already initialized?"); + assert(FrameIndexExprs.empty() && "Already initialized?"); assert(!MInsn && "Already initialized?"); assert((!E || E->isValid()) && "Expected valid expression"); assert(~FI && "Expected valid index"); - Expr.push_back(E); - FrameIndex.push_back(FI); + FrameIndexExprs.push_back({FI, E}); } /// Initialize from a DBG_VALUE instruction. void initializeDbgValue(const MachineInstr *DbgValue) { - assert(Expr.empty() && "Already initialized?"); - assert(FrameIndex.empty() && "Already initialized?"); + assert(FrameIndexExprs.empty() && "Already initialized?"); assert(!MInsn && "Already initialized?"); assert(Var == DbgValue->getDebugVariable() && "Wrong variable"); @@ -103,16 +105,15 @@ public: MInsn = DbgValue; if (auto *E = DbgValue->getDebugExpression()) if (E->getNumElements()) - Expr.push_back(E); + FrameIndexExprs.push_back({0, E}); } // Accessors. const DILocalVariable *getVariable() const { return Var; } const DILocation *getInlinedAt() const { return IA; } - ArrayRef<const DIExpression *> getExpression() const { return Expr; } const DIExpression *getSingleExpression() const { - assert(MInsn && Expr.size() <= 1); - return Expr.size() ? Expr[0] : nullptr; + assert(MInsn && FrameIndexExprs.size() <= 1); + return FrameIndexExprs.size() ? FrameIndexExprs[0].Expr : nullptr; } void setDIE(DIE &D) { TheDIE = &D; } DIE *getDIE() const { return TheDIE; } @@ -120,7 +121,9 @@ public: unsigned getDebugLocListIndex() const { return DebugLocListIndex; } StringRef getName() const { return Var->getName(); } const MachineInstr *getMInsn() const { return MInsn; } - ArrayRef<int> getFrameIndex() const { return FrameIndex; } + /// Get the FI entries, sorted by fragment offset. + ArrayRef<FrameIndexExpr> getFrameIndexExprs() const; + bool hasFrameIndexExprs() const { return !FrameIndexExprs.empty(); } void addMMIEntry(const DbgVariable &V) { assert(DebugLocListIndex == ~0U && !MInsn && "not an MMI entry"); @@ -128,16 +131,15 @@ public: assert(V.Var == Var && "conflicting variable"); assert(V.IA == IA && "conflicting inlined-at location"); - assert(!FrameIndex.empty() && "Expected an MMI entry"); - assert(!V.FrameIndex.empty() && "Expected an MMI entry"); - assert(Expr.size() == FrameIndex.size() && "Mismatched expressions"); - assert(V.Expr.size() == V.FrameIndex.size() && "Mismatched expressions"); + assert(!FrameIndexExprs.empty() && "Expected an MMI entry"); + assert(!V.FrameIndexExprs.empty() && "Expected an MMI entry"); - Expr.append(V.Expr.begin(), V.Expr.end()); - FrameIndex.append(V.FrameIndex.begin(), V.FrameIndex.end()); - assert(all_of(Expr, [](const DIExpression *E) { - return E && E->isFragment(); - }) && "conflicting locations for variable"); + FrameIndexExprs.append(V.FrameIndexExprs.begin(), V.FrameIndexExprs.end()); + assert(all_of(FrameIndexExprs, + [](FrameIndexExpr &FIE) { + return FIE.Expr && FIE.Expr->isFragment(); + }) && + "conflicting locations for variable"); } // Translate tag to proper Dwarf tag. @@ -167,11 +169,11 @@ public: bool hasComplexAddress() const { assert(MInsn && "Expected DBG_VALUE, not MMI variable"); - assert(FrameIndex.empty() && "Expected DBG_VALUE, not MMI variable"); - assert( - (Expr.empty() || (Expr.size() == 1 && Expr.back()->getNumElements())) && - "Invalid Expr for DBG_VALUE"); - return !Expr.empty(); + assert((FrameIndexExprs.empty() || + (FrameIndexExprs.size() == 1 && + FrameIndexExprs[0].Expr->getNumElements())) && + "Invalid Expr for DBG_VALUE"); + return !FrameIndexExprs.empty(); } bool isBlockByrefVariable() const; const DIType *getType() const; diff --git a/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp b/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp index a2887aa81895..8e312dcf276f 100644 --- a/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp +++ b/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp @@ -853,9 +853,11 @@ AArch64LoadStoreOpt::promoteLoadFromStore(MachineBasicBlock::iterator LoadI, .addImm(Imms); } } - StoreI->clearRegisterKills(StRt, TRI); - (void)BitExtMI; + // Clear kill flags between store and load. + for (MachineInstr &MI : make_range(StoreI->getIterator(), + BitExtMI->getIterator())) + MI.clearRegisterKills(StRt, TRI); DEBUG(dbgs() << "Promoting load by replacing :\n "); DEBUG(StoreI->print(dbgs())); diff --git a/lib/Target/ARM/ARMExpandPseudoInsts.cpp b/lib/Target/ARM/ARMExpandPseudoInsts.cpp index 95fcc8dcb453..baa4e0330cf4 100644 --- a/lib/Target/ARM/ARMExpandPseudoInsts.cpp +++ b/lib/Target/ARM/ARMExpandPseudoInsts.cpp @@ -1225,16 +1225,36 @@ bool ARMExpandPseudo::ExpandMI(MachineBasicBlock &MBB, } case ARM::tTPsoft: case ARM::TPsoft: { + const bool Thumb = Opcode == ARM::tTPsoft; + MachineInstrBuilder MIB; - if (Opcode == ARM::tTPsoft) + if (STI->genLongCalls()) { + MachineFunction *MF = MBB.getParent(); + MachineConstantPool *MCP = MF->getConstantPool(); + unsigned PCLabelID = AFI->createPICLabelUId(); + MachineConstantPoolValue *CPV = + ARMConstantPoolSymbol::Create(MF->getFunction()->getContext(), + "__aeabi_read_tp", PCLabelID, 0); + unsigned Reg = MI.getOperand(0).getReg(); MIB = BuildMI(MBB, MBBI, MI.getDebugLoc(), - TII->get( ARM::tBL)) - .addImm((unsigned)ARMCC::AL).addReg(0) - .addExternalSymbol("__aeabi_read_tp", 0); - else + TII->get(Thumb ? ARM::tLDRpci : ARM::LDRi12), Reg) + .addConstantPoolIndex(MCP->getConstantPoolIndex(CPV, 4)); + if (!Thumb) + MIB.addImm(0); + MIB.addImm(static_cast<unsigned>(ARMCC::AL)).addReg(0); + MIB = BuildMI(MBB, MBBI, MI.getDebugLoc(), - TII->get( ARM::BL)) - .addExternalSymbol("__aeabi_read_tp", 0); + TII->get(Thumb ? ARM::tBLXr : ARM::BLX)); + if (Thumb) + MIB.addImm(static_cast<unsigned>(ARMCC::AL)).addReg(0); + MIB.addReg(Reg, RegState::Kill); + } else { + MIB = BuildMI(MBB, MBBI, MI.getDebugLoc(), + TII->get(Thumb ? ARM::tBL : ARM::BL)); + if (Thumb) + MIB.addImm(static_cast<unsigned>(ARMCC::AL)).addReg(0); + MIB.addExternalSymbol("__aeabi_read_tp", 0); + } MIB->setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); TransferImpOps(MI, MIB, MIB); diff --git a/lib/Transforms/Scalar/LICM.cpp b/lib/Transforms/Scalar/LICM.cpp index 4c15c8a32bec..f51d11c04cb2 100644 --- a/lib/Transforms/Scalar/LICM.cpp +++ b/lib/Transforms/Scalar/LICM.cpp @@ -1196,10 +1196,7 @@ LoopInvariantCodeMotion::collectAliasInfoForLoop(Loop *L, LoopInfo *LI, auto mergeLoop = [&](Loop *L) { // Loop over the body of this loop, looking for calls, invokes, and stores. - // Because subloops have already been incorporated into AST, we skip blocks - // in subloops. for (BasicBlock *BB : L->blocks()) - if (LI->getLoopFor(BB) == L) // Ignore blocks in subloops. CurAST->add(*BB); // Incorporate the specified basic block }; diff --git a/test/CodeGen/AArch64/ldst-opt.mir b/test/CodeGen/AArch64/ldst-opt.mir index 8f0b71be3483..85b655b717ca 100644 --- a/test/CodeGen/AArch64/ldst-opt.mir +++ b/test/CodeGen/AArch64/ldst-opt.mir @@ -1,10 +1,4 @@ # RUN: llc -mtriple=aarch64--linux-gnu -run-pass=aarch64-ldst-opt %s -verify-machineinstrs -o - 2>&1 | FileCheck %s ---- | - define void @promote-load-from-store() { ret void } - define void @store-pair() { ret void } - define void @store-pair-clearkill0() { ret void } - define void @store-pair-clearkill1() { ret void } -... --- name: promote-load-from-store tracksRegLiveness: true @@ -130,3 +124,23 @@ body: | # CHECK-NOT: %w2 = COPY killed %w1 # CHECK: %w2 = COPY %w1 # CHECK: STPWi %w1, killed %w2, killed %x0, 0 +--- +name: store-load-clearkill +tracksRegLiveness: true +body: | + bb.0: + liveins: %w1 + + STRWui %w1, %sp, 0 :: (store 4) + %wzr = COPY killed %w1 ; killing use of %w1 + %w11 = LDRWui %sp, 0 :: (load 4) + HINT 0, implicit %w11 ; some use of %w11 +... +# When replaceing the load of a store-load pair with a copy the kill flags +# along the way need to be cleared. +# CHECK-LABEL: name: store-load-clearkill +# CHECK: STRWui %w1, %sp, 0 :: (store 4) +# CHECK-NOT: COPY killed %w1 +# CHECK: %wzr = COPY %w1 +# CHECK: %w11 = ORRWrs %wzr, %w1, 0 +# CHECK: HINT 0, implicit %w11 diff --git a/test/CodeGen/ARM/aeabi-read-tp.ll b/test/CodeGen/ARM/aeabi-read-tp.ll new file mode 100644 index 000000000000..5f9815b6cd77 --- /dev/null +++ b/test/CodeGen/ARM/aeabi-read-tp.ll @@ -0,0 +1,26 @@ +; RUN: llc -mtriple armv7---eabi -filetype asm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-SHORT +; RUN: llc -mtriple thumbv7---eabi -filetype asm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-SHORT +; RUN: llc -mtriple armv7---eabi -mattr=+long-calls -filetype asm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-LONG +; RUN: llc -mtriple thumbv7---eabi -mattr=+long-calls -filetype asm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-LONG + +@i = thread_local local_unnamed_addr global i32 0, align 4 + +define i32 @f() local_unnamed_addr { +entry: + %0 = load i32, i32* @i, align 4 + ret i32 %0 +} + +; CHECK-LABEL: f: +; CHECK-SHORT: ldr r1, [[VAR:.LCPI[0-9]+_[0-9]+]] +; CHECK-SHORT-NEXT: bl __aeabi_read_tp +; CHECK-SHORT: [[VAR]]: +; CHECK-SHORT-NEXT: .long i(TPOFF) + +; CHECK-LONG: ldr [[REG:r[0-9]+]], [[FUN:.LCPI[0-9]+_[0-9]+]] +; CHECK-LONG-NEXT: ldr r1, [[VAR:.LCPI[0-9]+_[0-9]+]] +; CHECK-LONG-NEXT: blx [[REG]] +; CHECK-LONG: [[VAR]]: +; CHECK-LONG-NEXT: .long i(TPOFF) +; CHECK-LONG: [[FUN]]: +; CHECK-LONG-NEXT: .long __aeabi_read_tp diff --git a/test/DebugInfo/X86/FrameIndexExprs.ll b/test/DebugInfo/X86/FrameIndexExprs.ll new file mode 100644 index 000000000000..8b2cefc4f8f8 --- /dev/null +++ b/test/DebugInfo/X86/FrameIndexExprs.ll @@ -0,0 +1,85 @@ +; PR31381: An assertion in the DWARF backend when fragments in MMI slots are +; sorted by largest offset first. +; RUN: llc -mtriple=x86_64-apple-darwin -filetype=obj < %s | llvm-dwarfdump -debug-dump=info - | FileCheck %s +; CHECK: DW_TAG_formal_parameter +; CHECK: DW_TAG_formal_parameter +; CHECK-NEXT: DW_AT_location [DW_FORM_exprloc] (<0xa> 91 78 93 03 93 06 91 7d 93 03 ) +; fbreg -8, piece 0x00000003, piece 0x00000006, fbreg -3, piece 0x00000003 +; CHECK-NEXT: DW_AT_abstract_origin {{.*}}"p" +source_filename = "bugpoint-reduced-simplified.ll" +target triple = "x86_64-apple-darwin" + +@f = common local_unnamed_addr global i32 0, align 4, !dbg !0 +@h = common local_unnamed_addr global i32 0, align 4, !dbg !6 + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.declare(metadata, metadata, metadata) #0 + +define void @fn4() local_unnamed_addr !dbg !12 { +entry: + %l1.sroa.7.i = alloca [3 x i8], align 1 + tail call void @llvm.dbg.declare(metadata [3 x i8]* %l1.sroa.7.i, metadata !15, metadata !26), !dbg !27 + %i.sroa.4.i = alloca [3 x i8], align 8 + tail call void @llvm.dbg.declare(metadata [3 x i8]* %i.sroa.4.i, metadata !15, metadata !32), !dbg !27 + %0 = load i32, i32* @h, align 4 + br label %while.body.i.i, !dbg !33 + +while.body.i.i: ; preds = %while.body.i.i, %entry + br label %while.body.i.i, !dbg !34 + +fn3.exit: ; No predecessors! + %1 = load i32, i32* @f, align 4 + %tobool.i = icmp eq i32 %1, 0 + br label %while.body.i + +while.body.i: ; preds = %if.end.i, %fn3.exit + br i1 %tobool.i, label %if.end.i, label %if.then.i + +if.then.i: ; preds = %while.body.i + br label %if.end.i + +if.end.i: ; preds = %if.then.i, %while.body.i + br label %while.body.i +} + +attributes #0 = { nounwind readnone } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!9, !10, !11} + +!0 = !DIGlobalVariableExpression(var: !1) +!1 = distinct !DIGlobalVariable(name: "f", scope: !2, file: !3, line: 8, type: !8, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5) +!3 = !DIFile(filename: "PR31381.c", directory: "/") +!4 = !{} +!5 = !{!0, !6} +!6 = !DIGlobalVariableExpression(var: !7) +!7 = distinct !DIGlobalVariable(name: "h", scope: !2, file: !3, line: 8, type: !8, isLocal: false, isDefinition: true) +!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!9 = !{i32 2, !"Dwarf Version", i32 4} +!10 = !{i32 2, !"Debug Info Version", i32 3} +!11 = !{i32 1, !"PIC Level", i32 2} +!12 = distinct !DISubprogram(name: "fn4", scope: !3, file: !3, line: 31, type: !13, isLocal: false, isDefinition: true, scopeLine: 32, isOptimized: true, unit: !2, variables: !4) +!13 = !DISubroutineType(types: !14) +!14 = !{null} +!15 = !DILocalVariable(name: "p", arg: 1, scope: !16, file: !3, line: 19, type: !19) +!16 = distinct !DISubprogram(name: "fn2", scope: !3, file: !3, line: 19, type: !17, isLocal: false, isDefinition: true, scopeLine: 20, flags: DIFlagPrototyped, isOptimized: true, unit: !2, variables: !25) +!17 = !DISubroutineType(types: !18) +!18 = !{null, !19} +!19 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !3, line: 1, size: 96, elements: !20) +!20 = !{!21, !23, !24} +!21 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !19, file: !3, line: 4, baseType: !22, size: 8, offset: 24) +!22 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!23 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !19, file: !3, line: 5, baseType: !8, size: 32, offset: 32) +!24 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !19, file: !3, line: 6, baseType: !8, size: 6, offset: 64, flags: DIFlagBitField, extraData: i64 64) +!25 = !{!15} +!26 = !DIExpression(DW_OP_LLVM_fragment, 72, 24) +!27 = !DILocation(line: 19, column: 20, scope: !16, inlinedAt: !28) +!28 = distinct !DILocation(line: 27, column: 3, scope: !29, inlinedAt: !30) +!29 = distinct !DISubprogram(name: "fn3", scope: !3, file: !3, line: 24, type: !13, isLocal: false, isDefinition: true, scopeLine: 25, isOptimized: true, unit: !2, variables: !4) +!30 = distinct !DILocation(line: 34, column: 7, scope: !31) +!31 = distinct !DILexicalBlock(scope: !12, file: !3, line: 33, column: 5) +!32 = !DIExpression(DW_OP_LLVM_fragment, 0, 24) +!33 = !DILocation(line: 22, column: 9, scope: !16, inlinedAt: !28) +!34 = !DILocation(line: 21, column: 3, scope: !35, inlinedAt: !28) +!35 = !DILexicalBlockFile(scope: !16, file: !3, discriminator: 2) |