[llvm] [AMDGPU] Fix pow with a negative base (PR #222248)
Tim Gymnich via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 9 02:48:23 PDT 2026
================
@@ -3310,6 +3312,63 @@ SDValue AMDGPUTargetLowering::lowerFEXP(SDValue Op, SelectionDAG &DAG) const {
return R;
}
+// No pow instruction or libcall to fall back on. fmul_legacy returns 0 for a
+// zero operand even against an infinity or a NaN, so pow(x, 0) and pow(1, y)
+// fall out as exp2(0) = 1.
+SDValue AMDGPUTargetLowering::lowerFPOW(SDValue Op, SelectionDAG &DAG) const {
+ EVT VT = Op.getValueType();
+ assert(VT == MVT::f32);
+
+ SDLoc SL(Op);
+ SDValue X = Op.getOperand(0);
+ SDValue Y = Op.getOperand(1);
+ SDNodeFlags Flags = Op->getFlags();
+
+ // Fast expansion: ignores denormals, NaN for a negative base.
+ if (allowApproxFunc(DAG, Flags)) {
+ SDValue Log = DAG.getNode(AMDGPUISD::LOG, SL, VT, X, Flags);
+ SDValue Mul = DAG.getNode(AMDGPUISD::FMUL_LEGACY, SL, VT, Y, Log, Flags);
+ return DAG.getNode(AMDGPUISD::EXP, SL, VT, Mul, Flags);
+ }
+
+ SDValue Abs = DAG.getNode(ISD::FABS, SL, VT, X, Flags);
+ SDValue Log = DAG.getNode(ISD::FLOG2, SL, VT, Abs, Flags);
+ SDValue Mul = DAG.getNode(AMDGPUISD::FMUL_LEGACY, SL, VT, Y, Log, Flags);
+ SDValue R = DAG.getNode(ISD::FEXP2, SL, VT, Mul, Flags);
+
+ EVT SetCCVT = getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT);
+ SDValue One = DAG.getConstantFP(1.0, SL, VT);
+
+ // Infinities count as integers, and every f32 >= 2^24 in magnitude is even.
+ SDValue YTrunc = DAG.getNode(ISD::FTRUNC, SL, VT, Y);
+ SDValue YIsInt = DAG.getSetCC(SL, SetCCVT, YTrunc, Y, ISD::SETOEQ);
+ SDValue YHalf =
+ DAG.getNode(ISD::FMUL, SL, VT, Y, DAG.getConstantFP(0.5, SL, VT));
+ SDValue YHalfTrunc = DAG.getNode(ISD::FTRUNC, SL, VT, YHalf);
+ SDValue YIsOdd =
+ DAG.getNode(ISD::AND, SL, SetCCVT, YIsInt,
+ DAG.getSetCC(SL, SetCCVT, YHalfTrunc, YHalf, ISD::SETONE));
+
+ // pow(-x, odd y) = -pow(x, y).
+ R = DAG.getNode(ISD::FCOPYSIGN, SL, VT, R,
+ DAG.getNode(ISD::SELECT, SL, VT, YIsOdd, X, One));
+
+ if (Flags.hasNoNaNs())
+ return R;
+
+ // A negative finite base to a non-integral power is NaN. -inf is excluded:
+ // the core already gives pow(+inf, y).
+ SDValue XNegFinite = DAG.getNode(
+ ISD::IS_FPCLASS, SL, SetCCVT, X,
+ DAG.getTargetConstant(fcNegNormal | fcNegSubnormal, SL, MVT::i32));
----------------
tgymnich wrote:
under `denormal_fpenv(...|preservesign)` subnormals should be treated as zero, thus we cannot include `fcNegSubnormal` here.
https://github.com/llvm/llvm-project/pull/222248
More information about the llvm-commits
mailing list