Files
clang-p2996/llvm/test/Transforms/SROA/phi-with-duplicate-pred.ll
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 739611870d,
and recommits 03e6d9d9d1
with a fixed assertion - we should check that DTU is there,
not just assert false...
2022-12-08 20:19:55 +03:00

270 lines
8.5 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
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64"
@a = external global i16, align 1
declare void @maybe_writes()
define void @f2(i1 %c1) {
; CHECK-LABEL: @f2(
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[C1:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.then:
; CHECK-NEXT: br label [[CLEANUP:%.*]]
; CHECK: cleanup:
; CHECK-NEXT: [[G_0_SROA_SPECULATE_LOAD_CLEANUP:%.*]] = load i16, ptr @a, align 1
; CHECK-NEXT: switch i32 2, label [[CLEANUP7:%.*]] [
; CHECK-NEXT: i32 0, label [[LBL1:%.*]]
; CHECK-NEXT: i32 2, label [[LBL1]]
; CHECK-NEXT: ]
; CHECK: if.else:
; CHECK-NEXT: br label [[LBL1]]
; CHECK: lbl1:
; CHECK-NEXT: [[G_0_SROA_SPECULATED:%.*]] = phi i16 [ [[G_0_SROA_SPECULATE_LOAD_CLEANUP]], [[CLEANUP]] ], [ [[G_0_SROA_SPECULATE_LOAD_CLEANUP]], [[CLEANUP]] ], [ undef, [[IF_ELSE]] ]
; CHECK-NEXT: unreachable
; CHECK: cleanup7:
; CHECK-NEXT: ret void
;
entry:
%e = alloca i16, align 1
br i1 %c1, label %if.then, label %if.else
if.then: ; preds = %entry
br label %cleanup
cleanup: ; preds = %if.then
switch i32 2, label %cleanup7 [
i32 0, label %lbl1
i32 2, label %lbl1
]
if.else: ; preds = %entry
br label %lbl1
lbl1: ; preds = %if.else, %cleanup, %cleanup
%g.0 = phi ptr [ @a, %cleanup ], [ @a, %cleanup ], [ %e, %if.else ]
%0 = load i16, ptr %g.0, align 1
unreachable
cleanup7: ; preds = %cleanup
ret void
}
define void @f3(i1 %c1) {
; CHECK-LABEL: @f3(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[E:%.*]] = alloca i16, align 1
; CHECK-NEXT: br i1 [[C1:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.then:
; CHECK-NEXT: br label [[CLEANUP:%.*]]
; CHECK: cleanup:
; CHECK-NEXT: switch i32 2, label [[CLEANUP7:%.*]] [
; CHECK-NEXT: i32 0, label [[LBL1:%.*]]
; CHECK-NEXT: i32 2, label [[LBL1]]
; CHECK-NEXT: ]
; CHECK: if.else:
; CHECK-NEXT: br label [[LBL1]]
; CHECK: lbl1:
; CHECK-NEXT: [[G_0:%.*]] = phi ptr [ @a, [[CLEANUP]] ], [ @a, [[CLEANUP]] ], [ [[E]], [[IF_ELSE]] ]
; CHECK-NEXT: br label [[FINAL:%.*]]
; CHECK: final:
; CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[G_0]], align 1
; CHECK-NEXT: unreachable
; CHECK: cleanup7:
; CHECK-NEXT: ret void
;
entry:
%e = alloca i16, align 1
br i1 %c1, label %if.then, label %if.else
if.then: ; preds = %entry
br label %cleanup
cleanup: ; preds = %if.then
switch i32 2, label %cleanup7 [
i32 0, label %lbl1
i32 2, label %lbl1
]
if.else: ; preds = %entry
br label %lbl1
lbl1: ; preds = %if.else, %cleanup, %cleanup
%g.0 = phi ptr [ @a, %cleanup ], [ @a, %cleanup ], [ %e, %if.else ]
br label %final
final:
%0 = load i16, ptr %g.0, align 1
unreachable
cleanup7: ; preds = %cleanup
ret void
}
define void @f4(i1 %c1) {
; CHECK-LABEL: @f4(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[E:%.*]] = alloca i16, align 1
; CHECK-NEXT: br i1 [[C1:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.then:
; CHECK-NEXT: br label [[CLEANUP:%.*]]
; CHECK: cleanup:
; CHECK-NEXT: switch i32 2, label [[CLEANUP7:%.*]] [
; CHECK-NEXT: i32 0, label [[LBL1:%.*]]
; CHECK-NEXT: i32 2, label [[LBL1]]
; CHECK-NEXT: ]
; CHECK: if.else:
; CHECK-NEXT: br label [[LBL1]]
; CHECK: lbl1:
; CHECK-NEXT: [[G_0:%.*]] = phi ptr [ @a, [[CLEANUP]] ], [ @a, [[CLEANUP]] ], [ [[E]], [[IF_ELSE]] ]
; CHECK-NEXT: br label [[FINAL:%.*]]
; CHECK: final:
; CHECK-NEXT: call void @maybe_writes()
; CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[G_0]], align 1
; CHECK-NEXT: unreachable
; CHECK: cleanup7:
; CHECK-NEXT: ret void
;
entry:
%e = alloca i16, align 1
br i1 %c1, label %if.then, label %if.else
if.then: ; preds = %entry
br label %cleanup
cleanup: ; preds = %if.then
switch i32 2, label %cleanup7 [
i32 0, label %lbl1
i32 2, label %lbl1
]
if.else: ; preds = %entry
br label %lbl1
lbl1: ; preds = %if.else, %cleanup, %cleanup
%g.0 = phi ptr [ @a, %cleanup ], [ @a, %cleanup ], [ %e, %if.else ]
br label %final
final:
call void @maybe_writes()
%0 = load i16, ptr %g.0, align 1
unreachable
cleanup7: ; preds = %cleanup
ret void
}
define void @f5(i1 %c1, i1 %c2) {
; CHECK-LABEL: @f5(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[E:%.*]] = alloca i16, align 1
; CHECK-NEXT: br i1 [[C1:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.then:
; CHECK-NEXT: br label [[CLEANUP:%.*]]
; CHECK: cleanup:
; CHECK-NEXT: switch i32 2, label [[CLEANUP7:%.*]] [
; CHECK-NEXT: i32 0, label [[LBL1:%.*]]
; CHECK-NEXT: i32 2, label [[LBL1]]
; CHECK-NEXT: ]
; CHECK: if.else:
; CHECK-NEXT: br label [[LBL1]]
; CHECK: lbl1:
; CHECK-NEXT: [[G_0:%.*]] = phi ptr [ @a, [[CLEANUP]] ], [ @a, [[CLEANUP]] ], [ [[E]], [[IF_ELSE]] ]
; CHECK-NEXT: br i1 [[C2:%.*]], label [[FINAL:%.*]], label [[CLEANUP7]]
; CHECK: final:
; CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[G_0]], align 1
; CHECK-NEXT: unreachable
; CHECK: cleanup7:
; CHECK-NEXT: ret void
;
entry:
%e = alloca i16, align 1
br i1 %c1, label %if.then, label %if.else
if.then: ; preds = %entry
br label %cleanup
cleanup: ; preds = %if.then
switch i32 2, label %cleanup7 [
i32 0, label %lbl1
i32 2, label %lbl1
]
if.else: ; preds = %entry
br label %lbl1
lbl1: ; preds = %if.else, %cleanup, %cleanup
%g.0 = phi ptr [ @a, %cleanup ], [ @a, %cleanup ], [ %e, %if.else ]
br i1 %c2, label %final, label %cleanup7
final:
%0 = load i16, ptr %g.0, align 1
unreachable
cleanup7: ; preds = %cleanup
ret void
}
define void @f6(i1 %c1) {
; CHECK-LABEL: @f6(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[E:%.*]] = alloca i16, align 1
; CHECK-NEXT: br i1 [[C1:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.then:
; CHECK-NEXT: br label [[CLEANUP:%.*]]
; CHECK: cleanup:
; CHECK-NEXT: switch i32 2, label [[CLEANUP7:%.*]] [
; CHECK-NEXT: i32 0, label [[LBL1:%.*]]
; CHECK-NEXT: i32 2, label [[LBL1]]
; CHECK-NEXT: ]
; CHECK: if.else:
; CHECK-NEXT: br label [[LBL1]]
; CHECK: lbl1:
; CHECK-NEXT: [[G_0:%.*]] = phi ptr [ @a, [[CLEANUP]] ], [ @a, [[CLEANUP]] ], [ [[E]], [[IF_ELSE]] ]
; CHECK-NEXT: br label [[FINAL:%.*]]
; CHECK: unreachable_pred:
; CHECK-NEXT: br label [[FINAL]]
; CHECK: final:
; CHECK-NEXT: call void @maybe_writes()
; CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[G_0]], align 1
; CHECK-NEXT: unreachable
; CHECK: cleanup7:
; CHECK-NEXT: ret void
;
entry:
%e = alloca i16, align 1
br i1 %c1, label %if.then, label %if.else
if.then: ; preds = %entry
br label %cleanup
cleanup: ; preds = %if.then
switch i32 2, label %cleanup7 [
i32 0, label %lbl1
i32 2, label %lbl1
]
if.else: ; preds = %entry
br label %lbl1
lbl1: ; preds = %if.else, %cleanup, %cleanup
%g.0 = phi ptr [ @a, %cleanup ], [ @a, %cleanup ], [ %e, %if.else ]
br label %final
unreachable_pred:
br label %final
final:
call void @maybe_writes()
%0 = load i16, ptr %g.0, align 1
unreachable
cleanup7: ; preds = %cleanup
ret void
}
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; CHECK-MODIFY-CFG: {{.*}}
; CHECK-PRESERVE-CFG: {{.*}}