| # RUN: llc -mtriple=amdgpu10.10 -run-pass=gcn-dpp-combine -o - %s | FileCheck --check-prefixes=CHECK,PRE-GFX11 %s | |
| # RUN: llc -mtriple=amdgpu10.30 -run-pass=gcn-dpp-combine -o - %s | FileCheck --check-prefixes=CHECK,PRE-GFX11 %s | |
| # RUN: llc -mtriple=amdgpu11.00 -run-pass=gcn-dpp-combine -o - %s | FileCheck --check-prefixes=CHECK,GFX11PLUS %s | |
| # RUN: llc -mtriple=amdgpu12.00 -run-pass=gcn-dpp-combine -o - %s | FileCheck --check-prefixes=CHECK,GFX11PLUS %s | |
| --- | |
| # The DPP value is src1 of a subtract, so folding requires commuting | |
| # V_SUB_U32_e32 into V_SUBREV_U32_dpp, which is not allowed. | |
| # CHECK-LABEL: name: dpp_commute_to_rev_sub | |
| # CHECK: %3:vgpr_32 = V_MOV_B32_dpp %2, %0, 1, 15, 15, 1, implicit $exec | |
| # CHECK-NEXT: %4:vgpr_32 = V_SUB_U32_e32 %1, %3, implicit $exec | |
| name: dpp_commute_to_rev_sub | |
| tracksRegLiveness: true | |
| body: | | |
| bb.0: | |
| liveins: $vgpr0, $vgpr1 | |
| %0:vgpr_32 = COPY $vgpr0 | |
| %1:vgpr_32 = COPY $vgpr1 | |
| %2:vgpr_32 = IMPLICIT_DEF | |
| %3:vgpr_32 = V_MOV_B32_dpp %2, %0, 1, 15, 15, 1, implicit $exec | |
| %4:vgpr_32 = V_SUB_U32_e32 %1, %3, implicit $exec | |
| S_NOP 0, implicit %4 | |
| ... | |
| --- | |
| # Both sources of the subtract are the same register, so a mis-routed DPP | |
| # silently yields the negated result rather than an obviously wrong instruction. | |
| # CHECK-LABEL: name: dpp_commute_to_rev_sub_same_reg | |
| # CHECK: %2:vgpr_32 = V_MOV_B32_dpp %1, %0, 0, 15, 15, 1, implicit $exec | |
| # CHECK-NEXT: %3:vgpr_32 = V_SUB_U32_e32 %0, %2, implicit $exec | |
| name: dpp_commute_to_rev_sub_same_reg | |
| tracksRegLiveness: true | |
| body: | | |
| bb.0: | |
| liveins: $vgpr0 | |
| %0:vgpr_32 = COPY $vgpr0 | |
| %1:vgpr_32 = IMPLICIT_DEF | |
| %2:vgpr_32 = V_MOV_B32_dpp %1, %0, 0, 15, 15, 1, implicit $exec | |
| %3:vgpr_32 = V_SUB_U32_e32 %0, %2, implicit $exec | |
| S_NOP 0, implicit %3 | |
| ... | |
| --- | |
| # A DPP mov feeding src0 of a REV opcode directly is rejected the same way as | |
| # one that has to be commuted into it. | |
| # CHECK-LABEL: name: dpp_rev_sub_src0 | |
| # CHECK: %3:vgpr_32 = V_MOV_B32_dpp %2, %0, 1, 15, 15, 1, implicit $exec | |
| # CHECK-NEXT: %4:vgpr_32 = V_SUBREV_U32_e32 %3, %1, implicit $exec | |
| name: dpp_rev_sub_src0 | |
| tracksRegLiveness: true | |
| body: | | |
| bb.0: | |
| liveins: $vgpr0, $vgpr1 | |
| %0:vgpr_32 = COPY $vgpr0 | |
| %1:vgpr_32 = COPY $vgpr1 | |
| %2:vgpr_32 = IMPLICIT_DEF | |
| %3:vgpr_32 = V_MOV_B32_dpp %2, %0, 1, 15, 15, 1, implicit $exec | |
| %4:vgpr_32 = V_SUBREV_U32_e32 %3, %1, implicit $exec | |
| S_NOP 0, implicit %4 | |
| ... | |
| --- | |
| # The carry in subtract commutes into V_SUBBREV_U32 (V_SUBREV_CO_CI_U32 on | |
| # gfx10+), which is a REV opcode as well. | |
| # CHECK-LABEL: name: dpp_commute_to_rev_subb | |
| # CHECK: %4:vgpr_32 = V_MOV_B32_dpp %3, %0, 1, 15, 15, 1, implicit $exec | |
| # CHECK-NEXT: %5:vgpr_32, %6:sreg_32_xm0_xexec = V_SUBB_U32_e64 %1, %4, %2, 0, implicit $exec | |
| name: dpp_commute_to_rev_subb | |
| tracksRegLiveness: true | |
| body: | | |
| bb.0: | |
| liveins: $vgpr0, $vgpr1, $sgpr0 | |
| %0:vgpr_32 = COPY $vgpr0 | |
| %1:vgpr_32 = COPY $vgpr1 | |
| %2:sreg_32_xm0_xexec = COPY $sgpr0 | |
| %3:vgpr_32 = IMPLICIT_DEF | |
| %4:vgpr_32 = V_MOV_B32_dpp %3, %0, 1, 15, 15, 1, implicit $exec | |
| %5:vgpr_32, %6:sreg_32_xm0_xexec = V_SUBB_U32_e64 %1, %4, %2, 0, implicit $exec | |
| S_NOP 0, implicit %5 | |
| ... | |
| --- | |
| # The shift REV opcodes take the shift amount in src0, and reversed their | |
| # operands before GFX11. | |
| # CHECK-LABEL: name: dpp_rev_shift_src0 | |
| # PRE-GFX11: %3:vgpr_32 = V_MOV_B32_dpp %2, %0, 1, 15, 15, 1, implicit $exec | |
| # PRE-GFX11-NEXT: %4:vgpr_32 = V_LSHLREV_B32_e32 %3, %1, implicit $exec | |
| # PRE-GFX11: %5:vgpr_32 = V_MOV_B32_dpp %2, %0, 1, 15, 15, 1, implicit $exec | |
| # PRE-GFX11-NEXT: %6:vgpr_32 = V_LSHRREV_B32_e32 %5, %1, implicit $exec | |
| # PRE-GFX11: %7:vgpr_32 = V_MOV_B32_dpp %2, %0, 1, 15, 15, 1, implicit $exec | |
| # PRE-GFX11-NEXT: %8:vgpr_32 = V_ASHRREV_I32_e32 %7, %1, implicit $exec | |
| # GFX11PLUS: %4:vgpr_32 = V_LSHLREV_B32_dpp %2, %0, %1, 1, 15, 15, 1, implicit $exec | |
| # GFX11PLUS: %6:vgpr_32 = V_LSHRREV_B32_dpp %2, %0, %1, 1, 15, 15, 1, implicit $exec | |
| # GFX11PLUS: %8:vgpr_32 = V_ASHRREV_I32_dpp %2, %0, %1, 1, 15, 15, 1, implicit $exec | |
| name: dpp_rev_shift_src0 | |
| tracksRegLiveness: true | |
| body: | | |
| bb.0: | |
| liveins: $vgpr0, $vgpr1 | |
| %0:vgpr_32 = COPY $vgpr0 | |
| %1:vgpr_32 = COPY $vgpr1 | |
| %2:vgpr_32 = IMPLICIT_DEF | |
| %3:vgpr_32 = V_MOV_B32_dpp %2, %0, 1, 15, 15, 1, implicit $exec | |
| %4:vgpr_32 = V_LSHLREV_B32_e32 %3, %1, implicit $exec | |
| %5:vgpr_32 = V_MOV_B32_dpp %2, %0, 1, 15, 15, 1, implicit $exec | |
| %6:vgpr_32 = V_LSHRREV_B32_e32 %5, %1, implicit $exec | |
| %7:vgpr_32 = V_MOV_B32_dpp %2, %0, 1, 15, 15, 1, implicit $exec | |
| %8:vgpr_32 = V_ASHRREV_I32_e32 %7, %1, implicit $exec | |
| S_NOP 0, implicit %4, implicit %6, implicit %8 | |
| ... | |
| --- | |
| # Float subtracts are an add with a negate modifier rather than a real operand | |
| # reversal, so V_SUBREV_F32 still takes the fold. | |
| # CHECK-LABEL: name: dpp_commute_to_rev_sub_f32 | |
| # CHECK: %4:vgpr_32 = V_SUBREV_F32_dpp %2, 0, %0, 0, %1, 1, 15, 15, 1, implicit $mode, implicit $exec | |
| name: dpp_commute_to_rev_sub_f32 | |
| tracksRegLiveness: true | |
| body: | | |
| bb.0: | |
| liveins: $vgpr0, $vgpr1 | |
| %0:vgpr_32 = COPY $vgpr0 | |
| %1:vgpr_32 = COPY $vgpr1 | |
| %2:vgpr_32 = IMPLICIT_DEF | |
| %3:vgpr_32 = V_MOV_B32_dpp %2, %0, 1, 15, 15, 1, implicit $exec | |
| %4:vgpr_32 = V_SUB_F32_e32 %1, %3, implicit $mode, implicit $exec | |
| S_NOP 0, implicit %4 | |
| ... | |
| --- | |
| # Positive control: the DPP value is already src0 of a non-REV opcode, so no | |
| # commute is needed and the fold is legal. | |
| # CHECK-LABEL: name: dpp_no_commute_needed | |
| # CHECK: %4:vgpr_32 = V_SUB_U32_dpp %2, %0, %1, 1, 15, 15, 1, implicit $exec | |
| name: dpp_no_commute_needed | |
| tracksRegLiveness: true | |
| body: | | |
| bb.0: | |
| liveins: $vgpr0, $vgpr1 | |
| %0:vgpr_32 = COPY $vgpr0 | |
| %1:vgpr_32 = COPY $vgpr1 | |
| %2:vgpr_32 = IMPLICIT_DEF | |
| %3:vgpr_32 = V_MOV_B32_dpp %2, %0, 1, 15, 15, 1, implicit $exec | |
| %4:vgpr_32 = V_SUB_U32_e32 %3, %1, implicit $exec | |
| S_NOP 0, implicit %4 | |
| ... | |
| --- | |
| # Positive control: commuting an opcode that is its own reverse keeps the same | |
| # opcode, so it still folds. | |
| # CHECK-LABEL: name: dpp_commute_symmetric | |
| # CHECK: %4:vgpr_32 = V_ADD_U32_dpp %2, %0, %1, 1, 15, 15, 1, implicit $exec | |
| # CHECK: %6:vgpr_32 = V_OR_B32_dpp %2, %0, %1, 1, 15, 15, 1, implicit $exec | |
| name: dpp_commute_symmetric | |
| tracksRegLiveness: true | |
| body: | | |
| bb.0: | |
| liveins: $vgpr0, $vgpr1 | |
| %0:vgpr_32 = COPY $vgpr0 | |
| %1:vgpr_32 = COPY $vgpr1 | |
| %2:vgpr_32 = IMPLICIT_DEF | |
| %3:vgpr_32 = V_MOV_B32_dpp %2, %0, 1, 15, 15, 1, implicit $exec | |
| %4:vgpr_32 = V_ADD_U32_e32 %1, %3, implicit $exec | |
| %5:vgpr_32 = V_MOV_B32_dpp %2, %0, 1, 15, 15, 1, implicit $exec | |
| %6:vgpr_32 = V_OR_B32_e32 %1, %5, implicit $exec | |
| S_NOP 0, implicit %4, implicit %6 | |
| ... |