-
Notifications
You must be signed in to change notification settings - Fork 13k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[SimplifyCFG] Select the first instruction that we can handle in passingValueIsAlwaysUndefined
#98802
Conversation
…singValueIsAlwaysUndefined`
@llvm/pr-subscribers-llvm-transforms Author: DianQK (DianQK) ChangesFixes #98799. Full diff: https://github.com/llvm/llvm-project/pull/98802.diff 3 Files Affected:
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
new file mode 100644
index 0000000000000..17073fa198202
--- /dev/null
+++ b/llvm/test/Transforms/PhaseOrdering/pr98799-inline-simplifycfg-ub.ll
@@ -0,0 +1,56 @@
+; 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: [[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: [[I2:%.*]] = icmp ne ptr [[I_I]], null
+; CUSTOM-NEXT: call void @llvm.assume(i1 [[I2]])
+; 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: [[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: [[I3:%.*]] = load i32, ptr [[I_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)
+;.
+; O2: [[META0]] = !{}
+;.
diff --git a/llvm/test/Transforms/SimplifyCFG/UnreachableEliminate.ll b/llvm/test/Transforms/SimplifyCFG/UnreachableEliminate.ll
index ef2d3219cca9b..c4602e72ecbce 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,72 @@ exit:
ret i32 %res
}
+; 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: [[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: [[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]]
+;
+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 }
;.
|
IR diff LGTM. I am running compile-time tests :) BTW, I think most of dead blocks are created by JumpThreading. Can we avoid this to further improve compilation time? |
I haven't read the JumpThreading code yet, if it can't be handled within it, perhaps we could create some sort of simple matching pattern to hand over to SimplifyCFG? |
|
I can't reproduce the problem yet, can you provide a more detailed test step? # CMake project
clang++ -D_FILE_OFFSET_BITS=64 -DCMAKE_BOOTSTRAP -DCMake_HAVE_CXX_MAKE_UNIQUE=1 -DCMake_HAVE_CXX_FILESYSTEM=1 -I/home/dianqk/llvm/CMake/build/Bootstrap.cmk -I/home/dianqk/llvm/CMake/Source -I/home/dianqk/llvm/CMake/Source/LexerParser -I/home/dianqk/llvm/CMake/Utilities/std -I/home/dianqk/llvm/CMake/Utilities -c /home/dianqk/llvm/CMake/Source/cmGeneratorExpressionLexer.cxx -o cmGeneratorExpressionLexer.o -emit-llvm -O3 -Xclang -disable-llvm-passes
# cmake (stage 1)
cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_ASSERTIONS=OFF -DBUILD_SHARED_LIBS=ON ...
# main branch
perf stat $LLVM_PROJECT/build-base/bin/opt -O2 cmGeneratorExpressionLexer.o --disable-output
339,409,679 instructions:u
# pr
perf stat $LLVM_PROJECT/build/bin/opt -O2 cmGeneratorExpressionLexer.o --disable-output
338,379,357 instructions:u
# b686e35ec
339,831,704 instructions:u |
It's surprising that b686e35 is making things worse: https://llvm-compile-time-tracker.com/compare.php?from=057abc842e581d01ac0bff435d779e3f506440ad&to=b686e35ecd81ae76fc517d14e133d44ed7ff9f4b&stat=instructions:u. But this PR has not changed overall: https://llvm-compile-time-tracker.com/compare.php?from=181e4c6291c94a38c0ee89d2128f8d70b15d2d23&to=b686e35ecd81ae76fc517d14e133d44ed7ff9f4b&stat=instructions%3Au. |
Can you try with |
Oops, I can reproduce it. b686e35 fixed. |
|
Hmm, at least locally, I can't reproduce |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Thank you!
…singValueIsAlwaysUndefined` (#98802) Summary: Fixes #98799. Test Plan: Reviewers: Subscribers: Tasks: Tags: Differential Revision: https://phabricator.intern.facebook.com/D60251495
Fixes #98799.
Perf: https://llvm-compile-time-tracker.com/compare.php?from=181e4c6291c94a38c0ee89d2128f8d70b15d2d23&to=b686e35ecd81ae76fc517d14e133d44ed7ff9f4b&stat=instructions%3Au