From eba860d1d33b145658157a7ceaf4a079e9db44f3 Mon Sep 17 00:00:00 2001 From: DianQK Date: Sat, 13 Jul 2024 21:52:14 +0800 Subject: [PATCH 1/6] Pre-commit test cases --- .../pr98799-inline-simplifycfg-ub.ll | 61 ++++++++++++++++ .../SimplifyCFG/UnreachableEliminate.ll | 71 ++++++++++++++++++- 2 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 llvm/test/Transforms/PhaseOrdering/pr98799-inline-simplifycfg-ub.ll diff --git a/llvm/test/Transforms/PhaseOrdering/pr98799-inline-simplifycfg-ub.ll b/llvm/test/Transforms/PhaseOrdering/pr98799-inline-simplifycfg-ub.ll new file mode 100644 index 0000000000000..35140cdb6a06c --- /dev/null +++ b/llvm/test/Transforms/PhaseOrdering/pr98799-inline-simplifycfg-ub.ll @@ -0,0 +1,61 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt < %s -passes=inline,simplifycfg -S | FileCheck --check-prefix=CUSTOM %s +; RUN: opt < %s -O2 -S | FileCheck --check-prefix=O2 %s + +define internal ptr @bar(ptr %arg, i1 %arg1) { +bb: + br i1 %arg1, label %bb4, label %bb2 + +bb2: + %i = load ptr, ptr %arg, align 8 + %i3 = getelementptr inbounds i8, ptr %i, i64 1 + store ptr %i3, ptr %arg, align 8 + br label %bb4 + +bb4: + %i5 = phi ptr [ %i, %bb2 ], [ null, %bb ] + ret ptr %i5 +} + +define i32 @foo(ptr %arg, i1 %arg1) { +; CUSTOM-LABEL: define i32 @foo( +; CUSTOM-SAME: ptr [[ARG:%.*]], i1 [[ARG1:%.*]]) { +; CUSTOM-NEXT: [[BB:.*]]: +; CUSTOM-NEXT: br i1 [[ARG1]], label %[[BAR_EXIT:.*]], label %[[BB2_I:.*]] +; CUSTOM: [[BB2_I]]: +; CUSTOM-NEXT: [[I_I:%.*]] = load ptr, ptr [[ARG]], align 8 +; CUSTOM-NEXT: [[I3_I:%.*]] = getelementptr inbounds i8, ptr [[I_I]], i64 1 +; CUSTOM-NEXT: store ptr [[I3_I]], ptr [[ARG]], align 8 +; CUSTOM-NEXT: br label %[[BAR_EXIT]] +; CUSTOM: [[BAR_EXIT]]: +; CUSTOM-NEXT: [[I5_I:%.*]] = phi ptr [ [[I_I]], %[[BB2_I]] ], [ null, %[[BB]] ] +; CUSTOM-NEXT: [[I2:%.*]] = icmp ne ptr [[I5_I]], null +; CUSTOM-NEXT: call void @llvm.assume(i1 [[I2]]) +; CUSTOM-NEXT: [[I3:%.*]] = load i32, ptr [[I5_I]], align 4 +; CUSTOM-NEXT: ret i32 [[I3]] +; +; O2-LABEL: define i32 @foo( +; O2-SAME: ptr nocapture [[ARG:%.*]], i1 [[ARG1:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { +; O2-NEXT: [[BB:.*]]: +; O2-NEXT: br i1 [[ARG1]], label %[[BAR_EXIT:.*]], label %[[BB2_I:.*]] +; O2: [[BB2_I]]: +; O2-NEXT: [[I_I:%.*]] = load ptr, ptr [[ARG]], align 8 +; O2-NEXT: [[I3_I:%.*]] = getelementptr inbounds i8, ptr [[I_I]], i64 1 +; O2-NEXT: store ptr [[I3_I]], ptr [[ARG]], align 8 +; O2-NEXT: br label %[[BAR_EXIT]] +; O2: [[BAR_EXIT]]: +; O2-NEXT: [[I5_I:%.*]] = phi ptr [ [[I_I]], %[[BB2_I]] ], [ null, %[[BB]] ] +; O2-NEXT: [[I2:%.*]] = icmp ne ptr [[I5_I]], null +; O2-NEXT: tail call void @llvm.assume(i1 [[I2]]) +; O2-NEXT: [[I3:%.*]] = load i32, ptr [[I5_I]], align 4 +; O2-NEXT: ret i32 [[I3]] +; +bb: + %i = call ptr @bar(ptr %arg, i1 %arg1) + %i2 = icmp ne ptr %i, null + call void @llvm.assume(i1 %i2) + %i3 = load i32, ptr %i, align 4 + ret i32 %i3 +} + +declare void @llvm.assume(i1) diff --git a/llvm/test/Transforms/SimplifyCFG/UnreachableEliminate.ll b/llvm/test/Transforms/SimplifyCFG/UnreachableEliminate.ll index ef2d3219cca9b..f928a8991a931 100644 --- a/llvm/test/Transforms/SimplifyCFG/UnreachableEliminate.ll +++ b/llvm/test/Transforms/SimplifyCFG/UnreachableEliminate.ll @@ -20,7 +20,7 @@ F: define void @test2() personality ptr @__gxx_personality_v0 { ; CHECK-LABEL: @test2( ; CHECK-NEXT: entry: -; CHECK-NEXT: call void @test2() #[[ATTR3:[0-9]+]] +; CHECK-NEXT: call void @test2() #[[ATTR4:[0-9]+]] ; CHECK-NEXT: ret void ; entry: @@ -242,6 +242,8 @@ declare ptr @fn_nonnull_deref_arg(ptr nonnull dereferenceable(4) %p) declare ptr @fn_nonnull_deref_or_null_arg(ptr nonnull dereferenceable_or_null(4) %p) declare ptr @fn_nonnull_arg(ptr nonnull %p) declare ptr @fn_noundef_arg(ptr noundef %p) +declare ptr @fn_ptr_arg(ptr) +declare ptr @fn_ptr_arg_nounwind_willreturn(ptr) nounwind willreturn define void @test9(i1 %X, ptr %Y) { ; CHECK-LABEL: @test9( @@ -855,10 +857,75 @@ exit: ret i32 %res } +; FIXME: From bb to bb5 is UB. +define i32 @test9_null_user_order_1(ptr %arg, i1 %arg1, ptr %arg2) { +; CHECK-LABEL: @test9_null_user_order_1( +; CHECK-NEXT: bb: +; CHECK-NEXT: br i1 [[ARG1:%.*]], label [[BB5:%.*]], label [[BB3:%.*]] +; CHECK: bb3: +; CHECK-NEXT: [[I:%.*]] = load ptr, ptr [[ARG:%.*]], align 8 +; CHECK-NEXT: [[I4:%.*]] = getelementptr inbounds i8, ptr [[I]], i64 1 +; CHECK-NEXT: store ptr [[I4]], ptr [[ARG]], align 8 +; CHECK-NEXT: br label [[BB5]] +; CHECK: bb5: +; CHECK-NEXT: [[I6:%.*]] = phi ptr [ [[I]], [[BB3]] ], [ null, [[BB:%.*]] ] +; CHECK-NEXT: [[I7:%.*]] = load i32, ptr [[I6]], align 4 +; CHECK-NEXT: [[I8:%.*]] = icmp ne ptr [[I6]], [[ARG2:%.*]] +; CHECK-NEXT: call void @fn_ptr_arg(i1 [[I8]]) +; CHECK-NEXT: ret i32 [[I7]] +; +bb: + br i1 %arg1, label %bb5, label %bb3 + +bb3: ; preds = %bb + %i = load ptr, ptr %arg, align 8 + %i4 = getelementptr inbounds i8, ptr %i, i64 1 + store ptr %i4, ptr %arg, align 8 + br label %bb5 + +bb5: ; preds = %bb3, %bb + %i6 = phi ptr [ %i, %bb3 ], [ null, %bb ] + %i7 = load i32, ptr %i6, align 4 + %i8 = icmp ne ptr %i6, %arg2 + call void @fn_ptr_arg(i1 %i8) + ret i32 %i7 +} + +define i32 @test9_null_user_order_2(ptr %arg, i1 %arg1, ptr %arg2) { +; CHECK-LABEL: @test9_null_user_order_2( +; CHECK-NEXT: bb: +; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[ARG1:%.*]], true +; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]]) +; CHECK-NEXT: [[I:%.*]] = load ptr, ptr [[ARG:%.*]], align 8 +; CHECK-NEXT: [[I4:%.*]] = getelementptr inbounds i8, ptr [[I]], i64 1 +; CHECK-NEXT: store ptr [[I4]], ptr [[ARG]], align 8 +; CHECK-NEXT: [[I8:%.*]] = icmp ne ptr [[I]], [[ARG2:%.*]] +; CHECK-NEXT: call void @fn_ptr_arg_nounwind_willreturn(i1 [[I8]]) +; CHECK-NEXT: [[I7:%.*]] = load i32, ptr [[I]], align 4 +; CHECK-NEXT: ret i32 [[I7]] +; +bb: + br i1 %arg1, label %bb5, label %bb3 + +bb3: ; preds = %bb + %i = load ptr, ptr %arg, align 8 + %i4 = getelementptr inbounds i8, ptr %i, i64 1 + store ptr %i4, ptr %arg, align 8 + br label %bb5 + +bb5: ; preds = %bb3, %bb + %i6 = phi ptr [ %i, %bb3 ], [ null, %bb ] + %i8 = icmp ne ptr %i6, %arg2 + call void @fn_ptr_arg_nounwind_willreturn(i1 %i8) + %i7 = load i32, ptr %i6, align 4 + ret i32 %i7 +} + attributes #0 = { null_pointer_is_valid } ;. ; CHECK: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) } ; CHECK: attributes #[[ATTR1:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } ; CHECK: attributes #[[ATTR2:[0-9]+]] = { null_pointer_is_valid } -; CHECK: attributes #[[ATTR3]] = { nounwind } +; CHECK: attributes #[[ATTR3:[0-9]+]] = { nounwind willreturn } +; CHECK: attributes #[[ATTR4]] = { nounwind } ;. From b12417f6282ae3c9b32cb08572ece67730459012 Mon Sep 17 00:00:00 2001 From: DianQK Date: Sat, 13 Jul 2024 22:23:48 +0800 Subject: [PATCH 2/6] [SimplifyCFG] Select the first instruction that we can handle in `passingValueIsAlwaysUndefined` --- llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 24 ++++++++++---- .../pr98799-inline-simplifycfg-ub.ll | 31 ++++++++----------- .../SimplifyCFG/UnreachableEliminate.ll | 13 +++----- 3 files changed, 36 insertions(+), 32 deletions(-) diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp index 3fa3c0f1f52b0..a743858855047 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -7573,13 +7573,25 @@ static bool passingValueIsAlwaysUndefined(Value *V, Instruction *I, bool PtrValu return false; if (C->isNullValue() || isa(C)) { - // Only look at the first use, avoid hurting compile time with long uselists - auto *Use = cast(*I->user_begin()); - // Bail out if Use is not in the same BB as I or Use == I or Use comes - // before I in the block. The latter two can be the case if Use is a PHI - // node. - if (Use->getParent() != I->getParent() || Use == I || Use->comesBefore(I)) + // Only look at the first use we can hanle, avoid hurting compile time with + // long uselists + auto FindUse = llvm::find_if(I->users(), [&I](auto *U) { + auto *Use = cast(U); + // Bail out if Use is not in the same BB as I or Use == I or Use comes + // before I in the block. The latter two can be the case if Use is a + // PHI node. + if (Use->getParent() != I->getParent() || Use == I || Use->comesBefore(I)) + return false; + // Change this list when we want to add new instructions. + if (!isa(Use) && !isa(Use) && + !isa(Use) && !isa(Use) && + !isa(Use) && !isa(Use) && !isa(Use)) + return false; + return true; + }); + if (FindUse == I->user_end()) return false; + auto *Use = cast(*FindUse); // Now make sure that there are no instructions in between that can alter // control flow (eg. calls) diff --git a/llvm/test/Transforms/PhaseOrdering/pr98799-inline-simplifycfg-ub.ll b/llvm/test/Transforms/PhaseOrdering/pr98799-inline-simplifycfg-ub.ll index 35140cdb6a06c..17073fa198202 100644 --- a/llvm/test/Transforms/PhaseOrdering/pr98799-inline-simplifycfg-ub.ll +++ b/llvm/test/Transforms/PhaseOrdering/pr98799-inline-simplifycfg-ub.ll @@ -20,34 +20,26 @@ bb4: define i32 @foo(ptr %arg, i1 %arg1) { ; CUSTOM-LABEL: define i32 @foo( ; CUSTOM-SAME: ptr [[ARG:%.*]], i1 [[ARG1:%.*]]) { -; CUSTOM-NEXT: [[BB:.*]]: -; CUSTOM-NEXT: br i1 [[ARG1]], label %[[BAR_EXIT:.*]], label %[[BB2_I:.*]] -; CUSTOM: [[BB2_I]]: +; CUSTOM-NEXT: [[BB:.*:]] +; CUSTOM-NEXT: [[TMP0:%.*]] = xor i1 [[ARG1]], true +; CUSTOM-NEXT: call void @llvm.assume(i1 [[TMP0]]) ; CUSTOM-NEXT: [[I_I:%.*]] = load ptr, ptr [[ARG]], align 8 ; CUSTOM-NEXT: [[I3_I:%.*]] = getelementptr inbounds i8, ptr [[I_I]], i64 1 ; CUSTOM-NEXT: store ptr [[I3_I]], ptr [[ARG]], align 8 -; CUSTOM-NEXT: br label %[[BAR_EXIT]] -; CUSTOM: [[BAR_EXIT]]: -; CUSTOM-NEXT: [[I5_I:%.*]] = phi ptr [ [[I_I]], %[[BB2_I]] ], [ null, %[[BB]] ] -; CUSTOM-NEXT: [[I2:%.*]] = icmp ne ptr [[I5_I]], null +; CUSTOM-NEXT: [[I2:%.*]] = icmp ne ptr [[I_I]], null ; CUSTOM-NEXT: call void @llvm.assume(i1 [[I2]]) -; CUSTOM-NEXT: [[I3:%.*]] = load i32, ptr [[I5_I]], align 4 +; CUSTOM-NEXT: [[I3:%.*]] = load i32, ptr [[I_I]], align 4 ; CUSTOM-NEXT: ret i32 [[I3]] ; ; O2-LABEL: define i32 @foo( ; O2-SAME: ptr nocapture [[ARG:%.*]], i1 [[ARG1:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { -; O2-NEXT: [[BB:.*]]: -; O2-NEXT: br i1 [[ARG1]], label %[[BAR_EXIT:.*]], label %[[BB2_I:.*]] -; O2: [[BB2_I]]: -; O2-NEXT: [[I_I:%.*]] = load ptr, ptr [[ARG]], align 8 +; O2-NEXT: [[BB:.*:]] +; O2-NEXT: [[TMP0:%.*]] = xor i1 [[ARG1]], true +; O2-NEXT: tail call void @llvm.assume(i1 [[TMP0]]) +; O2-NEXT: [[I_I:%.*]] = load ptr, ptr [[ARG]], align 8, !nonnull [[META0:![0-9]+]], !noundef [[META0]] ; O2-NEXT: [[I3_I:%.*]] = getelementptr inbounds i8, ptr [[I_I]], i64 1 ; O2-NEXT: store ptr [[I3_I]], ptr [[ARG]], align 8 -; O2-NEXT: br label %[[BAR_EXIT]] -; O2: [[BAR_EXIT]]: -; O2-NEXT: [[I5_I:%.*]] = phi ptr [ [[I_I]], %[[BB2_I]] ], [ null, %[[BB]] ] -; O2-NEXT: [[I2:%.*]] = icmp ne ptr [[I5_I]], null -; O2-NEXT: tail call void @llvm.assume(i1 [[I2]]) -; O2-NEXT: [[I3:%.*]] = load i32, ptr [[I5_I]], align 4 +; O2-NEXT: [[I3:%.*]] = load i32, ptr [[I_I]], align 4 ; O2-NEXT: ret i32 [[I3]] ; bb: @@ -59,3 +51,6 @@ bb: } declare void @llvm.assume(i1) +;. +; O2: [[META0]] = !{} +;. diff --git a/llvm/test/Transforms/SimplifyCFG/UnreachableEliminate.ll b/llvm/test/Transforms/SimplifyCFG/UnreachableEliminate.ll index f928a8991a931..c4602e72ecbce 100644 --- a/llvm/test/Transforms/SimplifyCFG/UnreachableEliminate.ll +++ b/llvm/test/Transforms/SimplifyCFG/UnreachableEliminate.ll @@ -857,20 +857,17 @@ exit: ret i32 %res } -; FIXME: From bb to bb5 is UB. +; From bb to bb5 is UB. define i32 @test9_null_user_order_1(ptr %arg, i1 %arg1, ptr %arg2) { ; CHECK-LABEL: @test9_null_user_order_1( ; CHECK-NEXT: bb: -; CHECK-NEXT: br i1 [[ARG1:%.*]], label [[BB5:%.*]], label [[BB3:%.*]] -; CHECK: bb3: +; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[ARG1:%.*]], true +; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]]) ; CHECK-NEXT: [[I:%.*]] = load ptr, ptr [[ARG:%.*]], align 8 ; CHECK-NEXT: [[I4:%.*]] = getelementptr inbounds i8, ptr [[I]], i64 1 ; CHECK-NEXT: store ptr [[I4]], ptr [[ARG]], align 8 -; CHECK-NEXT: br label [[BB5]] -; CHECK: bb5: -; CHECK-NEXT: [[I6:%.*]] = phi ptr [ [[I]], [[BB3]] ], [ null, [[BB:%.*]] ] -; CHECK-NEXT: [[I7:%.*]] = load i32, ptr [[I6]], align 4 -; CHECK-NEXT: [[I8:%.*]] = icmp ne ptr [[I6]], [[ARG2:%.*]] +; CHECK-NEXT: [[I7:%.*]] = load i32, ptr [[I]], align 4 +; CHECK-NEXT: [[I8:%.*]] = icmp ne ptr [[I]], [[ARG2:%.*]] ; CHECK-NEXT: call void @fn_ptr_arg(i1 [[I8]]) ; CHECK-NEXT: ret i32 [[I7]] ; From 044f73fca431e4662713fdc7281237f7822bd495 Mon Sep 17 00:00:00 2001 From: DianQK Date: Sun, 14 Jul 2024 18:10:38 +0800 Subject: [PATCH 3/6] Fix typo --- llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp index a743858855047..fc99778d21024 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -7573,7 +7573,7 @@ static bool passingValueIsAlwaysUndefined(Value *V, Instruction *I, bool PtrValu return false; if (C->isNullValue() || isa(C)) { - // Only look at the first use we can hanle, avoid hurting compile time with + // Only look at the first use we can handle, avoid hurting compile time with // long uselists auto FindUse = llvm::find_if(I->users(), [&I](auto *U) { auto *Use = cast(U); From 54c058d4849113219496d9a0963d8189be8b6e14 Mon Sep 17 00:00:00 2001 From: DianQK Date: Sun, 14 Jul 2024 21:56:47 +0800 Subject: [PATCH 4/6] Address comments --- llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp index fc99778d21024..0e164a92d3441 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -7583,11 +7583,22 @@ static bool passingValueIsAlwaysUndefined(Value *V, Instruction *I, bool PtrValu if (Use->getParent() != I->getParent() || Use == I || Use->comesBefore(I)) return false; // Change this list when we want to add new instructions. - if (!isa(Use) && !isa(Use) && - !isa(Use) && !isa(Use) && - !isa(Use) && !isa(Use) && !isa(Use)) + switch (Use->getOpcode()) { + default: return false; - return true; + case Instruction::GetElementPtr: + return true; + case Instruction::Ret: + return true; + case Instruction::BitCast: + return true; + case Instruction::Load: + return true; + case Instruction::Store: + return true; + case Instruction::Call: + return true; + } }); if (FindUse == I->user_end()) return false; From 057abc842e581d01ac0bff435d779e3f506440ad Mon Sep 17 00:00:00 2001 From: DianQK Date: Sun, 14 Jul 2024 22:12:48 +0800 Subject: [PATCH 5/6] *v* --- llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp index 0e164a92d3441..21664f040e758 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -7587,16 +7587,13 @@ static bool passingValueIsAlwaysUndefined(Value *V, Instruction *I, bool PtrValu default: return false; case Instruction::GetElementPtr: - return true; case Instruction::Ret: - return true; case Instruction::BitCast: - return true; case Instruction::Load: - return true; case Instruction::Store: - return true; case Instruction::Call: + case Instruction::CallBr: + case Instruction::Invoke: return true; } }); From b686e35ecd81ae76fc517d14e133d44ed7ff9f4b Mon Sep 17 00:00:00 2001 From: DianQK Date: Mon, 15 Jul 2024 07:32:35 +0800 Subject: [PATCH 6/6] Only check opcode in find_if --- llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp index 21664f040e758..8f717cb43bcb4 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -7575,13 +7575,8 @@ static bool passingValueIsAlwaysUndefined(Value *V, Instruction *I, bool PtrValu if (C->isNullValue() || isa(C)) { // Only look at the first use we can handle, avoid hurting compile time with // long uselists - auto FindUse = llvm::find_if(I->users(), [&I](auto *U) { + auto FindUse = llvm::find_if(I->users(), [](auto *U) { auto *Use = cast(U); - // Bail out if Use is not in the same BB as I or Use == I or Use comes - // before I in the block. The latter two can be the case if Use is a - // PHI node. - if (Use->getParent() != I->getParent() || Use == I || Use->comesBefore(I)) - return false; // Change this list when we want to add new instructions. switch (Use->getOpcode()) { default: @@ -7600,6 +7595,11 @@ static bool passingValueIsAlwaysUndefined(Value *V, Instruction *I, bool PtrValu if (FindUse == I->user_end()) return false; auto *Use = cast(*FindUse); + // Bail out if Use is not in the same BB as I or Use == I or Use comes + // before I in the block. The latter two can be the case if Use is a + // PHI node. + if (Use->getParent() != I->getParent() || Use == I || Use->comesBefore(I)) + return false; // Now make sure that there are no instructions in between that can alter // control flow (eg. calls)