[llvm] [SelectionDAG] Add expansion for llvm.convert.to.arbitrary.fp (PR #193595)

Dmitry Sidorov via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 23 06:33:18 PDT 2026


================
@@ -3782,6 +3782,479 @@ bool SelectionDAGLegalize::ExpandNode(SDNode *Node) {
     Results.push_back(Result);
     break;
   }
+  case ISD::CONVERT_TO_ARBITRARY_FP: {
+    // Expand conversion from a native IEEE float type to an arbitrary FP
+    // format, returning the result as an integer using bit manipulation.
+    //
+    // TODO: currently only conversions to FP4, FP6 and FP8 formats from OCP
+    // specification are expanded. Remaining arbitrary FP types: Float8E4M3,
+    // Float8E3M4, Float8E5M2FNUZ, Float8E4M3FNUZ, Float8E4M3B11FNUZ,
+    // Float8E8M0FNU.
+    EVT ResVT = Node->getValueType(0);
+
+    SDValue FloatVal = Node->getOperand(0);
+    const uint64_t SemEnum = Node->getConstantOperandVal(1);
+    const auto Sem = static_cast<APFloatBase::Semantics>(SemEnum);
+    const auto RoundMode =
+        static_cast<RoundingMode>(Node->getConstantOperandVal(2));
+    const bool Saturate = Node->getConstantOperandVal(3) != 0;
+
+    // Supported destination formats.
+    switch (Sem) {
+    case APFloatBase::S_Float8E5M2:
+    case APFloatBase::S_Float8E4M3FN:
+    case APFloatBase::S_Float6E3M2FN:
+    case APFloatBase::S_Float6E2M3FN:
+    case APFloatBase::S_Float4E2M1FN:
+      break;
+    default:
+      DAG.getContext()->emitError("CONVERT_TO_ARBITRARY_FP: not implemented "
+                                  "destination format (semantics enum " +
+                                  Twine(SemEnum) + ")");
+      Results.push_back(DAG.getPOISON(ResVT));
+      break;
+    }
+    if (!Results.empty())
+      break;
+
+    // Supported rounding modes.
+    switch (RoundMode) {
+    case RoundingMode::NearestTiesToEven:
+    case RoundingMode::TowardZero:
+    case RoundingMode::TowardPositive:
+    case RoundingMode::TowardNegative:
+    case RoundingMode::NearestTiesToAway:
+      break;
+    default:
+      DAG.getContext()->emitError(
+          "CONVERT_TO_ARBITRARY_FP: unsupported rounding mode (enum " +
+          Twine(static_cast<int>(RoundMode)) + ")");
+      Results.push_back(DAG.getPOISON(ResVT));
+      break;
+    }
+    if (!Results.empty())
+      break;
+
+    // Destination format parameters.
+    const fltSemantics &DstSem = APFloatBase::EnumToSemantics(Sem);
+    const unsigned DstBits = APFloat::getSizeInBits(DstSem);
+    const unsigned DstPrecision = APFloat::semanticsPrecision(DstSem);
+    const unsigned DstMant = DstPrecision - 1;
+    const unsigned DstExpBits = DstBits - DstMant - 1;
+    const int DstBias = 1 - APFloat::semanticsMinExponent(DstSem);
+    const unsigned DstExpMax = (1U << DstExpBits) - 1;
+    const uint64_t DstMantMask = (DstMant > 0) ? ((1ULL << DstMant) - 1) : 0;
+    const fltNonfiniteBehavior DstNFBehavior = DstSem.nonFiniteBehavior;
+    const fltNanEncoding DstNanEnc = DstSem.nanEncoding;
+
+    // Compute the maximum normal exponent for the destination format.
+    unsigned DstExpMaxNormal;
+    if (DstNFBehavior == fltNonfiniteBehavior::IEEE754)
+      DstExpMaxNormal = DstExpMax - 1;
+    else
+      DstExpMaxNormal = DstExpMax;
+
+    // For NanOnly formats the max exponent field for finite values
+    // is DstExpMax, but the encoding with exp = DstExpMax and
+    // mant = all-ones is NaN. So DstExpMaxNormal = DstExpMax, but max
+    // mantissa at that exponent is DstMantMask - 1 (if NanEnc == AllOnes) to
+    // avoid the NaN encoding.
+    uint64_t DstMaxMantAtMaxExp = DstMantMask;
+    if (DstNFBehavior == fltNonfiniteBehavior::NanOnly &&
+        DstNanEnc == fltNanEncoding::AllOnes)
+      DstMaxMantAtMaxExp = DstMantMask - 1;
+
+    // Source format parameters.
+    EVT SrcVT = FloatVal.getValueType();
+    const fltSemantics &SrcSem = SrcVT.getFltSemantics();
+    const unsigned SrcBits = APFloat::getSizeInBits(SrcSem);
+    const unsigned SrcPrecision = APFloat::semanticsPrecision(SrcSem);
+    const unsigned SrcMant = SrcPrecision - 1;
+    const unsigned SrcExpBits = SrcBits - SrcMant - 1;
+    const int SrcBias = 1 - APFloat::semanticsMinExponent(SrcSem);
+    const uint64_t SrcMantMask = (1ULL << SrcMant) - 1;
+    const uint64_t SrcExpMask = (1ULL << SrcExpBits) - 1;
+
+    // Work in the source integer type.
+    EVT IntVT = EVT::getIntegerVT(*DAG.getContext(), SrcBits);
----------------
MrSidims wrote:

CONVERT_TO_ARBITRARY_FP is handled in LegalizeVectorOps (just like previously added CONVERT_FROM_ARBITRARY_FP). I've added assertions to make the assumptions more readable.

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


More information about the llvm-commits mailing list