Files
clang-p2996/llvm/test/Transforms/SimplifyCFG/X86/sink-common-code-into-unreachable.ll
Roman Lebedev 82c8aca934 [SimplifyCFG] Be more aggressive when sinking into block followed by unreachable
I strongly believe we need some variant of this.

The main problem is e.g. that the glibc's assert has 4 parameters,
but the profitability check is only okay with one extra phi node,
so D116692 doesn't even trigger on most of the expected cases.

While that restriction probably makes sense in normal code, if we
are about to run off of a cliff (into an `unreachable`), this
successor block is unlikely so the cost to setup these PHI nodes
should not be on the hotpath, and shouldn't matter performance-wise.

Likewise, we don't sink if there are unconditional predecessors
UNLESS we'd sink at least one non-speculatable instruction,
which is a performance workaround, but if we are about to run into
`unreachable`, it shouldn't matter.

Note that we only allow the case where there are at
most unconditiona branches on the way to the unreachable block.

Differential Revision: https://reviews.llvm.org/D117045
2022-01-13 23:30:31 +03:00

125 lines
4.0 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -sink-common-insts -S | FileCheck %s
; RUN: opt < %s -passes='simplifycfg<sink-common-insts>' -S | FileCheck %s
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
target triple = "x86_64-pc-linux-gnu"
; `unreachable` block has conditional predecessors,
; but everything we'd sink from unconditional predecessors are speculatable.
; Also, too many phi's would normally be needed.
define void @t0(i4 %cond, i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h) {
; CHECK-LABEL: @t0(
; CHECK-NEXT: switch i4 [[COND:%.*]], label [[END:%.*]] [
; CHECK-NEXT: i4 0, label [[END_SINK_SPLIT:%.*]]
; CHECK-NEXT: i4 -1, label [[END_SINK_SPLIT]]
; CHECK-NEXT: i4 1, label [[BB1:%.*]]
; CHECK-NEXT: i4 -2, label [[BB1]]
; CHECK-NEXT: ]
; CHECK: bb1:
; CHECK-NEXT: br label [[END_SINK_SPLIT]]
; CHECK: end.sink.split:
; CHECK-NEXT: [[H_SINK:%.*]] = phi i32 [ [[H:%.*]], [[BB1]] ], [ [[E:%.*]], [[TMP0:%.*]] ], [ [[E]], [[TMP0]] ]
; CHECK-NEXT: [[G_SINK:%.*]] = phi i32 [ [[G:%.*]], [[BB1]] ], [ [[D:%.*]], [[TMP0]] ], [ [[D]], [[TMP0]] ]
; CHECK-NEXT: [[V4:%.*]] = add i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[V5:%.*]] = add i32 [[V4]], [[C:%.*]]
; CHECK-NEXT: [[V6:%.*]] = add i32 [[G_SINK]], [[H_SINK]]
; CHECK-NEXT: [[R7:%.*]] = add i32 [[V5]], [[V6]]
; CHECK-NEXT: call void @use32(i32 [[R7]])
; CHECK-NEXT: unreachable
; CHECK: end:
; CHECK-NEXT: unreachable
;
switch i4 %cond, label %end [
i4 0, label %bb0
i4 -1, label %bb0
i4 1, label %bb1
i4 -2, label %bb1
]
bb0:
%v0 = add i32 %a, %b
%v1 = add i32 %v0, %c
%v2 = add i32 %d, %e
%r3 = add i32 %v1, %v2
call void @use32(i32 %r3)
br label %end
bb1:
%v4 = add i32 %a, %b
%v5 = add i32 %v4, %c
%v6 = add i32 %g, %h
%r7 = add i32 %v5, %v6
call void @use32(i32 %r7)
br label %end
end:
unreachable
}
; Same, as @t0, but there's also a loop.
define void @t1(i4 %cond, i1 %cond.loop, i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h) {
; CHECK-LABEL: @t1(
; CHECK-NEXT: switch i4 [[COND:%.*]], label [[END_EARLY:%.*]] [
; CHECK-NEXT: i4 0, label [[BB0:%.*]]
; CHECK-NEXT: i4 -1, label [[BB0]]
; CHECK-NEXT: i4 1, label [[BB1:%.*]]
; CHECK-NEXT: i4 -2, label [[BB1]]
; CHECK-NEXT: ]
; CHECK: bb0:
; CHECK-NEXT: [[V0:%.*]] = add i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[V1:%.*]] = add i32 [[V0]], [[C:%.*]]
; CHECK-NEXT: [[V2:%.*]] = add i32 [[D:%.*]], [[E:%.*]]
; CHECK-NEXT: [[R3:%.*]] = add i32 [[V1]], [[V2]]
; CHECK-NEXT: call void @use32(i32 [[R3]])
; CHECK-NEXT: br label [[END_EARLY]]
; CHECK: bb1:
; CHECK-NEXT: [[V4:%.*]] = add i32 [[A]], [[B]]
; CHECK-NEXT: [[V5:%.*]] = add i32 [[V4]], [[C]]
; CHECK-NEXT: [[V6:%.*]] = add i32 [[G:%.*]], [[H:%.*]]
; CHECK-NEXT: [[R7:%.*]] = add i32 [[V5]], [[V6]]
; CHECK-NEXT: call void @use32(i32 [[R7]])
; CHECK-NEXT: br label [[END_EARLY]]
; CHECK: end.early:
; CHECK-NEXT: call void @sideeffect()
; CHECK-NEXT: br i1 [[COND_LOOP:%.*]], label [[END_EARLY]], label [[END:%.*]]
; CHECK: end:
; CHECK-NEXT: call void @sideeffect()
; CHECK-NEXT: unreachable
;
switch i4 %cond, label %end.early [
i4 0, label %bb0
i4 -1, label %bb0
i4 1, label %bb1
i4 -2, label %bb1
]
bb0:
%v0 = add i32 %a, %b
%v1 = add i32 %v0, %c
%v2 = add i32 %d, %e
%r3 = add i32 %v1, %v2
call void @use32(i32 %r3)
br label %end.early
bb1:
%v4 = add i32 %a, %b
%v5 = add i32 %v4, %c
%v6 = add i32 %g, %h
%r7 = add i32 %v5, %v6
call void @use32(i32 %r7)
br label %end.early
end.early:
call void @sideeffect()
br i1 %cond.loop, label %end.early, label %end
end:
call void @sideeffect()
unreachable
}
declare void @use32(i32) speculatable
declare void @sideeffect()