[llvm] [AMDGPU] Use `v_cvt_pk_*` instructions for i16_f32 saturated conversions (PR #202680)
Igor Wodiany via llvm-commits
llvm-commits at lists.llvm.org
Fri Jun 12 03:37:24 PDT 2026
================
@@ -3139,3 +3139,49 @@ defm V_DOT8_U32_U4 : VOP3P_Real_gfx10_gfx11_gfx12_gfx13<0x19>;
defm V_DOT4_I32_I8 : VOP3P_Real_gfx10 <0x16>;
defm V_DOT8_I32_I4 : VOP3P_Real_gfx10 <0x18>;
+
+//===----------------------------------------------------------------------===//
+// GFX11+ Patterns
+//===----------------------------------------------------------------------===//
+
+// Packed f32 -> i16 saturated conversion.
+multiclass CvtPkF32ToI16Pat<SDPatternOperator dagOp, Instruction inst> {
+ def : GCNPat<(v2i16 (build_vector
+ (i16 (dagOp (f32 (VOP3Mods f32:$src0, i32:$src0_modifiers)), i16)),
+ (i16 (dagOp (f32 (VOP3Mods f32:$src1, i32:$src1_modifiers)), i16)))),
+ (inst $src0_modifiers, $src0, $src1_modifiers, $src1)>;
+ def : GCNPat<(v2i16 (dagOp (v2f32 VReg_64:$src), i16)),
+ (inst 0, (EXTRACT_SUBREG VReg_64:$src, sub0),
+ 0, (EXTRACT_SUBREG VReg_64:$src, sub1))>;
+ def : GCNPat<(v2i16 (dagOp (v2f32 SReg_64:$src), i16)),
+ (inst 0, (EXTRACT_SUBREG SReg_64:$src, sub0),
+ 0, (EXTRACT_SUBREG SReg_64:$src, sub1))>;
+}
+
+multiclass FPToIntSatI16Pat<dag lhs, dag rhs> {
+ let True16Predicate = UseRealTrue16Insts in
+ def : GCNPat<lhs, (EXTRACT_SUBREG rhs, lo16)>;
+ let True16Predicate = NotUseRealTrue16Insts in
+ def : GCNPat<lhs, rhs>;
+}
+
+multiclass FPToSSatI16Pat<dag lhs, int hi, int lo> {
+ defm : FPToIntSatI16Pat<lhs,
+ (V_MED3_I32_e64 (V_CVT_I32_F32_e64 $src0_modifiers, $src0),
+ (V_MOV_B32_e32 (i32 lo)), (S_MOV_B32 (i32 hi)))>;
+}
+multiclass FPToUSatI16Pat<dag lhs, int hi> {
+ defm : FPToIntSatI16Pat<lhs,
+ (V_MIN_U32_e64 (V_CVT_U32_F32_e64 $src0_modifiers, $src0), (i32 hi))>;
+}
+
+let SubtargetPredicate = isGFX11Plus in {
+ // f32 -> i16 saturated conversion.
+ defm : CvtPkF32ToI16Pat<fp_to_sint_sat, V_CVT_PK_I16_F32_e64>;
+ defm : CvtPkF32ToI16Pat<fp_to_uint_sat, V_CVT_PK_U16_F32_e64>;
+}
+
+// Fallback for f32 -> i16 saturated conversion. Required because
----------------
IgWod wrote:
A follow up on this one:
> Is V_CVT_F16_F32 followed by V_CVT_I16_F16 a neater way to implement this?
The problem I see is that afaik f16 cannot represent all values in i16 range, so by first converting to f16 we lose some of the precision, potentially causing multiple f32 values to map to the same i16 number. It still maybe the case for f32 but f16 will make it worse. Not sure that's something we want to do.
> An on GFX11+ can you implement it by still using V_CVT_PK_I16_F32 but with one of the inputs being a dummy, and extracting only the relevant half of the result?
Done. I left GFX12 scalar case to still use s_cvt + s_min + smax. It's hard to say what's better: using a single VALU instruction or keeping data in SALU. So I kept it as it is.
https://github.com/llvm/llvm-project/pull/202680
More information about the llvm-commits
mailing list