|  | # RUN: llc -march=x86 -run-pass machine-cp -verify-machineinstrs -o - %s | FileCheck %s | 
|  |  | 
|  | --- | | 
|  | declare void @foo() | 
|  | define void @copyprop_remove_kill0() { ret void } | 
|  | define void @copyprop_remove_kill1() { ret void } | 
|  | define void @copyprop_remove_kill2() { ret void } | 
|  | define void @copyprop0() { ret void } | 
|  | define void @copyprop1() { ret void } | 
|  | define void @copyprop2() { ret void } | 
|  | define void @nocopyprop0() { ret void } | 
|  | define void @nocopyprop1() { ret void } | 
|  | define void @nocopyprop2() { ret void } | 
|  | define void @nocopyprop3() { ret void } | 
|  | define void @nocopyprop4() { ret void } | 
|  | define void @nocopyprop5() { ret void } | 
|  | ... | 
|  | --- | 
|  | # The second copy is redundant and will be removed, check that we also remove | 
|  | # the kill flag of intermediate instructions. | 
|  | # CHECK-LABEL: name: copyprop_remove_kill0 | 
|  | # CHECK: bb.0: | 
|  | # CHECK-NEXT: %rax = COPY %rdi | 
|  | # CHECK-NEXT: NOOP implicit %rdi | 
|  | # CHECK-NOT: COPY | 
|  | # CHECK-NEXT: NOOP implicit %rax, implicit %rdi | 
|  | name: copyprop_remove_kill0 | 
|  | body: | | 
|  | bb.0: | 
|  | %rax = COPY %rdi | 
|  | NOOP implicit killed %rdi | 
|  | %rdi = COPY %rax | 
|  | NOOP implicit %rax, implicit %rdi | 
|  | ... | 
|  | --- | 
|  | # The second copy is redundant and will be removed, check that we also remove | 
|  | # the kill flag of intermediate instructions. | 
|  | # CHECK-LABEL: name: copyprop_remove_kill1 | 
|  | # CHECK: bb.0: | 
|  | # CHECK-NEXT: %rax = COPY %rdi | 
|  | # CHECK-NEXT: NOOP implicit %edi | 
|  | # CHECK-NOT: COPY | 
|  | # CHECK-NEXT: NOOP implicit %rax, implicit %rdi | 
|  | name: copyprop_remove_kill1 | 
|  | body: | | 
|  | bb.0: | 
|  | %rax = COPY %rdi | 
|  | NOOP implicit killed %edi | 
|  | %rdi = COPY %rax | 
|  | NOOP implicit %rax, implicit %rdi | 
|  | ... | 
|  | --- | 
|  | # The second copy is redundant and will be removed, check that we also remove | 
|  | # the kill flag of intermediate instructions. | 
|  | # CHECK-LABEL: name: copyprop_remove_kill2 | 
|  | # CHECK: bb.0: | 
|  | # CHECK-NEXT: %ax = COPY %di | 
|  | # CHECK-NEXT: NOOP implicit %rdi | 
|  | # CHECK-NOT: COPY | 
|  | # CHECK-NEXT: NOOP implicit %rax, implicit %rdi | 
|  | name: copyprop_remove_kill2 | 
|  | body: | | 
|  | bb.0: | 
|  | %ax = COPY %di | 
|  | NOOP implicit killed %rdi | 
|  | %di = COPY %ax | 
|  | NOOP implicit %rax, implicit %rdi | 
|  | ... | 
|  | --- | 
|  | # The second copy is redundant; the call preserves the source and dest register. | 
|  | # CHECK-LABEL: name: copyprop0 | 
|  | # CHECK: bb.0: | 
|  | # CHECK-NEXT: %rax = COPY %rdi | 
|  | # CHECK-NEXT: CALL64pcrel32 @foo, csr_64_rt_mostregs | 
|  | # CHECK-NEXT: NOOP implicit %edi | 
|  | # CHECK-NOT: COPY | 
|  | # CHECK-NEXT: NOOP implicit %rax, implicit %rdi | 
|  | name: copyprop0 | 
|  | body: | | 
|  | bb.0: | 
|  | %rax = COPY %rdi | 
|  | CALL64pcrel32 @foo, csr_64_rt_mostregs | 
|  | NOOP implicit killed %edi | 
|  | %rdi = COPY %rax | 
|  | NOOP implicit %rax, implicit %rdi | 
|  | ... | 
|  | --- | 
|  | # The 2nd copy is redundant; The call preserves the source and dest register. | 
|  | # CHECK-LABEL: name: copyprop1 | 
|  | # CHECK: bb.0: | 
|  | # CHECK-NEXT: %rax = COPY %rdi | 
|  | # CHECK-NEXT: NOOP implicit %rax | 
|  | # CHECK-NEXT: NOOP implicit %rax, implicit %rdi | 
|  | name: copyprop1 | 
|  | body: | | 
|  | bb.0: | 
|  | %rax = COPY %rdi | 
|  | NOOP implicit killed %rax | 
|  | %rax = COPY %rdi | 
|  | NOOP implicit %rax, implicit %rdi | 
|  | ... | 
|  | --- | 
|  | # CHECK-LABEL: name: copyprop2 | 
|  | # CHECK: bb.0: | 
|  | # CHECK-NEXT: %rax = COPY %rdi | 
|  | # CHECK-NEXT: NOOP implicit %ax | 
|  | # CHECK-NEXT: CALL64pcrel32 @foo, csr_64_rt_mostregs | 
|  | # CHECK-NOT: %rax = COPY %rdi | 
|  | # CHECK-NEXT: NOOP implicit %rax, implicit %rdi | 
|  | name: copyprop2 | 
|  | body: | | 
|  | bb.0: | 
|  | %rax = COPY %rdi | 
|  | NOOP implicit killed %ax | 
|  | CALL64pcrel32 @foo, csr_64_rt_mostregs | 
|  | %rax = COPY %rdi | 
|  | NOOP implicit %rax, implicit %rdi | 
|  | ... | 
|  | --- | 
|  | # The second copy is not redundant if the source register (%rax) is clobbered | 
|  | # even if the dest (%rbp) is not. | 
|  | # CHECK-LABEL: name: nocopyprop0 | 
|  | # CHECK: bb.0: | 
|  | # CHECK-NEXT: %rax = COPY %rbp | 
|  | # CHECK-NEXT: CALL64pcrel32 @foo, csr_64, implicit %rax, implicit %rbp | 
|  | # CHECK-NEXT: %rbp = COPY %rax | 
|  | # CHECK-NEXT: NOOP implicit %rax, implicit %rbp | 
|  | name: nocopyprop0 | 
|  | body: | | 
|  | bb.0: | 
|  | %rax = COPY %rbp | 
|  | CALL64pcrel32 @foo, csr_64, implicit %rax, implicit %rbp | 
|  | %rbp = COPY %rax | 
|  | NOOP implicit %rax, implicit %rbp | 
|  | ... | 
|  | --- | 
|  | # The second copy is not redundant if the dest register (%rax) is clobbered | 
|  | # even if the source (%rbp) is not. | 
|  | # CHECK-LABEL: name: nocopyprop1 | 
|  | # CHECK: bb.0: | 
|  | # CHECK-NEXT: %rbp = COPY %rax | 
|  | # CHECK-NEXT: CALL64pcrel32 @foo, csr_64, implicit %rax, implicit %rbp | 
|  | # CHECK-NEXT: %rax = COPY %rbp | 
|  | # CHECK-NEXT: NOOP implicit %rax, implicit %rbp | 
|  | name: nocopyprop1 | 
|  | body: | | 
|  | bb.0: | 
|  | %rbp = COPY %rax | 
|  | CALL64pcrel32 @foo, csr_64, implicit %rax, implicit %rbp | 
|  | %rax = COPY %rbp | 
|  | NOOP implicit %rax, implicit %rbp | 
|  | ... | 
|  | --- | 
|  | # The second copy is not redundant if the source register (%rax) is clobbered | 
|  | # even if the dest (%rbp) is not. | 
|  | # CHECK-LABEL: name: nocopyprop2 | 
|  | # CHECK: bb.0: | 
|  | # CHECK-NEXT: %rax = COPY %rbp | 
|  | # CHECK-NEXT: CALL64pcrel32 @foo, csr_64, implicit %rax, implicit %rbp | 
|  | # CHECK-NEXT: %rax = COPY %rbp | 
|  | # CHECK-NEXT: NOOP implicit %rax, implicit %rbp | 
|  | name: nocopyprop2 | 
|  | body: | | 
|  | bb.0: | 
|  | %rax = COPY %rbp | 
|  | CALL64pcrel32 @foo, csr_64, implicit %rax, implicit %rbp | 
|  | %rax = COPY %rbp | 
|  | NOOP implicit %rax, implicit %rbp | 
|  | ... | 
|  | --- | 
|  | # The second copy is not redundant if the dest register (%rax) is clobbered | 
|  | # even if the source (%rbp) is not. | 
|  | # CHECK-LABEL: name: nocopyprop3 | 
|  | # CHECK: bb.0: | 
|  | # CHECK-NEXT: %rbp = COPY %rax | 
|  | # CHECK-NEXT: CALL64pcrel32 @foo, csr_64, implicit %rax, implicit %rbp | 
|  | # CHECK-NEXT: %rbp = COPY %rax | 
|  | # CHECK-NEXT: NOOP implicit %rax, implicit %rbp | 
|  | name: nocopyprop3 | 
|  | body: | | 
|  | bb.0: | 
|  | %rbp = COPY %rax | 
|  | CALL64pcrel32 @foo, csr_64, implicit %rax, implicit %rbp | 
|  | %rbp = COPY %rax | 
|  | NOOP implicit %rax, implicit %rbp | 
|  | ... | 
|  | --- | 
|  | # A reserved register may change its value so the 2nd copy is not redundant. | 
|  | # CHECK-LABEL: name: nocopyprop4 | 
|  | # CHECK: bb.0: | 
|  | # CHECK-NEXT: %rax = COPY %rip | 
|  | # CHECK-NEXT: NOOP implicit %rax | 
|  | # CHECK-NEXT: %rax = COPY %rip | 
|  | # CHECK-NEXT: NOOP implicit %rax | 
|  | name: nocopyprop4 | 
|  | body: | | 
|  | bb.0: | 
|  | %rax = COPY %rip | 
|  | NOOP implicit %rax | 
|  | %rax = COPY %rip | 
|  | NOOP implicit %rax | 
|  | ... | 
|  | --- | 
|  | # Writing to a reserved register may have additional effects (slightly illegal | 
|  | # testcase because writing to %rip like this should make the instruction a jump) | 
|  | # CHECK-LABEL: name: nocopyprop5 | 
|  | # CHECK: bb.0: | 
|  | # CHECK-NEXT: %rip = COPY %rax | 
|  | # CHECK-NEXT: %rip = COPY %rax | 
|  | name: nocopyprop5 | 
|  | body: | | 
|  | bb.0: | 
|  | %rip = COPY %rax | 
|  | %rip = COPY %rax | 
|  | ... |