[llvm] [DAG] Lower frem of power-2 using div/trunc/mul+sub (PR #91148)
Matt Arsenault via llvm-commits
llvm-commits at lists.llvm.org
Wed May 8 09:28:43 PDT 2024
================
@@ -17264,17 +17264,32 @@ SDValue DAGCombiner::visitFREM(SDNode *N) {
EVT VT = N->getValueType(0);
SDNodeFlags Flags = N->getFlags();
SelectionDAG::FlagInserter FlagsInserter(DAG, N);
+ SDLoc DL(N);
if (SDValue R = DAG.simplifyFPBinop(N->getOpcode(), N0, N1, Flags))
return R;
// fold (frem c1, c2) -> fmod(c1,c2)
- if (SDValue C = DAG.FoldConstantArithmetic(ISD::FREM, SDLoc(N), VT, {N0, N1}))
+ if (SDValue C = DAG.FoldConstantArithmetic(ISD::FREM, DL, VT, {N0, N1}))
return C;
if (SDValue NewSel = foldBinOpIntoSelect(N))
return NewSel;
+ // Lower frem N0, N1 => x - trunc(N0 / N1) * N1, providing N1 is an integer
+ // power of 2.
+ if (DAG.isKnownToBeAPowerOfTwoFP(N1) &&
+ (Flags.hasNoSignedZeros() || DAG.isKnownNonNegativeFP(N0)) &&
+ !TLI.isOperationLegal(ISD::FREM, VT) &&
+ TLI.isOperationLegalOrCustom(ISD::FMUL, VT) &&
+ TLI.isOperationLegalOrCustom(ISD::FDIV, VT) &&
+ TLI.isOperationLegalOrCustom(ISD::FTRUNC, VT)) {
+ SDValue Div = DAG.getNode(ISD::FDIV, DL, VT, N0, N1);
+ SDValue Rnd = DAG.getNode(ISD::FTRUNC, DL, VT, Div);
+ SDValue Mul = DAG.getNode(ISD::FMUL, DL, VT, Rnd, N1);
+ return DAG.getNode(ISD::FSUB, DL, VT, N0, Mul);
----------------
arsenm wrote:
One thing is you should be able to emit this fmul+fsub as an FMA + fneg. I was thinking you could introduce contract, but that's potentially wrong depending on downstream uses.
You probably need to directly check isFMAFasterThanFMulAndFAdd (and maybe if isFNegFree) and emit that instead of fmul+fsub
https://github.com/llvm/llvm-project/pull/91148
More information about the llvm-commits
mailing list