class Type;
class Use;
class Value;
+class DbgValueInst;
/// Helper class for SSA formation on a set of values defined in
/// multiple blocks.
/// 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<DbgValueInst *> &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
private:
Value *GetValueAtEndOfBlockInternal(BasicBlock *BB);
+ void UpdateDebugValue(Instruction *I, DbgValueInst *DbgValue);
};
/// Helper class for promoting a collection of loads and stores into SSA
#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"
// PHI insertion, of which we are prepared to do, clean these up now.
SSAUpdater SSAUpdate;
SmallVector<Use *, 16> UsesToRename;
+ SmallVector<DbgValueInst *, 4> DbgValues;
for (Instruction &I : *BB) {
// Scan all uses of this instruction to see if it is used outside of its
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");
while (!UsesToRename.empty())
SSAUpdate.RewriteUse(*UsesToRename.pop_back_val());
+ if (!DbgValues.empty()) {
+ SSAUpdate.UpdateDebugValues(&I, DbgValues);
+ DbgValues.clear();
+ }
+
LLVM_DEBUG(dbgs() << "\n");
}
}
#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"
U.set(V);
}
+void SSAUpdater::UpdateDebugValues(Instruction *I) {
+ SmallVector<DbgValueInst *, 4> DbgValues;
+ llvm::findDbgValues(DbgValues, I);
+ for (auto &DbgValue : DbgValues) {
+ if (DbgValue->getParent() == I->getParent())
+ continue;
+ UpdateDebugValue(I, DbgValue);
+ }
+}
+
+void SSAUpdater::UpdateDebugValues(Instruction *I,
+ SmallVectorImpl<DbgValueInst *> &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->setKillLocation();
+}
+
void SSAUpdater::RewriteUseAfterInsertions(Use &U) {
Instruction *User = cast<Instruction>(U.getUser());
@a = global i32 0, align 4
; Test that the llvm.dbg.value calls in a threaded block are correctly updated to
; target the locals in their threaded block, and not the unthreaded one.
-define void @test2(i32 %cond1, i32 %cond2) {
+define void @test1(i32 %cond1, i32 %cond2) {
; CHECK: [[globalptr:@.*]] = global i32 0, align 4
; CHECK: bb.cond2:
; CHECK: call void @llvm.dbg.value(metadata ptr null, metadata ![[DBG1ptr:[0-9]+]], metadata !DIExpression()), !dbg ![[DBG2ptr:[0-9]+]]
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()
!26 = !DILocation(line: 12, column: 1, scope: !5)
!27 = !DILocation(line: 13, column: 1, scope: !5)
!28 = !DILocation(line: 14, column: 1, scope: !5)
-!29 = !DILocation(line: 15, column: 1, scope: !5)
\ No newline at end of file
+!29 = !DILocation(line: 15, column: 1, scope: !5)