310 lines
10 KiB
YAML
310 lines
10 KiB
YAML
# RUN: llc -O0 -run-pass=aarch64-prelegalizer-combiner -global-isel %s -o - | FileCheck %s
|
|
# RUN: llc -O0 -run-pass=aarch64-prelegalizer-combiner -global-isel %s -o - \
|
|
# RUN: -debug-only=aarch64-prelegalizer-combiner,gi-combiner 2>&1 >/dev/null \
|
|
# RUN: | FileCheck %s --check-prefix=CHECK-WORKLIST
|
|
|
|
# REQUIRES: asserts
|
|
|
|
--- |
|
|
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
|
|
target triple = "aarch64--"
|
|
|
|
define void @multiple_copies(i8* %addr) {
|
|
entry:
|
|
br i1 0, label %if, label %else
|
|
if:
|
|
br label %exit
|
|
else:
|
|
br label %exit
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @sink_to_phi_trivially_dominating(i8* %addr) {
|
|
entry:
|
|
br i1 0, label %if, label %exit
|
|
if:
|
|
br label %exit
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @sink_to_phi_nondominating(i8* %addr) {
|
|
entry:
|
|
br i1 0, label %if, label %else
|
|
if:
|
|
br label %exit
|
|
else:
|
|
br label %exit
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @sink_to_phi_emptyblock(i8* %addr) {
|
|
entry:
|
|
br i1 0, label %if, label %else
|
|
if:
|
|
br label %exit
|
|
else:
|
|
br label %else2
|
|
else2:
|
|
br label %exit
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @use_doesnt_def_anything(i8* %addr) {
|
|
entry:
|
|
ret void
|
|
}
|
|
|
|
define void @op0_isnt_a_reg(i8* %addr) {
|
|
entry:
|
|
ret void
|
|
}
|
|
...
|
|
|
|
---
|
|
name: multiple_copies
|
|
# CHECK-LABEL: name: multiple_copies
|
|
tracksRegLiveness: true
|
|
body: |
|
|
bb.0.entry:
|
|
liveins: $x0, $w1
|
|
successors: %bb.1(0x40000000), %bb.2(0x40000000); %bb.1(50.00%), %bb.2(50.00%)
|
|
; CHECK: [[T0:%[0-9]+]]:_(s32) = G_SEXTLOAD
|
|
%0:_(p0) = COPY $x0
|
|
%1:_(s32) = COPY $w1
|
|
%2:_(s8) = G_LOAD %0 :: (load 1 from %ir.addr)
|
|
%3:_(s32) = G_SEXT %2
|
|
%4:_(s32) = G_CONSTANT i32 1
|
|
%5:_(s1) = G_ICMP intpred(ne), %1:_(s32), %4:_
|
|
G_BRCOND %5:_(s1), %bb.1
|
|
G_BR %bb.2.else
|
|
bb.1.if:
|
|
; CHECK: bb.1.if:
|
|
successors: %bb.3(0x80000000)
|
|
%10:_(s8) = G_CONSTANT i8 1
|
|
; CHECK: [[T1:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32)
|
|
%6:_(s8) = G_ADD %2, %10
|
|
; CHECK: [[T2:%[0-9]+]]:_(s8) = G_ADD [[T1]], {{.*}}
|
|
G_BR %bb.3.exit
|
|
bb.2.else:
|
|
; CHECK: bb.2.else:
|
|
successors: %bb.3(0x80000000)
|
|
%11:_(s8) = G_CONSTANT i8 1
|
|
; CHECK: [[T3:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32)
|
|
%7:_(s8) = G_SUB %2, %11
|
|
; CHECK: [[T4:%[0-9]+]]:_(s8) = G_SUB [[T3]], {{.*}}
|
|
G_BR %bb.3.exit
|
|
bb.3.exit:
|
|
; CHECK: bb.3.exit:
|
|
%8:_(s8) = G_PHI %6:_(s8), %bb.1, %7:_(s8), %bb.2
|
|
; CHECK: [[T5:%[0-9]+]]:_(s8) = G_PHI [[T2]](s8), %bb.1, [[T4]](s8)
|
|
%9:_(s32) = G_ZEXT %8
|
|
; CHECK: [[T6:%[0-9]+]]:_(s32) = G_ZEXT [[T5]](s8)
|
|
; CHECK: $w0 = COPY [[T0]](s32)
|
|
; CHECK: $w1 = COPY [[T6]](s32)
|
|
$w0 = COPY %3
|
|
$w1 = COPY %9
|
|
|
|
# Check that we report the correct modifications to the observer. This acts as
|
|
# a test of the debug output and a test.
|
|
#
|
|
# CHECK-WORKLIST-LABEL: Generic MI Combiner for: multiple_copies
|
|
# CHECK-WORKLIST: Try combining [[IN0:%[0-9]+]]:_(s8) = G_LOAD [[IN1:%[0-9]+]]:_(p0){{.*}} :: (load 1 from %ir.addr)
|
|
# CHECK-WORKLIST: Preferred use is: [[IN2:%[0-9]+]]:_(s32) = G_SEXT [[IN0]]:_(s8)
|
|
# CHECK-WORKLIST-DAG: Changing: [[IN0]]:_(s8) = G_LOAD [[IN1]]:_(p0){{.*}} :: (load 1 from %ir.addr)
|
|
# CHECK-WORKLIST-DAG: Changing: [[IN3:%[0-9]+]]:_(s8) = G_ADD [[IN0]]:_, [[IN4:%[0-9]+]]:_
|
|
# CHECK-WORKLIST-DAG: Changed: [[IN3]]:_(s8) = G_ADD [[NEW1:%[0-9]+]]:_, [[IN4]]:_
|
|
# CHECK-WORKLIST-DAG: Changing: [[IN5:%[0-9]+]]:_(s8) = G_SUB [[IN0]]:_, [[IN6:%[0-9]+]]:_
|
|
# CHECK-WORKLIST-DAG: Changed: [[IN5]]:_(s8) = G_SUB [[NEW2:%[0-9]+]]:_, [[IN6]]:_
|
|
# CHECK-WORKLIST-DAG: Erasing: [[IN2]]:_(s32) = G_SEXT [[IN0]]:_(s8)
|
|
# CHECK-WORKLIST-DAG: Changed: [[IN2]]:_(s32) = G_SEXTLOAD [[IN1]]:_(p0){{.*}} :: (load 1 from %ir.addr)
|
|
# CHECK-WORKLIST-DAG: Created: [[NEW1]]:_(s8) = G_TRUNC [[IN2]]:_(s32)
|
|
# CHECK-WORKLIST-DAG: Created: [[NEW2]]:_(s8) = G_TRUNC [[IN2]]:_(s32)
|
|
# CHECK-WORKLIST: Try combining
|
|
...
|
|
|
|
---
|
|
name: sink_to_phi_trivially_dominating
|
|
# CHECK-LABEL: name: sink_to_phi_trivially_dominating
|
|
# This test currently tests that we don't sink if we would sink to a phi. This
|
|
# is needed to avoid inserting into the middle of the leading G_PHI instructions
|
|
# of a BB
|
|
tracksRegLiveness: true
|
|
body: |
|
|
bb.0.entry:
|
|
liveins: $x0, $w1
|
|
successors: %bb.1(0x40000000), %bb.2(0x40000000); %bb.1(50.00%), %bb.2(50.00%)
|
|
; CHECK: [[T0:%[0-9]+]]:_(s32) = G_SEXTLOAD
|
|
%0:_(p0) = COPY $x0
|
|
%1:_(s32) = COPY $w1
|
|
%2:_(s8) = G_LOAD %0 :: (load 1 from %ir.addr)
|
|
; CHECK: [[T4:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32)
|
|
%3:_(s32) = G_SEXT %2
|
|
%4:_(s32) = G_CONSTANT i32 1
|
|
%5:_(s1) = G_ICMP intpred(ne), %1:_(s32), %4:_
|
|
G_BRCOND %5:_(s1), %bb.1
|
|
G_BR %bb.2.exit
|
|
bb.1.if:
|
|
; CHECK: bb.1.if:
|
|
successors: %bb.2(0x80000000)
|
|
%10:_(s8) = G_CONSTANT i8 1
|
|
; CHECK: [[T1:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32)
|
|
%6:_(s8) = G_ADD %2, %10
|
|
; CHECK: [[T2:%[0-9]+]]:_(s8) = G_ADD [[T1]], {{.*}}
|
|
G_BR %bb.2.exit
|
|
bb.2.exit:
|
|
; CHECK: bb.2.exit:
|
|
%8:_(s8) = G_PHI %6:_(s8), %bb.1, %2:_(s8), %bb.0
|
|
; CHECK: [[T5:%[0-9]+]]:_(s8) = G_PHI [[T2]](s8), %bb.1, [[T4]](s8)
|
|
%9:_(s32) = G_ZEXT %8
|
|
; CHECK: [[T6:%[0-9]+]]:_(s32) = G_ZEXT [[T5]](s8)
|
|
; CHECK: $w0 = COPY [[T0]](s32)
|
|
; CHECK: $w1 = COPY [[T6]](s32)
|
|
$w0 = COPY %3
|
|
$w1 = COPY %9
|
|
...
|
|
|
|
---
|
|
name: sink_to_phi_nondominating
|
|
# CHECK-LABEL: name: sink_to_phi_nondominating
|
|
tracksRegLiveness: true
|
|
body: |
|
|
bb.0.entry:
|
|
liveins: $x0, $w1
|
|
successors: %bb.1(0x40000000), %bb.2(0x40000000); %bb.1(50.00%), %bb.2(50.00%)
|
|
; CHECK: [[T0:%[0-9]+]]:_(s32) = G_SEXTLOAD
|
|
%0:_(p0) = COPY $x0
|
|
%1:_(s32) = COPY $w1
|
|
%2:_(s8) = G_LOAD %0 :: (load 1 from %ir.addr)
|
|
%3:_(s32) = G_CONSTANT i32 1
|
|
%4:_(s1) = G_ICMP intpred(ne), %1:_(s32), %3:_
|
|
G_BRCOND %4:_(s1), %bb.1
|
|
G_BR %bb.2.else
|
|
bb.1.if:
|
|
; CHECK: bb.1.if:
|
|
successors: %bb.3(0x80000000)
|
|
%5:_(s8) = G_CONSTANT i8 1
|
|
; CHECK: [[T1:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32)
|
|
%6:_(s8) = G_ADD %2, %5
|
|
; CHECK: [[T2:%[0-9]+]]:_(s8) = G_ADD [[T1]], {{.*}}
|
|
G_BR %bb.3.exit
|
|
bb.2.else:
|
|
; CHECK: bb.2.else:
|
|
successors: %bb.3(0x80000000)
|
|
%7:_(s8) = G_CONSTANT i8 1
|
|
; CHECK: [[T3:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32)
|
|
%8:_(s8) = G_SUB %2, %7
|
|
; CHECK: [[T4:%[0-9]+]]:_(s8) = G_SUB [[T3]], {{.*}}
|
|
G_BR %bb.3.exit
|
|
bb.3.exit:
|
|
; CHECK: bb.3.exit:
|
|
%9:_(s8) = G_PHI %6:_(s8), %bb.1, %8:_(s8), %bb.2
|
|
; CHECK: [[T5:%[0-9]+]]:_(s8) = G_PHI [[T2]](s8), %bb.1, [[T4]](s8)
|
|
%10:_(s32) = G_SEXT %2
|
|
%11:_(s32) = G_ZEXT %9
|
|
; CHECK: [[T6:%[0-9]+]]:_(s32) = G_ZEXT [[T5]](s8)
|
|
; CHECK: $w0 = COPY [[T0]](s32)
|
|
; CHECK: $w1 = COPY [[T6]](s32)
|
|
$w0 = COPY %10
|
|
$w1 = COPY %11
|
|
# CHECK-WORKLIST-LABEL: Generic MI Combiner for: sink_to_phi_nondominating
|
|
# CHECK-WORKLIST: Try combining [[IN0:%[0-9]+]]:_(s8) = G_LOAD [[IN1:%[0-9]+]]:_(p0){{.*}} :: (load 1 from %ir.addr)
|
|
# CHECK-WORKLIST: Preferred use is: [[IN2:%[0-9]+]]:_(s32) = G_SEXT [[IN0]]:_(s8)
|
|
# CHECK-WORKLIST-DAG: Changing: [[IN0]]:_(s8) = G_LOAD [[IN1]]:_(p0){{.*}} :: (load 1 from %ir.addr)
|
|
# CHECK-WORKLIST-DAG: Creating: G_TRUNC
|
|
# CHECK-WORKLIST-DAG: Changing: [[IN3:%[0-9]+]]:_(s8) = G_ADD [[IN0]]:_, [[IN4:%[0-9]+]]:_
|
|
# CHECK-WORKLIST-DAG: Changed: [[IN3]]:_(s8) = G_ADD [[OUT1:%[0-9]+]]:_, [[IN4]]:_
|
|
# CHECK-WORKLIST-DAG: Creating: G_TRUNC
|
|
# CHECK-WORKLIST-DAG: Changing: [[IN5:%[0-9]+]]:_(s8) = G_SUB [[IN0]]:_, [[IN6:%[0-9]+]]:_
|
|
# CHECK-WORKLIST-DAG: Changed: [[IN5]]:_(s8) = G_SUB [[OUT2:%[0-9]+]]:_, [[IN6]]:_
|
|
# CHECK-WORKLIST-DAG: Erasing: [[IN2]]:_(s32) = G_SEXT [[IN0]]:_(s8)
|
|
# CHECK-WORKLIST-DAG: Changed: [[IN2]]:_(s32) = G_SEXTLOAD [[IN1]]:_(p0){{.*}} :: (load 1 from %ir.addr)
|
|
# CHECK-WORKLIST-DAG: Created: [[OUT1]]:_(s8) = G_TRUNC [[IN2]]:_(s32)
|
|
# CHECK-WORKLIST-DAG: Created: [[OUT2]]:_(s8) = G_TRUNC [[IN2]]:_(s32)
|
|
# CHECK-WORKLIST: Try combining
|
|
...
|
|
|
|
---
|
|
name: sink_to_phi_emptyblock
|
|
# CHECK-LABEL: name: sink_to_phi_emptyblock
|
|
tracksRegLiveness: true
|
|
body: |
|
|
bb.0.entry:
|
|
liveins: $x0, $w1
|
|
successors: %bb.1(0x40000000), %bb.2(0x40000000); %bb.1(50.00%), %bb.2(50.00%)
|
|
; CHECK: [[T0:%[0-9]+]]:_(s32) = G_SEXTLOAD
|
|
%0:_(p0) = COPY $x0
|
|
%1:_(s32) = COPY $w1
|
|
%2:_(s8) = G_LOAD %0 :: (load 1 from %ir.addr)
|
|
%3:_(s32) = G_SEXT %2
|
|
%4:_(s32) = G_CONSTANT i32 1
|
|
%5:_(s1) = G_ICMP intpred(ne), %1:_(s32), %4:_
|
|
G_BRCOND %5:_(s1), %bb.1
|
|
G_BR %bb.2.else
|
|
bb.1.if:
|
|
; CHECK: bb.1.if:
|
|
successors: %bb.4(0x80000000)
|
|
%10:_(s8) = G_CONSTANT i8 1
|
|
; CHECK: [[T1:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32)
|
|
%6:_(s8) = G_ADD %2, %10
|
|
; CHECK: [[T2:%[0-9]+]]:_(s8) = G_ADD [[T1]], {{.*}}
|
|
G_BR %bb.4.exit
|
|
bb.2.else:
|
|
; CHECK: bb.2.else:
|
|
successors: %bb.3(0x80000000)
|
|
G_BR %bb.3.else2
|
|
bb.3.else2:
|
|
; CHECK: bb.3.else2:
|
|
successors: %bb.4(0x80000000)
|
|
; CHECK: [[T4:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32)
|
|
; Fallthrough
|
|
bb.4.exit:
|
|
; CHECK: bb.4.exit:
|
|
%8:_(s8) = G_PHI %6:_(s8), %bb.1, %2:_(s8), %bb.3
|
|
; CHECK: [[T5:%[0-9]+]]:_(s8) = G_PHI [[T2]](s8), %bb.1, [[T4]](s8)
|
|
%9:_(s32) = G_ZEXT %8
|
|
; CHECK: [[T6:%[0-9]+]]:_(s32) = G_ZEXT [[T5]](s8)
|
|
; CHECK: $w0 = COPY [[T0]](s32)
|
|
; CHECK: $w1 = COPY [[T6]](s32)
|
|
$w0 = COPY %3
|
|
$w1 = COPY %9
|
|
...
|
|
|
|
---
|
|
name: use_doesnt_def_anything
|
|
# CHECK-LABEL: name: use_doesnt_def_anything
|
|
# Check that we don't crash when inspecting a use that doesn't define anything.
|
|
# The real issue which was that the combine rule was looking through
|
|
# non-truncates as if they were truncates and attempting to obtain the result
|
|
# register. It would usually go on to make the right overall decision anyway but
|
|
# would sometimes crash on things like (SOME_INTRINSIC imm). This test covers
|
|
# the case that it would recover from.
|
|
tracksRegLiveness: true
|
|
body: |
|
|
bb.0.entry:
|
|
liveins: $x0, $w1
|
|
%0:_(p0) = COPY $x0
|
|
%1:_(s8) = G_LOAD %0 :: (load 1 from %ir.addr)
|
|
; CHECK: %1:_(s8) = G_LOAD %0(p0) :: (load 1 from %ir.addr)
|
|
G_STORE %1(s8), %0(p0) :: (store 1 into %ir.addr)
|
|
; CHECK: G_STORE %1(s8), %0(p0) :: (store 1 into %ir.addr)
|
|
...
|
|
|
|
---
|
|
name: op0_isnt_a_reg
|
|
# CHECK-LABEL: name: op0_isnt_a_reg
|
|
# This test covers the variant of use_doesnt_def_anything that would crash.
|
|
tracksRegLiveness: true
|
|
body: |
|
|
bb.0.entry:
|
|
liveins: $x0, $w1
|
|
%0:_(p0) = COPY $x0
|
|
%1:_(s8) = G_LOAD %0 :: (load 1 from %ir.addr)
|
|
; CHECK: %1:_(s8) = G_LOAD %0(p0) :: (load 1 from %ir.addr)
|
|
G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.aarch64.hint), %1(s8)
|
|
; CHECK: G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.aarch64.hint), %1(s8)
|
|
...
|