| ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 | |
| ; RUN: llc -mtriple=amdgpu12.50-amd-amdhsa -verify-machineinstrs < %s | FileCheck -check-prefix=GFX1250 %s | |
| ; RUN: llc -mtriple=amdgpu12.00-amd-amdhsa -verify-machineinstrs < %s | FileCheck -check-prefix=GFX1200 %s | |
| ; A VOPD3 component cannot encode a 32-bit literal, and on GFX1250 v_and_b32 can | |
| ; only be dual issued through VOPD3 as v_dual_bitop2_b32. A folded literal | |
| ; therefore costs one issue slot per use. | |
| ; | |
| ; The pair is built after register allocation, so the literal is folded first | |
| ; and moved back into a scalar register only where that buys a pair. Each pair | |
| ; gets its own short-lived register. | |
| ; | |
| ; GFX1200 has no VOPD3, so the immediate stays folded there. | |
| declare i32 @llvm.amdgcn.workitem.id.x() | |
| ; Two v_and_b32 operations use the same mask. Each pair gets one S_MOV_B32. | |
| define amdgpu_kernel void @mask_shared_by_two_pairs(ptr addrspace(1) %out, ptr addrspace(1) %in) { | |
| ; GFX1250-LABEL: mask_shared_by_two_pairs: | |
| ; GFX1250: ; %bb.0: ; %entry | |
| ; GFX1250-NEXT: s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 25, 1), 1 ; msbs: dst=0 src0=0 src1=0 src2=0 | |
| ; GFX1250-NEXT: s_mov_b64 s[64:65], 0 | |
| ; GFX1250-NEXT: v_nop | |
| ; GFX1250-NEXT: global_prefetch_b8 v0, s[64:65] scope:SCOPE_SE | |
| ; GFX1250-NEXT: s_load_b128 s[0:3], s[4:5], 0x0 nv | |
| ; GFX1250-NEXT: v_and_b32_e32 v4, 0x3ff, v0 | |
| ; GFX1250-NEXT: s_delay_alu instid0(VALU_DEP_1) | |
| ; GFX1250-NEXT: v_lshlrev_b32_e32 v0, 2, v4 | |
| ; GFX1250-NEXT: s_wait_kmcnt 0x0 | |
| ; GFX1250-NEXT: global_load_b64 v[2:3], v0, s[2:3] | |
| ; GFX1250-NEXT: s_wait_xcnt 0x0 | |
| ; GFX1250-NEXT: s_mov_b32 s2, 0xffff0000 | |
| ; GFX1250-NEXT: s_wait_loadcnt 0x0 | |
| ; GFX1250-NEXT: v_dual_lshlrev_b32 v0, 16, v2 :: v_dual_bitop2_b32 v1, s2, v2 bitop3:0x40 | |
| ; GFX1250-NEXT: s_mov_b32 s2, 0xffff0000 | |
| ; GFX1250-NEXT: s_delay_alu instid0(SALU_CYCLE_1) | |
| ; GFX1250-NEXT: v_dual_lshlrev_b32 v2, 16, v3 :: v_dual_bitop2_b32 v3, s2, v3 bitop3:0x40 | |
| ; GFX1250-NEXT: global_store_b128 v4, v[0:3], s[0:1] scale_offset | |
| ; GFX1250-NEXT: s_endpgm | |
| ; | |
| ; GFX1200-LABEL: mask_shared_by_two_pairs: | |
| ; GFX1200: ; %bb.0: ; %entry | |
| ; GFX1200-NEXT: s_load_b128 s[0:3], s[4:5], 0x0 | |
| ; GFX1200-NEXT: v_and_b32_e32 v4, 0x3ff, v0 | |
| ; GFX1200-NEXT: s_delay_alu instid0(VALU_DEP_1) | |
| ; GFX1200-NEXT: v_lshlrev_b32_e32 v0, 2, v4 | |
| ; GFX1200-NEXT: v_lshlrev_b32_e32 v4, 4, v4 | |
| ; GFX1200-NEXT: s_wait_kmcnt 0x0 | |
| ; GFX1200-NEXT: global_load_b64 v[2:3], v0, s[2:3] | |
| ; GFX1200-NEXT: s_wait_loadcnt 0x0 | |
| ; GFX1200-NEXT: v_lshlrev_b32_e32 v0, 16, v2 | |
| ; GFX1200-NEXT: v_and_b32_e32 v1, 0xffff0000, v2 | |
| ; GFX1200-NEXT: v_lshlrev_b32_e32 v2, 16, v3 | |
| ; GFX1200-NEXT: v_and_b32_e32 v3, 0xffff0000, v3 | |
| ; GFX1200-NEXT: global_store_b128 v4, v[0:3], s[0:1] | |
| ; GFX1200-NEXT: s_endpgm | |
| entry: | |
| %id = call i32 @llvm.amdgcn.workitem.id.x() | |
| %in.gep0 = getelementptr i32, ptr addrspace(1) %in, i32 %id | |
| %id1 = add i32 %id, 1 | |
| %in.gep1 = getelementptr i32, ptr addrspace(1) %in, i32 %id1 | |
| %data0 = load i32, ptr addrspace(1) %in.gep0 | |
| %data1 = load i32, ptr addrspace(1) %in.gep1 | |
| %lo0 = shl i32 %data0, 16 | |
| %hi0 = and i32 %data0, -65536 | |
| %lo1 = shl i32 %data1, 16 | |
| %hi1 = and i32 %data1, -65536 | |
| %ins0 = insertelement <4 x i32> poison, i32 %lo0, i32 0 | |
| %ins1 = insertelement <4 x i32> %ins0, i32 %hi0, i32 1 | |
| %ins2 = insertelement <4 x i32> %ins1, i32 %lo1, i32 2 | |
| %ins3 = insertelement <4 x i32> %ins2, i32 %hi1, i32 3 | |
| %out.gep = getelementptr <4 x i32>, ptr addrspace(1) %out, i32 %id | |
| store <4 x i32> %ins3, ptr addrspace(1) %out.gep | |
| ret void | |
| } | |
| ; The pair is inside a loop. The move stays next to it, so it runs once per | |
| ; iteration: one scalar instruction bought for one dual-issue slot. | |
| define amdgpu_kernel void @mask_in_loop_body(ptr addrspace(1) %out, ptr addrspace(1) %in, i32 %n) { | |
| ; GFX1250-LABEL: mask_in_loop_body: | |
| ; GFX1250: ; %bb.0: ; %entry | |
| ; GFX1250-NEXT: s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 25, 1), 1 ; msbs: dst=0 src0=0 src1=0 src2=0 | |
| ; GFX1250-NEXT: s_mov_b64 s[64:65], 0 | |
| ; GFX1250-NEXT: v_nop | |
| ; GFX1250-NEXT: global_prefetch_b8 v0, s[64:65] scope:SCOPE_SE | |
| ; GFX1250-NEXT: s_clause 0x1 | |
| ; GFX1250-NEXT: s_load_b128 s[0:3], s[4:5], 0x0 nv | |
| ; GFX1250-NEXT: s_load_b32 s6, s[4:5], 0x10 nv | |
| ; GFX1250-NEXT: v_and_b32_e32 v0, 0x3ff, v0 | |
| ; GFX1250-NEXT: s_delay_alu instid0(VALU_DEP_1) | |
| ; GFX1250-NEXT: v_dual_mov_b32 v1, 0 :: v_dual_mov_b32 v2, v0 | |
| ; GFX1250-NEXT: .LBB1_1: ; %loop | |
| ; GFX1250-NEXT: ; =>This Inner Loop Header: Depth=1 | |
| ; GFX1250-NEXT: s_wait_kmcnt 0x0 | |
| ; GFX1250-NEXT: global_load_b32 v3, v2, s[2:3] scale_offset | |
| ; GFX1250-NEXT: s_wait_xcnt 0x0 | |
| ; GFX1250-NEXT: v_add_nc_u32_e32 v2, 1, v2 | |
| ; GFX1250-NEXT: s_add_co_i32 s6, s6, -1 | |
| ; GFX1250-NEXT: s_delay_alu instid0(SALU_CYCLE_1) | instskip(SKIP_3) | instid1(VALU_DEP_1) | |
| ; GFX1250-NEXT: s_cmp_lg_u32 s6, 0 | |
| ; GFX1250-NEXT: s_mov_b32 s4, 0xffff0000 | |
| ; GFX1250-NEXT: s_wait_loadcnt 0x0 | |
| ; GFX1250-NEXT: v_dual_lshlrev_b32 v4, 16, v3 :: v_dual_bitop2_b32 v3, s4, v3 bitop3:0x40 | |
| ; GFX1250-NEXT: v_add3_u32 v1, v4, v3, v1 | |
| ; GFX1250-NEXT: s_cbranch_scc1 .LBB1_1 | |
| ; GFX1250-NEXT: ; %bb.2: ; %exit | |
| ; GFX1250-NEXT: global_store_b32 v0, v1, s[0:1] scale_offset | |
| ; GFX1250-NEXT: s_endpgm | |
| ; | |
| ; GFX1200-LABEL: mask_in_loop_body: | |
| ; GFX1200: ; %bb.0: ; %entry | |
| ; GFX1200-NEXT: s_clause 0x1 | |
| ; GFX1200-NEXT: s_load_b128 s[0:3], s[4:5], 0x0 | |
| ; GFX1200-NEXT: s_load_b32 s4, s[4:5], 0x10 | |
| ; GFX1200-NEXT: v_dual_mov_b32 v3, 0 :: v_dual_and_b32 v2, 0x3ff, v0 | |
| ; GFX1200-NEXT: s_delay_alu instid0(VALU_DEP_1) | |
| ; GFX1200-NEXT: v_mov_b32_e32 v0, v2 | |
| ; GFX1200-NEXT: .LBB1_1: ; %loop | |
| ; GFX1200-NEXT: ; =>This Inner Loop Header: Depth=1 | |
| ; GFX1200-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_2) | instid1(SALU_CYCLE_1) | |
| ; GFX1200-NEXT: v_ashrrev_i32_e32 v1, 31, v0 | |
| ; GFX1200-NEXT: s_wait_kmcnt 0x0 | |
| ; GFX1200-NEXT: s_add_co_i32 s4, s4, -1 | |
| ; GFX1200-NEXT: s_cmp_lg_u32 s4, 0 | |
| ; GFX1200-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_1) | instid1(VALU_DEP_2) | |
| ; GFX1200-NEXT: v_lshlrev_b64_e32 v[4:5], 2, v[0:1] | |
| ; GFX1200-NEXT: v_add_nc_u32_e32 v0, 1, v0 | |
| ; GFX1200-NEXT: v_add_co_u32 v4, vcc_lo, s2, v4 | |
| ; GFX1200-NEXT: s_wait_alu depctr_va_vcc(0) | |
| ; GFX1200-NEXT: s_delay_alu instid0(VALU_DEP_3) | instskip(SKIP_4) | instid1(VALU_DEP_1) | |
| ; GFX1200-NEXT: v_add_co_ci_u32_e64 v5, null, s3, v5, vcc_lo | |
| ; GFX1200-NEXT: global_load_b32 v1, v[4:5], off | |
| ; GFX1200-NEXT: s_wait_loadcnt 0x0 | |
| ; GFX1200-NEXT: v_lshlrev_b32_e32 v4, 16, v1 | |
| ; GFX1200-NEXT: v_and_b32_e32 v1, 0xffff0000, v1 | |
| ; GFX1200-NEXT: v_add3_u32 v3, v4, v1, v3 | |
| ; GFX1200-NEXT: s_cbranch_scc1 .LBB1_1 | |
| ; GFX1200-NEXT: ; %bb.2: ; %exit | |
| ; GFX1200-NEXT: v_lshlrev_b32_e32 v0, 2, v2 | |
| ; GFX1200-NEXT: global_store_b32 v0, v3, s[0:1] | |
| ; GFX1200-NEXT: s_endpgm | |
| entry: | |
| %id = call i32 @llvm.amdgcn.workitem.id.x() | |
| br label %loop | |
| loop: | |
| %i = phi i32 [ 0, %entry ], [ %i.next, %loop ] | |
| %acc = phi i32 [ 0, %entry ], [ %acc.next, %loop ] | |
| %idx = add i32 %i, %id | |
| %in.gep = getelementptr i32, ptr addrspace(1) %in, i32 %idx | |
| %data = load i32, ptr addrspace(1) %in.gep | |
| %lo = shl i32 %data, 16 | |
| %hi = and i32 %data, -65536 | |
| %sum = add i32 %lo, %hi | |
| %acc.next = add i32 %acc, %sum | |
| %i.next = add i32 %i, 1 | |
| %cmp = icmp eq i32 %i.next, %n | |
| br i1 %cmp, label %exit, label %loop | |
| exit: | |
| %out.gep = getelementptr i32, ptr addrspace(1) %out, i32 %id | |
| store i32 %acc.next, ptr addrspace(1) %out.gep | |
| ret void | |
| } | |
| ; v_lshl_add_u32 is not a VOPD component, so the v_and_b32 has no partner. No | |
| ; pair is built, and the literal keeps the encoding it was folded into. | |
| define amdgpu_kernel void @mask_without_pair(ptr addrspace(1) %out, ptr addrspace(1) %in) { | |
| ; GFX1250-LABEL: mask_without_pair: | |
| ; GFX1250: ; %bb.0: ; %entry | |
| ; GFX1250-NEXT: s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 25, 1), 1 ; msbs: dst=0 src0=0 src1=0 src2=0 | |
| ; GFX1250-NEXT: s_mov_b64 s[64:65], 0 | |
| ; GFX1250-NEXT: v_nop | |
| ; GFX1250-NEXT: global_prefetch_b8 v0, s[64:65] scope:SCOPE_SE | |
| ; GFX1250-NEXT: s_load_b128 s[0:3], s[4:5], 0x0 nv | |
| ; GFX1250-NEXT: v_and_b32_e32 v0, 0x3ff, v0 | |
| ; GFX1250-NEXT: s_wait_kmcnt 0x0 | |
| ; GFX1250-NEXT: global_load_b32 v1, v0, s[2:3] scale_offset | |
| ; GFX1250-NEXT: s_wait_loadcnt 0x0 | |
| ; GFX1250-NEXT: v_and_b32_e32 v2, 0xffff0000, v1 | |
| ; GFX1250-NEXT: s_delay_alu instid0(VALU_DEP_1) | |
| ; GFX1250-NEXT: v_lshl_add_u32 v1, v1, 16, v2 | |
| ; GFX1250-NEXT: global_store_b32 v0, v1, s[0:1] scale_offset | |
| ; GFX1250-NEXT: s_endpgm | |
| ; | |
| ; GFX1200-LABEL: mask_without_pair: | |
| ; GFX1200: ; %bb.0: ; %entry | |
| ; GFX1200-NEXT: s_load_b128 s[0:3], s[4:5], 0x0 | |
| ; GFX1200-NEXT: v_and_b32_e32 v0, 0x3ff, v0 | |
| ; GFX1200-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_4) | instid1(VALU_DEP_1) | |
| ; GFX1200-NEXT: v_lshlrev_b32_e32 v0, 2, v0 | |
| ; GFX1200-NEXT: s_wait_kmcnt 0x0 | |
| ; GFX1200-NEXT: global_load_b32 v1, v0, s[2:3] | |
| ; GFX1200-NEXT: s_wait_loadcnt 0x0 | |
| ; GFX1200-NEXT: v_and_b32_e32 v2, 0xffff0000, v1 | |
| ; GFX1200-NEXT: v_lshl_add_u32 v1, v1, 16, v2 | |
| ; GFX1200-NEXT: global_store_b32 v0, v1, s[0:1] | |
| ; GFX1200-NEXT: s_endpgm | |
| entry: | |
| %id = call i32 @llvm.amdgcn.workitem.id.x() | |
| %in.gep = getelementptr i32, ptr addrspace(1) %in, i32 %id | |
| %data = load i32, ptr addrspace(1) %in.gep | |
| %lo = shl i32 %data, 16 | |
| %hi = and i32 %data, -65536 | |
| %res = add i32 %lo, %hi | |
| %out.gep = getelementptr i32, ptr addrspace(1) %out, i32 %id | |
| store i32 %res, ptr addrspace(1) %out.gep | |
| ret void | |
| } | |
| ; An inline constant is legal in VOPD3, so the pair forms without a move. | |
| define amdgpu_kernel void @mask_inline_constant(ptr addrspace(1) %out, ptr addrspace(1) %in) { | |
| ; GFX1250-LABEL: mask_inline_constant: | |
| ; GFX1250: ; %bb.0: ; %entry | |
| ; GFX1250-NEXT: s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 25, 1), 1 ; msbs: dst=0 src0=0 src1=0 src2=0 | |
| ; GFX1250-NEXT: s_mov_b64 s[64:65], 0 | |
| ; GFX1250-NEXT: v_nop | |
| ; GFX1250-NEXT: global_prefetch_b8 v0, s[64:65] scope:SCOPE_SE | |
| ; GFX1250-NEXT: s_load_b128 s[0:3], s[4:5], 0x0 nv | |
| ; GFX1250-NEXT: v_and_b32_e32 v4, 0x3ff, v0 | |
| ; GFX1250-NEXT: s_delay_alu instid0(VALU_DEP_1) | |
| ; GFX1250-NEXT: v_lshlrev_b32_e32 v0, 2, v4 | |
| ; GFX1250-NEXT: s_wait_kmcnt 0x0 | |
| ; GFX1250-NEXT: global_load_b64 v[2:3], v0, s[2:3] | |
| ; GFX1250-NEXT: s_wait_loadcnt 0x0 | |
| ; GFX1250-NEXT: v_dual_lshlrev_b32 v0, 16, v2 :: v_dual_bitop2_b32 v1, 63, v2 bitop3:0x40 | |
| ; GFX1250-NEXT: v_dual_lshlrev_b32 v2, 16, v3 :: v_dual_bitop2_b32 v3, 63, v3 bitop3:0x40 | |
| ; GFX1250-NEXT: global_store_b128 v4, v[0:3], s[0:1] scale_offset | |
| ; GFX1250-NEXT: s_endpgm | |
| ; | |
| ; GFX1200-LABEL: mask_inline_constant: | |
| ; GFX1200: ; %bb.0: ; %entry | |
| ; GFX1200-NEXT: s_load_b128 s[0:3], s[4:5], 0x0 | |
| ; GFX1200-NEXT: v_and_b32_e32 v4, 0x3ff, v0 | |
| ; GFX1200-NEXT: s_delay_alu instid0(VALU_DEP_1) | |
| ; GFX1200-NEXT: v_lshlrev_b32_e32 v0, 2, v4 | |
| ; GFX1200-NEXT: v_lshlrev_b32_e32 v4, 4, v4 | |
| ; GFX1200-NEXT: s_wait_kmcnt 0x0 | |
| ; GFX1200-NEXT: global_load_b64 v[2:3], v0, s[2:3] | |
| ; GFX1200-NEXT: s_wait_loadcnt 0x0 | |
| ; GFX1200-NEXT: v_lshlrev_b32_e32 v0, 16, v2 | |
| ; GFX1200-NEXT: v_and_b32_e32 v1, 63, v2 | |
| ; GFX1200-NEXT: v_lshlrev_b32_e32 v2, 16, v3 | |
| ; GFX1200-NEXT: v_and_b32_e32 v3, 63, v3 | |
| ; GFX1200-NEXT: global_store_b128 v4, v[0:3], s[0:1] | |
| ; GFX1200-NEXT: s_endpgm | |
| entry: | |
| %id = call i32 @llvm.amdgcn.workitem.id.x() | |
| %in.gep0 = getelementptr i32, ptr addrspace(1) %in, i32 %id | |
| %id1 = add i32 %id, 1 | |
| %in.gep1 = getelementptr i32, ptr addrspace(1) %in, i32 %id1 | |
| %data0 = load i32, ptr addrspace(1) %in.gep0 | |
| %data1 = load i32, ptr addrspace(1) %in.gep1 | |
| %lo0 = shl i32 %data0, 16 | |
| %hi0 = and i32 %data0, 63 | |
| %lo1 = shl i32 %data1, 16 | |
| %hi1 = and i32 %data1, 63 | |
| %ins0 = insertelement <4 x i32> poison, i32 %lo0, i32 0 | |
| %ins1 = insertelement <4 x i32> %ins0, i32 %hi0, i32 1 | |
| %ins2 = insertelement <4 x i32> %ins1, i32 %lo1, i32 2 | |
| %ins3 = insertelement <4 x i32> %ins2, i32 %hi1, i32 3 | |
| %out.gep = getelementptr <4 x i32>, ptr addrspace(1) %out, i32 %id | |
| store <4 x i32> %ins3, ptr addrspace(1) %out.gep | |
| ret void | |
| } | |
| ; Same shape as mask_shared_by_two_pairs, but the function asked for small | |
| ; code. A move only makes the code longer, so the literals stay folded. | |
| define amdgpu_kernel void @mask_optsize(ptr addrspace(1) %out, ptr addrspace(1) %in) optsize { | |
| ; GFX1250-LABEL: mask_optsize: | |
| ; GFX1250: ; %bb.0: ; %entry | |
| ; GFX1250-NEXT: s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 25, 1), 1 ; msbs: dst=0 src0=0 src1=0 src2=0 | |
| ; GFX1250-NEXT: s_mov_b64 s[64:65], 0 | |
| ; GFX1250-NEXT: v_nop | |
| ; GFX1250-NEXT: global_prefetch_b8 v0, s[64:65] scope:SCOPE_SE | |
| ; GFX1250-NEXT: s_load_b128 s[0:3], s[4:5], 0x0 nv | |
| ; GFX1250-NEXT: v_and_b32_e32 v4, 0x3ff, v0 | |
| ; GFX1250-NEXT: s_delay_alu instid0(VALU_DEP_1) | |
| ; GFX1250-NEXT: v_lshlrev_b32_e32 v0, 2, v4 | |
| ; GFX1250-NEXT: s_wait_kmcnt 0x0 | |
| ; GFX1250-NEXT: global_load_b64 v[2:3], v0, s[2:3] | |
| ; GFX1250-NEXT: s_wait_loadcnt 0x0 | |
| ; GFX1250-NEXT: v_lshlrev_b32_e32 v0, 16, v2 | |
| ; GFX1250-NEXT: v_and_b32_e32 v1, 0xffff0000, v2 | |
| ; GFX1250-NEXT: v_lshlrev_b32_e32 v2, 16, v3 | |
| ; GFX1250-NEXT: v_and_b32_e32 v3, 0xffff0000, v3 | |
| ; GFX1250-NEXT: global_store_b128 v4, v[0:3], s[0:1] scale_offset | |
| ; GFX1250-NEXT: s_endpgm | |
| ; | |
| ; GFX1200-LABEL: mask_optsize: | |
| ; GFX1200: ; %bb.0: ; %entry | |
| ; GFX1200-NEXT: s_load_b128 s[0:3], s[4:5], 0x0 | |
| ; GFX1200-NEXT: v_and_b32_e32 v4, 0x3ff, v0 | |
| ; GFX1200-NEXT: s_delay_alu instid0(VALU_DEP_1) | |
| ; GFX1200-NEXT: v_lshlrev_b32_e32 v0, 2, v4 | |
| ; GFX1200-NEXT: v_lshlrev_b32_e32 v4, 4, v4 | |
| ; GFX1200-NEXT: s_wait_kmcnt 0x0 | |
| ; GFX1200-NEXT: global_load_b64 v[2:3], v0, s[2:3] | |
| ; GFX1200-NEXT: s_wait_loadcnt 0x0 | |
| ; GFX1200-NEXT: v_lshlrev_b32_e32 v0, 16, v2 | |
| ; GFX1200-NEXT: v_and_b32_e32 v1, 0xffff0000, v2 | |
| ; GFX1200-NEXT: v_lshlrev_b32_e32 v2, 16, v3 | |
| ; GFX1200-NEXT: v_and_b32_e32 v3, 0xffff0000, v3 | |
| ; GFX1200-NEXT: global_store_b128 v4, v[0:3], s[0:1] | |
| ; GFX1200-NEXT: s_endpgm | |
| entry: | |
| %id = call i32 @llvm.amdgcn.workitem.id.x() | |
| %in.gep0 = getelementptr i32, ptr addrspace(1) %in, i32 %id | |
| %id1 = add i32 %id, 1 | |
| %in.gep1 = getelementptr i32, ptr addrspace(1) %in, i32 %id1 | |
| %data0 = load i32, ptr addrspace(1) %in.gep0 | |
| %data1 = load i32, ptr addrspace(1) %in.gep1 | |
| %lo0 = shl i32 %data0, 16 | |
| %hi0 = and i32 %data0, -65536 | |
| %lo1 = shl i32 %data1, 16 | |
| %hi1 = and i32 %data1, -65536 | |
| %ins0 = insertelement <4 x i32> poison, i32 %lo0, i32 0 | |
| %ins1 = insertelement <4 x i32> %ins0, i32 %hi0, i32 1 | |
| %ins2 = insertelement <4 x i32> %ins1, i32 %lo1, i32 2 | |
| %ins3 = insertelement <4 x i32> %ins2, i32 %hi1, i32 3 | |
| %out.gep = getelementptr <4 x i32>, ptr addrspace(1) %out, i32 %id | |
| store <4 x i32> %ins3, ptr addrspace(1) %out.gep | |
| ret void | |
| } | |
| ; v_add_f32 is a plain VOPD component, which may carry a literal, so the pair | |
| ; forms with the literal in place. | |
| define amdgpu_kernel void @plain_vopd_component(ptr addrspace(1) %out, ptr addrspace(1) %in) { | |
| ; GFX1250-LABEL: plain_vopd_component: | |
| ; GFX1250: ; %bb.0: ; %entry | |
| ; GFX1250-NEXT: s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 25, 1), 1 ; msbs: dst=0 src0=0 src1=0 src2=0 | |
| ; GFX1250-NEXT: s_mov_b64 s[64:65], 0 | |
| ; GFX1250-NEXT: v_nop | |
| ; GFX1250-NEXT: global_prefetch_b8 v0, s[64:65] scope:SCOPE_SE | |
| ; GFX1250-NEXT: s_load_b128 s[0:3], s[4:5], 0x0 nv | |
| ; GFX1250-NEXT: v_and_b32_e32 v2, 0x3ff, v0 | |
| ; GFX1250-NEXT: s_delay_alu instid0(VALU_DEP_1) | |
| ; GFX1250-NEXT: v_lshlrev_b32_e32 v0, 2, v2 | |
| ; GFX1250-NEXT: s_wait_kmcnt 0x0 | |
| ; GFX1250-NEXT: global_load_b64 v[0:1], v0, s[2:3] | |
| ; GFX1250-NEXT: s_wait_loadcnt 0x0 | |
| ; GFX1250-NEXT: v_dual_add_f32 v0, 0x3dcccccd, v0 :: v_dual_add_f32 v1, 0x3dcccccd, v1 | |
| ; GFX1250-NEXT: global_store_b64 v2, v[0:1], s[0:1] scale_offset | |
| ; GFX1250-NEXT: s_endpgm | |
| ; | |
| ; GFX1200-LABEL: plain_vopd_component: | |
| ; GFX1200: ; %bb.0: ; %entry | |
| ; GFX1200-NEXT: s_load_b128 s[0:3], s[4:5], 0x0 | |
| ; GFX1200-NEXT: v_and_b32_e32 v2, 0x3ff, v0 | |
| ; GFX1200-NEXT: s_delay_alu instid0(VALU_DEP_1) | |
| ; GFX1200-NEXT: v_lshlrev_b32_e32 v0, 2, v2 | |
| ; GFX1200-NEXT: v_lshlrev_b32_e32 v2, 3, v2 | |
| ; GFX1200-NEXT: s_wait_kmcnt 0x0 | |
| ; GFX1200-NEXT: global_load_b64 v[0:1], v0, s[2:3] | |
| ; GFX1200-NEXT: s_wait_loadcnt 0x0 | |
| ; GFX1200-NEXT: v_dual_add_f32 v0, 0x3dcccccd, v0 :: v_dual_add_f32 v1, 0x3dcccccd, v1 | |
| ; GFX1200-NEXT: global_store_b64 v2, v[0:1], s[0:1] | |
| ; GFX1200-NEXT: s_endpgm | |
| entry: | |
| %id = call i32 @llvm.amdgcn.workitem.id.x() | |
| %in.gep0 = getelementptr float, ptr addrspace(1) %in, i32 %id | |
| %id1 = add i32 %id, 1 | |
| %in.gep1 = getelementptr float, ptr addrspace(1) %in, i32 %id1 | |
| %data0 = load float, ptr addrspace(1) %in.gep0 | |
| %data1 = load float, ptr addrspace(1) %in.gep1 | |
| %add0 = fadd float %data0, 0x3FB99999A0000000 | |
| %add1 = fadd float %data1, 0x3FB99999A0000000 | |
| %ins0 = insertelement <2 x float> poison, float %add0, i32 0 | |
| %ins1 = insertelement <2 x float> %ins0, float %add1, i32 1 | |
| %out.gep = getelementptr <2 x float>, ptr addrspace(1) %out, i32 %id | |
| store <2 x float> %ins1, ptr addrspace(1) %out.gep | |
| ret void | |
| } |