summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Transforms/Utils/Local.cpp
diff options
context:
space:
mode:
authorAdrian Prantl <aprantl@apple.com>2017-03-16 18:22:52 +0000
committerAdrian Prantl <aprantl@apple.com>2017-03-16 18:22:52 +0000
commit4377314a98d3f6c905d2c52c7a4d480a1a73c124 (patch)
tree466f7f5f73df5f03847d70805932897b30598604 /llvm/lib/Transforms/Utils/Local.cpp
parentcb46a6baf7424cb9e2c3085a0d622b0378dd314f (diff)
downloadbcm5719-llvm-4377314a98d3f6c905d2c52c7a4d480a1a73c124.tar.gz
bcm5719-llvm-4377314a98d3f6c905d2c52c7a4d480a1a73c124.zip
Salvage debug info from instructions about to be deleted
This patch improves debug info quality in InstCombine by looking at values that are about to be deleted, checking whether there are any dbg.value instrinsics referring to them, and potentially encoding the semantics of the deleted instruction into the dbg.value's DIExpression. In the example in the testcase (which was extracted from XNU) there is a sequence of %4 = load %struct.entry*, %struct.entry** %next2, align 8, !dbg !41 %5 = bitcast %struct.entry* %4 to i8*, !dbg !42 %add.ptr4 = getelementptr inbounds i8, i8* %5, i64 -8, !dbg !43 %6 = bitcast i8* %add.ptr4 to %struct.entry*, !dbg !44 call void @llvm.dbg.value(metadata %struct.entry* %6, i64 0, metadata !20, metadata !21), !dbg 34 When these instructions are eliminated by instcombine one after another, we can still salvage the otherwise dead debug info: - Bitcasts have no effect, so have the dbg.value point to operand(0) - Loads can be expressed via a DW_OP_deref - Constant gep instructions can be replaced by DWARF expression arithmetic The API introduced by this patch is not specific to instcombine and can be useful in other places, too. rdar://problem/30725338 Differential Revision: https://reviews.llvm.org/D30919 llvm-svn: 297971
Diffstat (limited to 'llvm/lib/Transforms/Utils/Local.cpp')
-rw-r--r--llvm/lib/Transforms/Utils/Local.cpp103
1 files changed, 69 insertions, 34 deletions
diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp
index acbc131118f..26cb1a8c8b0 100644
--- a/llvm/lib/Transforms/Utils/Local.cpp
+++ b/llvm/lib/Transforms/Utils/Local.cpp
@@ -1085,15 +1085,14 @@ 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.
- SmallVector<DbgValueInst *, 1> 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;
+ 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;
}
/// Inserts a llvm.dbg.value intrinsic before a store to an alloca'd value
@@ -1251,44 +1250,40 @@ DbgDeclareInst *llvm::FindAllocaDbgDeclare(Value *V) {
return nullptr;
}
-void llvm::findDbgValues(SmallVectorImpl<DbgValueInst *> &DbgValues, Value *V) {
+void llvm::findDbgValues(Value *V, std::function<void(DbgValueInst &)> Action) {
if (auto *L = LocalAsMetadata::getIfExists(V))
if (auto *MDV = MetadataAsValue::getIfExists(V->getContext(), L))
for (User *U : MDV->users())
if (DbgValueInst *DVI = dyn_cast<DbgValueInst>(U))
- DbgValues.push_back(DVI);
-}
-
-static void DIExprAddDeref(SmallVectorImpl<uint64_t> &Expr) {
- Expr.push_back(dwarf::DW_OP_deref);
+ Action(*DVI);
}
-static void DIExprAddOffset(SmallVectorImpl<uint64_t> &Expr, int Offset) {
+static void appendOffset(SmallVectorImpl<uint64_t> &Ops, int64_t Offset) {
if (Offset > 0) {
- Expr.push_back(dwarf::DW_OP_plus);
- Expr.push_back(Offset);
+ Ops.push_back(dwarf::DW_OP_plus);
+ Ops.push_back(Offset);
} else if (Offset < 0) {
- Expr.push_back(dwarf::DW_OP_minus);
- Expr.push_back(-Offset);
+ Ops.push_back(dwarf::DW_OP_minus);
+ Ops.push_back(-Offset);
}
}
-static DIExpression *BuildReplacementDIExpr(DIBuilder &Builder,
- DIExpression *DIExpr, bool Deref,
- int Offset) {
+/// Prepend \p DIExpr with a deref and offset operation.
+static DIExpression *prependDIExpr(DIBuilder &Builder, DIExpression *DIExpr,
+ bool Deref, int64_t 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<uint64_t, 4> NewDIExpr;
+ SmallVector<uint64_t, 4> Ops;
if (Deref)
- DIExprAddDeref(NewDIExpr);
- DIExprAddOffset(NewDIExpr, Offset);
+ Ops.push_back(dwarf::DW_OP_deref);
+ appendOffset(Ops, Offset);
if (DIExpr)
- NewDIExpr.append(DIExpr->elements_begin(), DIExpr->elements_end());
- return Builder.createExpression(NewDIExpr);
+ Ops.append(DIExpr->elements_begin(), DIExpr->elements_end());
+ return Builder.createExpression(Ops);
}
bool llvm::replaceDbgDeclare(Value *Address, Value *NewAddress,
@@ -1302,7 +1297,7 @@ bool llvm::replaceDbgDeclare(Value *Address, Value *NewAddress,
auto *DIExpr = DDI->getExpression();
assert(DIVar && "Missing variable");
- DIExpr = BuildReplacementDIExpr(Builder, DIExpr, Deref, Offset);
+ DIExpr = prependDIExpr(Builder, DIExpr, Deref, Offset);
// Insert llvm.dbg.declare immediately after the original alloca, and remove
// old llvm.dbg.declare.
@@ -1334,11 +1329,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<uint64_t, 4> NewDIExpr;
- DIExprAddDeref(NewDIExpr);
- DIExprAddOffset(NewDIExpr, Offset);
- NewDIExpr.append(DIExpr->elements_begin() + 1, DIExpr->elements_end());
- DIExpr = Builder.createExpression(NewDIExpr);
+ SmallVector<uint64_t, 4> Ops;
+ Ops.push_back(dwarf::DW_OP_deref);
+ appendOffset(Ops, Offset);
+ Ops.append(DIExpr->elements_begin() + 1, DIExpr->elements_end());
+ DIExpr = Builder.createExpression(Ops);
}
Builder.insertDbgValueIntrinsic(NewAddress, DVI->getOffset(), DIVar, DIExpr,
@@ -1357,6 +1352,46 @@ 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<BitCastInst>(&I))
+ findDbgValues(&I, [&](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<GetElementPtrInst>(&I))
+ findDbgValues(&I, [&](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<LoadInst>(&I))
+ findDbgValues(&I, [&](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
OpenPOWER on IntegriCloud