[llvm] [X86] Lower vector integer division and remainder through float division (PR #205263)
Phoebe Wang via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 5 01:15:22 PDT 2026
================
@@ -50564,6 +50572,123 @@ static SDValue combineMulToPMADD52(SDNode *N, const SDLoc &DL,
return SDValue();
}
+// x86 has no vector integer divide instructions. Lower vector
+// UDIV/SDIV/UREM/SREM through float division instead of scalarizing into N
+// scalar hardware divides.
+static SDValue combineIntDivRem(SDNode *N, SelectionDAG &DAG,
+ TargetLowering::DAGCombinerInfo &DCI,
+ const X86Subtarget &Subtarget) {
+ EVT VT = N->getValueType(0);
+ SDLoc DL(N);
+
+ // Vector division never survives op legalization to reach later rounds.
+ if (!VT.isVector() || !Subtarget.hasSSE2())
+ return SDValue();
+
+ SDValue Dividend = N->getOperand(0);
+ SDValue Divisor = N->getOperand(1);
+ unsigned Opc = N->getOpcode();
+
+ // Disabled lanes are poison and fdiv never traps, so ignore the mask.
+ if (Opc == ISD::MASKED_UDIV || Opc == ISD::MASKED_SDIV ||
+ Opc == ISD::MASKED_UREM || Opc == ISD::MASKED_SREM)
+ Opc = ISD::getUnmaskedBinOpOpcode(Opc);
+ bool IsRem = Opc == ISD::UREM || Opc == ISD::SREM;
+ bool IsSigned = Opc == ISD::SDIV || Opc == ISD::SREM;
+
+ // If the result is only read back as scalar extracts, scalarization computes
+ // just the demanded lanes.
+ if (all_of(N->users(), [](const SDNode *U) {
+ return U->getOpcode() == ISD::EXTRACT_VECTOR_ELT;
+ }))
+ return SDValue();
+
+ // Magic multiply lowers constant divisors cheaper than a divide.
+ if (DAG.isConstantIntBuildVectorOrConstantInt(Divisor))
+ return SDValue();
+
+ unsigned EltBits = VT.getScalarSizeInBits();
+ auto FitsFP = [&](SDValue V, const fltSemantics &Sem) {
+ unsigned Precision = APFloat::semanticsPrecision(Sem);
+ return IsSigned ? DAG.ComputeNumSignBits(V) + Precision > EltBits
+ : DAG.computeKnownBits(V).countMaxActiveBits() <= Precision;
+ };
+ auto BothFitFP = [&](const fltSemantics &Sem) {
+ return FitsFP(Dividend, Sem) && FitsFP(Divisor, Sem);
+ };
+ // i8/i16/i32: the operands fit the float mantissa
+ // exactly so one float divide recovers the exact quotient.
+ if (EltBits <= 32) {
+ // f32 recovers the quotient exactly when both operands fit in 24 bits
+ MVT FPSclVT = MVT::f64;
+ if (EltBits <= 16 || BothFitFP(APFloat::IEEEsingle()))
+ FPSclVT = MVT::f32;
+ EVT FPVT = VT.changeVectorElementType(*DAG.getContext(), FPSclVT);
+
+ // Nothing will split an illegal FP type after type legalization, so halve
+ // the divide while the integer halves stay legal.
+ if (!DCI.isBeforeLegalize() &&
+ !DAG.getTargetLoweringInfo().isTypeLegal(FPVT)) {
+ EVT HalfVT = VT.getHalfNumVectorElementsVT(*DAG.getContext());
+ if (DAG.getTargetLoweringInfo().isTypeLegal(HalfVT))
+ return splitVectorIntBinary(SDValue(N, 0), DAG, DL);
+ return SDValue();
+ }
+
+ bool IsStrict = DAG.getMachineFunction().getFunction().hasFnAttribute(
+ Attribute::StrictFP);
+ if (IsStrict) {
+ // The SAE forms are 512-bit only. Inputs widen into a zmm below, which
+ // requires 512-bit types to be legal.
+ if (!Subtarget.useAVX512Regs())
+ return SDValue();
+ // More lanes than one zmm divide can hold so split the divide.
+ if (FPVT.getSizeInBits() > 512)
+ return splitVectorIntBinary(SDValue(N, 0), DAG, DL);
----------------
phoebewang wrote:
Is the size possible not power-of-2? Can we just reture `SDValue()` and rely 50634 work for us?
https://github.com/llvm/llvm-project/pull/205263
More information about the llvm-commits
mailing list