[llvm] [AMDGPU] Implement llvm.fptosi.sat and llvm.fptoui.sat (PR #174726)

Jay Foad via llvm-commits llvm-commits at lists.llvm.org
Fri Jan 30 02:19:42 PST 2026


================
@@ -3762,6 +3775,86 @@ SDValue AMDGPUTargetLowering::LowerFP_TO_INT(const SDValue Op,
   return SDValue();
 }
 
+SDValue AMDGPUTargetLowering::LowerFP_TO_INT_SAT(const SDValue Op,
+                                                 SelectionDAG &DAG) const {
+  SDValue Src = Op.getOperand(0);
+  unsigned OpOpcode = Op.getOpcode();
+  EVT SrcVT = Src.getValueType();
+  EVT DstVT = Op.getValueType();
+  SDValue SatVTOp = Op.getNode()->getOperand(1);
+  EVT SatVT = cast<VTSDNode>(SatVTOp)->getVT();
+  SDLoc DL(Op);
+
+  uint64_t DstWidth = DstVT.getScalarSizeInBits();
+  uint64_t SatWidth = SatVT.getScalarSizeInBits();
+  assert(SatWidth <= DstWidth && "Saturation width cannot exceed result width");
+
+  // Will be selected natively
+  if (DstVT == MVT::i32 && SatWidth == DstWidth &&
+      (SrcVT == MVT::f32 || SrcVT == MVT::f64))
+    return Op;
+
+  const SDValue Int32VT = DAG.getValueType(MVT::i32);
+
+  // Perform all saturation at i32 and truncate
+  if (SatWidth < DstWidth) {
+    const uint64_t Int32Width = 32;
+    SDValue FpToInt32 = DAG.getNode(OpOpcode, DL, MVT::i32, Src, Int32VT);
+    SDValue Int32SatVal;
+
+    if (Op.getOpcode() == ISD::FP_TO_SINT_SAT) {
+      SDValue MinConst = DAG.getConstant(
+          APInt::getSignedMaxValue(SatWidth).sext(Int32Width), DL, MVT::i32);
+      SDValue MaxConst = DAG.getConstant(
+          APInt::getSignedMinValue(SatWidth).sext(Int32Width), DL, MVT::i32);
+      SDValue MinVal =
+          DAG.getNode(ISD::SMIN, DL, MVT::i32, FpToInt32, MinConst);
+      Int32SatVal = DAG.getNode(ISD::SMAX, DL, MVT::i32, MinVal, MaxConst);
+    } else {
+      SDValue MinConst = DAG.getConstant(
+          APInt::getMaxValue(SatWidth).zext(Int32Width), DL, MVT::i32);
+      Int32SatVal = DAG.getNode(ISD::UMIN, DL, MVT::i32, FpToInt32, MinConst);
+    }
+
+    if (DstWidth == Int32Width)
+      return Int32SatVal;
+    if (DstWidth < Int32Width)
+      return DAG.getNode(ISD::TRUNCATE, DL, DstVT, Int32SatVal);
+
+    // DstWidth > Int32Width
+    const unsigned Ext =
+        OpOpcode == ISD::FP_TO_SINT_SAT ? ISD::SIGN_EXTEND : ISD::ZERO_EXTEND;
+    return DAG.getNode(Ext, DL, DstVT, FpToInt32);
----------------
jayfoad wrote:

All of this can be done with a single `DAG.getExtOrTrunc`.

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


More information about the llvm-commits mailing list