# RUN: llc -mtriple=aarch64--linux-gnu -run-pass=aarch64-copyelim %s -verify-machineinstrs -o - | FileCheck %s
---
# Check that bb.0 COPY is seen through to allow the bb.1 COPY of XZR to be removed.
# CHECK-LABEL: name: test1
# CHECK-NOT: COPY %xzr
name:            test1
tracksRegLiveness: true
body:             |
  bb.0:
    liveins: %x0, %x1

    %x0 = COPY %x1
    CBNZX %x1, %bb.2

  bb.1:
    %x0 = COPY %xzr
    B %bb.3

  bb.2:
    liveins: %x1

    %x0 = LDRXui %x1, 0

  bb.3:
    liveins: %x0

    RET_ReallyLR implicit %x0

...
# Similar to test1, but with reversed COPY.
# CHECK-LABEL: name: test2
# CHECK-NOT: COPY %xzr
name:            test2
tracksRegLiveness: true
body:             |
  bb.0:
    liveins: %x0, %x1

    %x1 = COPY %x0
    CBNZX %x1, %bb.2

  bb.1:
    %x0 = COPY %xzr
    B %bb.3

  bb.2:
    liveins: %x1

    %x0 = LDRXui %x1, 0

  bb.3:
    liveins: %x0

    RET_ReallyLR implicit %x0

...
# Similar to test1, but with a clobber that prevents removal of the XZR COPY.
# CHECK-LABEL: name: test3
# CHECK: COPY %xzr
name:            test3
tracksRegLiveness: true
body:             |
  bb.0:
    liveins: %x0, %x1, %x2

    %x0 = COPY %x1
    %x1 = LDRXui %x1, 0
    CBNZX %x1, %bb.2

  bb.1:
    %x0 = COPY %xzr
    B %bb.3

  bb.2:
    liveins: %x1

    %x0 = LDRXui %x1, 0

  bb.3:
    liveins: %x0

    RET_ReallyLR implicit %x0

...
# Similar to test2, but with a clobber that prevents removal of the XZR COPY.
# CHECK-LABEL: name: test4
# CHECK: COPY %xzr
name:            test4
tracksRegLiveness: true
body:             |
  bb.0:
    liveins: %x0, %x1, %x2

    %x1 = COPY %x0
    %x1 = LDRXui %x1, 0
    CBNZX %x1, %bb.2

  bb.1:
    %x0 = COPY %xzr
    B %bb.3

  bb.2:
    liveins: %x1

    %x0 = LDRXui %x1, 0

  bb.3:
    liveins: %x0

    RET_ReallyLR implicit %x0

...
# Similar to test2, but with a clobber that prevents removal of the XZR COPY.
# CHECK-LABEL: name: test5
# CHECK: COPY %xzr
name:            test5
tracksRegLiveness: true
body:             |
  bb.0:
    liveins: %x0, %x1, %x2

    %x1 = COPY %x0
    %x0 = LDRXui %x1, 0
    CBNZX %x1, %bb.2

  bb.1:
    %x0 = COPY %xzr
    B %bb.3

  bb.2:
    liveins: %x1

    %x0 = LDRXui %x1, 0

  bb.3:
    liveins: %x0

    RET_ReallyLR implicit %x0

...
# Similar to test1, but with two levels of COPYs.
# CHECK-LABEL: name: test6
# CHECK-NOT: COPY %xzr
name:            test6
tracksRegLiveness: true
body:             |
  bb.0:
    liveins: %x0, %x1, %x2

    %x2 = COPY %x0
    %x1 = COPY %x2
    CBNZX %x1, %bb.2

  bb.1:
    %x0 = COPY %xzr
    B %bb.3

  bb.2:
    liveins: %x1

    %x0 = LDRXui %x1, 0

  bb.3:
    liveins: %x0

    RET_ReallyLR implicit %x0

...
# Similar to test1, but with two levels of COPYs and a clobber preventing COPY of XZR removal.
# CHECK-LABEL: name: test7
# CHECK: COPY %xzr
name:            test7
tracksRegLiveness: true
body:             |
  bb.0:
    liveins: %x0, %x1, %x2

    %x2 = COPY %x0
    %x0 = LDRXui %x1, 0
    %x1 = COPY %x2
    CBNZX %x1, %bb.2

  bb.1:
    %x0 = COPY %xzr
    B %bb.3

  bb.2:
    liveins: %x1

    %x0 = LDRXui %x1, 0

  bb.3:
    liveins: %x0

    RET_ReallyLR implicit %x0

...
# Check that the TargetRegs vector clobber update loop in
#  AArch64RedundantCopyElimination::optimizeCopy works correctly.
# CHECK-LABEL: name: test8
# CHECK: x0 = COPY %xzr
# CHECK: x1 = COPY %xzr
name:            test8
tracksRegLiveness: true
body:             |
  bb.0:
    liveins: %x0, %x1

    %x1 = COPY %x0
    CBNZX %x1, %bb.2

  bb.1:
    liveins: %x0, %x2

    %x0, %x1 = LDPXi %x2, 0
    %x0 = COPY %xzr
    %x1 = COPY %xzr
    B %bb.3

  bb.2:
    liveins: %x1

    %x0 = LDRXui %x1, 0

  bb.3:
    liveins: %x0

    RET_ReallyLR implicit %x0

...
# Check that copy isn't removed from a block with multiple predecessors.
# CHECK-LABEL: name: test9
# CHECK: x0 = COPY %xzr
# CHECK-NEXT: B %bb.3
name:            test9
tracksRegLiveness: true
body:             |
  bb.0:
    liveins: %x0, %x1

    CBNZX %x0, %bb.2

  bb.1:
    liveins: %x0, %x2

    %x0 = COPY %xzr
    B %bb.3

  bb.2:
    liveins: %x1

    %x0 = LDRXui %x1, 0

    CBNZX %x1, %bb.1

  bb.3:
    liveins: %x0

    RET_ReallyLR implicit %x0

...
# Eliminate redundant MOVi32imm 7 in bb.1
# Note: 32-bit compare/32-bit move imm
# Kill marker should be removed from compare.
# CHECK-LABEL: name: test10
# CHECK: SUBSWri %w0, 7, 0, implicit-def %nzcv
# CHECK: bb.1:
# CHECK-NOT: MOVi32imm
name:            test10
tracksRegLiveness: true
body:             |
  bb.0.entry:
    liveins: %w0, %x1

    dead %wzr = SUBSWri killed %w0, 7, 0, implicit-def %nzcv
    Bcc 1, %bb.2, implicit killed %nzcv
    B %bb.1

  bb.1:
    liveins: %x1

    %w0 = MOVi32imm 7
    STRWui killed %w0, killed %x1, 0

  bb.2:
    RET_ReallyLR
...
# Eliminate redundant MOVi32imm 7 in bb.1
# Note: 64-bit compare/32-bit move imm w/implicit def
# Kill marker should be removed from compare.
# CHECK-LABEL: name: test11
# CHECK: SUBSXri %x0, 7, 0, implicit-def %nzcv
# CHECK: bb.1:
# CHECK-NOT: MOVi32imm
name:            test11
tracksRegLiveness: true
body:             |
  bb.0.entry:
    liveins: %x0, %x1

    dead %xzr = SUBSXri killed %x0, 7, 0, implicit-def %nzcv
    Bcc 1, %bb.2, implicit killed %nzcv
    B %bb.1

  bb.1:
    liveins: %x1

    %w0 = MOVi32imm 7, implicit-def %x0
    STRXui killed %x0, killed %x1, 0

  bb.2:
    RET_ReallyLR
...
# Eliminate redundant MOVi32imm 7 in bb.1
# Note: 64-bit compare/32-bit move imm
# Kill marker should be removed from compare.
# CHECK-LABEL: name: test12
# CHECK: SUBSXri %x0, 7, 0, implicit-def %nzcv
# CHECK: bb.1:
# CHECK-NOT: MOVi32imm
name:            test12
tracksRegLiveness: true
body:             |
  bb.0.entry:
    liveins: %x0, %x1

    dead %xzr = SUBSXri killed %x0, 7, 0, implicit-def %nzcv
    Bcc 1, %bb.2, implicit killed %nzcv
    B %bb.1

  bb.1:
    liveins: %x1

    %w0 = MOVi32imm 7
    STRWui killed %w0, killed %x1, 0

  bb.2:
    RET_ReallyLR
...
# Don't eliminate MOVi32imm 7 in bb.1 as we don't necessarily know the upper 32-bits.
# Note: 32-bit compare/32-bit move imm w/implicit def
# Kill marker should remain on compare.
# CHECK-LABEL: name: test13
# CHECK: SUBSWri killed %w0, 7, 0, implicit-def %nzcv
# CHECK: bb.1:
# CHECK: MOVi32imm
name:            test13
tracksRegLiveness: true
body:             |
  bb.0.entry:
    liveins: %w0, %x1

    dead %wzr = SUBSWri killed %w0, 7, 0, implicit-def %nzcv
    Bcc 1, %bb.2, implicit killed %nzcv
    B %bb.1

  bb.1:
    liveins: %x1

    %w0 = MOVi32imm 7, implicit-def %x0
    STRXui killed %x0, killed %x1, 0

  bb.2:
    RET_ReallyLR
...
# We can't eliminate the MOVi32imm because of the clobbering LDRWui.
# CHECK-LABEL: name: test14
# CHECK: bb.1:
# CHECK: MOVi32imm
name:            test14
tracksRegLiveness: true
body:             |
  bb.0.entry:
    liveins: %w0, %x1, %x2

    dead %wzr = SUBSWri killed %w0, 7, 0, implicit-def %nzcv
    %w0 = LDRWui %x1, 0
    STRWui killed %w0, killed %x2, 0
    Bcc 1, %bb.2, implicit killed %nzcv
    B %bb.1

  bb.1:
    liveins: %x1

    %w0 = MOVi32imm 7
    STRWui killed %w0, killed %x1, 0

  bb.2:
    RET_ReallyLR
...
# We can't eliminate the MOVi32imm because of the clobbering LDRWui.
# CHECK-LABEL: name: test15
# CHECK: bb.1:
# CHECK: MOVi32imm
name:            test15
tracksRegLiveness: true
body:             |
  bb.0.entry:
    liveins: %w0, %x1, %x2

    dead %wzr = SUBSWri killed %w0, 7, 0, implicit-def %nzcv
    Bcc 1, %bb.2, implicit killed %nzcv
    B %bb.1

  bb.1:
    liveins: %x1, %x2

    %w0 = LDRWui %x1, 0
    STRWui killed %w0, killed %x2, 0
    %w0 = MOVi32imm 7
    STRWui killed %w0, killed %x1, 0

  bb.2:
    RET_ReallyLR
...
# Check that bb.0 COPY is seen through to allow the bb.1 MOVi32imm to be removed.
# CHECK-LABEL: name: test16
# CHECK: bb.1:
# CHECK-NOT: MOVi32imm
name:            test16
tracksRegLiveness: true
body:             |
  bb.0.entry:
    liveins: %w0, %x1

    dead %wzr = SUBSWri %w0, 7, 0, implicit-def %nzcv
    %w2 = COPY %w0
    Bcc 1, %bb.2, implicit killed %nzcv
    B %bb.1

  bb.1:
    liveins: %x1

    %w2 = MOVi32imm 7
    STRWui killed %w2, killed %x1, 0

  bb.2:
    RET_ReallyLR
...
# Check that bb.1 MOVi32imm is not removed due to self clobbering compare.
# CHECK-LABEL: name: test17
# CHECK: bb.1:
# CHECK: MOVi32imm
name:            test17
tracksRegLiveness: true
body:             |
  bb.0.entry:
    liveins: %w0, %x1

    dead %w0 = SUBSWri killed %w0, 7, 0, implicit-def %nzcv
    Bcc 1, %bb.2, implicit killed %nzcv
    B %bb.1

  bb.1:
    liveins: %x1

    %w0 = MOVi32imm 7
    STRWui killed %w0, killed %x1, 0

  bb.2:
    RET_ReallyLR
...
# Make sure the MOVi64imm is not removed.  In one version of this patch the
# MOVi64imm immediate was truncated to 32 bits and incorrectly matched because
# the low 32 bits of 4252017623040 are all zero.
# CHECK-LABEL: name: test18
# CHECK: bb.1:
# CHECK: MOVi64imm
name:            test18
tracksRegLiveness: true
body:             |
  bb.0.entry:
    liveins: %x0, %x1

    CBNZX killed %x0, %bb.2
    B %bb.1

  bb.1:
    liveins: %x1

    %x0 = MOVi64imm 4252017623040
    STRXui killed %x0, killed %x1, 0

  bb.2:
    RET_ReallyLR
...
# Eliminate redundant MOVi32imm -1 in bb.1
# Note: 32-bit compare/32-bit move imm
# Kill marker should be removed from compare.
# CHECK-LABEL: name: test19
# CHECK: ADDSWri %w0, 1, 0, implicit-def %nzcv
# CHECK: bb.1:
# CHECK-NOT: MOVi32imm
name:            test19
tracksRegLiveness: true
body:             |
  bb.0.entry:
    liveins: %w0, %x1

    dead %wzr = ADDSWri killed %w0, 1, 0, implicit-def %nzcv
    Bcc 1, %bb.2, implicit killed %nzcv
    B %bb.1

  bb.1:
    liveins: %x1

    %w0 = MOVi32imm -1
    STRWui killed %w0, killed %x1, 0

  bb.2:
    RET_ReallyLR
...
# Eliminate redundant MOVi64imm -1 in bb.1
# Note: 64-bit compare/64-bit move imm
# Kill marker should be removed from compare.
# CHECK-LABEL: name: test20
# CHECK: ADDSXri %x0, 1, 0, implicit-def %nzcv
# CHECK: bb.1:
# CHECK-NOT: MOVi64imm
name:            test20
tracksRegLiveness: true
body:             |
  bb.0:
    liveins: %x0, %x1

    dead %xzr = ADDSXri killed %x0, 1, 0, implicit-def %nzcv
    Bcc 1, %bb.2, implicit killed %nzcv
    B %bb.1

  bb.1:
    liveins: %x1

    %x0 = MOVi64imm -1
    STRXui killed %x0, killed %x1, 0

  bb.2:
    RET_ReallyLR
...
# Eliminate redundant MOVi32imm -1 in bb.1
# Note: 64-bit compare/32-bit move imm
# Kill marker should be removed from compare.
# CHECK-LABEL: name: test21
# CHECK: ADDSXri %x0, 1, 0, implicit-def %nzcv
# CHECK: bb.1:
# CHECK-NOT: MOVi32imm
name:            test21
tracksRegLiveness: true
body:             |
  bb.0.entry:
    liveins: %x0, %x1

    dead %xzr = ADDSXri killed %x0, 1, 0, implicit-def %nzcv
    Bcc 1, %bb.2, implicit killed %nzcv
    B %bb.1

  bb.1:
    liveins: %x1

    %w0 = MOVi32imm -1
    STRWui killed %w0, killed %x1, 0

  bb.2:
    RET_ReallyLR
...
# Don't eliminate MOVi64imm -1 in bb.1 as we don't necessarily know the upper 32-bits.
# Note: 32-bit compare/64-bit move imm
# CHECK-LABEL: name: test22
# CHECK: bb.1:
# CHECK: MOVi64imm
name:            test22
tracksRegLiveness: true
body:             |
  bb.0.entry:
    liveins: %w0, %x1

    dead %wzr = ADDSWri killed %w0, 1, 0, implicit-def %nzcv
    Bcc 1, %bb.2, implicit killed %nzcv
    B %bb.1

  bb.1:
    liveins: %x1

    %x0 = MOVi64imm -1
    STRXui killed %x0, killed %x1, 0

  bb.2:
    RET_ReallyLR
...
# Eliminate redundant MOVi32imm 4096 in bb.1 when the compare has a shifted immediate.
# CHECK-LABEL: name: test23
# CHECK: bb.1:
# CHECK-NOT: MOVi32imm
name:            test23
tracksRegLiveness: true
body:             |
  bb.0.entry:
    liveins: %w0, %x1

    dead %wzr = SUBSWri killed %w0, 1, 12, implicit-def %nzcv
    Bcc 1, %bb.2, implicit killed %nzcv
    B %bb.1

  bb.1:
    liveins: %x1

    %w0 = MOVi32imm 4096
    STRWui killed %w0, killed %x1, 0

  bb.2:
    RET_ReallyLR
