| ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py | |
| ; RUN: llc -mtriple=amdgpu11.50 < %s | FileCheck -check-prefixes=CHECK,GFX1150 %s | |
| ; RUN: llc -mtriple=amdgpu11.50 -global-isel < %s | FileCheck -check-prefixes=CHECK,GFX1150 %s | |
| ; RUN: llc -mtriple=amdgpu12.00 < %s | FileCheck -check-prefixes=CHECK,GFX12 %s | |
| ; RUN: llc -mtriple=amdgpu12.00 -global-isel < %s | FileCheck -check-prefixes=CHECK,GFX12 %s | |
| define amdgpu_vs float @fadd_f32(float inreg %a, float inreg %b) { | |
| ; CHECK-LABEL: fadd_f32: | |
| ; CHECK: ; %bb.0: | |
| ; CHECK-NEXT: s_add_f32 s0, s0, s1 | |
| ; CHECK-NEXT: s_delay_alu instid0(SALU_CYCLE_3) | |
| ; CHECK-NEXT: v_mov_b32_e32 v0, s0 | |
| ; CHECK-NEXT: ; return to shader part epilog | |
| %add = fadd float %a, %b | |
| ret float %add | |
| } | |
| define amdgpu_vs float @fsub_f32(float inreg %a, float inreg %b) { | |
| ; CHECK-LABEL: fsub_f32: | |
| ; CHECK: ; %bb.0: | |
| ; CHECK-NEXT: s_sub_f32 s0, s0, s1 | |
| ; CHECK-NEXT: s_delay_alu instid0(SALU_CYCLE_3) | |
| ; CHECK-NEXT: v_mov_b32_e32 v0, s0 | |
| ; CHECK-NEXT: ; return to shader part epilog | |
| %sub = fsub float %a, %b | |
| ret float %sub | |
| } | |
| define amdgpu_vs float @fmul_f32(float inreg %a, float inreg %b) { | |
| ; CHECK-LABEL: fmul_f32: | |
| ; CHECK: ; %bb.0: | |
| ; CHECK-NEXT: s_mul_f32 s0, s0, s1 | |
| ; CHECK-NEXT: s_delay_alu instid0(SALU_CYCLE_3) | |
| ; CHECK-NEXT: v_mov_b32_e32 v0, s0 | |
| ; CHECK-NEXT: ; return to shader part epilog | |
| %mul = fmul float %a, %b | |
| ret float %mul | |
| } | |
| define amdgpu_vs float @fmin_f32(float inreg %a, float inreg %b) { | |
| ; GFX1150-LABEL: fmin_f32: | |
| ; GFX1150: ; %bb.0: | |
| ; GFX1150-NEXT: s_min_f32 s0, s0, s1 | |
| ; GFX1150-NEXT: s_delay_alu instid0(SALU_CYCLE_3) | |
| ; GFX1150-NEXT: v_mov_b32_e32 v0, s0 | |
| ; GFX1150-NEXT: ; return to shader part epilog | |
| ; | |
| ; GFX12-LABEL: fmin_f32: | |
| ; GFX12: ; %bb.0: | |
| ; GFX12-NEXT: s_min_num_f32 s0, s0, s1 | |
| ; GFX12-NEXT: s_delay_alu instid0(SALU_CYCLE_3) | |
| ; GFX12-NEXT: v_mov_b32_e32 v0, s0 | |
| ; GFX12-NEXT: ; return to shader part epilog | |
| %min = call float @llvm.minnum.f32(float %a, float %b) | |
| ret float %min | |
| } | |
| define amdgpu_vs float @fmax_f32(float inreg %a, float inreg %b) { | |
| ; GFX1150-LABEL: fmax_f32: | |
| ; GFX1150: ; %bb.0: | |
| ; GFX1150-NEXT: s_max_f32 s0, s0, s1 | |
| ; GFX1150-NEXT: s_delay_alu instid0(SALU_CYCLE_3) | |
| ; GFX1150-NEXT: v_mov_b32_e32 v0, s0 | |
| ; GFX1150-NEXT: ; return to shader part epilog | |
| ; | |
| ; GFX12-LABEL: fmax_f32: | |
| ; GFX12: ; %bb.0: | |
| ; GFX12-NEXT: s_max_num_f32 s0, s0, s1 | |
| ; GFX12-NEXT: s_delay_alu instid0(SALU_CYCLE_3) | |
| ; GFX12-NEXT: v_mov_b32_e32 v0, s0 | |
| ; GFX12-NEXT: ; return to shader part epilog | |
| %max = call float @llvm.maxnum.f32(float %a, float %b) | |
| ret float %max | |
| } | |
| define amdgpu_vs half @fadd_f16(half inreg %a, half inreg %b) { | |
| ; CHECK-LABEL: fadd_f16: | |
| ; CHECK: ; %bb.0: | |
| ; CHECK-NEXT: s_add_f16 s0, s0, s1 | |
| ; CHECK-NEXT: s_delay_alu instid0(SALU_CYCLE_3) | |
| ; CHECK-NEXT: v_mov_b32_e32 v0, s0 | |
| ; CHECK-NEXT: ; return to shader part epilog | |
| %add = fadd half %a, %b | |
| ret half %add | |
| } | |
| define amdgpu_vs half @fsub_f16(half inreg %a, half inreg %b) { | |
| ; CHECK-LABEL: fsub_f16: | |
| ; CHECK: ; %bb.0: | |
| ; CHECK-NEXT: s_sub_f16 s0, s0, s1 | |
| ; CHECK-NEXT: s_delay_alu instid0(SALU_CYCLE_3) | |
| ; CHECK-NEXT: v_mov_b32_e32 v0, s0 | |
| ; CHECK-NEXT: ; return to shader part epilog | |
| %sub = fsub half %a, %b | |
| ret half %sub | |
| } | |
| define amdgpu_vs half @fmul_f16(half inreg %a, half inreg %b) { | |
| ; CHECK-LABEL: fmul_f16: | |
| ; CHECK: ; %bb.0: | |
| ; CHECK-NEXT: s_mul_f16 s0, s0, s1 | |
| ; CHECK-NEXT: s_delay_alu instid0(SALU_CYCLE_3) | |
| ; CHECK-NEXT: v_mov_b32_e32 v0, s0 | |
| ; CHECK-NEXT: ; return to shader part epilog | |
| %mul = fmul half %a, %b | |
| ret half %mul | |
| } | |
| define amdgpu_vs half @fmin_f16(half inreg %a, half inreg %b) { | |
| ; GFX1150-LABEL: fmin_f16: | |
| ; GFX1150: ; %bb.0: | |
| ; GFX1150-NEXT: s_min_f16 s0, s0, s1 | |
| ; GFX1150-NEXT: s_delay_alu instid0(SALU_CYCLE_3) | |
| ; GFX1150-NEXT: v_mov_b32_e32 v0, s0 | |
| ; GFX1150-NEXT: ; return to shader part epilog | |
| ; | |
| ; GFX12-LABEL: fmin_f16: | |
| ; GFX12: ; %bb.0: | |
| ; GFX12-NEXT: s_min_num_f16 s0, s0, s1 | |
| ; GFX12-NEXT: s_delay_alu instid0(SALU_CYCLE_3) | |
| ; GFX12-NEXT: v_mov_b32_e32 v0, s0 | |
| ; GFX12-NEXT: ; return to shader part epilog | |
| %min = call half @llvm.minnum.f16(half %a, half %b) | |
| ret half %min | |
| } | |
| define amdgpu_vs half @fmax_f16(half inreg %a, half inreg %b) { | |
| ; GFX1150-LABEL: fmax_f16: | |
| ; GFX1150: ; %bb.0: | |
| ; GFX1150-NEXT: s_max_f16 s0, s0, s1 | |
| ; GFX1150-NEXT: s_delay_alu instid0(SALU_CYCLE_3) | |
| ; GFX1150-NEXT: v_mov_b32_e32 v0, s0 | |
| ; GFX1150-NEXT: ; return to shader part epilog | |
| ; | |
| ; GFX12-LABEL: fmax_f16: | |
| ; GFX12: ; %bb.0: | |
| ; GFX12-NEXT: s_max_num_f16 s0, s0, s1 | |
| ; GFX12-NEXT: s_delay_alu instid0(SALU_CYCLE_3) | |
| ; GFX12-NEXT: v_mov_b32_e32 v0, s0 | |
| ; GFX12-NEXT: ; return to shader part epilog | |
| %max = call half @llvm.maxnum.f16(half %a, half %b) | |
| ret half %max | |
| } | |
| ; TODO: Fix GISEL RB legalize rule for amdgcn_cvt_pkrtz to select s_cvt_pk_rtz_f16_f32 | |
| define amdgpu_vs <2 x half> @s_cvt_pkrtz_v2f16_f32(float inreg %x, float inreg %y) { | |
| ; CHECK-LABEL: s_cvt_pkrtz_v2f16_f32: | |
| ; CHECK: ; %bb.0: | |
| ; CHECK-NEXT: s_cvt_pk_rtz_f16_f32 s0, s0, s1 | |
| ; CHECK-NEXT: s_delay_alu instid0(SALU_CYCLE_3) | |
| ; CHECK-NEXT: v_mov_b32_e32 v0, s0 | |
| ; CHECK-NEXT: ; return to shader part epilog | |
| %result = call <2 x half> @llvm.amdgcn.cvt.pkrtz(float %x, float %y) | |
| ret <2 x half> %result | |
| } | |
| define amdgpu_vs float @fmac_f32(float inreg %a, float inreg %b, float inreg %c) { | |
| ; CHECK-LABEL: fmac_f32: | |
| ; CHECK: ; %bb.0: | |
| ; CHECK-NEXT: s_fmac_f32 s0, s1, s2 | |
| ; CHECK-NEXT: s_delay_alu instid0(SALU_CYCLE_3) | |
| ; CHECK-NEXT: v_mov_b32_e32 v0, s0 | |
| ; CHECK-NEXT: ; return to shader part epilog | |
| %res = call float @llvm.fma.f32(float %b, float %c, float %a) | |
| ret float %res | |
| } | |
| ; Check selection of mov + fmac if src2 of fmac has a use later on | |
| define amdgpu_vs float @fmac_f32_with_mov(float inreg %a, float inreg %b, float inreg %c) { | |
| ; CHECK-LABEL: fmac_f32_with_mov: | |
| ; CHECK: ; %bb.0: | |
| ; CHECK-NEXT: s_mov_b32 s3, s2 | |
| ; CHECK-NEXT: s_delay_alu instid0(SALU_CYCLE_1) | instskip(NEXT) | instid1(SALU_CYCLE_3) | |
| ; CHECK-NEXT: s_fmac_f32 s3, s0, s1 | |
| ; CHECK-NEXT: s_add_f32 s0, s3, s2 | |
| ; CHECK-NEXT: s_delay_alu instid0(SALU_CYCLE_3) | |
| ; CHECK-NEXT: v_mov_b32_e32 v0, s0 | |
| ; CHECK-NEXT: ; return to shader part epilog | |
| %fma = call float @llvm.fma.f32(float %a, float %b, float %c) | |
| %res = fadd float %fma, %c | |
| ret float %res | |
| } | |
| define amdgpu_vs half @fmac_f16(half inreg %a, half inreg %b, half inreg %c) { | |
| ; CHECK-LABEL: fmac_f16: | |
| ; CHECK: ; %bb.0: | |
| ; CHECK-NEXT: s_fmac_f16 s0, s1, s2 | |
| ; CHECK-NEXT: s_delay_alu instid0(SALU_CYCLE_3) | |
| ; CHECK-NEXT: v_mov_b32_e32 v0, s0 | |
| ; CHECK-NEXT: ; return to shader part epilog | |
| %res = call half @llvm.fma.f16(half %b, half %c, half %a) | |
| ret half %res | |
| } | |
| ; Check selection of mov + fmac if src2 of fmac has a use later | |
| define amdgpu_vs half @fmac_f16_with_mov(half inreg %a, half inreg %b, half inreg %c) { | |
| ; CHECK-LABEL: fmac_f16_with_mov: | |
| ; CHECK: ; %bb.0: | |
| ; CHECK-NEXT: s_mov_b32 s3, s2 | |
| ; CHECK-NEXT: s_delay_alu instid0(SALU_CYCLE_1) | instskip(NEXT) | instid1(SALU_CYCLE_3) | |
| ; CHECK-NEXT: s_fmac_f16 s3, s0, s1 | |
| ; CHECK-NEXT: s_add_f16 s0, s3, s2 | |
| ; CHECK-NEXT: s_delay_alu instid0(SALU_CYCLE_3) | |
| ; CHECK-NEXT: v_mov_b32_e32 v0, s0 | |
| ; CHECK-NEXT: ; return to shader part epilog | |
| %fma = call half @llvm.fma.f16(half %a, half %b, half %c) | |
| %res = fadd half %fma, %c | |
| ret half %res | |
| } | |
| ; Regression test for crash in SIFoldOperands | |
| define amdgpu_ps float @_amdgpu_ps_main() { | |
| ; GFX1150-LABEL: _amdgpu_ps_main: | |
| ; GFX1150: ; %bb.0: ; %bb | |
| ; GFX1150-NEXT: s_mov_b32 s0, 0 | |
| ; GFX1150-NEXT: s_delay_alu instid0(SALU_CYCLE_1) | |
| ; GFX1150-NEXT: s_mov_b32 s1, s0 | |
| ; GFX1150-NEXT: s_mov_b32 s2, s0 | |
| ; GFX1150-NEXT: s_mov_b32 s3, s0 | |
| ; GFX1150-NEXT: s_buffer_load_b64 s[0:1], s[0:3], 0x0 | |
| ; GFX1150-NEXT: s_waitcnt lgkmcnt(0) | |
| ; GFX1150-NEXT: s_fmac_f32 s0, s1, 4.0 | |
| ; GFX1150-NEXT: s_delay_alu instid0(SALU_CYCLE_3) | |
| ; GFX1150-NEXT: v_mov_b32_e32 v0, s0 | |
| ; GFX1150-NEXT: ; return to shader part epilog | |
| ; | |
| ; GFX12-LABEL: _amdgpu_ps_main: | |
| ; GFX12: ; %bb.0: ; %bb | |
| ; GFX12-NEXT: s_mov_b32 s0, 0 | |
| ; GFX12-NEXT: s_delay_alu instid0(SALU_CYCLE_1) | |
| ; GFX12-NEXT: s_mov_b32 s1, s0 | |
| ; GFX12-NEXT: s_mov_b32 s2, s0 | |
| ; GFX12-NEXT: s_mov_b32 s3, s0 | |
| ; GFX12-NEXT: s_buffer_load_b64 s[0:1], s[0:3], 0x0 | |
| ; GFX12-NEXT: s_wait_kmcnt 0x0 | |
| ; GFX12-NEXT: s_fmac_f32 s0, s1, 4.0 | |
| ; GFX12-NEXT: s_delay_alu instid0(SALU_CYCLE_3) | |
| ; GFX12-NEXT: v_mov_b32_e32 v0, s0 | |
| ; GFX12-NEXT: ; return to shader part epilog | |
| bb: | |
| %i = call i32 @llvm.amdgcn.ptr.s.buffer.load.i32(ptr addrspace(8) null, i32 0, i32 0), !invariant.load !{} | |
| %i1 = bitcast i32 %i to float | |
| %i2 = call i32 @llvm.amdgcn.ptr.s.buffer.load.i32(ptr addrspace(8) null, i32 4, i32 0), !invariant.load !{} | |
| %i3 = bitcast i32 %i2 to float | |
| %i4 = fmul contract float %i3, 4.0 | |
| %i5 = fadd contract float %i4, %i1 | |
| ret float %i5 | |
| } | |
| declare i32 @llvm.amdgcn.ptr.s.buffer.load.i32(ptr addrspace(8), i32, i32 immarg) | |
| declare float @llvm.minnum.f32(float, float) | |
| declare float @llvm.maxnum.f32(float, float) | |
| declare half @llvm.minnum.f16(half, half) | |
| declare half @llvm.maxnum.f16(half, half) | |
| declare <2 x half> @llvm.amdgcn.cvt.pkrtz(float, float) | |
| declare float @llvm.fma.f32(float, float, float) nounwind readnone | |
| declare half @llvm.fma.f16(half, half, half) nounwind readnone |