| # RUN: llc -mtriple=amdgpu10.10 -run-pass=gcn-dpp-combine -verify-machineinstrs -o - %s | FileCheck --check-prefixes=CHECK,PRE-GFX11 %s |
| # RUN: llc -mtriple=amdgpu10.30 -run-pass=gcn-dpp-combine -verify-machineinstrs -o - %s | FileCheck --check-prefixes=CHECK,PRE-GFX11 %s |
| # RUN: llc -mtriple=amdgpu11.00 -run-pass=gcn-dpp-combine -verify-machineinstrs -o - %s | FileCheck --check-prefixes=CHECK,GFX11PLUS %s |
| # RUN: llc -mtriple=amdgpu12.00 -run-pass=gcn-dpp-combine -verify-machineinstrs -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 |
| ... |