blob: 2584e5b9fd1199a8ce8c41cb363b75b76737fe7e [file] [edit]
; 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
}