1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 18:54:02 +01:00
llvm-mirror/test/Transforms/SimplifyCFG/UnreachableEliminate.ll
Teresa Johnson 2ba9de8337 [SimplifyCFG] Look for control flow changes instead of side effects.
When passingValueIsAlwaysUndefined scans for an instruction between an
inst with a null or undef argument and its first use, it was checking
for instructions that may have side effects, which is a superset of the
instructions it intended to find (as per the comments, control flow
changing instructions that would prevent reaching the uses). Switch
to using isGuaranteedToTransferExecutionToSuccessor() instead.

Without this change, when enabling -fwhole-program-vtables, which causes
assumes to be inserted by clang, we can get different simplification
decisions. In particular, when building with instrumentation FDO it can
affect the optimizations decisions before FDO matching, leading to some
mismatches.

I had to modify d83507-knowledge-retention-bug.ll since this fix enables
more aggressive optimization of that code such that it no longer tested
the original bug it was meant to test. I removed the undef which still
provokes the original failure (confirmed by temporarily reverting the
fix) and also changed it to just invoke the passes of interest to narrow
the testing.

Similarly I needed to adjust code for UnreachableEliminate.ll to avoid
an undef which was causing the function body to get optimized away with
this fix.

Differential Revision: https://reviews.llvm.org/D101507
2021-05-03 13:32:22 -07:00

579 lines
14 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s
define void @test1(i1 %C, i1* %BP) {
; CHECK-LABEL: @test1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[C:%.*]], true
; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]])
; CHECK-NEXT: ret void
;
entry:
br i1 %C, label %T, label %F
T:
store i1 %C, i1* %BP
unreachable
F:
ret void
}
define void @test2() personality i32 (...)* @__gxx_personality_v0 {
; CHECK-LABEL: @test2(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @test2()
; CHECK-NEXT: ret void
;
entry:
invoke void @test2( )
to label %N unwind label %U
U:
%res = landingpad { i8* }
cleanup
unreachable
N:
ret void
}
declare i32 @__gxx_personality_v0(...)
define i32 @test3(i32 %v) {
; CHECK-LABEL: @test3(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[V:%.*]], 2
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[COND]], i32 2, i32 1
; CHECK-NEXT: ret i32 [[SPEC_SELECT]]
;
entry:
switch i32 %v, label %default [
i32 1, label %U
i32 2, label %T
]
default:
ret i32 1
U:
unreachable
T:
ret i32 2
}
;; We can either convert the following control-flow to a select or remove the
;; unreachable control flow because of the undef store of null. Make sure we do
;; the latter.
define void @test5(i1 %cond, i8* %ptr) {
; CHECK-LABEL: @test5(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[COND:%.*]], true
; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]])
; CHECK-NEXT: store i8 2, i8* [[PTR:%.*]], align 8
; CHECK-NEXT: ret void
;
entry:
br i1 %cond, label %bb1, label %bb3
bb3:
br label %bb2
bb1:
br label %bb2
bb2:
%ptr.2 = phi i8* [ %ptr, %bb3 ], [ null, %bb1 ]
store i8 2, i8* %ptr.2, align 8
ret void
}
declare void @llvm.assume(i1)
declare i1 @llvm.type.test(i8*, metadata) nounwind readnone
;; Same as the above test but make sure the unreachable control flow is still
;; removed in the presence of a type test / assume sequence.
define void @test5_type_test_assume(i1 %cond, i8* %ptr, [3 x i8*]* %vtable) {
; CHECK-LABEL: @test5_type_test_assume(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[COND:%.*]], true
; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]])
; CHECK-NEXT: [[VTABLE:%.*]] = bitcast [3 x i8*]* %vtable to i8*
; CHECK-NEXT: [[P:%.*]] = call i1 @llvm.type.test(i8* [[VTABLE]], metadata !"foo")
; CHECK-NEXT: tail call void @llvm.assume(i1 [[P]])
; CHECK-NEXT: store i8 2, i8* [[PTR:%.*]], align 8
; CHECK-NEXT: ret void
;
entry:
br i1 %cond, label %bb1, label %bb3
bb3:
br label %bb2
bb1:
br label %bb2
bb2:
%ptr.2 = phi i8* [ %ptr, %bb3 ], [ null, %bb1 ]
%vtablei8 = bitcast [3 x i8*]* %vtable to i8*
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"foo")
tail call void @llvm.assume(i1 %p)
store i8 2, i8* %ptr.2, align 8
ret void
}
define void @test5_no_null_opt(i1 %cond, i8* %ptr) #0 {
; CHECK-LABEL: @test5_no_null_opt(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[PTR_2:%.*]] = select i1 [[COND:%.*]], i8* null, i8* [[PTR:%.*]]
; CHECK-NEXT: store i8 2, i8* [[PTR_2]], align 8
; CHECK-NEXT: ret void
;
entry:
br i1 %cond, label %bb1, label %bb3
bb3:
br label %bb2
bb1:
br label %bb2
bb2:
%ptr.2 = phi i8* [ %ptr, %bb3 ], [ null, %bb1 ]
store i8 2, i8* %ptr.2, align 8
ret void
}
define void @test6(i1 %cond, i8* %ptr) {
; CHECK-LABEL: @test6(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[COND:%.*]], true
; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]])
; CHECK-NEXT: store i8 2, i8* [[PTR:%.*]], align 8
; CHECK-NEXT: ret void
;
entry:
br i1 %cond, label %bb1, label %bb2
bb1:
br label %bb2
bb2:
%ptr.2 = phi i8* [ %ptr, %entry ], [ null, %bb1 ]
store i8 2, i8* %ptr.2, align 8
ret void
}
define void @test6_no_null_opt(i1 %cond, i8* %ptr) #0 {
; CHECK-LABEL: @test6_no_null_opt(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[COND:%.*]], i8* null, i8* [[PTR:%.*]]
; CHECK-NEXT: store i8 2, i8* [[SPEC_SELECT]], align 8
; CHECK-NEXT: ret void
;
entry:
br i1 %cond, label %bb1, label %bb2
bb1:
br label %bb2
bb2:
%ptr.2 = phi i8* [ %ptr, %entry ], [ null, %bb1 ]
store i8 2, i8* %ptr.2, align 8
ret void
}
define i32 @test7(i1 %X) {
; CHECK-LABEL: @test7(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[X:%.*]], true
; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]])
; CHECK-NEXT: ret i32 0
;
entry:
br i1 %X, label %if, label %else
if:
call void undef()
br label %else
else:
%phi = phi i32 [ 0, %entry ], [ 1, %if ]
ret i32 %phi
}
define void @test8(i1 %X, void ()* %Y) {
; CHECK-LABEL: @test8(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[X:%.*]], true
; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]])
; CHECK-NEXT: call void [[Y:%.*]]()
; CHECK-NEXT: ret void
;
entry:
br i1 %X, label %if, label %else
if:
br label %else
else:
%phi = phi void ()* [ %Y, %entry ], [ null, %if ]
call void %phi()
ret void
}
define void @test8_no_null_opt(i1 %X, void ()* %Y) #0 {
; CHECK-LABEL: @test8_no_null_opt(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[X:%.*]], void ()* null, void ()* [[Y:%.*]]
; CHECK-NEXT: call void [[SPEC_SELECT]]()
; CHECK-NEXT: ret void
;
entry:
br i1 %X, label %if, label %else
if:
br label %else
else:
%phi = phi void ()* [ %Y, %entry ], [ null, %if ]
call void %phi()
ret void
}
declare i8* @fn_nonnull_noundef_arg(i8* nonnull noundef %p)
declare i8* @fn_nonnull_deref_arg(i8* nonnull dereferenceable(4) %p)
declare i8* @fn_nonnull_deref_or_null_arg(i8* nonnull dereferenceable_or_null(4) %p)
declare i8* @fn_nonnull_arg(i8* nonnull %p)
declare i8* @fn_noundef_arg(i8* noundef %p)
define void @test9(i1 %X, i8* %Y) {
; CHECK-LABEL: @test9(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[X:%.*]], true
; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]])
; CHECK-NEXT: [[TMP1:%.*]] = call i8* @fn_nonnull_noundef_arg(i8* [[Y:%.*]])
; CHECK-NEXT: ret void
;
entry:
br i1 %X, label %if, label %else
if:
br label %else
else:
%phi = phi i8* [ %Y, %entry ], [ null, %if ]
call i8* @fn_nonnull_noundef_arg(i8* %phi)
ret void
}
; Optimizing this code should produce assume.
define void @test9_deref(i1 %X, i8* %Y) {
; CHECK-LABEL: @test9_deref(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[X:%.*]], true
; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]])
; CHECK-NEXT: [[TMP1:%.*]] = call i8* @fn_nonnull_deref_arg(i8* [[Y:%.*]])
; CHECK-NEXT: ret void
;
entry:
br i1 %X, label %if, label %else
if:
br label %else
else:
%phi = phi i8* [ %Y, %entry ], [ null, %if ]
call i8* @fn_nonnull_deref_arg(i8* %phi)
ret void
}
; Optimizing this code should produce assume.
define void @test9_deref_or_null(i1 %X, i8* %Y) {
; CHECK-LABEL: @test9_deref_or_null(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[X:%.*]], true
; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]])
; CHECK-NEXT: [[TMP1:%.*]] = call i8* @fn_nonnull_deref_or_null_arg(i8* [[Y:%.*]])
; CHECK-NEXT: ret void
;
entry:
br i1 %X, label %if, label %else
if:
br label %else
else:
%phi = phi i8* [ %Y, %entry ], [ null, %if ]
call i8* @fn_nonnull_deref_or_null_arg(i8* %phi)
ret void
}
define void @test9_undef(i1 %X, i8* %Y) {
; CHECK-LABEL: @test9_undef(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = call i8* @fn_noundef_arg(i8* [[Y:%.*]])
; CHECK-NEXT: ret void
;
entry:
br i1 %X, label %if, label %else
if:
br label %else
else:
%phi = phi i8* [ %Y, %entry ], [ undef, %if ]
call i8* @fn_noundef_arg(i8* %phi)
ret void
}
define void @test9_undef_null_defined(i1 %X, i8* %Y) #0 {
; CHECK-LABEL: @test9_undef_null_defined(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = call i8* @fn_noundef_arg(i8* [[Y:%.*]])
; CHECK-NEXT: ret void
;
entry:
br i1 %X, label %if, label %else
if:
br label %else
else:
%phi = phi i8* [ %Y, %entry ], [ undef, %if ]
call i8* @fn_noundef_arg(i8* %phi)
ret void
}
define void @test9_null_callsite(i1 %X, i8* %Y) {
; CHECK-LABEL: @test9_null_callsite(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[X:%.*]], true
; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]])
; CHECK-NEXT: [[TMP1:%.*]] = call i8* @fn_nonnull_arg(i8* noundef nonnull [[Y:%.*]])
; CHECK-NEXT: ret void
;
entry:
br i1 %X, label %if, label %else
if:
br label %else
else:
%phi = phi i8* [ %Y, %entry ], [ null, %if ]
call i8* @fn_nonnull_arg(i8* nonnull noundef %phi)
ret void
}
define void @test9_gep_mismatch(i1 %X, i8* %Y, i8* %P) {
; CHECK-LABEL: @test9_gep_mismatch(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[X:%.*]], i8* null, i8* [[Y:%.*]]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, i8* [[P:%.*]], i64 0
; CHECK-NEXT: [[TMP0:%.*]] = call i8* @fn_nonnull_noundef_arg(i8* [[GEP]])
; CHECK-NEXT: ret void
;
entry:
br i1 %X, label %if, label %else
if:
br label %else
else:
%phi = phi i8* [ %Y, %entry ], [ null, %if ]
%gep = getelementptr inbounds i8, i8* %P, i64 0
call i8* @fn_nonnull_noundef_arg(i8* %gep)
ret void
}
define void @test9_gep_zero(i1 %X, i8* %Y) {
; CHECK-LABEL: @test9_gep_zero(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[X:%.*]], true
; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]])
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, i8* [[Y:%.*]], i64 0
; CHECK-NEXT: [[TMP1:%.*]] = call i8* @fn_nonnull_noundef_arg(i8* [[GEP]])
; CHECK-NEXT: ret void
;
entry:
br i1 %X, label %if, label %else
if:
br label %else
else:
%phi = phi i8* [ %Y, %entry ], [ null, %if ]
%gep = getelementptr inbounds i8, i8* %phi, i64 0
call i8* @fn_nonnull_noundef_arg(i8* %gep)
ret void
}
define void @test9_gep_bitcast(i1 %X, i32* %Y) {
; CHECK-LABEL: @test9_gep_bitcast(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[X:%.*]], true
; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]])
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i32, i32* [[Y:%.*]], i64 0
; CHECK-NEXT: [[BC:%.*]] = bitcast i32* [[GEP]] to i8*
; CHECK-NEXT: [[TMP1:%.*]] = call i8* @fn_nonnull_noundef_arg(i8* [[BC]])
; CHECK-NEXT: ret void
;
entry:
br i1 %X, label %if, label %else
if:
br label %else
else:
%phi = phi i32* [ %Y, %entry ], [ null, %if ]
%gep = getelementptr inbounds i32, i32* %phi, i64 0
%bc = bitcast i32* %gep to i8*
call i8* @fn_nonnull_noundef_arg(i8* %bc)
ret void
}
define void @test9_gep_nonzero(i1 %X, i8* %Y) {
; CHECK-LABEL: @test9_gep_nonzero(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[X:%.*]], i8* null, i8* [[Y:%.*]]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, i8* [[SPEC_SELECT]], i64 12
; CHECK-NEXT: [[TMP0:%.*]] = call i8* @fn_nonnull_noundef_arg(i8* [[GEP]])
; CHECK-NEXT: ret void
;
entry:
br i1 %X, label %if, label %else
if:
br label %else
else:
%phi = phi i8* [ %Y, %entry ], [ null, %if ]
%gep = getelementptr i8, i8* %phi, i64 12
call i8* @fn_nonnull_noundef_arg(i8* %gep)
ret void
}
define void @test9_gep_inbounds_nonzero(i1 %X, i8* %Y) {
; CHECK-LABEL: @test9_gep_inbounds_nonzero(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[X:%.*]], i8* null, i8* [[Y:%.*]]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, i8* [[SPEC_SELECT]], i64 12
; CHECK-NEXT: [[TMP0:%.*]] = call i8* @fn_nonnull_noundef_arg(i8* [[GEP]])
; CHECK-NEXT: ret void
;
entry:
br i1 %X, label %if, label %else
if:
br label %else
else:
%phi = phi i8* [ %Y, %entry ], [ null, %if ]
%gep = getelementptr inbounds i8, i8* %phi, i64 12
call i8* @fn_nonnull_noundef_arg(i8* %gep)
ret void
}
define void @test9_gep_inbouds_unknown_null(i1 %X, i8* %Y, i64 %I) {
; CHECK-LABEL: @test9_gep_inbouds_unknown_null(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[X:%.*]], i8* null, i8* [[Y:%.*]]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, i8* [[SPEC_SELECT]], i64 [[I:%.*]]
; CHECK-NEXT: [[TMP0:%.*]] = call i8* @fn_nonnull_noundef_arg(i8* [[GEP]])
; CHECK-NEXT: ret void
;
entry:
br i1 %X, label %if, label %else
if:
br label %else
else:
%phi = phi i8* [ %Y, %entry ], [ null, %if ]
%gep = getelementptr inbounds i8, i8* %phi, i64 %I
call i8* @fn_nonnull_noundef_arg(i8* %gep)
ret void
}
define void @test9_gep_unknown_null(i1 %X, i8* %Y, i64 %I) {
; CHECK-LABEL: @test9_gep_unknown_null(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[X:%.*]], i8* null, i8* [[Y:%.*]]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, i8* [[SPEC_SELECT]], i64 [[I:%.*]]
; CHECK-NEXT: [[TMP0:%.*]] = call i8* @fn_nonnull_noundef_arg(i8* [[GEP]])
; CHECK-NEXT: ret void
;
entry:
br i1 %X, label %if, label %else
if:
br label %else
else:
%phi = phi i8* [ %Y, %entry ], [ null, %if ]
%gep = getelementptr i8, i8* %phi, i64 %I
call i8* @fn_nonnull_noundef_arg(i8* %gep)
ret void
}
define void @test9_gep_unknown_undef(i1 %X, i8* %Y, i64 %I) {
; CHECK-LABEL: @test9_gep_unknown_undef(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, i8* [[Y:%.*]], i64 [[I:%.*]]
; CHECK-NEXT: [[TMP0:%.*]] = call i8* @fn_noundef_arg(i8* [[GEP]])
; CHECK-NEXT: ret void
;
entry:
br i1 %X, label %if, label %else
if:
br label %else
else:
%phi = phi i8* [ %Y, %entry ], [ undef, %if ]
%gep = getelementptr i8, i8* %phi, i64 %I
call i8* @fn_noundef_arg(i8* %gep)
ret void
}
define void @test9_missing_noundef(i1 %X, i8* %Y) {
; CHECK-LABEL: @test9_missing_noundef(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[X:%.*]], i8* null, i8* [[Y:%.*]]
; CHECK-NEXT: [[TMP0:%.*]] = call i8* @fn_nonnull_arg(i8* [[SPEC_SELECT]])
; CHECK-NEXT: ret void
;
entry:
br i1 %X, label %if, label %else
if:
br label %else
else:
%phi = phi i8* [ %Y, %entry ], [ null, %if ]
call i8* @fn_nonnull_arg(i8* %phi)
ret void
}
define void @test9_null_defined(i1 %X, i8* %Y) #0 {
; CHECK-LABEL: @test9_null_defined(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[X:%.*]], i8* null, i8* [[Y:%.*]]
; CHECK-NEXT: [[TMP0:%.*]] = call i8* @fn_nonnull_noundef_arg(i8* [[SPEC_SELECT]])
; CHECK-NEXT: ret void
;
entry:
br i1 %X, label %if, label %else
if:
br label %else
else:
%phi = phi i8* [ %Y, %entry ], [ null, %if ]
call i8* @fn_nonnull_noundef_arg(i8* %phi)
ret void
}
attributes #0 = { null_pointer_is_valid }