Skip to content

Commit 8afb643

Browse files
authored
[SimplifyCFG] Select the first instruction that we can handle in passingValueIsAlwaysUndefined (#98802)
Fixes #98799.
1 parent cc97a0d commit 8afb643

File tree

3 files changed

+146
-6
lines changed

3 files changed

+146
-6
lines changed

llvm/lib/Transforms/Utils/SimplifyCFG.cpp

+24-4
Original file line numberDiff line numberDiff line change
@@ -7573,11 +7573,31 @@ static bool passingValueIsAlwaysUndefined(Value *V, Instruction *I, bool PtrValu
75737573
return false;
75747574

75757575
if (C->isNullValue() || isa<UndefValue>(C)) {
7576-
// Only look at the first use, avoid hurting compile time with long uselists
7577-
auto *Use = cast<Instruction>(*I->user_begin());
7576+
// Only look at the first use we can handle, avoid hurting compile time with
7577+
// long uselists
7578+
auto FindUse = llvm::find_if(I->users(), [](auto *U) {
7579+
auto *Use = cast<Instruction>(U);
7580+
// Change this list when we want to add new instructions.
7581+
switch (Use->getOpcode()) {
7582+
default:
7583+
return false;
7584+
case Instruction::GetElementPtr:
7585+
case Instruction::Ret:
7586+
case Instruction::BitCast:
7587+
case Instruction::Load:
7588+
case Instruction::Store:
7589+
case Instruction::Call:
7590+
case Instruction::CallBr:
7591+
case Instruction::Invoke:
7592+
return true;
7593+
}
7594+
});
7595+
if (FindUse == I->user_end())
7596+
return false;
7597+
auto *Use = cast<Instruction>(*FindUse);
75787598
// Bail out if Use is not in the same BB as I or Use == I or Use comes
7579-
// before I in the block. The latter two can be the case if Use is a PHI
7580-
// node.
7599+
// before I in the block. The latter two can be the case if Use is a
7600+
// PHI node.
75817601
if (Use->getParent() != I->getParent() || Use == I || Use->comesBefore(I))
75827602
return false;
75837603

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2+
; RUN: opt < %s -passes=inline,simplifycfg -S | FileCheck --check-prefix=CUSTOM %s
3+
; RUN: opt < %s -O2 -S | FileCheck --check-prefix=O2 %s
4+
5+
define internal ptr @bar(ptr %arg, i1 %arg1) {
6+
bb:
7+
br i1 %arg1, label %bb4, label %bb2
8+
9+
bb2:
10+
%i = load ptr, ptr %arg, align 8
11+
%i3 = getelementptr inbounds i8, ptr %i, i64 1
12+
store ptr %i3, ptr %arg, align 8
13+
br label %bb4
14+
15+
bb4:
16+
%i5 = phi ptr [ %i, %bb2 ], [ null, %bb ]
17+
ret ptr %i5
18+
}
19+
20+
define i32 @foo(ptr %arg, i1 %arg1) {
21+
; CUSTOM-LABEL: define i32 @foo(
22+
; CUSTOM-SAME: ptr [[ARG:%.*]], i1 [[ARG1:%.*]]) {
23+
; CUSTOM-NEXT: [[BB:.*:]]
24+
; CUSTOM-NEXT: [[TMP0:%.*]] = xor i1 [[ARG1]], true
25+
; CUSTOM-NEXT: call void @llvm.assume(i1 [[TMP0]])
26+
; CUSTOM-NEXT: [[I_I:%.*]] = load ptr, ptr [[ARG]], align 8
27+
; CUSTOM-NEXT: [[I3_I:%.*]] = getelementptr inbounds i8, ptr [[I_I]], i64 1
28+
; CUSTOM-NEXT: store ptr [[I3_I]], ptr [[ARG]], align 8
29+
; CUSTOM-NEXT: [[I2:%.*]] = icmp ne ptr [[I_I]], null
30+
; CUSTOM-NEXT: call void @llvm.assume(i1 [[I2]])
31+
; CUSTOM-NEXT: [[I3:%.*]] = load i32, ptr [[I_I]], align 4
32+
; CUSTOM-NEXT: ret i32 [[I3]]
33+
;
34+
; O2-LABEL: define i32 @foo(
35+
; O2-SAME: ptr nocapture [[ARG:%.*]], i1 [[ARG1:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
36+
; O2-NEXT: [[BB:.*:]]
37+
; O2-NEXT: [[TMP0:%.*]] = xor i1 [[ARG1]], true
38+
; O2-NEXT: tail call void @llvm.assume(i1 [[TMP0]])
39+
; O2-NEXT: [[I_I:%.*]] = load ptr, ptr [[ARG]], align 8, !nonnull [[META0:![0-9]+]], !noundef [[META0]]
40+
; O2-NEXT: [[I3_I:%.*]] = getelementptr inbounds i8, ptr [[I_I]], i64 1
41+
; O2-NEXT: store ptr [[I3_I]], ptr [[ARG]], align 8
42+
; O2-NEXT: [[I3:%.*]] = load i32, ptr [[I_I]], align 4
43+
; O2-NEXT: ret i32 [[I3]]
44+
;
45+
bb:
46+
%i = call ptr @bar(ptr %arg, i1 %arg1)
47+
%i2 = icmp ne ptr %i, null
48+
call void @llvm.assume(i1 %i2)
49+
%i3 = load i32, ptr %i, align 4
50+
ret i32 %i3
51+
}
52+
53+
declare void @llvm.assume(i1)
54+
;.
55+
; O2: [[META0]] = !{}
56+
;.

llvm/test/Transforms/SimplifyCFG/UnreachableEliminate.ll

+66-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ F:
2020
define void @test2() personality ptr @__gxx_personality_v0 {
2121
; CHECK-LABEL: @test2(
2222
; CHECK-NEXT: entry:
23-
; CHECK-NEXT: call void @test2() #[[ATTR3:[0-9]+]]
23+
; CHECK-NEXT: call void @test2() #[[ATTR4:[0-9]+]]
2424
; CHECK-NEXT: ret void
2525
;
2626
entry:
@@ -242,6 +242,8 @@ declare ptr @fn_nonnull_deref_arg(ptr nonnull dereferenceable(4) %p)
242242
declare ptr @fn_nonnull_deref_or_null_arg(ptr nonnull dereferenceable_or_null(4) %p)
243243
declare ptr @fn_nonnull_arg(ptr nonnull %p)
244244
declare ptr @fn_noundef_arg(ptr noundef %p)
245+
declare ptr @fn_ptr_arg(ptr)
246+
declare ptr @fn_ptr_arg_nounwind_willreturn(ptr) nounwind willreturn
245247

246248
define void @test9(i1 %X, ptr %Y) {
247249
; CHECK-LABEL: @test9(
@@ -855,10 +857,72 @@ exit:
855857
ret i32 %res
856858
}
857859

860+
; From bb to bb5 is UB.
861+
define i32 @test9_null_user_order_1(ptr %arg, i1 %arg1, ptr %arg2) {
862+
; CHECK-LABEL: @test9_null_user_order_1(
863+
; CHECK-NEXT: bb:
864+
; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[ARG1:%.*]], true
865+
; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]])
866+
; CHECK-NEXT: [[I:%.*]] = load ptr, ptr [[ARG:%.*]], align 8
867+
; CHECK-NEXT: [[I4:%.*]] = getelementptr inbounds i8, ptr [[I]], i64 1
868+
; CHECK-NEXT: store ptr [[I4]], ptr [[ARG]], align 8
869+
; CHECK-NEXT: [[I7:%.*]] = load i32, ptr [[I]], align 4
870+
; CHECK-NEXT: [[I8:%.*]] = icmp ne ptr [[I]], [[ARG2:%.*]]
871+
; CHECK-NEXT: call void @fn_ptr_arg(i1 [[I8]])
872+
; CHECK-NEXT: ret i32 [[I7]]
873+
;
874+
bb:
875+
br i1 %arg1, label %bb5, label %bb3
876+
877+
bb3: ; preds = %bb
878+
%i = load ptr, ptr %arg, align 8
879+
%i4 = getelementptr inbounds i8, ptr %i, i64 1
880+
store ptr %i4, ptr %arg, align 8
881+
br label %bb5
882+
883+
bb5: ; preds = %bb3, %bb
884+
%i6 = phi ptr [ %i, %bb3 ], [ null, %bb ]
885+
%i7 = load i32, ptr %i6, align 4
886+
%i8 = icmp ne ptr %i6, %arg2
887+
call void @fn_ptr_arg(i1 %i8)
888+
ret i32 %i7
889+
}
890+
891+
define i32 @test9_null_user_order_2(ptr %arg, i1 %arg1, ptr %arg2) {
892+
; CHECK-LABEL: @test9_null_user_order_2(
893+
; CHECK-NEXT: bb:
894+
; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[ARG1:%.*]], true
895+
; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]])
896+
; CHECK-NEXT: [[I:%.*]] = load ptr, ptr [[ARG:%.*]], align 8
897+
; CHECK-NEXT: [[I4:%.*]] = getelementptr inbounds i8, ptr [[I]], i64 1
898+
; CHECK-NEXT: store ptr [[I4]], ptr [[ARG]], align 8
899+
; CHECK-NEXT: [[I8:%.*]] = icmp ne ptr [[I]], [[ARG2:%.*]]
900+
; CHECK-NEXT: call void @fn_ptr_arg_nounwind_willreturn(i1 [[I8]])
901+
; CHECK-NEXT: [[I7:%.*]] = load i32, ptr [[I]], align 4
902+
; CHECK-NEXT: ret i32 [[I7]]
903+
;
904+
bb:
905+
br i1 %arg1, label %bb5, label %bb3
906+
907+
bb3: ; preds = %bb
908+
%i = load ptr, ptr %arg, align 8
909+
%i4 = getelementptr inbounds i8, ptr %i, i64 1
910+
store ptr %i4, ptr %arg, align 8
911+
br label %bb5
912+
913+
bb5: ; preds = %bb3, %bb
914+
%i6 = phi ptr [ %i, %bb3 ], [ null, %bb ]
915+
%i8 = icmp ne ptr %i6, %arg2
916+
call void @fn_ptr_arg_nounwind_willreturn(i1 %i8)
917+
%i7 = load i32, ptr %i6, align 4
918+
ret i32 %i7
919+
}
920+
858921
attributes #0 = { null_pointer_is_valid }
859922
;.
860923
; CHECK: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) }
861924
; CHECK: attributes #[[ATTR1:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
862925
; CHECK: attributes #[[ATTR2:[0-9]+]] = { null_pointer_is_valid }
863-
; CHECK: attributes #[[ATTR3]] = { nounwind }
926+
; CHECK: attributes #[[ATTR3:[0-9]+]] = { nounwind willreturn }
927+
; CHECK: attributes #[[ATTR4]] = { nounwind }
864928
;.

0 commit comments

Comments
 (0)