[llvm] [DAGCombiner][LegalizeTypes] Fuse i128 sdiv+srem / udiv+urem into single __divmodti4 / __udivmodti4 call (PR #187908)
Takashi Idobe via llvm-commits
llvm-commits at lists.llvm.org
Fri May 1 06:05:52 PDT 2026
================
@@ -4939,6 +4943,87 @@ void DAGTypeLegalizer::ExpandIntRes_SADDSUBO(SDNode *Node,
ReplaceValueWith(SDValue(Node, 1), Ovf);
}
+void DAGTypeLegalizer::ExpandIntRes_DIVREM(SDNode *N, unsigned ResNo,
+ SDValue &Lo, SDValue &Hi) {
+ SDLoc dl(N);
+ EVT VT = N->getValueType(0);
+ bool IsSigned = (N->getOpcode() == ISD::SDIVREM);
+
+ // Only i128 is handled here; other widths require generalizing this
+ // function to select the libcall by VT.
+ RTLIB::Libcall LC = IsSigned ? RTLIB::SDIVREM_I128 : RTLIB::UDIVREM_I128;
+ assert(VT == MVT::i128 &&
+ "ExpandIntRes_DIVREM only handles i128; generalize by VT first");
+
+ // If no fused divrem libcall is available (or VT is not i128 in release
+ // builds), fall back to separate div and rem.
+ if (VT != MVT::i128 ||
+ DAG.getLibcalls().getLibcallImpl(LC) == RTLIB::Unsupported) {
+ unsigned DivOp = IsSigned ? ISD::SDIV : ISD::UDIV;
+ unsigned RemOp = IsSigned ? ISD::SREM : ISD::UREM;
+ SDValue Ops[2] = {N->getOperand(0), N->getOperand(1)};
+ SDValue Q = DAG.getNode(DivOp, dl, VT, Ops);
+ SDValue R = DAG.getNode(RemOp, dl, VT, Ops);
+ if (ResNo == 0) {
+ SplitInteger(Q, Lo, Hi);
+ ReplaceValueWith(SDValue(N, 1), R);
+ } else {
+ SplitInteger(R, Lo, Hi);
+ ReplaceValueWith(SDValue(N, 0), Q);
+ }
+ return;
+ }
+
+ // Emit __divmodti4 / __udivmodti4:
+ // RetTy libcall(RetTy a, RetTy b, RetTy *rem)
+ // The quotient is the return value; the remainder is written via pointer.
+ Type *RetTy = VT.getTypeForEVT(*DAG.getContext());
+ TargetLowering::ArgListTy Args;
+ for (const SDValue &Op : N->op_values()) {
+ TargetLowering::ArgListEntry Entry(
+ Op, Op.getValueType().getTypeForEVT(*DAG.getContext()));
+ Entry.IsSExt = IsSigned;
+ Entry.IsZExt = !IsSigned;
+ Args.push_back(Entry);
+ }
+
+ // The libcall writes the remainder via a pointer argument; allocate a stack
+ // slot for it and pass its address as the third argument.
+ SDValue FIPtr = DAG.CreateStackTemporary(VT);
+ TargetLowering::ArgListEntry PtrEntry(
+ FIPtr, PointerType::getUnqual(RetTy->getContext()));
+ Args.push_back(PtrEntry);
+
+ RTLIB::LibcallImpl LCImpl = DAG.getLibcalls().getLibcallImpl(LC);
+ TargetLowering::CallLoweringInfo CLI(DAG);
+ CLI.setDebugLoc(dl)
+ .setChain(DAG.getEntryNode())
+ .setLibCallee(
+ DAG.getLibcalls().getLibcallImplCallingConv(LCImpl), RetTy,
+ DAG.getExternalSymbol(LCImpl, TLI.getPointerTy(DAG.getDataLayout())),
----------------
Takashiidobe wrote:
Made that change for both this and the Win64 function.
https://github.com/llvm/llvm-project/pull/187908
More information about the llvm-commits
mailing list