| # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6 | |
| # RUN: llc -mtriple=amdgpu9.00 -run-pass=si-fold-operands -o - %s | FileCheck %s | |
| # A V_CMP already writes 0 to the bits of inactive lanes, so ANDing its result | |
| # with EXEC is a no-op. | |
| --- | |
| name: vcmp_e64 | |
| tracksRegLiveness: true | |
| body: | | |
| bb.0: | |
| liveins: $vgpr0, $vgpr1 | |
| ; CHECK-LABEL: name: vcmp_e64 | |
| ; CHECK: liveins: $vgpr0, $vgpr1 | |
| ; CHECK-NEXT: {{ $}} | |
| ; CHECK-NEXT: [[V_CMP_LT_I32_e64_:%[0-9]+]]:sreg_64_xexec = V_CMP_LT_I32_e64 $vgpr0, $vgpr1, implicit $exec | |
| ; CHECK-NEXT: $vcc = COPY [[V_CMP_LT_I32_e64_]] | |
| ; CHECK-NEXT: S_ENDPGM 0, implicit $vcc | |
| %0:sreg_64_xexec = V_CMP_LT_I32_e64 $vgpr0, $vgpr1, implicit $exec | |
| %1:sreg_64_xexec = S_AND_B64 $exec, %0, implicit-def dead $scc | |
| $vcc = COPY %1 | |
| S_ENDPGM 0, implicit $vcc | |
| ... | |
| # The AND is commutative, so EXEC may be either operand. | |
| --- | |
| name: vcmp_e64_commuted | |
| tracksRegLiveness: true | |
| body: | | |
| bb.0: | |
| liveins: $vgpr0, $vgpr1 | |
| ; CHECK-LABEL: name: vcmp_e64_commuted | |
| ; CHECK: liveins: $vgpr0, $vgpr1 | |
| ; CHECK-NEXT: {{ $}} | |
| ; CHECK-NEXT: [[V_CMP_LT_I32_e64_:%[0-9]+]]:sreg_64_xexec = V_CMP_LT_I32_e64 $vgpr0, $vgpr1, implicit $exec | |
| ; CHECK-NEXT: $vcc = COPY [[V_CMP_LT_I32_e64_]] | |
| ; CHECK-NEXT: S_ENDPGM 0, implicit $vcc | |
| %0:sreg_64_xexec = V_CMP_LT_I32_e64 $vgpr0, $vgpr1, implicit $exec | |
| %1:sreg_64_xexec = S_AND_B64 %0, $exec, implicit-def dead $scc | |
| $vcc = COPY %1 | |
| S_ENDPGM 0, implicit $vcc | |
| ... | |
| # V_CMP_CLASS is not marked isCompare, but is still a VOPC. | |
| --- | |
| name: vcmp_class | |
| tracksRegLiveness: true | |
| body: | | |
| bb.0: | |
| liveins: $vgpr0 | |
| ; CHECK-LABEL: name: vcmp_class | |
| ; CHECK: liveins: $vgpr0 | |
| ; CHECK-NEXT: {{ $}} | |
| ; CHECK-NEXT: [[V_CMP_CLASS_F32_e64_:%[0-9]+]]:sreg_64_xexec = V_CMP_CLASS_F32_e64 0, $vgpr0, 3, implicit $exec | |
| ; CHECK-NEXT: $vcc = COPY [[V_CMP_CLASS_F32_e64_]] | |
| ; CHECK-NEXT: S_ENDPGM 0, implicit $vcc | |
| %0:sreg_64_xexec = V_CMP_CLASS_F32_e64 0, $vgpr0, 3, implicit $exec | |
| %1:sreg_64_xexec = S_AND_B64 $exec, %0, implicit-def dead $scc | |
| $vcc = COPY %1 | |
| S_ENDPGM 0, implicit $vcc | |
| ... | |
| # Bitwise combinations of lane masks are still masked by EXEC. | |
| --- | |
| name: and_or_xor_tree | |
| tracksRegLiveness: true | |
| body: | | |
| bb.0: | |
| liveins: $vgpr0, $vgpr1, $vgpr2 | |
| ; CHECK-LABEL: name: and_or_xor_tree | |
| ; CHECK: liveins: $vgpr0, $vgpr1, $vgpr2 | |
| ; CHECK-NEXT: {{ $}} | |
| ; CHECK-NEXT: [[V_CMP_LT_I32_e64_:%[0-9]+]]:sreg_64_xexec = V_CMP_LT_I32_e64 $vgpr0, $vgpr1, implicit $exec | |
| ; CHECK-NEXT: [[V_CMP_LT_I32_e64_1:%[0-9]+]]:sreg_64_xexec = V_CMP_LT_I32_e64 $vgpr1, $vgpr2, implicit $exec | |
| ; CHECK-NEXT: [[S_OR_B64_:%[0-9]+]]:sreg_64_xexec = S_OR_B64 [[V_CMP_LT_I32_e64_]], [[V_CMP_LT_I32_e64_1]], implicit-def dead $scc | |
| ; CHECK-NEXT: [[S_XOR_B64_:%[0-9]+]]:sreg_64_xexec = S_XOR_B64 [[S_OR_B64_]], [[V_CMP_LT_I32_e64_]], implicit-def dead $scc | |
| ; CHECK-NEXT: $vcc = COPY [[S_XOR_B64_]] | |
| ; CHECK-NEXT: S_ENDPGM 0, implicit $vcc | |
| %0:sreg_64_xexec = V_CMP_LT_I32_e64 $vgpr0, $vgpr1, implicit $exec | |
| %1:sreg_64_xexec = V_CMP_LT_I32_e64 $vgpr1, $vgpr2, implicit $exec | |
| %2:sreg_64_xexec = S_OR_B64 %0, %1, implicit-def dead $scc | |
| %3:sreg_64_xexec = S_XOR_B64 %2, %0, implicit-def dead $scc | |
| %4:sreg_64_xexec = S_AND_B64 $exec, %3, implicit-def dead $scc | |
| $vcc = COPY %4 | |
| S_ENDPGM 0, implicit $vcc | |
| ... | |
| # S_AND only needs one of its operands to be masked by EXEC. | |
| --- | |
| name: and_one_masked_operand | |
| tracksRegLiveness: true | |
| body: | | |
| bb.0: | |
| liveins: $vgpr0, $vgpr1, $sgpr0_sgpr1 | |
| ; CHECK-LABEL: name: and_one_masked_operand | |
| ; CHECK: liveins: $vgpr0, $vgpr1, $sgpr0_sgpr1 | |
| ; CHECK-NEXT: {{ $}} | |
| ; CHECK-NEXT: [[V_CMP_LT_I32_e64_:%[0-9]+]]:sreg_64_xexec = V_CMP_LT_I32_e64 $vgpr0, $vgpr1, implicit $exec | |
| ; CHECK-NEXT: [[S_AND_B64_:%[0-9]+]]:sreg_64_xexec = S_AND_B64 [[V_CMP_LT_I32_e64_]], $sgpr0_sgpr1, implicit-def dead $scc | |
| ; CHECK-NEXT: $vcc = COPY [[S_AND_B64_]] | |
| ; CHECK-NEXT: S_ENDPGM 0, implicit $vcc | |
| %0:sreg_64_xexec = V_CMP_LT_I32_e64 $vgpr0, $vgpr1, implicit $exec | |
| %1:sreg_64_xexec = S_AND_B64 %0, $sgpr0_sgpr1, implicit-def dead $scc | |
| %2:sreg_64_xexec = S_AND_B64 $exec, %1, implicit-def dead $scc | |
| $vcc = COPY %2 | |
| S_ENDPGM 0, implicit $vcc | |
| ... | |
| # The AND may write a physical register, as inserted by moveToVALU. | |
| --- | |
| name: physreg_dst | |
| tracksRegLiveness: true | |
| body: | | |
| bb.0: | |
| liveins: $vgpr0, $vgpr1 | |
| ; CHECK-LABEL: name: physreg_dst | |
| ; CHECK: liveins: $vgpr0, $vgpr1 | |
| ; CHECK-NEXT: {{ $}} | |
| ; CHECK-NEXT: [[V_CMP_LT_I32_e64_:%[0-9]+]]:sreg_64_xexec = V_CMP_LT_I32_e64 $vgpr0, $vgpr1, implicit $exec | |
| ; CHECK-NEXT: $vcc = COPY [[V_CMP_LT_I32_e64_]] | |
| ; CHECK-NEXT: S_ENDPGM 0, implicit $vcc | |
| %0:sreg_64_xexec = V_CMP_LT_I32_e64 $vgpr0, $vgpr1, implicit $exec | |
| $vcc = S_AND_B64 $exec, %0, implicit-def dead $scc | |
| S_ENDPGM 0, implicit $vcc | |
| ... | |
| # Negative test: S_OR needs both operands to be masked by EXEC. | |
| --- | |
| name: or_one_masked_operand | |
| tracksRegLiveness: true | |
| body: | | |
| bb.0: | |
| liveins: $vgpr0, $vgpr1, $sgpr0_sgpr1 | |
| ; CHECK-LABEL: name: or_one_masked_operand | |
| ; CHECK: liveins: $vgpr0, $vgpr1, $sgpr0_sgpr1 | |
| ; CHECK-NEXT: {{ $}} | |
| ; CHECK-NEXT: [[V_CMP_LT_I32_e64_:%[0-9]+]]:sreg_64_xexec = V_CMP_LT_I32_e64 $vgpr0, $vgpr1, implicit $exec | |
| ; CHECK-NEXT: [[S_OR_B64_:%[0-9]+]]:sreg_64_xexec = S_OR_B64 [[V_CMP_LT_I32_e64_]], $sgpr0_sgpr1, implicit-def dead $scc | |
| ; CHECK-NEXT: [[S_AND_B64_:%[0-9]+]]:sreg_64_xexec = S_AND_B64 $exec, [[S_OR_B64_]], implicit-def dead $scc | |
| ; CHECK-NEXT: $vcc = COPY [[S_AND_B64_]] | |
| ; CHECK-NEXT: S_ENDPGM 0, implicit $vcc | |
| %0:sreg_64_xexec = V_CMP_LT_I32_e64 $vgpr0, $vgpr1, implicit $exec | |
| %1:sreg_64_xexec = S_OR_B64 %0, $sgpr0_sgpr1, implicit-def dead $scc | |
| %2:sreg_64_xexec = S_AND_B64 $exec, %1, implicit-def dead $scc | |
| $vcc = COPY %2 | |
| S_ENDPGM 0, implicit $vcc | |
| ... | |
| # Negative test: the V_CMP is in a different basic block, so we cannot tell | |
| # which EXEC mask it ran under. | |
| --- | |
| name: vcmp_in_predecessor | |
| tracksRegLiveness: true | |
| body: | | |
| ; CHECK-LABEL: name: vcmp_in_predecessor | |
| ; CHECK: bb.0: | |
| ; CHECK-NEXT: successors: %bb.1(0x80000000) | |
| ; CHECK-NEXT: liveins: $vgpr0, $vgpr1 | |
| ; CHECK-NEXT: {{ $}} | |
| ; CHECK-NEXT: [[V_CMP_LT_I32_e64_:%[0-9]+]]:sreg_64_xexec = V_CMP_LT_I32_e64 $vgpr0, $vgpr1, implicit $exec | |
| ; CHECK-NEXT: {{ $}} | |
| ; CHECK-NEXT: bb.1: | |
| ; CHECK-NEXT: [[S_AND_B64_:%[0-9]+]]:sreg_64_xexec = S_AND_B64 $exec, [[V_CMP_LT_I32_e64_]], implicit-def dead $scc | |
| ; CHECK-NEXT: $vcc = COPY [[S_AND_B64_]] | |
| ; CHECK-NEXT: S_ENDPGM 0, implicit $vcc | |
| bb.0: | |
| liveins: $vgpr0, $vgpr1 | |
| %0:sreg_64_xexec = V_CMP_LT_I32_e64 $vgpr0, $vgpr1, implicit $exec | |
| bb.1: | |
| %1:sreg_64_xexec = S_AND_B64 $exec, %0, implicit-def dead $scc | |
| $vcc = COPY %1 | |
| S_ENDPGM 0, implicit $vcc | |
| ... | |
| # Negative test: the SCC defined by the AND is used. | |
| --- | |
| name: scc_not_dead | |
| tracksRegLiveness: true | |
| body: | | |
| bb.0: | |
| liveins: $vgpr0, $vgpr1 | |
| ; CHECK-LABEL: name: scc_not_dead | |
| ; CHECK: liveins: $vgpr0, $vgpr1 | |
| ; CHECK-NEXT: {{ $}} | |
| ; CHECK-NEXT: [[V_CMP_LT_I32_e64_:%[0-9]+]]:sreg_64_xexec = V_CMP_LT_I32_e64 $vgpr0, $vgpr1, implicit $exec | |
| ; CHECK-NEXT: [[S_AND_B64_:%[0-9]+]]:sreg_64_xexec = S_AND_B64 $exec, [[V_CMP_LT_I32_e64_]], implicit-def $scc | |
| ; CHECK-NEXT: [[S_CSELECT_B32_:%[0-9]+]]:sreg_32 = S_CSELECT_B32 1, 0, implicit $scc | |
| ; CHECK-NEXT: $vcc = COPY [[S_AND_B64_]] | |
| ; CHECK-NEXT: S_ENDPGM 0, implicit $vcc, implicit [[S_CSELECT_B32_]] | |
| %0:sreg_64_xexec = V_CMP_LT_I32_e64 $vgpr0, $vgpr1, implicit $exec | |
| %1:sreg_64_xexec = S_AND_B64 $exec, %0, implicit-def $scc | |
| %2:sreg_32 = S_CSELECT_B32 1, 0, implicit $scc | |
| $vcc = COPY %1 | |
| S_ENDPGM 0, implicit $vcc, implicit %2 | |
| ... | |
| # S_ANDN2 is masked by EXEC if its first operand is. | |
| --- | |
| name: andn2_first_operand_masked | |
| tracksRegLiveness: true | |
| body: | | |
| bb.0: | |
| liveins: $vgpr0, $vgpr1, $sgpr0_sgpr1 | |
| ; CHECK-LABEL: name: andn2_first_operand_masked | |
| ; CHECK: liveins: $vgpr0, $vgpr1, $sgpr0_sgpr1 | |
| ; CHECK-NEXT: {{ $}} | |
| ; CHECK-NEXT: [[V_CMP_LT_I32_e64_:%[0-9]+]]:sreg_64_xexec = V_CMP_LT_I32_e64 $vgpr0, $vgpr1, implicit $exec | |
| ; CHECK-NEXT: [[S_ANDN2_B64_:%[0-9]+]]:sreg_64_xexec = S_ANDN2_B64 [[V_CMP_LT_I32_e64_]], $sgpr0_sgpr1, implicit-def dead $scc | |
| ; CHECK-NEXT: $vcc = COPY [[S_ANDN2_B64_]] | |
| ; CHECK-NEXT: S_ENDPGM 0, implicit $vcc | |
| %0:sreg_64_xexec = V_CMP_LT_I32_e64 $vgpr0, $vgpr1, implicit $exec | |
| %1:sreg_64_xexec = S_ANDN2_B64 %0, $sgpr0_sgpr1, implicit-def dead $scc | |
| %2:sreg_64_xexec = S_AND_B64 $exec, %1, implicit-def dead $scc | |
| $vcc = COPY %2 | |
| S_ENDPGM 0, implicit $vcc | |
| ... | |
| # Negative test: the second operand of S_ANDN2 is inverted, so it does not help. | |
| --- | |
| name: andn2_second_operand_masked | |
| tracksRegLiveness: true | |
| body: | | |
| bb.0: | |
| liveins: $vgpr0, $vgpr1, $sgpr0_sgpr1 | |
| ; CHECK-LABEL: name: andn2_second_operand_masked | |
| ; CHECK: liveins: $vgpr0, $vgpr1, $sgpr0_sgpr1 | |
| ; CHECK-NEXT: {{ $}} | |
| ; CHECK-NEXT: [[V_CMP_LT_I32_e64_:%[0-9]+]]:sreg_64_xexec = V_CMP_LT_I32_e64 $vgpr0, $vgpr1, implicit $exec | |
| ; CHECK-NEXT: [[S_ANDN2_B64_:%[0-9]+]]:sreg_64_xexec = S_ANDN2_B64 $sgpr0_sgpr1, [[V_CMP_LT_I32_e64_]], implicit-def dead $scc | |
| ; CHECK-NEXT: [[S_AND_B64_:%[0-9]+]]:sreg_64_xexec = S_AND_B64 $exec, [[S_ANDN2_B64_]], implicit-def dead $scc | |
| ; CHECK-NEXT: $vcc = COPY [[S_AND_B64_]] | |
| ; CHECK-NEXT: S_ENDPGM 0, implicit $vcc | |
| %0:sreg_64_xexec = V_CMP_LT_I32_e64 $vgpr0, $vgpr1, implicit $exec | |
| %1:sreg_64_xexec = S_ANDN2_B64 $sgpr0_sgpr1, %0, implicit-def dead $scc | |
| %2:sreg_64_xexec = S_AND_B64 $exec, %1, implicit-def dead $scc | |
| $vcc = COPY %2 | |
| S_ENDPGM 0, implicit $vcc | |
| ... | |
| # Look through a COPY of the lane mask. | |
| --- | |
| name: copy_of_vcmp | |
| tracksRegLiveness: true | |
| body: | | |
| bb.0: | |
| liveins: $vgpr0, $vgpr1 | |
| ; CHECK-LABEL: name: copy_of_vcmp | |
| ; CHECK: liveins: $vgpr0, $vgpr1 | |
| ; CHECK-NEXT: {{ $}} | |
| ; CHECK-NEXT: [[V_CMP_LT_I32_e64_:%[0-9]+]]:sreg_64_xexec = V_CMP_LT_I32_e64 $vgpr0, $vgpr1, implicit $exec | |
| ; CHECK-NEXT: $vcc = COPY [[V_CMP_LT_I32_e64_]] | |
| ; CHECK-NEXT: S_ENDPGM 0, implicit $vcc | |
| %0:sreg_64_xexec = V_CMP_LT_I32_e64 $vgpr0, $vgpr1, implicit $exec | |
| %1:sreg_64 = COPY %0 | |
| %2:sreg_64_xexec = S_AND_B64 $exec, %1, implicit-def dead $scc | |
| $vcc = COPY %2 | |
| S_ENDPGM 0, implicit $vcc | |
| ... | |
| # After the fold the result of the AND is replaced by %0, which is then used | |
| # after the S_OR, so the kill flag on the S_OR must be cleared. | |
| --- | |
| name: src_used_after_kill | |
| tracksRegLiveness: true | |
| body: | | |
| bb.0: | |
| liveins: $vgpr0, $vgpr1, $sgpr0_sgpr1 | |
| ; CHECK-LABEL: name: src_used_after_kill | |
| ; CHECK: liveins: $vgpr0, $vgpr1, $sgpr0_sgpr1 | |
| ; CHECK-NEXT: {{ $}} | |
| ; CHECK-NEXT: [[V_CMP_LT_I32_e64_:%[0-9]+]]:sreg_64_xexec = V_CMP_LT_I32_e64 $vgpr0, $vgpr1, implicit $exec | |
| ; CHECK-NEXT: [[S_OR_B64_:%[0-9]+]]:sreg_64_xexec = S_OR_B64 [[V_CMP_LT_I32_e64_]], $sgpr0_sgpr1, implicit-def dead $scc | |
| ; CHECK-NEXT: $vcc = COPY [[V_CMP_LT_I32_e64_]] | |
| ; CHECK-NEXT: S_ENDPGM 0, implicit $vcc, implicit [[S_OR_B64_]] | |
| %0:sreg_64_xexec = V_CMP_LT_I32_e64 $vgpr0, $vgpr1, implicit $exec | |
| %1:sreg_64_xexec = S_AND_B64 $exec, %0, implicit-def dead $scc | |
| %2:sreg_64_xexec = S_OR_B64 killed %0, $sgpr0_sgpr1, implicit-def dead $scc | |
| $vcc = COPY %1 | |
| S_ENDPGM 0, implicit $vcc, implicit %2 | |
| ... |