diff --git a/llvm/include/llvm/Transforms/Utils/Local.h b/llvm/include/llvm/Transforms/Utils/Local.h index 2ef93b7d203c..aea0ff919801 100644 --- a/llvm/include/llvm/Transforms/Utils/Local.h +++ b/llvm/include/llvm/Transforms/Utils/Local.h @@ -282,12 +282,8 @@ bool LowerDbgDeclare(Function &F); /// Finds the llvm.dbg.declare intrinsic corresponding to an alloca, if any. DbgDeclareInst *FindAllocaDbgDeclare(Value *V); -/// Finds the llvm.dbg.value intrinsics describing a value and invoke \p Action -/// on it. -void findDbgValues(Value *V, std::function Action); - -/// Constants for \p replaceDbgDeclare and friends. -enum { NoDeref = false, WithDeref = true }; +/// Finds the llvm.dbg.value intrinsics describing a value, if any. +void findDbgValues(SmallVectorImpl &DbgValues, Value *V); /// Replaces llvm.dbg.declare instruction when the address it describes /// is replaced with a new value. If Deref is true, an additional DW_OP_deref is @@ -314,11 +310,6 @@ bool replaceDbgDeclareForAlloca(AllocaInst *AI, Value *NewAllocaAddress, void replaceDbgValueForAlloca(AllocaInst *AI, Value *NewAllocaAddress, DIBuilder &Builder, int Offset = 0); -/// Assuming the instruction \p I is going to be deleted, attempt to salvage any -/// dbg.value intrinsics referring to \p I by rewriting its effect into a -/// DIExpression. -void salvageDebugInfo(Instruction &I); - /// Remove all instructions from a basic block other than it's terminator /// and any present EH pad instructions. unsigned removeAllNonTerminatorAndEHPadInstructions(BasicBlock *BB); diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h index 0a3382e1903f..0d76cdf371ea 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h +++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h @@ -28,9 +28,6 @@ #include "llvm/IR/PatternMatch.h" #include "llvm/Pass.h" #include "llvm/Transforms/InstCombine/InstCombineWorklist.h" -#include "llvm/Transforms/Utils/Local.h" -#include "llvm/Support/Dwarf.h" -#include "llvm/IR/DIBuilder.h" #define DEBUG_TYPE "instcombine" @@ -473,9 +470,8 @@ public: /// methods should return the value returned by this function. Instruction *eraseInstFromFunction(Instruction &I) { DEBUG(dbgs() << "IC: ERASE " << I << '\n'); - assert(I.use_empty() && "Cannot erase instruction that is used!"); - salvageDebugInfo(I); + assert(I.use_empty() && "Cannot erase instruction that is used!"); // Make sure that we reprocess all operands now that we reduced their // use counts. if (I.getNumOperands() < 8) { diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp index 431055233e92..acbc131118f2 100644 --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -1085,14 +1085,15 @@ static bool PhiHasDebugValue(DILocalVariable *DIVar, // Since we can't guarantee that the original dbg.declare instrinsic // is removed by LowerDbgDeclare(), we need to make sure that we are // not inserting the same dbg.value intrinsic over and over. - bool Found = false; - findDbgValues(APN, [&](DbgValueInst &DVI) { - assert(DVI.getValue() == APN); - assert(DVI.getOffset() == 0); - if ((DVI.getVariable() == DIVar) && (DVI.getExpression() == DIExpr)) - Found = true; - }); - return Found; + SmallVector DbgValues; + findDbgValues(DbgValues, APN); + for (auto *DVI : DbgValues) { + assert(DVI->getValue() == APN); + assert(DVI->getOffset() == 0); + if ((DVI->getVariable() == DIVar) && (DVI->getExpression() == DIExpr)) + return true; + } + return false; } /// Inserts a llvm.dbg.value intrinsic before a store to an alloca'd value @@ -1250,40 +1251,44 @@ DbgDeclareInst *llvm::FindAllocaDbgDeclare(Value *V) { return nullptr; } -void llvm::findDbgValues(Value *V, std::function Action) { +void llvm::findDbgValues(SmallVectorImpl &DbgValues, Value *V) { if (auto *L = LocalAsMetadata::getIfExists(V)) if (auto *MDV = MetadataAsValue::getIfExists(V->getContext(), L)) for (User *U : MDV->users()) if (DbgValueInst *DVI = dyn_cast(U)) - Action(*DVI); + DbgValues.push_back(DVI); } -static void appendOffset(SmallVectorImpl &Ops, int64_t Offset) { +static void DIExprAddDeref(SmallVectorImpl &Expr) { + Expr.push_back(dwarf::DW_OP_deref); +} + +static void DIExprAddOffset(SmallVectorImpl &Expr, int Offset) { if (Offset > 0) { - Ops.push_back(dwarf::DW_OP_plus); - Ops.push_back(Offset); + Expr.push_back(dwarf::DW_OP_plus); + Expr.push_back(Offset); } else if (Offset < 0) { - Ops.push_back(dwarf::DW_OP_minus); - Ops.push_back(-Offset); + Expr.push_back(dwarf::DW_OP_minus); + Expr.push_back(-Offset); } } -/// Prepend \p DIExpr with a deref and offset operation. -static DIExpression *prependDIExpr(DIBuilder &Builder, DIExpression *DIExpr, - bool Deref, int64_t Offset) { +static DIExpression *BuildReplacementDIExpr(DIBuilder &Builder, + DIExpression *DIExpr, bool Deref, + int Offset) { if (!Deref && !Offset) return DIExpr; // Create a copy of the original DIDescriptor for user variable, prepending // "deref" operation to a list of address elements, as new llvm.dbg.declare // will take a value storing address of the memory for variable, not // alloca itself. - SmallVector Ops; + SmallVector NewDIExpr; if (Deref) - Ops.push_back(dwarf::DW_OP_deref); - appendOffset(Ops, Offset); + DIExprAddDeref(NewDIExpr); + DIExprAddOffset(NewDIExpr, Offset); if (DIExpr) - Ops.append(DIExpr->elements_begin(), DIExpr->elements_end()); - return Builder.createExpression(Ops); + NewDIExpr.append(DIExpr->elements_begin(), DIExpr->elements_end()); + return Builder.createExpression(NewDIExpr); } bool llvm::replaceDbgDeclare(Value *Address, Value *NewAddress, @@ -1297,7 +1302,7 @@ bool llvm::replaceDbgDeclare(Value *Address, Value *NewAddress, auto *DIExpr = DDI->getExpression(); assert(DIVar && "Missing variable"); - DIExpr = prependDIExpr(Builder, DIExpr, Deref, Offset); + DIExpr = BuildReplacementDIExpr(Builder, DIExpr, Deref, Offset); // Insert llvm.dbg.declare immediately after the original alloca, and remove // old llvm.dbg.declare. @@ -1329,11 +1334,11 @@ static void replaceOneDbgValueForAlloca(DbgValueInst *DVI, Value *NewAddress, // Insert the offset immediately after the first deref. // We could just change the offset argument of dbg.value, but it's unsigned... if (Offset) { - SmallVector Ops; - Ops.push_back(dwarf::DW_OP_deref); - appendOffset(Ops, Offset); - Ops.append(DIExpr->elements_begin() + 1, DIExpr->elements_end()); - DIExpr = Builder.createExpression(Ops); + SmallVector NewDIExpr; + DIExprAddDeref(NewDIExpr); + DIExprAddOffset(NewDIExpr, Offset); + NewDIExpr.append(DIExpr->elements_begin() + 1, DIExpr->elements_end()); + DIExpr = Builder.createExpression(NewDIExpr); } Builder.insertDbgValueIntrinsic(NewAddress, DVI->getOffset(), DIVar, DIExpr, @@ -1352,46 +1357,6 @@ void llvm::replaceDbgValueForAlloca(AllocaInst *AI, Value *NewAllocaAddress, } } -void llvm::salvageDebugInfo(Instruction &I) { - auto MDWrap = [&](Value *V) { - return MetadataAsValue::get(I.getContext(), ValueAsMetadata::get(V)); - }; - auto &M = *I.getModule(); - if (auto *BitCast = dyn_cast(&I)) - findDbgValues(BitCast, [&](DbgValueInst &DVI) { - // Bitcasts are entirely irrelevant for debug info. Rewrite the dbg.value - // to use the cast's source. - DVI.setOperand(0, MDWrap(I.getOperand(0))); - DEBUG(dbgs() << "SALVAGE: " << DVI << '\n'); - }); - else if (auto *GEP = dyn_cast(&I)) - findDbgValues(GEP, [&](DbgValueInst &DVI) { - unsigned BitWidth = - M.getDataLayout().getPointerSizeInBits(GEP->getPointerAddressSpace()); - APInt Offset(BitWidth, 0); - // Rewrite a constant GEP into a DIExpression. - if (GEP->accumulateConstantOffset(M.getDataLayout(), Offset)) { - auto *DIExpr = DVI.getExpression(); - DIBuilder DIB(M, /*AllowUnresolved*/ false); - // GEP offsets are i32 and thus alwaus fit into an int64_t. - DIExpr = prependDIExpr(DIB, DIExpr, NoDeref, Offset.getSExtValue()); - DVI.setOperand(0, MDWrap(I.getOperand(0))); - DVI.setOperand(3, MetadataAsValue::get(I.getContext(), DIExpr)); - DEBUG(dbgs() << "SALVAGE: " << DVI << '\n'); - } - }); - else if (auto *Load = dyn_cast(&I)) - findDbgValues(Load, [&](DbgValueInst &DVI) { - // Rewrite the load into DW_OP_deref. - auto *DIExpr = DVI.getExpression(); - DIBuilder DIB(M, /*AllowUnresolved*/ false); - DIExpr = prependDIExpr(DIB, DIExpr, WithDeref, 0); - DVI.setOperand(0, MDWrap(I.getOperand(0))); - DVI.setOperand(3, MetadataAsValue::get(I.getContext(), DIExpr)); - DEBUG(dbgs() << "SALVAGE: " << DVI << '\n'); - }); -} - unsigned llvm::removeAllNonTerminatorAndEHPadInstructions(BasicBlock *BB) { unsigned NumDeadInst = 0; // Delete the instructions backwards, as it has a reduced likelihood of diff --git a/llvm/test/Transforms/InstCombine/debuginfo-dce.ll b/llvm/test/Transforms/InstCombine/debuginfo-dce.ll deleted file mode 100644 index e23aef7334d5..000000000000 --- a/llvm/test/Transforms/InstCombine/debuginfo-dce.ll +++ /dev/null @@ -1,106 +0,0 @@ -; RUN: opt -instcombine %s -S -o - | FileCheck %s -; Verify that the eliminated instructions (bitcast, gep, load) are salvaged into -; a DIExpression. -; -; Originally created from the following C source and then heavily isolated/reduced. -; -; struct entry { -; struct entry *next; -; }; -; void scan(struct entry *queue, struct entry *end) -; { -; struct entry *entry; -; for (entry = (struct entry *)((char *)(queue->next) - 8); -; &entry->next == end; -; entry = (struct entry *)((char *)(entry->next) - 8)) { -; } -; } - -; ModuleID = '' -source_filename = "test.c" -target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-apple-macosx10.12.0" - -%struct.entry = type { %struct.entry* } - -; Function Attrs: nounwind ssp uwtable -define void @salvage_load(%struct.entry** %queue) local_unnamed_addr #0 !dbg !14 { -entry: - %im_not_dead = alloca %struct.entry* - %0 = load %struct.entry*, %struct.entry** %queue, align 8, !dbg !19 - %1 = load %struct.entry*, %struct.entry** %queue, align 8, !dbg !19 - call void @llvm.dbg.value(metadata %struct.entry* %1, i64 0, metadata !18, metadata !20), !dbg !19 -; CHECK: define void @salvage_load -; CHECK-NEXT: entry: -; CHECK-NEXT: call void @llvm.dbg.value(metadata %struct.entry** %queue, i64 0, -; CHECK-SAME: metadata ![[LOAD_EXPR:[0-9]+]]) - store %struct.entry* %1, %struct.entry** %im_not_dead, align 8 - ret void, !dbg !21 -} - -; Function Attrs: nounwind ssp uwtable -define void @salvage_bitcast(%struct.entry* %queue) local_unnamed_addr #0 !dbg !14 { -entry: - %im_not_dead = alloca i8* - %0 = bitcast %struct.entry* %queue to i8*, !dbg !19 - %1 = bitcast %struct.entry* %queue to i8*, !dbg !19 - call void @llvm.dbg.value(metadata i8* %1, i64 0, metadata !18, metadata !20), !dbg !19 -; CHECK: define void @salvage_bitcast -; CHECK-NEXT: entry: -; CHECK-NEXT: call void @llvm.dbg.value(metadata %struct.entry* %queue, i64 0, -; CHECK-SAME: metadata ![[BITCAST_EXPR:[0-9]+]]) - store i8* %1, i8** %im_not_dead, align 8 - ret void, !dbg !21 -} - -; Function Attrs: nounwind ssp uwtable -define void @salvage_gep(%struct.entry* %queue, %struct.entry* %end) local_unnamed_addr #0 !dbg !14 { -entry: - %im_not_dead = alloca %struct.entry** - %0 = getelementptr inbounds %struct.entry, %struct.entry* %queue, i32 -1, i32 0, !dbg !19 - %1 = getelementptr inbounds %struct.entry, %struct.entry* %queue, i32 -1, i32 0, !dbg !19 - call void @llvm.dbg.value(metadata %struct.entry** %1, i64 0, metadata !18, metadata !20), !dbg !19 -; CHECK: define void @salvage_gep -; CHECK-NEXT: entry: -; CHECK-NEXT: call void @llvm.dbg.value(metadata %struct.entry* %queue, i64 0, -; CHECK-SAME: metadata ![[GEP_EXPR:[0-9]+]]) - store %struct.entry** %1, %struct.entry*** %im_not_dead, align 8 - ret void, !dbg !21 -} - -; CHECK: ![[LOAD_EXPR]] = !DIExpression(DW_OP_deref, DW_OP_plus, 0) -; CHECK: ![[BITCAST_EXPR]] = !DIExpression(DW_OP_plus, 0) -; CHECK: ![[GEP_EXPR]] = !DIExpression(DW_OP_minus, 8, DW_OP_plus, 0) - -; Function Attrs: nounwind readnone -declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #1 - -attributes #0 = { nounwind ssp uwtable } -attributes #1 = { nounwind readnone } - -!llvm.dbg.cu = !{!0} -!llvm.module.flags = !{!10, !11, !12} -!llvm.ident = !{!13} - -!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 5.0.0 (trunk 297628) (llvm/trunk 297643)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3) -!1 = !DIFile(filename: "test.c", directory: "/") -!2 = !{} -!3 = !{!4, !8} -!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64) -!5 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "entry", file: !1, line: 1, size: 64, elements: !6) -!6 = !{!7} -!7 = !DIDerivedType(tag: DW_TAG_member, name: "next", scope: !5, file: !1, line: 2, baseType: !4, size: 64) -!8 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !9, size: 64) -!9 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) -!10 = !{i32 2, !"Dwarf Version", i32 4} -!11 = !{i32 2, !"Debug Info Version", i32 3} -!12 = !{i32 1, !"PIC Level", i32 2} -!13 = !{!"clang version 5.0.0 (trunk 297628) (llvm/trunk 297643)"} -!14 = distinct !DISubprogram(name: "scan", scope: !1, file: !1, line: 4, type: !15, isLocal: false, isDefinition: true, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !17) -!15 = !DISubroutineType(types: !16) -!16 = !{null, !4, !4} -!17 = !{!18} -!18 = !DILocalVariable(name: "entry", scope: !14, file: !1, line: 6, type: !4) -!19 = !DILocation(line: 6, column: 17, scope: !14) -!20 = !DIExpression(DW_OP_plus, 0) -!21 = !DILocation(line: 11, column: 1, scope: !14)