@@ -900,6 +900,41 @@ namespace {
900900 ISD::NodeType ExtType);
901901 };
902902
903+ /// Generic remainder optimization : Folds a remainder operation (A % B) by reusing the computed quotient (A / B).
904+ static SDValue PerformREMCombineGeneric(SDNode *N, DAGCombiner &DC,
905+ CodeGenOptLevel OptLevel) {
906+ assert(N->getOpcode() == ISD::SREM || N->getOpcode() == ISD::UREM);
907+
908+ // Don't do anything at less than -O2.
909+ if (OptLevel < CodeGenOptLevel::Default)
910+ return SDValue();
911+
912+ SelectionDAG &DAG = DC.getDAG();
913+ SDLoc DL(N);
914+ EVT VT = N->getValueType(0);
915+ bool IsSigned = N->getOpcode() == ISD::SREM;
916+ unsigned DivOpc = IsSigned ? ISD::SDIV : ISD::UDIV;
917+
918+ const SDValue &Num = N->getOperand(0);
919+ const SDValue &Den = N->getOperand(1);
920+
921+ AttributeList Attr = DC.getDAG().getMachineFunction().getFunction().getAttributes();
922+ if (DC.getDAG().getTargetLoweringInfo().isIntDivCheap(N->getValueType(0), Attr))
923+ return SDValue();
924+
925+ for (const SDNode *U : Num->users()) {
926+ if (U->getOpcode() == DivOpc && U->getOperand(0) == Num &&
927+ U->getOperand(1) == Den) {
928+ // Num % Den -> Num - (Num / Den) * Den
929+ return DAG.getNode(ISD::SUB, DL, VT, Num,
930+ DAG.getNode(ISD::MUL, DL, VT,
931+ DAG.getNode(DivOpc, DL, VT, Num, Den),
932+ Den));
933+ }
934+ }
935+ return SDValue();
936+ }
937+
903938/// This class is a DAGUpdateListener that removes any deleted
904939/// nodes from the worklist.
905940class WorklistRemover : public SelectionDAG::DAGUpdateListener {
@@ -5400,6 +5435,9 @@ SDValue DAGCombiner::visitREM(SDNode *N) {
54005435 if (SDValue NewSel = foldBinOpIntoSelect(N))
54015436 return NewSel;
54025437
5438+ if (SDValue V = PerformREMCombineGeneric(N, *this, OptLevel))
5439+ return V;
5440+
54035441 if (isSigned) {
54045442 // If we know the sign bits of both operands are zero, strength reduce to a
54055443 // urem instead. Handles (X & 0x0FFFFFFF) %s 16 -> X&15
0 commit comments