| ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 |
| ; RUN: llc -mtriple=amdgpu10.30-unknown-amdhsa < %s | FileCheck %s |
| |
| ; Generic expansion of llvm.convert.{to,from}.arbitrary.fp for Float8E5M3FNU. |
| ; gfx1030 has no fp8 conversion hardware, so this exercises |
| ; TargetLowering::expand{CONVERT_TO,CONVERT_FROM}_ARBITRARY_FP. |
| |
| define i8 @to_e5m3fnu_1_0() { |
| ; CHECK-LABEL: to_e5m3fnu_1_0: |
| ; CHECK: ; %bb.0: |
| ; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) |
| ; CHECK-NEXT: v_mov_b32_e32 v0, 0x78 |
| ; CHECK-NEXT: s_setpc_b64 s[30:31] |
| %r = call i8 @llvm.convert.to.arbitrary.fp.i8.f32(float 1.0, metadata !"Float8E5M3FNU", metadata !"round.tonearest", i1 false) |
| ret i8 %r |
| } |
| |
| define i8 @to_e5m3fnu_1_5() { |
| ; CHECK-LABEL: to_e5m3fnu_1_5: |
| ; CHECK: ; %bb.0: |
| ; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) |
| ; CHECK-NEXT: v_mov_b32_e32 v0, 0x7c |
| ; CHECK-NEXT: s_setpc_b64 s[30:31] |
| %r = call i8 @llvm.convert.to.arbitrary.fp.i8.f32(float 1.5, metadata !"Float8E5M3FNU", metadata !"round.tonearest", i1 false) |
| ret i8 %r |
| } |
| |
| define i8 @to_e5m3fnu_2_0() { |
| ; CHECK-LABEL: to_e5m3fnu_2_0: |
| ; CHECK: ; %bb.0: |
| ; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) |
| ; CHECK-NEXT: v_mov_b32_e32 v0, 0x80 |
| ; CHECK-NEXT: s_setpc_b64 s[30:31] |
| %r = call i8 @llvm.convert.to.arbitrary.fp.i8.f32(float 2.0, metadata !"Float8E5M3FNU", metadata !"round.tonearest", i1 false) |
| ret i8 %r |
| } |
| |
| ; Largest finite value: exp=31, mant=6. |
| define i8 @to_e5m3fnu_max_finite() { |
| ; CHECK-LABEL: to_e5m3fnu_max_finite: |
| ; CHECK: ; %bb.0: |
| ; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) |
| ; CHECK-NEXT: v_mov_b32_e32 v0, 0xfe |
| ; CHECK-NEXT: s_setpc_b64 s[30:31] |
| %r = call i8 @llvm.convert.to.arbitrary.fp.i8.f32(float 114688.0, metadata !"Float8E5M3FNU", metadata !"round.tonearest", i1 false) |
| ret i8 %r |
| } |
| |
| ; 2^-15 is denormal in this format: exp=0, mant=4. |
| define i8 @to_e5m3fnu_denormal() { |
| ; CHECK-LABEL: to_e5m3fnu_denormal: |
| ; CHECK: ; %bb.0: |
| ; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) |
| ; CHECK-NEXT: v_mov_b32_e32 v0, 4 |
| ; CHECK-NEXT: s_setpc_b64 s[30:31] |
| %r = call i8 @llvm.convert.to.arbitrary.fp.i8.f32(float 0x3F00000000000000, metadata !"Float8E5M3FNU", metadata !"round.tonearest", i1 false) |
| ret i8 %r |
| } |
| |
| define i8 @to_e5m3fnu_pos_zero() { |
| ; CHECK-LABEL: to_e5m3fnu_pos_zero: |
| ; CHECK: ; %bb.0: |
| ; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) |
| ; CHECK-NEXT: v_mov_b32_e32 v0, 0 |
| ; CHECK-NEXT: s_setpc_b64 s[30:31] |
| %r = call i8 @llvm.convert.to.arbitrary.fp.i8.f32(float 0.0, metadata !"Float8E5M3FNU", metadata !"round.tonearest", i1 false) |
| ret i8 %r |
| } |
| |
| ; -0.0 is representable as +0 even without saturation. |
| define i8 @to_e5m3fnu_neg_zero() { |
| ; CHECK-LABEL: to_e5m3fnu_neg_zero: |
| ; CHECK: ; %bb.0: |
| ; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) |
| ; CHECK-NEXT: v_mov_b32_e32 v0, 0 |
| ; CHECK-NEXT: s_setpc_b64 s[30:31] |
| %r = call i8 @llvm.convert.to.arbitrary.fp.i8.f32(float -0.0, metadata !"Float8E5M3FNU", metadata !"round.tonearest", i1 false) |
| ret i8 %r |
| } |
| |
| define i8 @to_e5m3fnu_nan() { |
| ; CHECK-LABEL: to_e5m3fnu_nan: |
| ; CHECK: ; %bb.0: |
| ; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) |
| ; CHECK-NEXT: v_mov_b32_e32 v0, 0xff |
| ; CHECK-NEXT: s_setpc_b64 s[30:31] |
| %r = call i8 @llvm.convert.to.arbitrary.fp.i8.f32(float 0x7FF8000000000000, metadata !"Float8E5M3FNU", metadata !"round.tonearest", i1 false) |
| ret i8 %r |
| } |
| |
| ; The format has no Inf, so a saturating conversion clamps to max finite. |
| define i8 @to_e5m3fnu_inf_saturate() { |
| ; CHECK-LABEL: to_e5m3fnu_inf_saturate: |
| ; CHECK: ; %bb.0: |
| ; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) |
| ; CHECK-NEXT: v_mov_b32_e32 v0, 0xfe |
| ; CHECK-NEXT: s_setpc_b64 s[30:31] |
| %r = call i8 @llvm.convert.to.arbitrary.fp.i8.f32(float 0x7FF0000000000000, metadata !"Float8E5M3FNU", metadata !"round.tonearest", i1 true) |
| ret i8 %r |
| } |
| |
| ; Negative values are unrepresentable; saturating clamps them to zero. |
| define i8 @to_e5m3fnu_negative_saturate() { |
| ; CHECK-LABEL: to_e5m3fnu_negative_saturate: |
| ; CHECK: ; %bb.0: |
| ; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) |
| ; CHECK-NEXT: v_mov_b32_e32 v0, 0 |
| ; CHECK-NEXT: s_setpc_b64 s[30:31] |
| %r = call i8 @llvm.convert.to.arbitrary.fp.i8.f32(float -1.0, metadata !"Float8E5M3FNU", metadata !"round.tonearest", i1 true) |
| ret i8 %r |
| } |
| |
| define i8 @to_e5m3fnu_dynamic(float %x) { |
| ; CHECK-LABEL: to_e5m3fnu_dynamic: |
| ; CHECK: ; %bb.0: |
| ; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) |
| ; CHECK-NEXT: v_frexp_exp_i32_f32_e32 v1, v0 |
| ; CHECK-NEXT: v_frexp_mant_f32_e32 v3, v0 |
| ; CHECK-NEXT: s_mov_b32 s4, 0x7fffff |
| ; CHECK-NEXT: v_sub_nc_u32_e32 v2, 7, v1 |
| ; CHECK-NEXT: v_and_or_b32 v4, v3, s4, 0x800000 |
| ; CHECK-NEXT: v_and_b32_e32 v8, 0x7ffff, v3 |
| ; CHECK-NEXT: v_bfe_u32 v9, v3, 20, 3 |
| ; CHECK-NEXT: v_lshrrev_b32_e32 v3, 19, v3 |
| ; CHECK-NEXT: v_min_u32_e32 v2, 31, v2 |
| ; CHECK-NEXT: v_sub_nc_u32_e64 v5, v2, 1 clamp |
| ; CHECK-NEXT: v_lshrrev_b32_e32 v7, v2, v4 |
| ; CHECK-NEXT: v_bfe_u32 v6, v4, 0, v5 |
| ; CHECK-NEXT: v_lshrrev_b32_e32 v4, v5, v4 |
| ; CHECK-NEXT: v_cmp_ne_u32_e32 vcc_lo, 0, v6 |
| ; CHECK-NEXT: v_cndmask_b32_e64 v6, 0, 1, vcc_lo |
| ; CHECK-NEXT: v_cmp_ne_u32_e32 vcc_lo, 0, v8 |
| ; CHECK-NEXT: v_and_or_b32 v5, v7, 1, v6 |
| ; CHECK-NEXT: v_cndmask_b32_e64 v6, 0, 1, vcc_lo |
| ; CHECK-NEXT: v_cmp_ne_u32_e32 vcc_lo, 0, v2 |
| ; CHECK-NEXT: v_and_b32_e32 v4, v4, v5 |
| ; CHECK-NEXT: v_and_or_b32 v5, v9, 1, v6 |
| ; CHECK-NEXT: v_cndmask_b32_e32 v2, 0, v4, vcc_lo |
| ; CHECK-NEXT: v_and_b32_e32 v3, v3, v5 |
| ; CHECK-NEXT: v_add_nc_u32_e32 v2, v7, v2 |
| ; CHECK-NEXT: v_add_nc_u32_e32 v3, v9, v3 |
| ; CHECK-NEXT: v_cmp_lt_i32_e32 vcc_lo, 7, v2 |
| ; CHECK-NEXT: v_cmp_lt_i32_e64 s4, 7, v3 |
| ; CHECK-NEXT: v_cndmask_b32_e64 v2, v2, 0, vcc_lo |
| ; CHECK-NEXT: v_cndmask_b32_e64 v3, v3, 0, s4 |
| ; CHECK-NEXT: v_cndmask_b32_e64 v4, 0, 8, vcc_lo |
| ; CHECK-NEXT: v_add_co_ci_u32_e64 v1, null, 14, v1, s4 |
| ; CHECK-NEXT: v_or_b32_e32 v2, v4, v2 |
| ; CHECK-NEXT: v_lshl_or_b32 v3, v1, 3, v3 |
| ; CHECK-NEXT: v_cmp_gt_i32_e32 vcc_lo, 1, v1 |
| ; CHECK-NEXT: v_cndmask_b32_e32 v1, v3, v2, vcc_lo |
| ; CHECK-NEXT: v_cmp_neq_f32_e32 vcc_lo, 0, v0 |
| ; CHECK-NEXT: v_cndmask_b32_e32 v1, 0, v1, vcc_lo |
| ; CHECK-NEXT: v_cmp_o_f32_e32 vcc_lo, v0, v0 |
| ; CHECK-NEXT: v_cndmask_b32_e32 v0, 0xff, v1, vcc_lo |
| ; CHECK-NEXT: s_setpc_b64 s[30:31] |
| %r = call i8 @llvm.convert.to.arbitrary.fp.i8.f32(float %x, metadata !"Float8E5M3FNU", metadata !"round.tonearest", i1 false) |
| ret i8 %r |
| } |
| |
| define float @from_e5m3fnu_1_0() { |
| ; CHECK-LABEL: from_e5m3fnu_1_0: |
| ; CHECK: ; %bb.0: |
| ; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) |
| ; CHECK-NEXT: v_mov_b32_e32 v0, 1.0 |
| ; CHECK-NEXT: s_setpc_b64 s[30:31] |
| %r = call float @llvm.convert.from.arbitrary.fp.f32.i8(i8 120, metadata !"Float8E5M3FNU") |
| ret float %r |
| } |
| |
| define float @from_e5m3fnu_1_5() { |
| ; CHECK-LABEL: from_e5m3fnu_1_5: |
| ; CHECK: ; %bb.0: |
| ; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) |
| ; CHECK-NEXT: v_mov_b32_e32 v0, 0x3fc00000 |
| ; CHECK-NEXT: s_setpc_b64 s[30:31] |
| %r = call float @llvm.convert.from.arbitrary.fp.f32.i8(i8 124, metadata !"Float8E5M3FNU") |
| ret float %r |
| } |
| |
| define float @from_e5m3fnu_2_0() { |
| ; CHECK-LABEL: from_e5m3fnu_2_0: |
| ; CHECK: ; %bb.0: |
| ; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) |
| ; CHECK-NEXT: v_mov_b32_e32 v0, 2.0 |
| ; CHECK-NEXT: s_setpc_b64 s[30:31] |
| %r = call float @llvm.convert.from.arbitrary.fp.f32.i8(i8 128, metadata !"Float8E5M3FNU") |
| ret float %r |
| } |
| |
| define float @from_e5m3fnu_max_finite() { |
| ; CHECK-LABEL: from_e5m3fnu_max_finite: |
| ; CHECK: ; %bb.0: |
| ; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) |
| ; CHECK-NEXT: v_mov_b32_e32 v0, 0x47e00000 |
| ; CHECK-NEXT: s_setpc_b64 s[30:31] |
| %r = call float @llvm.convert.from.arbitrary.fp.f32.i8(i8 254, metadata !"Float8E5M3FNU") |
| ret float %r |
| } |
| |
| define float @from_e5m3fnu_denormal() { |
| ; CHECK-LABEL: from_e5m3fnu_denormal: |
| ; CHECK: ; %bb.0: |
| ; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) |
| ; CHECK-NEXT: v_bfrev_b32_e32 v0, 28 |
| ; CHECK-NEXT: s_setpc_b64 s[30:31] |
| %r = call float @llvm.convert.from.arbitrary.fp.f32.i8(i8 4, metadata !"Float8E5M3FNU") |
| ret float %r |
| } |
| |
| define float @from_e5m3fnu_nan() { |
| ; CHECK-LABEL: from_e5m3fnu_nan: |
| ; CHECK: ; %bb.0: |
| ; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) |
| ; CHECK-NEXT: v_mov_b32_e32 v0, 0x7fc00000 |
| ; CHECK-NEXT: s_setpc_b64 s[30:31] |
| %r = call float @llvm.convert.from.arbitrary.fp.f32.i8(i8 255, metadata !"Float8E5M3FNU") |
| ret float %r |
| } |
| |
| define float @from_e5m3fnu_zero() { |
| ; CHECK-LABEL: from_e5m3fnu_zero: |
| ; CHECK: ; %bb.0: |
| ; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) |
| ; CHECK-NEXT: v_mov_b32_e32 v0, 0 |
| ; CHECK-NEXT: s_setpc_b64 s[30:31] |
| %r = call float @llvm.convert.from.arbitrary.fp.f32.i8(i8 0, metadata !"Float8E5M3FNU") |
| ret float %r |
| } |
| |
| define float @from_e5m3fnu_dynamic(i8 %x) { |
| ; CHECK-LABEL: from_e5m3fnu_dynamic: |
| ; CHECK: ; %bb.0: |
| ; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) |
| ; CHECK-NEXT: v_and_b32_e32 v0, 0xffff, v0 |
| ; CHECK-NEXT: v_and_b32_e32 v1, 7, v0 |
| ; CHECK-NEXT: v_bfe_u32 v0, v0, 3, 5 |
| ; CHECK-NEXT: v_ffbh_u32_e32 v2, v1 |
| ; CHECK-NEXT: v_lshlrev_b32_e32 v5, 20, v1 |
| ; CHECK-NEXT: v_cmp_ne_u32_e32 vcc_lo, 0, v1 |
| ; CHECK-NEXT: v_cmp_eq_u32_e64 s4, 0, v0 |
| ; CHECK-NEXT: v_sub_nc_u32_e32 v3, 31, v2 |
| ; CHECK-NEXT: v_add_nc_u32_e32 v4, -8, v2 |
| ; CHECK-NEXT: v_sub_nc_u32_e32 v2, 0x8d, v2 |
| ; CHECK-NEXT: s_and_b32 vcc_lo, s4, vcc_lo |
| ; CHECK-NEXT: v_cmp_eq_u32_e64 s4, 31, v0 |
| ; CHECK-NEXT: v_lshlrev_b32_e64 v3, v3, 1 |
| ; CHECK-NEXT: v_xor_b32_e32 v3, v1, v3 |
| ; CHECK-NEXT: v_lshlrev_b32_e32 v3, v4, v3 |
| ; CHECK-NEXT: v_lshl_or_b32 v4, v0, 23, v5 |
| ; CHECK-NEXT: v_lshl_or_b32 v2, v2, 23, v3 |
| ; CHECK-NEXT: v_add_nc_u32_e32 v3, 0x38000000, v4 |
| ; CHECK-NEXT: v_or_b32_e32 v4, v0, v1 |
| ; CHECK-NEXT: v_cndmask_b32_e32 v2, v3, v2, vcc_lo |
| ; CHECK-NEXT: v_cmp_ne_u32_e64 s5, 0, v4 |
| ; CHECK-NEXT: v_cmp_eq_u32_e32 vcc_lo, 7, v1 |
| ; CHECK-NEXT: v_cndmask_b32_e64 v0, 0, v2, s5 |
| ; CHECK-NEXT: s_and_b32 s4, s4, vcc_lo |
| ; CHECK-NEXT: v_cndmask_b32_e64 v0, v0, 0x7fc00000, s4 |
| ; CHECK-NEXT: s_setpc_b64 s[30:31] |
| %r = call float @llvm.convert.from.arbitrary.fp.f32.i8(i8 %x, metadata !"Float8E5M3FNU") |
| ret float %r |
| } |