# RUN: llc -mtriple=aarch64-linux-gnu -run-pass machine-combiner -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 ...