llvm/llvm/test/CodeGen/AArch64/machine-combiner-subadd2.mir

# RUN: llc -mtriple=aarch64-linux-gnu -run-pass machine-combiner -verify-machineinstrs -o - %s | FileCheck %s

# The test cases in this file check following transformation if the right form
# can reduce latency.
#     A - (B + C)  ==>   (A - B) - C

---
# 32 bit.

# CHECK-LABEL: name: test1
# CHECK:       [[TMP:%[0-9]+]]:gpr32common = SUBWrr killed %3, %4
# CHECK-NEXT:  %7:gpr32 = SUBWrr killed [[TMP]], %5

name:            test1
registers:
  - { id: 0, class: gpr32common }
  - { id: 1, class: gpr32 }
  - { id: 2, class: gpr32 }
  - { id: 3, class: gpr32common }
  - { id: 4, class: gpr32common }
  - { id: 5, class: gpr32 }
  - { id: 6, class: gpr32 }
  - { id: 7, class: gpr32 }
  - { id: 8, class: gpr32 }
body:              |
  bb.0:
    %2:gpr32 = COPY $w2
    %1:gpr32 = COPY $w1
    %0:gpr32common = COPY $w0
    %3:gpr32common = ORRWri %2:gpr32, 1600
    %4:gpr32common = ADDWri %0:gpr32common, 100, 0
    %5:gpr32 = EORWrs %1:gpr32, %4:gpr32common, 8
    %6:gpr32 = ADDWrr %5:gpr32, %4:gpr32common
    %7:gpr32 = SUBWrr killed %3:gpr32common, killed %6:gpr32
    %8:gpr32 = EORWrs killed %7:gpr32, %5:gpr32, 141
    $w0 = COPY %8:gpr32
    RET_ReallyLR implicit $w0

...
---
# 64 bit.

# CHECK-LABEL: name: test2
# CHECK:       [[TMP:%[0-9]+]]:gpr64common = SUBXrr killed %3, %4
# CHECK-NEXT:  %7:gpr64 = SUBXrr killed [[TMP]], %5

name:            test2
registers:
  - { id: 0, class: gpr64common }
  - { id: 1, class: gpr64 }
  - { id: 2, class: gpr64 }
  - { id: 3, class: gpr64common }
  - { id: 4, class: gpr64common }
  - { id: 5, class: gpr64 }
  - { id: 6, class: gpr64 }
  - { id: 7, class: gpr64 }
  - { id: 8, class: gpr64 }
body:              |
  bb.0:
    %2:gpr64 = COPY $x2
    %1:gpr64 = COPY $x1
    %0:gpr64common = COPY $x0
    %3:gpr64common = ORRXri %2:gpr64, 1600
    %4:gpr64common = ADDXri %0:gpr64common, 100, 0
    %5:gpr64 = EORXrs %1:gpr64, %4:gpr64common, 8
    %6:gpr64 = ADDXrr %5:gpr64, %4:gpr64common
    %7:gpr64 = SUBXrr killed %3:gpr64common, killed %6:gpr64
    %8:gpr64 = EORXrs killed %7:gpr64, %5:gpr64, 141
    $x0 = COPY %8:gpr64
    RET_ReallyLR implicit $x0

...
---
# Negative test. The right form can't reduce latency.

# CHECK-LABEL: name: test3
# CHECK:       %6:gpr32 = ADDWrr killed %3, %4
# CHECK-NEXT:  %7:gpr32 = SUBWrr %5, killed %6

name:           test3
registers:
  - { id: 0, class: gpr32common }
  - { id: 1, class: gpr32 }
  - { id: 2, class: gpr32 }
  - { id: 3, class: gpr32common }
  - { id: 4, class: gpr32common }
  - { id: 5, class: gpr32 }
  - { id: 6, class: gpr32 }
  - { id: 7, class: gpr32 }
  - { id: 8, class: gpr32 }
body:              |
  bb.0:
    %2:gpr32 = COPY $w2
    %1:gpr32 = COPY $w1
    %0:gpr32common = COPY $w0
    %3:gpr32common = ORRWri %2:gpr32, 1600
    %4:gpr32common = ADDWri %0:gpr32common, 100, 0
    %5:gpr32 = EORWrs %1:gpr32, %4:gpr32common, 8
    %6:gpr32 = ADDWrr killed %3:gpr32common, %4:gpr32common
    %7:gpr32 = SUBWrr %5:gpr32, killed %6:gpr32
    %8:gpr32 = EORWrs killed %7:gpr32, %5:gpr32, 141
    $w0 = COPY %8:gpr32
    RET_ReallyLR implicit $w0

...
---
# Dead define of flag registers should not block transformation.

# CHECK-LABEL: name: test4
# CHECK:       [[TMP:%[0-9]+]]:gpr64common = SUBXrr killed %3, %4
# CHECK-NEXT:  %7:gpr64 = SUBXrr killed [[TMP]], %5

name:            test4
registers:
  - { id: 0, class: gpr64common }
  - { id: 1, class: gpr64 }
  - { id: 2, class: gpr64 }
  - { id: 3, class: gpr64common }
  - { id: 4, class: gpr64common }
  - { id: 5, class: gpr64 }
  - { id: 6, class: gpr64 }
  - { id: 7, class: gpr64 }
  - { id: 8, class: gpr64 }
body:              |
  bb.0:
    %2:gpr64 = COPY $x2
    %1:gpr64 = COPY $x1
    %0:gpr64common = COPY $x0
    %3:gpr64common = ORRXri %2:gpr64, 1600
    %4:gpr64common = ADDXri %0:gpr64common, 100, 0
    %5:gpr64 = EORXrs %1:gpr64, %4:gpr64common, 8
    %6:gpr64 = ADDSXrr %5:gpr64, %4:gpr64common, implicit-def dead $nzcv
    %7:gpr64 = SUBSXrr killed %3:gpr64common, killed %6:gpr64, implicit-def dead $nzcv
    %8:gpr64 = EORXrs killed %7:gpr64, %5:gpr64, 141
    $x0 = COPY %8:gpr64
    RET_ReallyLR implicit $x0

...
---
# Non dead define of flag register in SUB can block the transformation.

# CHECK-LABEL: name: test5
# CHECK:       %6:gpr32 = ADDWrr %5, %4
# CHECK-NEXT:  %7:gpr32 = SUBSWrr killed %3, killed %6, implicit-def $nzcv

name:            test5
registers:
  - { id: 0, class: gpr32common }
  - { id: 1, class: gpr32 }
  - { id: 2, class: gpr32 }
  - { id: 3, class: gpr32common }
  - { id: 4, class: gpr32common }
  - { id: 5, class: gpr32 }
  - { id: 6, class: gpr32 }
  - { id: 7, class: gpr32 }
  - { id: 8, class: gpr32 }
body:              |
  bb.0:
    %2:gpr32 = COPY $w2
    %1:gpr32 = COPY $w1
    %0:gpr32common = COPY $w0
    %3:gpr32common = ORRWri %2:gpr32, 1600
    %4:gpr32common = ADDWri %0:gpr32common, 100, 0
    %5:gpr32 = EORWrs %1:gpr32, %4:gpr32common, 8
    %6:gpr32 = ADDWrr %5:gpr32, %4:gpr32common
    %7:gpr32 = SUBSWrr killed %3:gpr32common, killed %6:gpr32, implicit-def $nzcv
    %8:gpr32 = EORWrs killed %7:gpr32, %5:gpr32, 141
    $w0 = COPY %8:gpr32
    RET_ReallyLR implicit $w0

...
---
# Non dead define of flag register in ADD can block the transformation.

# CHECK-LABEL: name: test6
# CHECK:       %6:gpr64 = ADDSXrr %5, %4, implicit-def $nzcv
# CHECK-NEXT:  %7:gpr64 = SUBXrr killed %3, killed %6

name:            test6
registers:
  - { id: 0, class: gpr64common }
  - { id: 1, class: gpr64 }
  - { id: 2, class: gpr64 }
  - { id: 3, class: gpr64common }
  - { id: 4, class: gpr64common }
  - { id: 5, class: gpr64 }
  - { id: 6, class: gpr64 }
  - { id: 7, class: gpr64 }
  - { id: 8, class: gpr64 }
body:              |
  bb.0:
    %2:gpr64 = COPY $x2
    %1:gpr64 = COPY $x1
    %0:gpr64common = COPY $x0
    %3:gpr64common = ORRXri %2:gpr64, 1600
    %4:gpr64common = ADDXri %0:gpr64common, 100, 0
    %5:gpr64 = EORXrs %1:gpr64, %4:gpr64common, 8
    %6:gpr64 = ADDSXrr %5:gpr64, %4:gpr64common, implicit-def $nzcv
    %7:gpr64 = SUBXrr killed %3:gpr64common, killed %6:gpr64
    %8:gpr64 = EORXrs killed %7:gpr64, %5:gpr64, 141
    $x0 = COPY %8:gpr64
    RET_ReallyLR implicit $x0

...
---
# ADD has multiple uses, so it is always required, we should not transform it.

# CHECK-LABEL: name: test7
# CHECK:       %6:gpr32 = ADDWrr %5, %4
# CHECK-NEXT:  %7:gpr32 = SUBWrr killed %3, %6

name:            test7
registers:
  - { id: 0, class: gpr32common }
  - { id: 1, class: gpr32 }
  - { id: 2, class: gpr32 }
  - { id: 3, class: gpr32common }
  - { id: 4, class: gpr32common }
  - { id: 5, class: gpr32 }
  - { id: 6, class: gpr32 }
  - { id: 7, class: gpr32 }
  - { id: 8, class: gpr32 }
  - { id: 9, class: gpr32 }
body:              |
  bb.0:
    %2:gpr32 = COPY $w2
    %1:gpr32 = COPY $w1
    %0:gpr32common = COPY $w0
    %3:gpr32common = ORRWri %2:gpr32, 1600
    %4:gpr32common = ADDWri %0:gpr32common, 100, 0
    %5:gpr32 = EORWrs %1:gpr32, %4:gpr32common, 8
    %6:gpr32 = ADDWrr %5:gpr32, %4:gpr32common
    %7:gpr32 = SUBWrr killed %3:gpr32common, %6:gpr32
    %8:gpr32 = EORWrs killed %7:gpr32, %5:gpr32, 141
    %9:gpr32 = ADDWrr %8:gpr32, %6:gpr32
    $w0 = COPY %9:gpr32
    RET_ReallyLR implicit $w0

...
---
# Drop nowrap flags in SUB

# CHECK-LABEL: name: test8
# CHECK:       [[SUBXrr:%[0-9]+]]:gpr64 = SUBXrr %1, %0
# CHECK-NEXT:  %4:gpr64common = SUBXrr killed [[SUBXrr]], killed %2

name:            test8
registers:
  - { id: 0, class: gpr64 }
  - { id: 1, class: gpr64 }
  - { id: 2, class: gpr64common }
  - { id: 3, class: gpr64 }
  - { id: 4, class: gpr64common }
  - { id: 5, class: gpr64 }
body:              |
  bb.0:
    %1:gpr64 = COPY $x1
    %0:gpr64 = COPY $x0
    %2:gpr64common = ORRXri %0:gpr64, 4096
    %3:gpr64 = ADDXrr killed %2:gpr64common, %0:gpr64
    %4:gpr64common = nsw SUBSXrr %1:gpr64, killed %3:gpr64, implicit-def dead $nzcv
    %5:gpr64 = SUBSXri %4:gpr64common, 0, 0, implicit-def $nzcv
    $x0 = COPY %5:gpr64
    RET_ReallyLR implicit $x0

...