[llvm] [DAGCombiner][LegalizeTypes] Fuse i128 sdiv+srem / udiv+urem into single __divmodti4 / __udivmodti4 call (PR #187908)
Craig Topper via llvm-commits
llvm-commits at lists.llvm.org
Thu Mar 26 23:14:05 PDT 2026
================
@@ -30640,6 +30613,72 @@ SDValue X86TargetLowering::LowerWin64_i128OP(SDValue Op, SelectionDAG &DAG) cons
return DAG.getBitcast(VT, CallInfo.first);
}
+void X86TargetLowering::LowerWin64_i128DIVREM(SDNode *N, SelectionDAG &DAG,
+ SDValue &Quot,
+ SDValue &Rem) const {
+ assert(Subtarget.isTargetWin64() && "Unexpected target");
+ EVT VT = N->getValueType(0);
+ assert(VT == MVT::i128 && "Unexpected type");
+
+ bool isSigned = N->getOpcode() == ISD::SDIVREM;
+ RTLIB::Libcall LC = isSigned ? RTLIB::SDIVREM_I128 : RTLIB::UDIVREM_I128;
+ RTLIB::LibcallImpl LCImpl = DAG.getLibcalls().getLibcallImpl(LC);
+
+ SDLoc dl(N);
+
+ // If no fused divrem libcall is available, fall back to separate div and rem.
+ // This goes through LowerWin64_i128OP with the correct pointer-arg ABI.
+ if (LCImpl == RTLIB::Unsupported) {
+ unsigned DivOp = isSigned ? ISD::SDIV : ISD::UDIV;
+ unsigned RemOp = isSigned ? ISD::SREM : ISD::UREM;
+ Quot = DAG.getNode(DivOp, dl, VT, N->getOperand(0), N->getOperand(1));
+ Rem = DAG.getNode(RemOp, dl, VT, N->getOperand(0), N->getOperand(1));
+ return;
+ }
+ SDValue InChain = DAG.getEntryNode();
+
+ TargetLowering::ArgListTy Args;
+
+ // Spill both i128 inputs to stack temporaries and pass as pointers as per
+ // Win64 CC (Win64 has no calling convention for passing i128 by value).
+ for (unsigned i = 0; i < 2; ++i) {
+ EVT ArgVT = N->getOperand(i).getValueType();
+ assert(ArgVT == MVT::i128 && "Unexpected argument type");
+ SDValue StackPtr = DAG.CreateStackTemporary(ArgVT, 16);
+ int SPFI = cast<FrameIndexSDNode>(StackPtr.getNode())->getIndex();
+ MachinePointerInfo MPI =
+ MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), SPFI);
+ InChain =
+ DAG.getStore(InChain, dl, N->getOperand(i), StackPtr, MPI, Align(16));
+ Args.emplace_back(StackPtr, PointerType::get(*DAG.getContext(), 0));
+ }
+
+ // Allocate a stack slot for the remainder output pointer.
+ MachineFunction &MF = DAG.getMachineFunction();
+ int RemFI = MF.getFrameInfo().CreateStackObject(16, Align(16), false);
+ SDValue RemPtr = DAG.getFrameIndex(RemFI, getPointerTy(DAG.getDataLayout()));
+ Args.emplace_back(RemPtr, PointerType::get(*DAG.getContext(), 0));
+
+ SDValue Callee =
+ DAG.getExternalSymbol(LCImpl, getPointerTy(DAG.getDataLayout()));
+
+ TargetLowering::CallLoweringInfo CLI(DAG);
+ CLI.setDebugLoc(dl)
+ .setChain(InChain)
+ .setLibCallee(
+ DAG.getLibcalls().getLibcallImplCallingConv(LCImpl),
+ static_cast<EVT>(MVT::v2i64).getTypeForEVT(*DAG.getContext()), Callee,
----------------
topperc wrote:
This `static_cast<EVT>(MVT::v2i64)` looks really weird to me. Is that invoking the EVT constructor?
https://github.com/llvm/llvm-project/pull/187908
More information about the llvm-commits
mailing list