Roman Lebedev 4f7e5d2206
[SROA] For non-speculatable loads of selects -- split block, insert then/else blocks, form two-entry PHI node, take 2
Currently, SROA is CFG-preserving.
Not doing so does not affect any pipeline test. (???)
Internally, SROA requires Dominator Tree, and uses it solely for the final `-mem2reg` call.

By design, we can't really SROA alloca if their address escapes somehow,
but we have logic to deal with `load` of `select`/`PHI`,
where at least one of the possible addresses prevents promotion,
by speculating the `load`s and `select`ing between loaded values.

As one would expect, that requires ensuring that the speculation is actually legal.
Even ignoring complexity bailouts, that logic does not deal with everything,
e.g. `isSafeToLoadUnconditionally()` does not recurse into hands of `select`.
There can also be cases where the load is genuinely non-speculate.

So if we can't prove that the load can be speculated,
unfold the select, produce two-entry phi node, and perform predicated load.

Now, that transformation must obviously update Dominator Tree,
since we require it later on. Doing so is trivial.
Additionally, we don't want to do this for the final SROA invocation (D136806).

In the end, this ends up having negative (!) compile-time cost:
https://llvm-compile-time-tracker.com/compare.php?from=c6d7e80ec4c17a415673b1cfd25924f98ac83608&to=ddf9600365093ea50d7e278696cbfa01641c959d&stat=instructions:u

Though indeed, this only deals with `select`s, `PHI`s are still using speculation.

Should we update some more analysis?

Reviewed By: arsenm

Differential Revision: https://reviews.llvm.org/D138238

This reverts commit 739611870d3b06605afe25cc07833f6a62de9545,
and recommits 03e6d9d9d1d48e43f3efc35eb75369b90d4510d5
with a fixed assertion - we should check that DTU is there,
not just assert false...
2022-12-08 20:19:55 +03:00

515 lines
18 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes='sroa<preserve-cfg>' < %s | FileCheck %s --check-prefixes=CHECK,CHECK-PRESERVE-CFG
; RUN: opt -S -passes='sroa<modify-cfg>' < %s | FileCheck %s --check-prefixes=CHECK,CHECK-MODIFY-CFG
%pair = type { i32, i32 }
define i32 @test_sroa_phi_gep(i1 %cond) {
; CHECK-LABEL: @test_sroa_phi_gep(
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_THEN:%.*]], label [[END:%.*]]
; CHECK: if.then:
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: [[PHI_SROA_PHI_SROA_SPECULATED:%.*]] = phi i32 [ 1, [[ENTRY:%.*]] ], [ 2, [[IF_THEN]] ]
; CHECK-NEXT: ret i32 [[PHI_SROA_PHI_SROA_SPECULATED]]
;
entry:
%a = alloca %pair, align 4
%b = alloca %pair, align 4
%gep_a = getelementptr inbounds %pair, ptr %a, i32 0, i32 1
%gep_b = getelementptr inbounds %pair, ptr %b, i32 0, i32 1
store i32 1, ptr %gep_a, align 4
store i32 2, ptr %gep_b, align 4
br i1 %cond, label %if.then, label %end
if.then:
br label %end
end:
%phi = phi ptr [ %a, %entry], [ %b, %if.then ]
%gep = getelementptr inbounds %pair, ptr %phi, i32 0, i32 1
%load = load i32, ptr %gep, align 4
ret i32 %load
}
define i32 @test_sroa_phi_gep_non_inbound(i1 %cond) {
; CHECK-LABEL: @test_sroa_phi_gep_non_inbound(
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_THEN:%.*]], label [[END:%.*]]
; CHECK: if.then:
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: [[PHI_SROA_PHI_SROA_SPECULATED:%.*]] = phi i32 [ 1, [[ENTRY:%.*]] ], [ 2, [[IF_THEN]] ]
; CHECK-NEXT: ret i32 [[PHI_SROA_PHI_SROA_SPECULATED]]
;
entry:
%a = alloca %pair, align 4
%b = alloca %pair, align 4
%gep_a = getelementptr %pair, ptr %a, i32 0, i32 1
%gep_b = getelementptr %pair, ptr %b, i32 0, i32 1
store i32 1, ptr %gep_a, align 4
store i32 2, ptr %gep_b, align 4
br i1 %cond, label %if.then, label %end
if.then:
br label %end
end:
%phi = phi ptr [ %a, %entry], [ %b, %if.then ]
%gep = getelementptr %pair, ptr %phi, i32 0, i32 1
%load = load i32, ptr %gep, align 4
ret i32 %load
}
define i32 @test_sroa_phi_gep_poison(i1 %cond) {
; CHECK-LABEL: @test_sroa_phi_gep_poison(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca [[PAIR:%.*]], align 4
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_THEN:%.*]], label [[END:%.*]]
; CHECK: if.then:
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ [[A]], [[ENTRY:%.*]] ], [ poison, [[IF_THEN]] ]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [[PAIR]], ptr [[PHI]], i32 0, i32 1
; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[GEP]], align 4
; CHECK-NEXT: ret i32 [[LOAD]]
;
entry:
%a = alloca %pair, align 4
br i1 %cond, label %if.then, label %end
if.then:
br label %end
end:
%phi = phi ptr [ %a, %entry], [ poison, %if.then ]
%gep = getelementptr inbounds %pair, ptr %phi, i32 0, i32 1
%load = load i32, ptr %gep, align 4
ret i32 %load
}
@g = global %pair zeroinitializer, align 4
define i32 @test_sroa_phi_gep_global(i1 %cond) {
; CHECK-LABEL: @test_sroa_phi_gep_global(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca [[PAIR:%.*]], align 4
; CHECK-NEXT: [[GEP_A:%.*]] = getelementptr inbounds [[PAIR]], ptr [[A]], i32 0, i32 1
; CHECK-NEXT: store i32 1, ptr [[GEP_A]], align 4
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_THEN:%.*]], label [[END:%.*]]
; CHECK: if.then:
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ [[A]], [[ENTRY:%.*]] ], [ @g, [[IF_THEN]] ]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [[PAIR]], ptr [[PHI]], i32 0, i32 1
; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[GEP]], align 4
; CHECK-NEXT: ret i32 [[LOAD]]
;
entry:
%a = alloca %pair, align 4
%gep_a = getelementptr inbounds %pair, ptr %a, i32 0, i32 1
store i32 1, ptr %gep_a, align 4
br i1 %cond, label %if.then, label %end
if.then:
br label %end
end:
%phi = phi ptr [ %a, %entry], [ @g, %if.then ]
%gep = getelementptr inbounds %pair, ptr %phi, i32 0, i32 1
%load = load i32, ptr %gep, align 4
ret i32 %load
}
define i32 @test_sroa_phi_gep_arg_phi_inspt(i1 %cond) {
; CHECK-LABEL: @test_sroa_phi_gep_arg_phi_inspt(
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[COND:%.*]], label [[FOR:%.*]], label [[END:%.*]]
; CHECK: for:
; CHECK-NEXT: [[PHI_INSPT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I:%.*]], [[FOR]] ]
; CHECK-NEXT: [[I]] = add i32 [[PHI_INSPT]], 1
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[I]], 10
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[FOR]], label [[END]]
; CHECK: end:
; CHECK-NEXT: [[PHI_SROA_PHI_SROA_SPECULATED:%.*]] = phi i32 [ 1, [[ENTRY]] ], [ 2, [[FOR]] ]
; CHECK-NEXT: ret i32 [[PHI_SROA_PHI_SROA_SPECULATED]]
;
entry:
%a = alloca %pair, align 4
%b = alloca %pair, align 4
%gep_a = getelementptr inbounds %pair, ptr %a, i32 0, i32 1
%gep_b = getelementptr inbounds %pair, ptr %b, i32 0, i32 1
store i32 1, ptr %gep_a, align 4
store i32 2, ptr %gep_b, align 4
br i1 %cond, label %for, label %end
for:
%phi_inspt = phi i32 [ 0, %entry ], [ %i, %for ]
%i = add i32 %phi_inspt, 1
%loop.cond = icmp ult i32 %i, 10
br i1 %loop.cond, label %for, label %end
end:
%phi = phi ptr [ %a, %entry], [ %b, %for ]
%gep = getelementptr inbounds %pair, ptr %phi, i32 0, i32 1
%load = load i32, ptr %gep, align 4
ret i32 %load
}
define i32 @test_sroa_phi_gep_phi_inspt(i1 %cond) {
; CHECK-LABEL: @test_sroa_phi_gep_phi_inspt(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca [[PAIR:%.*]], align 4
; CHECK-NEXT: [[B:%.*]] = alloca [[PAIR]], align 4
; CHECK-NEXT: [[GEP_A:%.*]] = getelementptr inbounds [[PAIR]], ptr [[A]], i32 0, i32 1
; CHECK-NEXT: [[GEP_B:%.*]] = getelementptr inbounds [[PAIR]], ptr [[B]], i32 0, i32 1
; CHECK-NEXT: store i32 1, ptr [[GEP_A]], align 4
; CHECK-NEXT: store i32 2, ptr [[GEP_B]], align 4
; CHECK-NEXT: br i1 [[COND:%.*]], label [[FOR:%.*]], label [[END:%.*]]
; CHECK: for:
; CHECK-NEXT: [[PHI_IN:%.*]] = phi ptr [ null, [[ENTRY:%.*]] ], [ [[B]], [[FOR]] ]
; CHECK-NEXT: [[PHI_INSPT:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[I:%.*]], [[FOR]] ]
; CHECK-NEXT: [[I]] = add i32 [[PHI_INSPT]], 1
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[I]], 10
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[FOR]], label [[END]]
; CHECK: end:
; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ [[A]], [[ENTRY]] ], [ [[PHI_IN]], [[FOR]] ]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [[PAIR]], ptr [[PHI]], i32 0, i32 1
; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[GEP]], align 4
; CHECK-NEXT: ret i32 [[LOAD]]
;
entry:
%a = alloca %pair, align 4
%b = alloca %pair, align 4
%gep_a = getelementptr inbounds %pair, ptr %a, i32 0, i32 1
%gep_b = getelementptr inbounds %pair, ptr %b, i32 0, i32 1
store i32 1, ptr %gep_a, align 4
store i32 2, ptr %gep_b, align 4
br i1 %cond, label %for, label %end
for:
%phi_in = phi ptr [ null, %entry ], [ %b, %for ]
%phi_inspt = phi i32 [ 0, %entry ], [ %i, %for ]
%i = add i32 %phi_inspt, 1
%loop.cond = icmp ult i32 %i, 10
br i1 %loop.cond, label %for, label %end
end:
%phi = phi ptr [ %a, %entry], [ %phi_in, %for ]
%gep = getelementptr inbounds %pair, ptr %phi, i32 0, i32 1
%load = load i32, ptr %gep, align 4
ret i32 %load
}
define i32 @test_sroa_gep_phi_gep(i1 %cond) {
; CHECK-LABEL: @test_sroa_gep_phi_gep(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A_SROA_0:%.*]] = alloca i32, align 4
; CHECK-NEXT: br i1 [[COND:%.*]], label [[FOR:%.*]], label [[END:%.*]]
; CHECK: for:
; CHECK-NEXT: [[PHI_I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I:%.*]], [[FOR]] ]
; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ [[A_SROA_0]], [[ENTRY]] ], [ [[GEP_FOR:%.*]], [[FOR]] ]
; CHECK-NEXT: [[I]] = add i32 [[PHI_I]], 1
; CHECK-NEXT: [[GEP_FOR]] = getelementptr inbounds i32, ptr [[PHI]], i32 0
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[I]], 10
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[FOR]], label [[END]]
; CHECK: end:
; CHECK-NEXT: [[PHI_END:%.*]] = phi ptr [ [[A_SROA_0]], [[ENTRY]] ], [ [[PHI]], [[FOR]] ]
; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[PHI_END]], align 4
; CHECK-NEXT: ret i32 [[LOAD]]
;
entry:
%a = alloca %pair, align 4
%gep_a = getelementptr inbounds %pair, ptr %a, i32 0, i32 1
br i1 %cond, label %for, label %end
for:
%phi_i = phi i32 [ 0, %entry ], [ %i, %for ]
%phi = phi ptr [ %gep_a, %entry], [ %gep_for, %for ]
%i = add i32 %phi_i, 1
%gep_for = getelementptr inbounds i32, i32* %phi, i32 0
%loop.cond = icmp ult i32 %i, 10
br i1 %loop.cond, label %for, label %end
end:
%phi_end = phi ptr [ %gep_a, %entry], [ %phi, %for ]
%load = load i32, ptr %phi_end, align 4
ret i32 %load
}
define i32 @test_sroa_invoke_phi_gep(i1 %cond) personality ptr @__gxx_personality_v0 {
; CHECK-LABEL: @test_sroa_invoke_phi_gep(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca [[PAIR:%.*]], align 4
; CHECK-NEXT: br i1 [[COND:%.*]], label [[CALL:%.*]], label [[END:%.*]]
; CHECK: call:
; CHECK-NEXT: [[B:%.*]] = invoke ptr @foo()
; CHECK-NEXT: to label [[END]] unwind label [[INVOKE_CATCH:%.*]]
; CHECK: end:
; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ [[A]], [[ENTRY:%.*]] ], [ [[B]], [[CALL]] ]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [[PAIR]], ptr [[PHI]], i32 0, i32 1
; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[GEP]], align 4
; CHECK-NEXT: ret i32 [[LOAD]]
; CHECK: invoke_catch:
; CHECK-NEXT: [[RES:%.*]] = landingpad { ptr, i32 }
; CHECK-NEXT: catch ptr null
; CHECK-NEXT: ret i32 0
;
entry:
%a = alloca %pair, align 4
br i1 %cond, label %call, label %end
call:
%b = invoke ptr @foo()
to label %end unwind label %invoke_catch
end:
%phi = phi ptr [ %a, %entry], [ %b, %call ]
%gep = getelementptr inbounds %pair, ptr %phi, i32 0, i32 1
%load = load i32, ptr %gep, align 4
ret i32 %load
invoke_catch:
%res = landingpad { ptr, i32 }
catch ptr null
ret i32 0
}
define i32 @test_sroa_phi_gep_nonconst_idx(i1 %cond, i32 %idx) {
; CHECK-LABEL: @test_sroa_phi_gep_nonconst_idx(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca [[PAIR:%.*]], align 4
; CHECK-NEXT: [[B:%.*]] = alloca [[PAIR]], align 4
; CHECK-NEXT: [[GEP_A:%.*]] = getelementptr inbounds [[PAIR]], ptr [[A]], i32 0, i32 1
; CHECK-NEXT: [[GEP_B:%.*]] = getelementptr inbounds [[PAIR]], ptr [[B]], i32 0, i32 1
; CHECK-NEXT: store i32 1, ptr [[GEP_A]], align 4
; CHECK-NEXT: store i32 2, ptr [[GEP_B]], align 4
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_THEN:%.*]], label [[END:%.*]]
; CHECK: if.then:
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ [[A]], [[ENTRY:%.*]] ], [ [[B]], [[IF_THEN]] ]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [[PAIR]], ptr [[PHI]], i32 [[IDX:%.*]], i32 1
; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[GEP]], align 4
; CHECK-NEXT: ret i32 [[LOAD]]
;
entry:
%a = alloca %pair, align 4
%b = alloca %pair, align 4
%gep_a = getelementptr inbounds %pair, ptr %a, i32 0, i32 1
%gep_b = getelementptr inbounds %pair, ptr %b, i32 0, i32 1
store i32 1, ptr %gep_a, align 4
store i32 2, ptr %gep_b, align 4
br i1 %cond, label %if.then, label %end
if.then:
br label %end
end:
%phi = phi ptr [ %a, %entry], [ %b, %if.then ]
%gep = getelementptr inbounds %pair, ptr %phi, i32 %idx, i32 1
%load = load i32, ptr %gep, align 4
ret i32 %load
}
define void @test_sroa_gep_phi_select_other_block(i1 %c1, i1 %c2, ptr %ptr) {
; CHECK-LABEL: @test_sroa_gep_phi_select_other_block(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[ALLOCA:%.*]] = alloca [[PAIR:%.*]], align 8
; CHECK-NEXT: br label [[WHILE_BODY:%.*]]
; CHECK: while.body:
; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ [[ALLOCA]], [[ENTRY:%.*]] ], [ [[SELECT:%.*]], [[WHILE_BODY]] ]
; CHECK-NEXT: [[SELECT]] = select i1 [[C1:%.*]], ptr [[PHI]], ptr [[PTR:%.*]]
; CHECK-NEXT: br i1 [[C2:%.*]], label [[EXIT:%.*]], label [[WHILE_BODY]]
; CHECK: exit:
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [[PAIR]], ptr [[PHI]], i64 1
; CHECK-NEXT: unreachable
;
entry:
%alloca = alloca %pair, align 8
br label %while.body
while.body:
%phi = phi ptr [ %alloca, %entry ], [ %select, %while.body ]
%select = select i1 %c1, ptr %phi, ptr %ptr
br i1 %c2, label %exit, label %while.body
exit:
%gep = getelementptr inbounds %pair, ptr %phi, i64 1
unreachable
}
define void @test_sroa_gep_phi_select_same_block(i1 %c1, i1 %c2, ptr %ptr) {
; CHECK-LABEL: @test_sroa_gep_phi_select_same_block(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[ALLOCA:%.*]] = alloca [[PAIR:%.*]], align 8
; CHECK-NEXT: br label [[WHILE_BODY:%.*]]
; CHECK: while.body:
; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ [[ALLOCA]], [[ENTRY:%.*]] ], [ [[SELECT:%.*]], [[WHILE_BODY]] ]
; CHECK-NEXT: [[SELECT]] = select i1 [[C1:%.*]], ptr [[PHI]], ptr [[PTR:%.*]]
; CHECK-NEXT: [[PHI_SROA_GEP:%.*]] = getelementptr inbounds [[PAIR]], ptr [[PHI]], i64 1
; CHECK-NEXT: [[PTR_SROA_GEP:%.*]] = getelementptr inbounds [[PAIR]], ptr [[PTR]], i64 1
; CHECK-NEXT: [[SELECT_SROA_SEL:%.*]] = select i1 [[C1]], ptr [[PHI_SROA_GEP]], ptr [[PTR_SROA_GEP]]
; CHECK-NEXT: br i1 [[C2:%.*]], label [[EXIT:%.*]], label [[WHILE_BODY]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
%alloca = alloca %pair, align 8
br label %while.body
while.body:
%phi = phi ptr [ %alloca, %entry ], [ %select, %while.body ]
%select = select i1 %c1, ptr %phi, ptr %ptr
%gep = getelementptr inbounds %pair, ptr %select, i64 1
br i1 %c2, label %exit, label %while.body
exit:
ret void
}
define i32 @test_sroa_gep_cast_phi_gep(i1 %cond) {
; CHECK-LABEL: @test_sroa_gep_cast_phi_gep(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A_SROA_0:%.*]] = alloca i32, align 4
; CHECK-NEXT: store i32 1065353216, ptr [[A_SROA_0]], align 4
; CHECK-NEXT: br i1 [[COND:%.*]], label [[FOR:%.*]], label [[END:%.*]]
; CHECK: for:
; CHECK-NEXT: [[PHI_I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I:%.*]], [[FOR]] ]
; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ [[A_SROA_0]], [[ENTRY]] ], [ [[GEP_FOR:%.*]], [[FOR]] ]
; CHECK-NEXT: [[I]] = add i32 [[PHI_I]], 1
; CHECK-NEXT: [[GEP_FOR]] = getelementptr inbounds float, ptr [[PHI]], i32 0
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[I]], 10
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[FOR]], label [[END]]
; CHECK: end:
; CHECK-NEXT: [[PHI_END:%.*]] = phi ptr [ [[A_SROA_0]], [[ENTRY]] ], [ [[PHI]], [[FOR]] ]
; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[PHI_END]], align 4
; CHECK-NEXT: ret i32 [[LOAD]]
;
entry:
%a = alloca %pair, align 4
%gep_a = getelementptr inbounds %pair, ptr %a, i32 0, i32 1
store float 1.0, ptr %gep_a, align 4
br i1 %cond, label %for, label %end
for:
%phi_i = phi i32 [ 0, %entry ], [ %i, %for ]
%phi = phi ptr [ %gep_a, %entry], [ %gep_for, %for ]
%i = add i32 %phi_i, 1
%gep_for = getelementptr inbounds float, float* %phi, i32 0
%loop.cond = icmp ult i32 %i, 10
br i1 %loop.cond, label %for, label %end
end:
%phi_end = phi ptr [ %gep_a, %entry], [ %phi, %for ]
%load = load i32, ptr %phi_end, align 4
ret i32 %load
}
define void @unreachable_term(i1 %c1) {
; CHECK-LABEL: @unreachable_term(
; CHECK-NEXT: [[A_SROA_0:%.*]] = alloca i32, align 4
; CHECK-NEXT: unreachable
; CHECK: bb1:
; CHECK-NEXT: br label [[BB1_I:%.*]]
; CHECK: bb1.i:
; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ [[A_SROA_0]], [[BB1:%.*]] ], [ null, [[BB1_I]] ]
; CHECK-NEXT: store i32 0, ptr [[PHI]], align 1
; CHECK-NEXT: br i1 [[C1:%.*]], label [[BB1_I]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: br label [[BB2:%.*]]
; CHECK: bb2:
; CHECK-NEXT: ret void
;
%a = alloca [3 x i32], align 1
unreachable
bb1:
br label %bb1.i
bb1.i:
%phi = phi ptr [ %a, %bb1 ], [ null, %bb1.i ]
store i32 0, ptr %phi, align 1
br i1 %c1, label %bb1.i, label %exit
exit:
br label %bb2
bb2:
ret void
}
define void @constant_value_phi(i1 %c1) {
; CHECK-LABEL: @constant_value_phi(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LAND_LHS_TRUE_I:%.*]]
; CHECK: land.lhs.true.i:
; CHECK-NEXT: br i1 [[C1:%.*]], label [[COND_END_I:%.*]], label [[COND_END_I]]
; CHECK: cond.end.i:
; CHECK-NEXT: unreachable
;
entry:
%s1 = alloca [3 x i16]
%s = alloca [3 x i16]
br label %land.lhs.true.i
land.lhs.true.i: ; preds = %entry
br i1 %c1, label %cond.end.i, label %cond.end.i
cond.end.i: ; preds = %land.lhs.true.i, %land.lhs.true.i
%.pre-phi1 = phi ptr [ %s1, %land.lhs.true.i ], [ %s1, %land.lhs.true.i ]
call void @llvm.memcpy.p0.p0.i64(ptr %.pre-phi1, ptr %s, i64 3, i1 false)
%load = load i16, ptr %s
unreachable
}
define i32 @test_sroa_phi_gep_multiple_values_from_same_block(i32 %arg) {
; CHECK-LABEL: @test_sroa_phi_gep_multiple_values_from_same_block(
; CHECK-NEXT: bb.1:
; CHECK-NEXT: switch i32 [[ARG:%.*]], label [[BB_3:%.*]] [
; CHECK-NEXT: i32 1, label [[BB_2:%.*]]
; CHECK-NEXT: i32 2, label [[BB_2]]
; CHECK-NEXT: i32 3, label [[BB_4:%.*]]
; CHECK-NEXT: i32 4, label [[BB_4]]
; CHECK-NEXT: ]
; CHECK: bb.2:
; CHECK-NEXT: br label [[BB_4]]
; CHECK: bb.3:
; CHECK-NEXT: br label [[BB_4]]
; CHECK: bb.4:
; CHECK-NEXT: [[PHI_SROA_PHI_SROA_SPECULATED:%.*]] = phi i32 [ undef, [[BB_3]] ], [ undef, [[BB_2]] ], [ undef, [[BB_1:%.*]] ], [ undef, [[BB_1]] ]
; CHECK-NEXT: ret i32 [[PHI_SROA_PHI_SROA_SPECULATED]]
;
bb.1:
%a = alloca %pair, align 4
%b = alloca %pair, align 4
switch i32 %arg, label %bb.3 [
i32 1, label %bb.2
i32 2, label %bb.2
i32 3, label %bb.4
i32 4, label %bb.4
]
bb.2: ; preds = %bb.1, %bb.1
br label %bb.4
bb.3: ; preds = %bb.1
br label %bb.4
bb.4: ; preds = %bb.1, %bb.1, %bb.3, %bb.2
%phi = phi ptr [ %a, %bb.3 ], [ %a, %bb.2 ], [ %b, %bb.1 ], [ %b, %bb.1 ]
%gep = getelementptr inbounds %pair, ptr %phi, i32 0, i32 1
%load = load i32, ptr %gep, align 4
ret i32 %load
}
declare ptr @foo()
declare i32 @__gxx_personality_v0(...)
declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg)
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; CHECK-MODIFY-CFG: {{.*}}
; CHECK-PRESERVE-CFG: {{.*}}