blob: 05573ab3eb67743806520a1bf4a8d79be885e85d [file] [log] [blame] [edit]
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5
# RUN: llc -mtriple=aarch64 -o - %s -run-pass=aarch64-condopt | FileCheck %s
# Test unsigned comparison optimization in AArch64ConditionOptimizer.
#
# Condition codes used:
# HI = 8 (unsigned greater than)
# HS = 2 (unsigned greater than or equal)
# LO = 3 (unsigned less than)
# LS = 9 (unsigned less than or equal)
#
# The pass transforms:
# (a > 10 && ...) || (a > 9 && ...) -> (a > 10 && ...) || (a >= 10 && ...)
# by adjusting one compare's immediate and condition code.
---
# CMP/CMP with HI/HI (unsigned >): imm differs by 1
# Head: cmp w0, #10; b.hi (w0 > 10 unsigned)
# True: cmp w0, #11; b.hi (w0 > 11 unsigned)
# Expected: One CMP adjusted to HS (>=)
name: cmp_cmp_hi_hi
tracksRegLiveness: true
body: |
; CHECK-LABEL: name: cmp_cmp_hi_hi
; CHECK: bb.0:
; CHECK-NEXT: successors: %bb.1(0x40000000), %bb.2(0x40000000)
; CHECK-NEXT: liveins: $w0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr32common = COPY $w0
; CHECK-NEXT: [[SUBSWri:%[0-9]+]]:gpr32 = SUBSWri [[COPY]], 11, 0, implicit-def $nzcv
; CHECK-NEXT: Bcc 2, %bb.1, implicit $nzcv
; CHECK-NEXT: B %bb.2
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.1:
; CHECK-NEXT: successors: %bb.2(0x80000000)
; CHECK-NEXT: liveins: $w0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[SUBSWri1:%[0-9]+]]:gpr32 = SUBSWri [[COPY]], 11, 0, implicit-def $nzcv
; CHECK-NEXT: Bcc 8, %bb.2, implicit $nzcv
; CHECK-NEXT: B %bb.2
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.2:
; CHECK-NEXT: liveins: $w0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 1
; CHECK-NEXT: $w0 = COPY [[MOVi32imm]]
; CHECK-NEXT: RET undef $lr, implicit $w0
bb.0:
liveins: $w0
%0:gpr32common = COPY $w0
%1:gpr32 = SUBSWri %0, 10, 0, implicit-def $nzcv
Bcc 8, %bb.1, implicit $nzcv
B %bb.2
bb.1:
liveins: $w0
%2:gpr32 = SUBSWri %0, 11, 0, implicit-def $nzcv
Bcc 8, %bb.2, implicit $nzcv
B %bb.2
bb.2:
liveins: $w0
%3:gpr32 = MOVi32imm 1
$w0 = COPY %3
RET undef $lr, implicit $w0
...
---
# CMP/CMP with LO/LO (unsigned <): imm differs by 1
# Head: cmp w0, #10; b.lo (w0 < 10 unsigned)
# True: cmp w0, #11; b.lo (w0 < 11 unsigned)
# Expected: One CMP adjusted to LS (<=)
name: cmp_cmp_lo_lo
tracksRegLiveness: true
body: |
; CHECK-LABEL: name: cmp_cmp_lo_lo
; CHECK: bb.0:
; CHECK-NEXT: successors: %bb.1(0x40000000), %bb.2(0x40000000)
; CHECK-NEXT: liveins: $w0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr32common = COPY $w0
; CHECK-NEXT: [[SUBSWri:%[0-9]+]]:gpr32 = SUBSWri [[COPY]], 10, 0, implicit-def $nzcv
; CHECK-NEXT: Bcc 3, %bb.1, implicit $nzcv
; CHECK-NEXT: B %bb.2
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.1:
; CHECK-NEXT: successors: %bb.2(0x80000000)
; CHECK-NEXT: liveins: $w0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[SUBSWri1:%[0-9]+]]:gpr32 = SUBSWri [[COPY]], 10, 0, implicit-def $nzcv
; CHECK-NEXT: Bcc 9, %bb.2, implicit $nzcv
; CHECK-NEXT: B %bb.2
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.2:
; CHECK-NEXT: liveins: $w0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 1
; CHECK-NEXT: $w0 = COPY [[MOVi32imm]]
; CHECK-NEXT: RET undef $lr, implicit $w0
bb.0:
liveins: $w0
%0:gpr32common = COPY $w0
%1:gpr32 = SUBSWri %0, 10, 0, implicit-def $nzcv
Bcc 3, %bb.1, implicit $nzcv
B %bb.2
bb.1:
liveins: $w0
%2:gpr32 = SUBSWri %0, 11, 0, implicit-def $nzcv
Bcc 3, %bb.2, implicit $nzcv
B %bb.2
bb.2:
liveins: $w0
%3:gpr32 = MOVi32imm 1
$w0 = COPY %3
RET undef $lr, implicit $w0
...
---
# CMP/CMP with HI/LO (unsigned > and <): imm differs by 2
# Head: cmp w0, #10; b.hi (w0 > 10 unsigned)
# True: cmp w0, #12; b.lo (w0 < 12 unsigned)
# This is the "a > 10 || a < 12" pattern -> always true for a == 11
# Expected: Adjusted to use same immediate
name: cmp_cmp_hi_lo
tracksRegLiveness: true
body: |
; CHECK-LABEL: name: cmp_cmp_hi_lo
; CHECK: bb.0:
; CHECK-NEXT: successors: %bb.1(0x40000000), %bb.2(0x40000000)
; CHECK-NEXT: liveins: $w0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr32common = COPY $w0
; CHECK-NEXT: [[SUBSWri:%[0-9]+]]:gpr32 = SUBSWri [[COPY]], 11, 0, implicit-def $nzcv
; CHECK-NEXT: Bcc 2, %bb.1, implicit $nzcv
; CHECK-NEXT: B %bb.2
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.1:
; CHECK-NEXT: successors: %bb.2(0x80000000)
; CHECK-NEXT: liveins: $w0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[SUBSWri1:%[0-9]+]]:gpr32 = SUBSWri [[COPY]], 11, 0, implicit-def $nzcv
; CHECK-NEXT: Bcc 9, %bb.2, implicit $nzcv
; CHECK-NEXT: B %bb.2
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.2:
; CHECK-NEXT: liveins: $w0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 1
; CHECK-NEXT: $w0 = COPY [[MOVi32imm]]
; CHECK-NEXT: RET undef $lr, implicit $w0
bb.0:
liveins: $w0
%0:gpr32common = COPY $w0
%1:gpr32 = SUBSWri %0, 10, 0, implicit-def $nzcv
Bcc 8, %bb.1, implicit $nzcv
B %bb.2
bb.1:
liveins: $w0
%2:gpr32 = SUBSWri %0, 12, 0, implicit-def $nzcv
Bcc 3, %bb.2, implicit $nzcv
B %bb.2
bb.2:
liveins: $w0
%3:gpr32 = MOVi32imm 1
$w0 = COPY %3
RET undef $lr, implicit $w0
...
---
# CMN/CMN with HI/HI: using ADDSWri (compare with negated immediate)
# Head: cmn w0, #1; b.hi (w0 > -1 unsigned, i.e., w0 != 0xFFFFFFFF)
# True: cmn w0, #2; b.hi (w0 > -2 unsigned)
name: cmn_cmn_hi_hi
tracksRegLiveness: true
body: |
; CHECK-LABEL: name: cmn_cmn_hi_hi
; CHECK: bb.0:
; CHECK-NEXT: successors: %bb.1(0x40000000), %bb.2(0x40000000)
; CHECK-NEXT: liveins: $w0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr32common = COPY $w0
; CHECK-NEXT: [[ADDSWri:%[0-9]+]]:gpr32 = ADDSWri [[COPY]], 1, 0, implicit-def $nzcv
; CHECK-NEXT: Bcc 8, %bb.1, implicit $nzcv
; CHECK-NEXT: B %bb.2
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.1:
; CHECK-NEXT: successors: %bb.2(0x80000000)
; CHECK-NEXT: liveins: $w0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[ADDSWri1:%[0-9]+]]:gpr32 = ADDSWri [[COPY]], 1, 0, implicit-def $nzcv
; CHECK-NEXT: Bcc 2, %bb.2, implicit $nzcv
; CHECK-NEXT: B %bb.2
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.2:
; CHECK-NEXT: liveins: $w0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 1
; CHECK-NEXT: $w0 = COPY [[MOVi32imm]]
; CHECK-NEXT: RET undef $lr, implicit $w0
bb.0:
liveins: $w0
%0:gpr32common = COPY $w0
%1:gpr32 = ADDSWri %0, 1, 0, implicit-def $nzcv
Bcc 8, %bb.1, implicit $nzcv
B %bb.2
bb.1:
liveins: $w0
%2:gpr32 = ADDSWri %0, 2, 0, implicit-def $nzcv
Bcc 8, %bb.2, implicit $nzcv
B %bb.2
bb.2:
liveins: $w0
%3:gpr32 = MOVi32imm 1
$w0 = COPY %3
RET undef $lr, implicit $w0
...
---
# CSINC/CSINC with HI/HI (unsigned >): imm differs by 1
name: csinc_hi_hi_intrablock
tracksRegLiveness: true
body: |
bb.0:
liveins: $w0
; CHECK-LABEL: name: csinc_hi_hi_intrablock
; CHECK: liveins: $w0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr32common = COPY $w0
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr32 = COPY [[COPY]]
; CHECK-NEXT: [[SUBSWri:%[0-9]+]]:gpr32 = SUBSWri [[COPY]], 11, 0, implicit-def $nzcv
; CHECK-NEXT: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr [[COPY1]], $wzr, 2, implicit $nzcv
; CHECK-NEXT: [[SUBSWri1:%[0-9]+]]:gpr32 = SUBSWri [[COPY]], 11, 0, implicit-def $nzcv
; CHECK-NEXT: [[CSINCWr1:%[0-9]+]]:gpr32 = CSINCWr [[COPY1]], $wzr, 8, implicit $nzcv
; CHECK-NEXT: $w0 = COPY [[CSINCWr1]]
; CHECK-NEXT: RET undef $lr, implicit $w0
%0:gpr32common = COPY $w0
%1:gpr32 = COPY %0
%2:gpr32 = SUBSWri %0, 10, 0, implicit-def $nzcv
%3:gpr32 = CSINCWr %1, $wzr, 8, implicit $nzcv
%4:gpr32 = SUBSWri %0, 11, 0, implicit-def $nzcv
%5:gpr32 = CSINCWr %1, $wzr, 8, implicit $nzcv
$w0 = COPY %5
RET undef $lr, implicit $w0
...
---
# CSINC/CSINC with LO/LO (unsigned <): imm differs by 1
name: csinc_lo_lo_intrablock
tracksRegLiveness: true
body: |
bb.0:
liveins: $w0
; CHECK-LABEL: name: csinc_lo_lo_intrablock
; CHECK: liveins: $w0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr32common = COPY $w0
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr32 = COPY [[COPY]]
; CHECK-NEXT: [[SUBSWri:%[0-9]+]]:gpr32 = SUBSWri [[COPY]], 10, 0, implicit-def $nzcv
; CHECK-NEXT: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr [[COPY1]], $wzr, 3, implicit $nzcv
; CHECK-NEXT: [[SUBSWri1:%[0-9]+]]:gpr32 = SUBSWri [[COPY]], 10, 0, implicit-def $nzcv
; CHECK-NEXT: [[CSINCWr1:%[0-9]+]]:gpr32 = CSINCWr [[COPY1]], $wzr, 9, implicit $nzcv
; CHECK-NEXT: $w0 = COPY [[CSINCWr1]]
; CHECK-NEXT: RET undef $lr, implicit $w0
%0:gpr32common = COPY $w0
%1:gpr32 = COPY %0
%2:gpr32 = SUBSWri %0, 10, 0, implicit-def $nzcv
%3:gpr32 = CSINCWr %1, $wzr, 3, implicit $nzcv
%4:gpr32 = SUBSWri %0, 11, 0, implicit-def $nzcv
%5:gpr32 = CSINCWr %1, $wzr, 3, implicit $nzcv
$w0 = COPY %5
RET undef $lr, implicit $w0
...
---
# Test: HI with immediate 0 can be optimized by adjusting upward
# Head: cmp w0, #0; b.hi (w0 > 0 unsigned)
# True: cmp w0, #1; b.hi (w0 > 1 unsigned)
# Expected: Head adjusted to cmp #1; b.hs (w0 >= 1, equivalent to w0 > 0)
name: cmp_cmp_hi_hi_wrap
tracksRegLiveness: true
body: |
; CHECK-LABEL: name: cmp_cmp_hi_hi_wrap
; CHECK: bb.0:
; CHECK-NEXT: successors: %bb.1(0x40000000), %bb.2(0x40000000)
; CHECK-NEXT: liveins: $w0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr32common = COPY $w0
; CHECK-NEXT: [[SUBSWri:%[0-9]+]]:gpr32 = SUBSWri [[COPY]], 1, 0, implicit-def $nzcv
; CHECK-NEXT: Bcc 2, %bb.1, implicit $nzcv
; CHECK-NEXT: B %bb.2
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.1:
; CHECK-NEXT: successors: %bb.2(0x80000000)
; CHECK-NEXT: liveins: $w0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[SUBSWri1:%[0-9]+]]:gpr32 = SUBSWri [[COPY]], 1, 0, implicit-def $nzcv
; CHECK-NEXT: Bcc 8, %bb.2, implicit $nzcv
; CHECK-NEXT: B %bb.2
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.2:
; CHECK-NEXT: liveins: $w0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 1
; CHECK-NEXT: $w0 = COPY [[MOVi32imm]]
; CHECK-NEXT: RET undef $lr, implicit $w0
bb.0:
liveins: $w0
%0:gpr32common = COPY $w0
%1:gpr32 = SUBSWri %0, 0, 0, implicit-def $nzcv
Bcc 8, %bb.1, implicit $nzcv
B %bb.2
bb.1:
liveins: $w0
%2:gpr32 = SUBSWri %0, 1, 0, implicit-def $nzcv
Bcc 8, %bb.2, implicit $nzcv
B %bb.2
bb.2:
liveins: $w0
%3:gpr32 = MOVi32imm 1
$w0 = COPY %3
RET undef $lr, implicit $w0
...
---
# Signed CMP/CMN with GT/GT at -1/0 boundary: cmn 1 -> cmp 0 transformation
# Head: cmn w0, #1; b.gt (w0 > -1 signed, i.e., w0 >= 0)
# True: cmp w0, #0; b.gt (w0 > 0 signed)
# Expected: Head adjusted to cmp #0; b.ge (w0 >= 0, equivalent to w0 > -1)
# This tests the cmn 1 -> cmp 0 opcode flip for signed comparisons.
# Condition codes: GT = 10 (signed >), GE = 11 (signed >=)
name: cmn_cmp_gt_gt_signed_boundary
tracksRegLiveness: true
body: |
; CHECK-LABEL: name: cmn_cmp_gt_gt_signed_boundary
; CHECK: bb.0:
; CHECK-NEXT: successors: %bb.1(0x40000000), %bb.2(0x40000000)
; CHECK-NEXT: liveins: $w0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr32common = COPY $w0
; CHECK-NEXT: [[ADDSWri:%[0-9]+]]:gpr32 = ADDSWri [[COPY]], 1, 0, implicit-def $nzcv
; CHECK-NEXT: Bcc 10, %bb.1, implicit $nzcv
; CHECK-NEXT: B %bb.2
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.1:
; CHECK-NEXT: successors: %bb.2(0x80000000)
; CHECK-NEXT: liveins: $w0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[SUBSWri:%[0-9]+]]:gpr32 = SUBSWri [[COPY]], 0, 0, implicit-def $nzcv
; CHECK-NEXT: Bcc 10, %bb.2, implicit $nzcv
; CHECK-NEXT: B %bb.2
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.2:
; CHECK-NEXT: liveins: $w0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 1
; CHECK-NEXT: $w0 = COPY [[MOVi32imm]]
; CHECK-NEXT: RET undef $lr, implicit $w0
bb.0:
liveins: $w0
%0:gpr32common = COPY $w0
%1:gpr32 = ADDSWri %0, 1, 0, implicit-def $nzcv
Bcc 10, %bb.1, implicit $nzcv
B %bb.2
bb.1:
liveins: $w0
%2:gpr32 = SUBSWri %0, 0, 0, implicit-def $nzcv
Bcc 10, %bb.2, implicit $nzcv
B %bb.2
bb.2:
liveins: $w0
%3:gpr32 = MOVi32imm 1
$w0 = COPY %3
RET undef $lr, implicit $w0
...
---
# Mixed signed/unsigned should NOT optimize
# Head: cmp w0, #10; b.gt (signed >)
# True: cmp w0, #11; b.hi (unsigned >)
name: cmp_cmp_gt_hi_no_opt
tracksRegLiveness: true
body: |
; CHECK-LABEL: name: cmp_cmp_gt_hi_no_opt
; CHECK: bb.0:
; CHECK-NEXT: successors: %bb.1(0x40000000), %bb.2(0x40000000)
; CHECK-NEXT: liveins: $w0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr32common = COPY $w0
; CHECK-NEXT: [[SUBSWri:%[0-9]+]]:gpr32 = SUBSWri [[COPY]], 11, 0, implicit-def $nzcv
; CHECK-NEXT: Bcc 10, %bb.1, implicit $nzcv
; CHECK-NEXT: B %bb.2
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.1:
; CHECK-NEXT: successors: %bb.2(0x80000000)
; CHECK-NEXT: liveins: $w0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[SUBSWri1:%[0-9]+]]:gpr32 = SUBSWri [[COPY]], 11, 0, implicit-def $nzcv
; CHECK-NEXT: Bcc 8, %bb.2, implicit $nzcv
; CHECK-NEXT: B %bb.2
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.2:
; CHECK-NEXT: liveins: $w0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 1
; CHECK-NEXT: $w0 = COPY [[MOVi32imm]]
; CHECK-NEXT: RET undef $lr, implicit $w0
bb.0:
liveins: $w0
%0:gpr32common = COPY $w0
%1:gpr32 = SUBSWri %0, 10, 0, implicit-def $nzcv
Bcc 12, %bb.1, implicit $nzcv
B %bb.2
bb.1:
liveins: $w0
%2:gpr32 = SUBSWri %0, 11, 0, implicit-def $nzcv
Bcc 8, %bb.2, implicit $nzcv
B %bb.2
bb.2:
liveins: $w0
%3:gpr32 = MOVi32imm 1
$w0 = COPY %3
RET undef $lr, implicit $w0
...
---
# 64-bit variant: CMP/CMP with HI/HI
name: cmp_cmp_hi_hi_64
tracksRegLiveness: true
body: |
; CHECK-LABEL: name: cmp_cmp_hi_hi_64
; CHECK: bb.0:
; CHECK-NEXT: successors: %bb.1(0x40000000), %bb.2(0x40000000)
; CHECK-NEXT: liveins: $x0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr64common = COPY $x0
; CHECK-NEXT: [[SUBSXri:%[0-9]+]]:gpr64 = SUBSXri [[COPY]], 11, 0, implicit-def $nzcv
; CHECK-NEXT: Bcc 2, %bb.1, implicit $nzcv
; CHECK-NEXT: B %bb.2
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.1:
; CHECK-NEXT: successors: %bb.2(0x80000000)
; CHECK-NEXT: liveins: $x0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[SUBSXri1:%[0-9]+]]:gpr64 = SUBSXri [[COPY]], 11, 0, implicit-def $nzcv
; CHECK-NEXT: Bcc 8, %bb.2, implicit $nzcv
; CHECK-NEXT: B %bb.2
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.2:
; CHECK-NEXT: liveins: $x0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[MOVi64imm:%[0-9]+]]:gpr64 = MOVi64imm 1
; CHECK-NEXT: $x0 = COPY [[MOVi64imm]]
; CHECK-NEXT: RET undef $lr, implicit $x0
bb.0:
liveins: $x0
%0:gpr64common = COPY $x0
%1:gpr64 = SUBSXri %0, 10, 0, implicit-def $nzcv
Bcc 8, %bb.1, implicit $nzcv
B %bb.2
bb.1:
liveins: $x0
%2:gpr64 = SUBSXri %0, 11, 0, implicit-def $nzcv
Bcc 8, %bb.2, implicit $nzcv
B %bb.2
bb.2:
liveins: $x0
%3:gpr64 = MOVi64imm 1
$x0 = COPY %3
RET undef $lr, implicit $x0
...