[llvm] [AMDGPU] Use `v_cvt_pk_*` instructions for i16_f32 saturated conversions (PR #202680)

Jay Foad via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 12 03:48:05 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
----------------
jayfoad wrote:

> > 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.

Right, that was a dumb idea, sorry!

https://github.com/llvm/llvm-project/pull/202680


More information about the llvm-commits mailing list