[llvm] [AMDGPU] Add custom lowering of llvm.convert.from.arbitrary.fp for FP8 (PR #194144)

Dmitry Sidorov via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 30 16:04:36 PDT 2026


================
@@ -10569,6 +10584,123 @@ SDValue SITargetLowering::lowerWorkitemID(SelectionDAG &DAG, SDValue Op,
                      DAG.getValueType(SmallVT));
 }
 
+// Pack vector inputs as hw instruction is packed.
+// FIXME: note, packing loses lane-wise poison. Should we do something about
+// it?
+SDValue SITargetLowering::packBytesToI32(SelectionDAG &DAG, const SDLoc &SL,
+                                         SDValue Src, unsigned NumBytes,
+                                         unsigned FirstLane) {
+  EVT SrcEltVT = Src.getValueType().getVectorElementType();
+  SDValue PackedI32;
+  for (unsigned I = 0; I != NumBytes; ++I) {
+    SDValue Elt = DAG.getExtractVectorElt(SL, SrcEltVT, Src, FirstLane + I);
+    SDValue Byte = DAG.getZExtOrTrunc(Elt, SL, MVT::i32);
+    Byte = DAG.getNode(ISD::AND, SL, MVT::i32, Byte,
+                       DAG.getConstant(0xFF, SL, MVT::i32));
+    if (I != 0)
+      Byte = DAG.getNode(ISD::SHL, SL, MVT::i32, Byte,
+                         DAG.getConstant(I * 8, SL, MVT::i32));
+    PackedI32 =
+        I == 0 ? Byte : DAG.getNode(ISD::OR, SL, MVT::i32, PackedI32, Byte);
+  }
+  return PackedI32;
+}
+
+SDValue SITargetLowering::lowerFromFP8ToF32(SDValue Op, bool IsBF8,
+                                            SelectionDAG &DAG) const {
+  EVT DstVT = Op.getValueType();
+  SDLoc SL(Op);
+  SDValue Src = Op.getOperand(0);
+
+  if (DstVT == MVT::f32) {
+    unsigned IntrID =
+        IsBF8 ? Intrinsic::amdgcn_cvt_f32_bf8 : Intrinsic::amdgcn_cvt_f32_fp8;
+    SDValue SrcI32 = DAG.getAnyExtOrTrunc(Src, SL, MVT::i32);
+    return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, SL, MVT::f32,
+                       DAG.getTargetConstant(IntrID, SL, MVT::i32), SrcI32,
+                       DAG.getTargetConstant(0, SL, MVT::i32));
+  }
+
+  auto EmitPk = [&](SDValue PackedI32, unsigned WordSel) {
+    unsigned IntrID = IsBF8 ? Intrinsic::amdgcn_cvt_pk_f32_bf8
+                            : Intrinsic::amdgcn_cvt_pk_f32_fp8;
+    return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, SL, MVT::v2f32,
+                       DAG.getTargetConstant(IntrID, SL, MVT::i32), PackedI32,
+                       DAG.getTargetConstant(WordSel, SL, MVT::i1));
+  };
+
+  if (DstVT == MVT::v2f32)
+    return EmitPk(packBytesToI32(DAG, SL, Src, 2, 0), 0);
+
+  SDValue PackedI32 = packBytesToI32(DAG, SL, Src, 4, 0);
+  SDValue Lo = EmitPk(PackedI32, 0);
+  SDValue Hi = EmitPk(PackedI32, 1);
+  return DAG.getNode(ISD::CONCAT_VECTORS, SL, MVT::v4f32, Lo, Hi);
+}
+
+SDValue SITargetLowering::lowerFromFP8ToF16(SDValue Op, bool IsBF8,
+                                            SelectionDAG &DAG) const {
+  assert(Subtarget->hasGFX1250Insts() &&
+         "unscaled fp8/bf8 -> f16 requires gfx1250+");
+  EVT DstVT = Op.getValueType();
+  SDLoc SL(Op);
+  SDValue Src = Op.getOperand(0);
+
+  // amdgcn_cvt_f16_{fp8,bf8}(i32 src, byte_sel) -> f16.
+  // amdgcn_cvt_pk_f16_{fp8,bf8}(i16 src) -> v2f16.
+  if (!DstVT.isVector()) {
+    unsigned IntrID =
+        IsBF8 ? Intrinsic::amdgcn_cvt_f16_bf8 : Intrinsic::amdgcn_cvt_f16_fp8;
+    SDValue SrcI32 = DAG.getAnyExtOrTrunc(Src, SL, MVT::i32);
+    return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, SL, MVT::f16,
----------------
MrSidims wrote:

Moved to .td for scalars

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


More information about the llvm-commits mailing list