[llvm] [SimplifyCFG] Select the first instruction that we can handle in `passingValueIsAlwaysUndefined` (PR #98802)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Jul 14 02:03:46 PDT 2024
https://github.com/DianQK created https://github.com/llvm/llvm-project/pull/98802
Fixes #98799.
>From eba860d1d33b145658157a7ceaf4a079e9db44f3 Mon Sep 17 00:00:00 2001
From: DianQK <dianqk at dianqk.net>
Date: Sat, 13 Jul 2024 21:52:14 +0800
Subject: [PATCH 1/2] 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 <dianqk at dianqk.net>
Date: Sat, 13 Jul 2024 22:23:48 +0800
Subject: [PATCH 2/2] [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<UndefValue>(C)) {
- // Only look at the first use, avoid hurting compile time with long uselists
- auto *Use = cast<Instruction>(*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<Instruction>(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<GetElementPtrInst>(Use) && !isa<ReturnInst>(Use) &&
+ !isa<BitCastInst>(Use) && !isa<LoadInst>(Use) &&
+ !isa<StoreInst>(Use) && !isa<AssumeInst>(Use) && !isa<CallBase>(Use))
+ return false;
+ return true;
+ });
+ if (FindUse == I->user_end())
return false;
+ auto *Use = cast<Instruction>(*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]]
;
More information about the llvm-commits
mailing list