Skip to content

Commit 697fcd0

Browse files
authored
[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 :)
1 parent ee73651 commit 697fcd0

File tree

2 files changed

+233
-0
lines changed

2 files changed

+233
-0
lines changed

llvm/lib/Transforms/Utils/SimplifyCFG.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7524,6 +7524,13 @@ static bool passingValueIsAlwaysUndefined(Value *V, Instruction *I, bool PtrValu
75247524
SI->getPointerAddressSpace())) &&
75257525
SI->getPointerOperand() == I;
75267526

7527+
// llvm.assume(false/undef) always triggers immediate UB.
7528+
if (auto *Assume = dyn_cast<AssumeInst>(Use)) {
7529+
// Ignore assume operand bundles.
7530+
if (I == Assume->getArgOperand(0))
7531+
return true;
7532+
}
7533+
75277534
if (auto *CB = dyn_cast<CallBase>(Use)) {
75287535
if (C->isNullValue() && NullPointerIsDefined(CB->getFunction()))
75297536
return false;

llvm/test/Transforms/SimplifyCFG/UnreachableEliminate.ll

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,7 +627,233 @@ else:
627627
ret void
628628
}
629629

630+
define i32 @test_assume_false(i32 %cond) {
631+
; CHECK-LABEL: @test_assume_false(
632+
; CHECK-NEXT: entry:
633+
; CHECK-NEXT: switch i32 [[COND:%.*]], label [[DEFAULT:%.*]] [
634+
; CHECK-NEXT: i32 0, label [[EXIT:%.*]]
635+
; CHECK-NEXT: i32 1, label [[CASE1:%.*]]
636+
; CHECK-NEXT: i32 2, label [[CASE2:%.*]]
637+
; CHECK-NEXT: ]
638+
; CHECK: case1:
639+
; CHECK-NEXT: br label [[EXIT]]
640+
; CHECK: case2:
641+
; CHECK-NEXT: br label [[EXIT]]
642+
; CHECK: default:
643+
; CHECK-NEXT: unreachable
644+
; CHECK: exit:
645+
; CHECK-NEXT: [[RES:%.*]] = phi i32 [ 2, [[CASE1]] ], [ 3, [[CASE2]] ], [ 1, [[ENTRY:%.*]] ]
646+
; CHECK-NEXT: call void @llvm.assume(i1 true)
647+
; CHECK-NEXT: ret i32 [[RES]]
648+
;
649+
entry:
650+
switch i32 %cond, label %default [
651+
i32 0, label %case0
652+
i32 1, label %case1
653+
i32 2, label %case2
654+
]
655+
656+
case0:
657+
br label %exit
658+
659+
case1:
660+
br label %exit
661+
662+
case2:
663+
br label %exit
664+
665+
default:
666+
br label %exit
667+
668+
exit:
669+
%bool = phi i1 [ false, %default ], [ true, %case0 ], [ true, %case1 ], [ true, %case2 ]
670+
%res = phi i32 [ 0, %default ], [ 1, %case0 ], [ 2, %case1 ], [ 3, %case2 ]
671+
call void @llvm.assume(i1 %bool)
672+
ret i32 %res
673+
}
674+
675+
define i32 @test_assume_undef(i32 %cond) {
676+
; CHECK-LABEL: @test_assume_undef(
677+
; CHECK-NEXT: entry:
678+
; CHECK-NEXT: switch i32 [[COND:%.*]], label [[DEFAULT:%.*]] [
679+
; CHECK-NEXT: i32 0, label [[EXIT:%.*]]
680+
; CHECK-NEXT: i32 1, label [[CASE1:%.*]]
681+
; CHECK-NEXT: i32 2, label [[CASE2:%.*]]
682+
; CHECK-NEXT: ]
683+
; CHECK: case1:
684+
; CHECK-NEXT: br label [[EXIT]]
685+
; CHECK: case2:
686+
; CHECK-NEXT: br label [[EXIT]]
687+
; CHECK: default:
688+
; CHECK-NEXT: unreachable
689+
; CHECK: exit:
690+
; CHECK-NEXT: [[RES:%.*]] = phi i32 [ 2, [[CASE1]] ], [ 3, [[CASE2]] ], [ 1, [[ENTRY:%.*]] ]
691+
; CHECK-NEXT: call void @llvm.assume(i1 true)
692+
; CHECK-NEXT: ret i32 [[RES]]
693+
;
694+
entry:
695+
switch i32 %cond, label %default [
696+
i32 0, label %case0
697+
i32 1, label %case1
698+
i32 2, label %case2
699+
]
700+
701+
case0:
702+
br label %exit
703+
704+
case1:
705+
br label %exit
706+
707+
case2:
708+
br label %exit
709+
710+
default:
711+
br label %exit
712+
713+
exit:
714+
%bool = phi i1 [ undef, %default ], [ true, %case0 ], [ true, %case1 ], [ true, %case2 ]
715+
%res = phi i32 [ 0, %default ], [ 1, %case0 ], [ 2, %case1 ], [ 3, %case2 ]
716+
call void @llvm.assume(i1 %bool)
717+
ret i32 %res
718+
}
719+
720+
define i32 @test_assume_var(i32 %cond, i1 %var) {
721+
; CHECK-LABEL: @test_assume_var(
722+
; CHECK-NEXT: entry:
723+
; CHECK-NEXT: switch i32 [[COND:%.*]], label [[DEFAULT:%.*]] [
724+
; CHECK-NEXT: i32 0, label [[EXIT:%.*]]
725+
; CHECK-NEXT: i32 1, label [[CASE1:%.*]]
726+
; CHECK-NEXT: i32 2, label [[CASE2:%.*]]
727+
; CHECK-NEXT: ]
728+
; CHECK: case1:
729+
; CHECK-NEXT: br label [[EXIT]]
730+
; CHECK: case2:
731+
; CHECK-NEXT: br label [[EXIT]]
732+
; CHECK: default:
733+
; CHECK-NEXT: br label [[EXIT]]
734+
; CHECK: exit:
735+
; CHECK-NEXT: [[BOOL:%.*]] = phi i1 [ [[VAR:%.*]], [[DEFAULT]] ], [ true, [[CASE1]] ], [ true, [[CASE2]] ], [ true, [[ENTRY:%.*]] ]
736+
; CHECK-NEXT: [[RES:%.*]] = phi i32 [ 0, [[DEFAULT]] ], [ 2, [[CASE1]] ], [ 3, [[CASE2]] ], [ 1, [[ENTRY]] ]
737+
; CHECK-NEXT: call void @llvm.assume(i1 [[BOOL]])
738+
; CHECK-NEXT: ret i32 [[RES]]
739+
;
740+
entry:
741+
switch i32 %cond, label %default [
742+
i32 0, label %case0
743+
i32 1, label %case1
744+
i32 2, label %case2
745+
]
746+
747+
case0:
748+
br label %exit
630749

750+
case1:
751+
br label %exit
752+
753+
case2:
754+
br label %exit
755+
756+
default:
757+
br label %exit
758+
759+
exit:
760+
%bool = phi i1 [ %var, %default ], [ true, %case0 ], [ true, %case1 ], [ true, %case2 ]
761+
%res = phi i32 [ 0, %default ], [ 1, %case0 ], [ 2, %case1 ], [ 3, %case2 ]
762+
call void @llvm.assume(i1 %bool)
763+
ret i32 %res
764+
}
765+
766+
define i32 @test_assume_bundle_nonnull(i32 %cond, ptr nonnull %p) {
767+
; CHECK-LABEL: @test_assume_bundle_nonnull(
768+
; CHECK-NEXT: entry:
769+
; CHECK-NEXT: switch i32 [[COND:%.*]], label [[DEFAULT:%.*]] [
770+
; CHECK-NEXT: i32 0, label [[EXIT:%.*]]
771+
; CHECK-NEXT: i32 1, label [[CASE1:%.*]]
772+
; CHECK-NEXT: i32 2, label [[CASE2:%.*]]
773+
; CHECK-NEXT: ]
774+
; CHECK: case1:
775+
; CHECK-NEXT: br label [[EXIT]]
776+
; CHECK: case2:
777+
; CHECK-NEXT: br label [[EXIT]]
778+
; CHECK: default:
779+
; CHECK-NEXT: br label [[EXIT]]
780+
; CHECK: exit:
781+
; CHECK-NEXT: [[PTR:%.*]] = phi ptr [ null, [[DEFAULT]] ], [ [[P:%.*]], [[CASE1]] ], [ [[P]], [[CASE2]] ], [ [[P]], [[ENTRY:%.*]] ]
782+
; CHECK-NEXT: [[RES:%.*]] = phi i32 [ 0, [[DEFAULT]] ], [ 2, [[CASE1]] ], [ 3, [[CASE2]] ], [ 1, [[ENTRY]] ]
783+
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(ptr [[PTR]]) ]
784+
; CHECK-NEXT: ret i32 [[RES]]
785+
;
786+
entry:
787+
switch i32 %cond, label %default [
788+
i32 0, label %case0
789+
i32 1, label %case1
790+
i32 2, label %case2
791+
]
792+
793+
case0:
794+
br label %exit
795+
796+
case1:
797+
br label %exit
798+
799+
case2:
800+
br label %exit
801+
802+
default:
803+
br label %exit
804+
805+
exit:
806+
%ptr = phi ptr [ null, %default ], [ %p, %case0 ], [ %p, %case1 ], [ %p, %case2 ]
807+
%res = phi i32 [ 0, %default ], [ 1, %case0 ], [ 2, %case1 ], [ 3, %case2 ]
808+
call void @llvm.assume(i1 true) [ "nonnull"(ptr %ptr) ]
809+
ret i32 %res
810+
}
811+
812+
define i32 @test_assume_bundle_align(i32 %cond, ptr nonnull %p) {
813+
; CHECK-LABEL: @test_assume_bundle_align(
814+
; CHECK-NEXT: entry:
815+
; CHECK-NEXT: switch i32 [[COND:%.*]], label [[DEFAULT:%.*]] [
816+
; CHECK-NEXT: i32 0, label [[EXIT:%.*]]
817+
; CHECK-NEXT: i32 1, label [[CASE1:%.*]]
818+
; CHECK-NEXT: i32 2, label [[CASE2:%.*]]
819+
; CHECK-NEXT: ]
820+
; CHECK: case1:
821+
; CHECK-NEXT: br label [[EXIT]]
822+
; CHECK: case2:
823+
; CHECK-NEXT: br label [[EXIT]]
824+
; CHECK: default:
825+
; CHECK-NEXT: br label [[EXIT]]
826+
; CHECK: exit:
827+
; CHECK-NEXT: [[PTR:%.*]] = phi ptr [ null, [[DEFAULT]] ], [ [[P:%.*]], [[CASE1]] ], [ [[P]], [[CASE2]] ], [ [[P]], [[ENTRY:%.*]] ]
828+
; CHECK-NEXT: [[RES:%.*]] = phi i32 [ 0, [[DEFAULT]] ], [ 2, [[CASE1]] ], [ 3, [[CASE2]] ], [ 1, [[ENTRY]] ]
829+
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[PTR]], i32 8) ]
830+
; CHECK-NEXT: ret i32 [[RES]]
831+
;
832+
entry:
833+
switch i32 %cond, label %default [
834+
i32 0, label %case0
835+
i32 1, label %case1
836+
i32 2, label %case2
837+
]
838+
839+
case0:
840+
br label %exit
841+
842+
case1:
843+
br label %exit
844+
845+
case2:
846+
br label %exit
847+
848+
default:
849+
br label %exit
850+
851+
exit:
852+
%ptr = phi ptr [ null, %default ], [ %p, %case0 ], [ %p, %case1 ], [ %p, %case2 ]
853+
%res = phi i32 [ 0, %default ], [ 1, %case0 ], [ 2, %case1 ], [ 3, %case2 ]
854+
call void @llvm.assume(i1 true) [ "align"(ptr %ptr, i32 8) ]
855+
ret i32 %res
856+
}
631857

632858
attributes #0 = { null_pointer_is_valid }
633859
;.

0 commit comments

Comments
 (0)