diff --git a/llvm/include/llvm/Transforms/Utils/SSAUpdater.h b/llvm/include/llvm/Transforms/Utils/SSAUpdater.h --- a/llvm/include/llvm/Transforms/Utils/SSAUpdater.h +++ b/llvm/include/llvm/Transforms/Utils/SSAUpdater.h @@ -28,6 +28,7 @@ class Type; class Use; class Value; +class DbgValueInst; /// Helper class for SSA formation on a set of values defined in /// multiple blocks. @@ -114,6 +115,15 @@ /// be below it. void RewriteUse(Use &U); + /// Rewrite debug value intrinsics to conform to a new SSA form. + /// + /// This will scout out all the debug value instrinsics associated with + /// the instruction. Anything outside of its block will have its + /// value set to the new SSA value if available, and undef if not. + void UpdateDebugValues(Instruction *I); + void UpdateDebugValues(Instruction *I, + SmallVectorImpl &DbgValues); + /// Rewrite a use like \c RewriteUse but handling in-block definitions. /// /// This version of the method can rewrite uses in the same block as @@ -123,6 +133,7 @@ private: Value *GetValueAtEndOfBlockInternal(BasicBlock *BB); + void UpdateDebugValue(Instruction *I, DbgValueInst *DbgValue); }; /// Helper class for promoting a collection of loads and stores into SSA diff --git a/llvm/lib/Transforms/Scalar/JumpThreading.cpp b/llvm/lib/Transforms/Scalar/JumpThreading.cpp --- a/llvm/lib/Transforms/Scalar/JumpThreading.cpp +++ b/llvm/lib/Transforms/Scalar/JumpThreading.cpp @@ -40,6 +40,7 @@ #include "llvm/IR/ConstantRange.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/DebugInfo.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" #include "llvm/IR/InstrTypes.h" @@ -2038,6 +2039,7 @@ // PHI insertion, of which we are prepared to do, clean these up now. SSAUpdater SSAUpdate; SmallVector UsesToRename; + SmallVector DbgValues; for (Instruction &I : *BB) { // Scan all uses of this instruction to see if it is used outside of its @@ -2053,8 +2055,16 @@ UsesToRename.push_back(&U); } + // Find debug values outside of the block + findDbgValues(DbgValues, &I); + DbgValues.erase(remove_if(DbgValues, + [&](const DbgValueInst *DbgVal) { + return DbgVal->getParent() == BB; + }), + DbgValues.end()); + // If there are no uses outside the block, we're done with this instruction. - if (UsesToRename.empty()) + if (UsesToRename.empty() && DbgValues.empty()) continue; LLVM_DEBUG(dbgs() << "JT: Renaming non-local uses of: " << I << "\n"); @@ -2067,6 +2077,11 @@ while (!UsesToRename.empty()) SSAUpdate.RewriteUse(*UsesToRename.pop_back_val()); + if (!DbgValues.empty()) { + SSAUpdate.UpdateDebugValues(&I, DbgValues); + DbgValues.clear(); + } + LLVM_DEBUG(dbgs() << "\n"); } } diff --git a/llvm/lib/Transforms/Utils/SSAUpdater.cpp b/llvm/lib/Transforms/Utils/SSAUpdater.cpp --- a/llvm/lib/Transforms/Utils/SSAUpdater.cpp +++ b/llvm/lib/Transforms/Utils/SSAUpdater.cpp @@ -19,6 +19,7 @@ #include "llvm/IR/BasicBlock.h" #include "llvm/IR/CFG.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/DebugInfo.h" #include "llvm/IR/DebugLoc.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" @@ -195,6 +196,33 @@ U.set(V); } +void SSAUpdater::UpdateDebugValues(Instruction *I) { + SmallVector DbgValues; + llvm::findDbgValues(DbgValues, I); + for (auto &DbgValue : DbgValues) { + if (DbgValue->getParent() == I->getParent()) + continue; + UpdateDebugValue(I, DbgValue); + } +} + +void SSAUpdater::UpdateDebugValues(Instruction *I, + SmallVectorImpl &DbgValues) { + for (auto &DbgValue : DbgValues) { + UpdateDebugValue(I, DbgValue); + } +} + +void SSAUpdater::UpdateDebugValue(Instruction *I, DbgValueInst *DbgValue) { + BasicBlock *UserBB = DbgValue->getParent(); + if (HasValueForBlock(UserBB)) { + Value *NewVal = GetValueInMiddleOfBlock(UserBB); + DbgValue->replaceVariableLocationOp(I, NewVal); + } + else + DbgValue->setUndef(); +} + void SSAUpdater::RewriteUseAfterInsertions(Use &U) { Instruction *User = cast(U.getUser()); diff --git a/llvm/test/Transforms/JumpThreading/thread-debug-info.ll b/llvm/test/Transforms/JumpThreading/thread-debug-info.ll --- a/llvm/test/Transforms/JumpThreading/thread-debug-info.ll +++ b/llvm/test/Transforms/JumpThreading/thread-debug-info.ll @@ -49,6 +49,48 @@ ret void, !dbg !29 } +; This is testing for debug value instrinsics outside of the threaded block pointing to a value +; inside to correctly take any new definitions. +define void @test2(i32 %cond1, i32 %cond2) !dbg !5 { +; CHECK: bb.f3 +; CHECK: call void @llvm.dbg.value(metadata ptr @a, metadata !{{[0-9]+}}, metadata !DIExpression()), !dbg !{{[0-9]+}} +; CHECK: bb.f4 +; CHECK-NEXT: [[PTR3:%.*]] = phi ptr [ null, %bb.cond2 ] +; CHECK-NEXT: call void @llvm.dbg.value(metadata ptr [[PTR3]], metadata !{{[0-9]+}}, metadata !DIExpression()), !dbg !{{[0-9]+}} +entry: + %tobool = icmp eq i32 %cond1, 0, !dbg !15 + br i1 %tobool, label %bb.cond2, label %bb.f1, !dbg !16 + +bb.f1: ; preds = %entry + call void @f1(), !dbg !17 + br label %bb.cond2, !dbg !18 + +bb.cond2: ; preds = %bb.f1, %entry + %ptr = phi ptr [ null, %bb.f1 ], [ @a, %entry ], !dbg !19 + %tobool1 = icmp eq i32 %cond2, 0, !dbg !20 + br i1 %tobool1, label %bb.file, label %bb.f2, !dbg !21 + +bb.f2: ; preds = %bb.cond2 + call void @f2(), !dbg !22 + br label %exit, !dbg !23 + +bb.file: ; preds = %bb.cond2 + %cmp = icmp eq ptr %ptr, null, !dbg !24 + call void @llvm.dbg.value(metadata ptr %ptr, metadata !14, metadata !DIExpression()), !dbg !21 + br i1 %cmp, label %bb.f4, label %bb.f3, !dbg !25 + +bb.f3: ; preds = %bb.file + call void @f3(), !dbg !26 + br label %exit, !dbg !27 + +bb.f4: ; preds = %bb.file + call void @f4(), !dbg !28 + br label %exit, !dbg !29 + +exit: ; preds = %bb.f4, %bb.f3, %bb.f2 + ret void, !dbg !29 +} + declare void @f1() declare void @f2()