[llvm] [RISCV] Lower scalar FP (freeze poison) as a fmv/fcvt from x0. (PR #225549)

Eli Friedman via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 22 16:47:22 PDT 2026


================
@@ -1243,75 +1311,19 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
   }
   case ISD::ConstantFP: {
     const APFloat &APF = cast<ConstantFPSDNode>(Node)->getValueAPF();
-
-    bool Is64Bit = Subtarget->is64Bit();
-    bool HasZdinx = Subtarget->hasStdExtZdinx();
-
-    bool NegZeroF64 = APF.isNegZero() && VT == MVT::f64;
-    SDValue Imm;
-    // For +0.0 or f64 -0.0 we need to start from X0. For all others, we will
-    // create an integer immediate.
-    if (APF.isPosZero() || NegZeroF64) {
-      if (VT == MVT::f64 && HasZdinx && !Is64Bit)
-        Imm = CurDAG->getRegister(RISCV::X0_Pair, MVT::f64);
-      else
-        Imm = CurDAG->getRegister(RISCV::X0, XLenVT);
-    } else {
-      Imm = selectImm(CurDAG, DL, XLenVT, APF.bitcastToAPInt().getSExtValue(),
-                      *Subtarget);
-    }
-
-    unsigned Opc;
-    switch (VT.SimpleTy) {
-    default:
-      llvm_unreachable("Unexpected size");
-    case MVT::bf16:
-      assert(Subtarget->hasStdExtZfbfmin());
-      Opc = RISCV::FMV_H_X;
-      break;
-    case MVT::f16:
-      Opc = Subtarget->hasStdExtZhinxmin() ? RISCV::COPY : RISCV::FMV_H_X;
-      break;
-    case MVT::f32:
-      Opc = Subtarget->hasStdExtZfinx() ? RISCV::COPY : RISCV::FMV_W_X;
-      break;
-    case MVT::f64:
-      // For RV32, we can't move from a GPR, we need to convert instead. This
-      // should only happen for +0.0 and -0.0.
-      assert((Subtarget->is64Bit() || APF.isZero()) && "Unexpected constant");
-      if (HasZdinx)
-        Opc = RISCV::COPY;
-      else
-        Opc = Is64Bit ? RISCV::FMV_D_X : RISCV::FCVT_D_W;
-      break;
-    }
-
-    SDNode *Res;
-    if (VT.SimpleTy == MVT::f16 && Opc == RISCV::COPY) {
-      Res =
-          CurDAG->getTargetExtractSubreg(RISCV::sub_16, DL, VT, Imm).getNode();
-    } else if (VT.SimpleTy == MVT::f32 && Opc == RISCV::COPY) {
-      Res =
-          CurDAG->getTargetExtractSubreg(RISCV::sub_32, DL, VT, Imm).getNode();
-    } else if (Opc == RISCV::FCVT_D_W_IN32X || Opc == RISCV::FCVT_D_W)
-      Res = CurDAG->getMachineNode(
-          Opc, DL, VT, Imm,
-          CurDAG->getTargetConstant(RISCVFPRndMode::RNE, DL, XLenVT));
-    else
-      Res = CurDAG->getMachineNode(Opc, DL, VT, Imm);
-
-    // For f64 -0.0, we need to insert a fneg.d idiom.
-    if (NegZeroF64) {
-      Opc = RISCV::FSGNJN_D;
-      if (HasZdinx)
-        Opc = Is64Bit ? RISCV::FSGNJN_D_INX : RISCV::FSGNJN_D_IN32X;
-      Res =
-          CurDAG->getMachineNode(Opc, DL, VT, SDValue(Res, 0), SDValue(Res, 0));
-    }
-
-    ReplaceNode(Node, Res);
+    selectFPConstant(Node, DL, VT, APF);
     return;
   }
+  case ISD::FREEZE:
+    // Lower (freeze poison) to a zero producing instruction so we properly
+    // nan-box to FLEN.
+    if (VT.isFloatingPoint() && !VT.isVector() && Subtarget->hasStdExtF() &&
+        Node->getOperand(0).getOpcode() == ISD::POISON) {
----------------
efriedma-quic wrote:

It's fine to lower "FREEZE(POISON)" this way, but I think you also need some handling for "FREEZE(X)", where you don't know if X is poison.  (Maybe something like `fmv.x.w a0, fa0; fmv.w.x fa0, a0`.)

Alternatively, we could maintain the NaN-boxing for poison values.  Instead of lowering POISON to IMPLICIT_DEF, lower it to `fmv.d.x fa0, zero`, and forbid any operation on f32 that would corrupt the high bits.  Then FREEZE can be a no-op.  Not sure if anything else would need to be adjusted.

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


More information about the llvm-commits mailing list