[llvm] 697fcd0 - [SimplifyCFG] Handle `llvm.assume` in `passingValueIsAlwaysUndefined` (#89929)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Apr 25 05:48:00 PDT 2024
Author: Yingwei Zheng
Date: 2024-04-25T20:47:56+08:00
New Revision: 697fcd009855a579f756dfe34498a815ed9dc3fd
URL: https://github.com/llvm/llvm-project/commit/697fcd009855a579f756dfe34498a815ed9dc3fd
DIFF: https://github.com/llvm/llvm-project/commit/697fcd009855a579f756dfe34498a815ed9dc3fd.diff
LOG: [SimplifyCFG] Handle `llvm.assume` in `passingValueIsAlwaysUndefined` (#89929)
See the following example:
```
define i32 @test(i32 %cond) {
entry:
switch i32 %cond, label %default [
i32 0, label %case0
i32 1, label %case1
i32 2, label %case2
]
case0:
br label %exit
case1:
br label %exit
case2:
br label %exit
default:
br label %exit
exit:
%bool = phi i1 [ false, %default ], [ true, %case0 ], [ true, %case1 ], [ true, %case2 ]
%res = phi i32 [ 0, %default ], [ 1, %case0 ], [ 2, %case1 ], [ 3, %case2 ]
call void @llvm.assume(i1 %bool)
ret i32 %res
}
```
The edge `%default -> %bool` is dead since it will trigger an immediate
UB.
Alive2: https://alive2.llvm.org/ce/z/gywJiE
My benchmark shows many rust applications and some c/c++ applications
(e.g., arrow/php/qemu) will benefit from this patch :)
Added:
Modified:
llvm/lib/Transforms/Utils/SimplifyCFG.cpp
llvm/test/Transforms/SimplifyCFG/UnreachableEliminate.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 3eda669eb8a726..4db72461c95e47 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -7524,6 +7524,13 @@ static bool passingValueIsAlwaysUndefined(Value *V, Instruction *I, bool PtrValu
SI->getPointerAddressSpace())) &&
SI->getPointerOperand() == I;
+ // llvm.assume(false/undef) always triggers immediate UB.
+ if (auto *Assume = dyn_cast<AssumeInst>(Use)) {
+ // Ignore assume operand bundles.
+ if (I == Assume->getArgOperand(0))
+ return true;
+ }
+
if (auto *CB = dyn_cast<CallBase>(Use)) {
if (C->isNullValue() && NullPointerIsDefined(CB->getFunction()))
return false;
diff --git a/llvm/test/Transforms/SimplifyCFG/UnreachableEliminate.ll b/llvm/test/Transforms/SimplifyCFG/UnreachableEliminate.ll
index 757340527ec030..ef2d3219cca9b6 100644
--- a/llvm/test/Transforms/SimplifyCFG/UnreachableEliminate.ll
+++ b/llvm/test/Transforms/SimplifyCFG/UnreachableEliminate.ll
@@ -627,7 +627,233 @@ else:
ret void
}
+define i32 @test_assume_false(i32 %cond) {
+; CHECK-LABEL: @test_assume_false(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: switch i32 [[COND:%.*]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT: i32 0, label [[EXIT:%.*]]
+; CHECK-NEXT: i32 1, label [[CASE1:%.*]]
+; CHECK-NEXT: i32 2, label [[CASE2:%.*]]
+; CHECK-NEXT: ]
+; CHECK: case1:
+; CHECK-NEXT: br label [[EXIT]]
+; CHECK: case2:
+; CHECK-NEXT: br label [[EXIT]]
+; CHECK: default:
+; CHECK-NEXT: unreachable
+; CHECK: exit:
+; CHECK-NEXT: [[RES:%.*]] = phi i32 [ 2, [[CASE1]] ], [ 3, [[CASE2]] ], [ 1, [[ENTRY:%.*]] ]
+; CHECK-NEXT: call void @llvm.assume(i1 true)
+; CHECK-NEXT: ret i32 [[RES]]
+;
+entry:
+ switch i32 %cond, label %default [
+ i32 0, label %case0
+ i32 1, label %case1
+ i32 2, label %case2
+ ]
+
+case0:
+ br label %exit
+
+case1:
+ br label %exit
+
+case2:
+ br label %exit
+
+default:
+ br label %exit
+
+exit:
+ %bool = phi i1 [ false, %default ], [ true, %case0 ], [ true, %case1 ], [ true, %case2 ]
+ %res = phi i32 [ 0, %default ], [ 1, %case0 ], [ 2, %case1 ], [ 3, %case2 ]
+ call void @llvm.assume(i1 %bool)
+ ret i32 %res
+}
+
+define i32 @test_assume_undef(i32 %cond) {
+; CHECK-LABEL: @test_assume_undef(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: switch i32 [[COND:%.*]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT: i32 0, label [[EXIT:%.*]]
+; CHECK-NEXT: i32 1, label [[CASE1:%.*]]
+; CHECK-NEXT: i32 2, label [[CASE2:%.*]]
+; CHECK-NEXT: ]
+; CHECK: case1:
+; CHECK-NEXT: br label [[EXIT]]
+; CHECK: case2:
+; CHECK-NEXT: br label [[EXIT]]
+; CHECK: default:
+; CHECK-NEXT: unreachable
+; CHECK: exit:
+; CHECK-NEXT: [[RES:%.*]] = phi i32 [ 2, [[CASE1]] ], [ 3, [[CASE2]] ], [ 1, [[ENTRY:%.*]] ]
+; CHECK-NEXT: call void @llvm.assume(i1 true)
+; CHECK-NEXT: ret i32 [[RES]]
+;
+entry:
+ switch i32 %cond, label %default [
+ i32 0, label %case0
+ i32 1, label %case1
+ i32 2, label %case2
+ ]
+
+case0:
+ br label %exit
+
+case1:
+ br label %exit
+
+case2:
+ br label %exit
+
+default:
+ br label %exit
+
+exit:
+ %bool = phi i1 [ undef, %default ], [ true, %case0 ], [ true, %case1 ], [ true, %case2 ]
+ %res = phi i32 [ 0, %default ], [ 1, %case0 ], [ 2, %case1 ], [ 3, %case2 ]
+ call void @llvm.assume(i1 %bool)
+ ret i32 %res
+}
+
+define i32 @test_assume_var(i32 %cond, i1 %var) {
+; CHECK-LABEL: @test_assume_var(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: switch i32 [[COND:%.*]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT: i32 0, label [[EXIT:%.*]]
+; CHECK-NEXT: i32 1, label [[CASE1:%.*]]
+; CHECK-NEXT: i32 2, label [[CASE2:%.*]]
+; CHECK-NEXT: ]
+; CHECK: case1:
+; CHECK-NEXT: br label [[EXIT]]
+; CHECK: case2:
+; CHECK-NEXT: br label [[EXIT]]
+; CHECK: default:
+; CHECK-NEXT: br label [[EXIT]]
+; CHECK: exit:
+; CHECK-NEXT: [[BOOL:%.*]] = phi i1 [ [[VAR:%.*]], [[DEFAULT]] ], [ true, [[CASE1]] ], [ true, [[CASE2]] ], [ true, [[ENTRY:%.*]] ]
+; CHECK-NEXT: [[RES:%.*]] = phi i32 [ 0, [[DEFAULT]] ], [ 2, [[CASE1]] ], [ 3, [[CASE2]] ], [ 1, [[ENTRY]] ]
+; CHECK-NEXT: call void @llvm.assume(i1 [[BOOL]])
+; CHECK-NEXT: ret i32 [[RES]]
+;
+entry:
+ switch i32 %cond, label %default [
+ i32 0, label %case0
+ i32 1, label %case1
+ i32 2, label %case2
+ ]
+
+case0:
+ br label %exit
+case1:
+ br label %exit
+
+case2:
+ br label %exit
+
+default:
+ br label %exit
+
+exit:
+ %bool = phi i1 [ %var, %default ], [ true, %case0 ], [ true, %case1 ], [ true, %case2 ]
+ %res = phi i32 [ 0, %default ], [ 1, %case0 ], [ 2, %case1 ], [ 3, %case2 ]
+ call void @llvm.assume(i1 %bool)
+ ret i32 %res
+}
+
+define i32 @test_assume_bundle_nonnull(i32 %cond, ptr nonnull %p) {
+; CHECK-LABEL: @test_assume_bundle_nonnull(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: switch i32 [[COND:%.*]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT: i32 0, label [[EXIT:%.*]]
+; CHECK-NEXT: i32 1, label [[CASE1:%.*]]
+; CHECK-NEXT: i32 2, label [[CASE2:%.*]]
+; CHECK-NEXT: ]
+; CHECK: case1:
+; CHECK-NEXT: br label [[EXIT]]
+; CHECK: case2:
+; CHECK-NEXT: br label [[EXIT]]
+; CHECK: default:
+; CHECK-NEXT: br label [[EXIT]]
+; CHECK: exit:
+; CHECK-NEXT: [[PTR:%.*]] = phi ptr [ null, [[DEFAULT]] ], [ [[P:%.*]], [[CASE1]] ], [ [[P]], [[CASE2]] ], [ [[P]], [[ENTRY:%.*]] ]
+; CHECK-NEXT: [[RES:%.*]] = phi i32 [ 0, [[DEFAULT]] ], [ 2, [[CASE1]] ], [ 3, [[CASE2]] ], [ 1, [[ENTRY]] ]
+; CHECK-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(ptr [[PTR]]) ]
+; CHECK-NEXT: ret i32 [[RES]]
+;
+entry:
+ switch i32 %cond, label %default [
+ i32 0, label %case0
+ i32 1, label %case1
+ i32 2, label %case2
+ ]
+
+case0:
+ br label %exit
+
+case1:
+ br label %exit
+
+case2:
+ br label %exit
+
+default:
+ br label %exit
+
+exit:
+ %ptr = phi ptr [ null, %default ], [ %p, %case0 ], [ %p, %case1 ], [ %p, %case2 ]
+ %res = phi i32 [ 0, %default ], [ 1, %case0 ], [ 2, %case1 ], [ 3, %case2 ]
+ call void @llvm.assume(i1 true) [ "nonnull"(ptr %ptr) ]
+ ret i32 %res
+}
+
+define i32 @test_assume_bundle_align(i32 %cond, ptr nonnull %p) {
+; CHECK-LABEL: @test_assume_bundle_align(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: switch i32 [[COND:%.*]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT: i32 0, label [[EXIT:%.*]]
+; CHECK-NEXT: i32 1, label [[CASE1:%.*]]
+; CHECK-NEXT: i32 2, label [[CASE2:%.*]]
+; CHECK-NEXT: ]
+; CHECK: case1:
+; CHECK-NEXT: br label [[EXIT]]
+; CHECK: case2:
+; CHECK-NEXT: br label [[EXIT]]
+; CHECK: default:
+; CHECK-NEXT: br label [[EXIT]]
+; CHECK: exit:
+; CHECK-NEXT: [[PTR:%.*]] = phi ptr [ null, [[DEFAULT]] ], [ [[P:%.*]], [[CASE1]] ], [ [[P]], [[CASE2]] ], [ [[P]], [[ENTRY:%.*]] ]
+; CHECK-NEXT: [[RES:%.*]] = phi i32 [ 0, [[DEFAULT]] ], [ 2, [[CASE1]] ], [ 3, [[CASE2]] ], [ 1, [[ENTRY]] ]
+; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[PTR]], i32 8) ]
+; CHECK-NEXT: ret i32 [[RES]]
+;
+entry:
+ switch i32 %cond, label %default [
+ i32 0, label %case0
+ i32 1, label %case1
+ i32 2, label %case2
+ ]
+
+case0:
+ br label %exit
+
+case1:
+ br label %exit
+
+case2:
+ br label %exit
+
+default:
+ br label %exit
+
+exit:
+ %ptr = phi ptr [ null, %default ], [ %p, %case0 ], [ %p, %case1 ], [ %p, %case2 ]
+ %res = phi i32 [ 0, %default ], [ 1, %case0 ], [ 2, %case1 ], [ 3, %case2 ]
+ call void @llvm.assume(i1 true) [ "align"(ptr %ptr, i32 8) ]
+ ret i32 %res
+}
attributes #0 = { null_pointer_is_valid }
;.
More information about the llvm-commits
mailing list