| ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 |
| ; RUN: llc -mtriple=amdgpu9.00 < %s | FileCheck -check-prefix=GFX9 %s |
| ; RUN: llc -mtriple=amdgpu10.10 < %s | FileCheck -check-prefix=GFX10 %s |
| |
| ; Verify that uniform (SGPR) byte-packing operations produce v_perm_b32 |
| ; instead of scalar s_and/s_lshl/s_or sequences. The OR and AND DAG combines |
| ; that create PERM nodes were previously gated on isDivergent(), preventing |
| ; uniform values from using the more efficient v_perm_b32 instruction. |
| |
| ; OR combine: pack low bytes of two uniform values. |
| define amdgpu_kernel void @or_uniform_two_bytes(ptr addrspace(1) %out, i32 inreg %a, i32 inreg %b) { |
| ; GFX9-LABEL: or_uniform_two_bytes: |
| ; GFX9: ; %bb.0: |
| ; GFX9-NEXT: s_load_dwordx4 s[0:3], s[4:5], 0x24 |
| ; GFX9-NEXT: v_mov_b32_e32 v2, 0x6050400 |
| ; GFX9-NEXT: v_mov_b32_e32 v0, 0 |
| ; GFX9-NEXT: s_waitcnt lgkmcnt(0) |
| ; GFX9-NEXT: s_and_b32 s3, s3, 0xff |
| ; GFX9-NEXT: v_mov_b32_e32 v1, s2 |
| ; GFX9-NEXT: v_perm_b32 v1, s3, v1, v2 |
| ; GFX9-NEXT: global_store_dword v0, v1, s[0:1] |
| ; GFX9-NEXT: s_endpgm |
| ; |
| ; GFX10-LABEL: or_uniform_two_bytes: |
| ; GFX10: ; %bb.0: |
| ; GFX10-NEXT: s_load_dwordx4 s[0:3], s[4:5], 0x24 |
| ; GFX10-NEXT: v_mov_b32_e32 v0, 0x6050400 |
| ; GFX10-NEXT: v_mov_b32_e32 v1, 0 |
| ; GFX10-NEXT: s_waitcnt lgkmcnt(0) |
| ; GFX10-NEXT: s_and_b32 s3, s3, 0xff |
| ; GFX10-NEXT: v_perm_b32 v0, s3, s2, v0 |
| ; GFX10-NEXT: global_store_dword v1, v0, s[0:1] |
| ; GFX10-NEXT: s_endpgm |
| %a.byte = and i32 %a, 255 |
| %b.byte = and i32 %b, 255 |
| %b.shifted = shl i32 %b.byte, 8 |
| %packed = or i32 %a.byte, %b.shifted |
| store i32 %packed, ptr addrspace(1) %out |
| ret void |
| } |
| |
| ; OR combine: pack 4 uniform i8 values (the WMMA scale operand pattern). |
| define amdgpu_kernel void @or_uniform_v4i8(ptr addrspace(1) %out, i8 inreg %a, i8 inreg %b) { |
| ; GFX9-LABEL: or_uniform_v4i8: |
| ; GFX9: ; %bb.0: |
| ; GFX9-NEXT: s_load_dword s2, s[4:5], 0x2c |
| ; GFX9-NEXT: s_load_dwordx2 s[0:1], s[4:5], 0x24 |
| ; GFX9-NEXT: v_mov_b32_e32 v2, 0x1010104 |
| ; GFX9-NEXT: v_mov_b32_e32 v0, 0 |
| ; GFX9-NEXT: s_waitcnt lgkmcnt(0) |
| ; GFX9-NEXT: s_and_b32 s3, s2, 0xff |
| ; GFX9-NEXT: v_mov_b32_e32 v1, s2 |
| ; GFX9-NEXT: v_perm_b32 v1, s3, v1, v2 |
| ; GFX9-NEXT: global_store_dword v0, v1, s[0:1] |
| ; GFX9-NEXT: s_endpgm |
| ; |
| ; GFX10-LABEL: or_uniform_v4i8: |
| ; GFX10: ; %bb.0: |
| ; GFX10-NEXT: s_clause 0x1 |
| ; GFX10-NEXT: s_load_dword s2, s[4:5], 0x2c |
| ; GFX10-NEXT: s_load_dwordx2 s[0:1], s[4:5], 0x24 |
| ; GFX10-NEXT: v_mov_b32_e32 v0, 0x1010104 |
| ; GFX10-NEXT: v_mov_b32_e32 v1, 0 |
| ; GFX10-NEXT: s_waitcnt lgkmcnt(0) |
| ; GFX10-NEXT: s_and_b32 s3, s2, 0xff |
| ; GFX10-NEXT: v_perm_b32 v0, s3, s2, v0 |
| ; GFX10-NEXT: global_store_dword v1, v0, s[0:1] |
| ; GFX10-NEXT: s_endpgm |
| %v0 = insertelement <4 x i8> poison, i8 %a, i64 0 |
| %v1 = insertelement <4 x i8> %v0, i8 %b, i64 1 |
| %v2 = insertelement <4 x i8> %v1, i8 %b, i64 2 |
| %v3 = insertelement <4 x i8> %v2, i8 %b, i64 3 |
| %packed = bitcast <4 x i8> %v3 to i32 |
| store i32 %packed, ptr addrspace(1) %out |
| ret void |
| } |
| |
| ; OR combine: splat a uniform i8 into all 4 byte lanes. |
| define amdgpu_kernel void @or_uniform_splat_i8(ptr addrspace(1) %out, i8 inreg %a) { |
| ; GFX9-LABEL: or_uniform_splat_i8: |
| ; GFX9: ; %bb.0: |
| ; GFX9-NEXT: s_load_dword s2, s[4:5], 0x2c |
| ; GFX9-NEXT: s_load_dwordx2 s[0:1], s[4:5], 0x24 |
| ; GFX9-NEXT: v_mov_b32_e32 v1, 0x4040404 |
| ; GFX9-NEXT: v_mov_b32_e32 v0, 0 |
| ; GFX9-NEXT: s_waitcnt lgkmcnt(0) |
| ; GFX9-NEXT: s_and_b32 s2, s2, 0xff |
| ; GFX9-NEXT: v_perm_b32 v1, s2, s2, v1 |
| ; GFX9-NEXT: global_store_dword v0, v1, s[0:1] |
| ; GFX9-NEXT: s_endpgm |
| ; |
| ; GFX10-LABEL: or_uniform_splat_i8: |
| ; GFX10: ; %bb.0: |
| ; GFX10-NEXT: s_clause 0x1 |
| ; GFX10-NEXT: s_load_dword s2, s[4:5], 0x2c |
| ; GFX10-NEXT: s_load_dwordx2 s[0:1], s[4:5], 0x24 |
| ; GFX10-NEXT: v_mov_b32_e32 v0, 0 |
| ; GFX10-NEXT: s_waitcnt lgkmcnt(0) |
| ; GFX10-NEXT: s_and_b32 s2, s2, 0xff |
| ; GFX10-NEXT: v_perm_b32 v1, s2, s2, 0x4040404 |
| ; GFX10-NEXT: global_store_dword v0, v1, s[0:1] |
| ; GFX10-NEXT: s_endpgm |
| %v0 = insertelement <4 x i8> poison, i8 %a, i64 0 |
| %v1 = insertelement <4 x i8> %v0, i8 %a, i64 1 |
| %v2 = insertelement <4 x i8> %v1, i8 %a, i64 2 |
| %v3 = insertelement <4 x i8> %v2, i8 %a, i64 3 |
| %packed = bitcast <4 x i8> %v3 to i32 |
| store i32 %packed, ptr addrspace(1) %out |
| ret void |
| } |
| |
| ; AND combine: interleave bytes from two uniform sources using complementary |
| ; OR masks. and(or(a, 0xFF00FF00), or(b, 0x00FF00FF)) selects even bytes from |
| ; b and odd bytes from a. |
| define amdgpu_kernel void @and_uniform_interleave_bytes(ptr addrspace(1) %out, i32 inreg %a, i32 inreg %b) { |
| ; GFX9-LABEL: and_uniform_interleave_bytes: |
| ; GFX9: ; %bb.0: |
| ; GFX9-NEXT: s_load_dwordx4 s[0:3], s[4:5], 0x24 |
| ; GFX9-NEXT: v_mov_b32_e32 v2, 0x7020500 |
| ; GFX9-NEXT: v_mov_b32_e32 v0, 0 |
| ; GFX9-NEXT: s_waitcnt lgkmcnt(0) |
| ; GFX9-NEXT: v_mov_b32_e32 v1, s2 |
| ; GFX9-NEXT: v_perm_b32 v1, s3, v1, v2 |
| ; GFX9-NEXT: global_store_dword v0, v1, s[0:1] |
| ; GFX9-NEXT: s_endpgm |
| ; |
| ; GFX10-LABEL: and_uniform_interleave_bytes: |
| ; GFX10: ; %bb.0: |
| ; GFX10-NEXT: s_load_dwordx4 s[0:3], s[4:5], 0x24 |
| ; GFX10-NEXT: v_mov_b32_e32 v0, 0x7020500 |
| ; GFX10-NEXT: v_mov_b32_e32 v1, 0 |
| ; GFX10-NEXT: s_waitcnt lgkmcnt(0) |
| ; GFX10-NEXT: v_perm_b32 v0, s3, s2, v0 |
| ; GFX10-NEXT: global_store_dword v1, v0, s[0:1] |
| ; GFX10-NEXT: s_endpgm |
| %a.or = or i32 %a, -16711936 |
| %b.or = or i32 %b, 16711935 |
| %result = and i32 %a.or, %b.or |
| store i32 %result, ptr addrspace(1) %out |
| ret void |
| } |