[llvm] [DAGCombiner] Extend FP-to-Int cast without requiring nsz (PR #161093)
Yi-Chi Lee via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 29 09:17:49 PDT 2025
================
@@ -18860,27 +18862,57 @@ SDValue DAGCombiner::visitFPOW(SDNode *N) {
static SDValue foldFPToIntToFP(SDNode *N, const SDLoc &DL, SelectionDAG &DAG,
const TargetLowering &TLI) {
- // We only do this if the target has legal ftrunc. Otherwise, we'd likely be
- // replacing casts with a libcall. We also must be allowed to ignore -0.0
- // because FTRUNC will return -0.0 for (-1.0, -0.0), but using integer
- // conversions would return +0.0.
+ // We can fold the fpto[us]i -> [us]itofp pattern into a single ftrunc.
+ // If NoSignedZerosFPMath is enabled, this is a direct replacement.
+ // Otherwise, for strict math, we must handle edge cases:
+ // 1. For signed conversions, clamp out-of-range values to the valid
+ // integer range before the trunc.
+ // 2. For unsigned conversions, use FABS. A negative float becomes integer 0,
+ // which must convert back to +0.0. FTRUNC on its own could produce -0.0.
+
// FIXME: We should be able to use node-level FMF here.
- // TODO: If strict math, should we use FABS (+ range check for signed cast)?
EVT VT = N->getValueType(0);
- if (!TLI.isOperationLegal(ISD::FTRUNC, VT) ||
- !DAG.getTarget().Options.NoSignedZerosFPMath)
+ if (!TLI.isOperationLegal(ISD::FTRUNC, VT))
return SDValue();
// fptosi/fptoui round towards zero, so converting from FP to integer and
// back is the same as an 'ftrunc': [us]itofp (fpto[us]i X) --> ftrunc X
SDValue N0 = N->getOperand(0);
if (N->getOpcode() == ISD::SINT_TO_FP && N0.getOpcode() == ISD::FP_TO_SINT &&
- N0.getOperand(0).getValueType() == VT)
- return DAG.getNode(ISD::FTRUNC, DL, VT, N0.getOperand(0));
+ N0.getOperand(0).getValueType() == VT) {
+ if (DAG.getTarget().Options.NoSignedZerosFPMath)
+ return DAG.getNode(ISD::FTRUNC, DL, VT, N0.getOperand(0));
+
+ // Strict math: clamp to the signed integer range before truncating.
+ unsigned IntWidth = N0.getValueSizeInBits();
+ APInt APMax = APInt::getSignedMaxValue(IntWidth);
+ APInt APMin = APInt::getSignedMinValue(IntWidth);
+
+ APFloat MaxAPF(VT.getFltSemantics());
+ MaxAPF.convertFromAPInt(APMax, true, APFloat::rmTowardZero);
+ APFloat MinAPF(VT.getFltSemantics());
+ MinAPF.convertFromAPInt(APMin, true, APFloat::rmTowardZero);
+
+ SDValue MaxFP = DAG.getConstantFP(MaxAPF, DL, VT);
+ SDValue MinFP = DAG.getConstantFP(MinAPF, DL, VT);
+
+ SDValue Clamped = DAG.getNode(
+ ISD::FMINNUM, DL, VT,
+ DAG.getNode(ISD::FMAXNUM, DL, VT, N0->getOperand(0), MinFP), MaxFP);
+ return DAG.getNode(ISD::FTRUNC, DL, VT, Clamped);
+ }
----------------
yichi170 wrote:
Sure, will handle unsigned cases in this PR.
https://github.com/llvm/llvm-project/pull/161093
More information about the llvm-commits
mailing list