Skip to content

Commit 329a5d0

Browse files
committed
[RISCV][ISelLowering] Use Zicond for FP selects on Zfinx/Zdinx
When Zfinx or Zdinx is enabled, FP values live in the integer register file, so there is no GPR<->FPR move cost. In this configuration we can profitably lower floating-point `select` nodes through an integer `ISD::SELECT` so that the existing Zicond patterns generate branchless czero/cmov sequences instead of control-flow branches. This covers patterns such as: // Case 1: integer condition float sel(int cond, float a, float b) { return cond ? a : b; } // Case 2: floating-point condition float cmp_sel(float a, float b, float c, float d) { return (a > b) ? c : d; } In Case 1 we bitcast the FP operands to an XLen integer type, form an integer `select` with the original integer condition `cond`, and then bitcast the result back to float, allowing it to be lowered to a Zicond-based cmov/czero sequence. In Case 2 the floating-point compare is already lowered to an integer 0/1 value in a GPR (e.g. `flt.s` / `fle.s` / `feq.s`), so we can reuse that integer result as the Zicond condition and apply the same scheme. The transformation is gated on both Zicond and Zfinx/Zdinx, so classic F/D implementations (where FP values live in a separate FP register file) continue to use the existing branch-based lowering and do not pay for extra GPR<->FPR moves. FP semantics are unchanged: we only reinterpret the FP operands as integers; no numeric conversions are introduced.
1 parent 02a997c commit 329a5d0

File tree

1 file changed

+30
-0
lines changed

1 file changed

+30
-0
lines changed

llvm/lib/Target/RISCV/RISCVISelLowering.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9555,6 +9555,36 @@ SDValue RISCVTargetLowering::lowerSELECT(SDValue Op, SelectionDAG &DAG) const {
95559555
if (SDValue V = lowerSelectToBinOp(Op.getNode(), DAG, Subtarget))
95569556
return V;
95579557

9558+
// When there is no cost for GPR <-> FGPR, we can use zicond select for
9559+
// floating value when CondV is int type
9560+
bool FPinGPR = Subtarget.hasStdExtZfinx() || Subtarget.hasStdExtZdinx();
9561+
bool UseZicondForFPSel = Subtarget.hasStdExtZicond() && FPinGPR &&
9562+
VT.isFloatingPoint() &&
9563+
CondV.getValueType().isInteger();
9564+
if (UseZicondForFPSel) {
9565+
MVT XLenIntVT = Subtarget.getXLenVT();
9566+
9567+
auto CastToInt = [&](SDValue V) -> SDValue {
9568+
if (VT == MVT::f32 && Subtarget.is64Bit()) {
9569+
return DAG.getNode(RISCVISD::FMV_X_ANYEXTW_RV64, DL, XLenIntVT, V);
9570+
}
9571+
return DAG.getBitcast(XLenIntVT, V);
9572+
};
9573+
9574+
SDValue TrueVInt = CastToInt(TrueV);
9575+
SDValue FalseVInt = CastToInt(FalseV);
9576+
9577+
// Emit integer SELECT (lowers to Zicond)
9578+
SDValue ResultInt =
9579+
DAG.getNode(ISD::SELECT, DL, XLenIntVT, CondV, TrueVInt, FalseVInt);
9580+
9581+
// Convert back to floating VT
9582+
if (VT == MVT::f32 && Subtarget.is64Bit()) {
9583+
return DAG.getNode(RISCVISD::FMV_W_X_RV64, DL, VT, ResultInt);
9584+
}
9585+
return DAG.getBitcast(VT, ResultInt);
9586+
}
9587+
95589588
// When Zicond or XVentanaCondOps is present, emit CZERO_EQZ and CZERO_NEZ
95599589
// nodes to implement the SELECT. Performing the lowering here allows for
95609590
// greater control over when CZERO_{EQZ/NEZ} are used vs another branchless

0 commit comments

Comments
 (0)