[llvm] [LegalizeTypes] Expand 128-bit UDIV/UREM by constant via Chunk Addition (PR #146238)

Simon Pilgrim via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 2 06:13:58 PST 2026


================
@@ -8200,6 +8198,82 @@ bool TargetLowering::expandDIVREMByConstant(SDNode *N,
                               DAG.getConstant(0, dl, HiLoVT));
       Sum = DAG.getNode(ISD::ADD, dl, HiLoVT, Sum, Carry);
     }
+
+  } else {
+    // If we cannot split in two halves. Let's look for a smaller chunk
+    // width where (1 << ChunkWidth) mod Divisor == 1.
+    // This ensures that the sum of all such chunks modulo Divisor
+    // is equivalent to the original value modulo Divisor.
+    const APInt &Divisor = CN->getAPIntValue();
+    unsigned BitWidth = VT.getScalarSizeInBits();
+    unsigned BestChunkWidth = 0;
+
+    // Determine the largest legal scalar integer type we can safely use
+    // for chunk operations.
+    unsigned MaxChunk;
+    EVT LegalVT = EVT(getRegisterType(*DAG.getContext(), VT));
+    if (LegalVT.isInteger())
+      MaxChunk = LegalVT.getSizeInBits();
+    else
+      return false;
+
+    // Clamp to the original bit width.
+    MaxChunk = std::min(MaxChunk, BitWidth);
+
+    // Find the largest chunk width W in (MaxChunk/2, MaxChunk] satisfying
+    //   (1 << W) % Divisor == 1.
+    // Then 2^W ≡ 1 (mod Divisor), so a value written in base 2^W can be
+    // reduced modulo Divisor by summing its W-bit chunks.
+    for (unsigned i = MaxChunk; i > MaxChunk / 2; --i) {
+      APInt Pow2 = APInt::getOneBitSet(BitWidth, i);
+      if (Pow2.urem(Divisor).isOne()) {
+        BestChunkWidth = i;
+        break;
+      }
+    }
+
+    // If we found a good chunk width, slice the number and sum the pieces.
+    if (!BestChunkWidth)
+      return false;
+
+    EVT ChunkVT = EVT::getIntegerVT(*DAG.getContext(), BestChunkWidth);
+
+    SDValue In =
+        LL ? DAG.getNode(ISD::BUILD_PAIR, dl, VT, LL, LH) : N->getOperand(0);
+
+    SmallVector<SDValue, 8> Parts;
+    // Split into fixed-size chunks
+    for (unsigned i = 0; i < BitWidth; i += BestChunkWidth) {
+      SDValue Shift = DAG.getShiftAmountConstant(i, VT, dl);
+      SDValue Chunk = DAG.getNode(ISD::SRL, dl, VT, In, Shift);
+      Chunk = DAG.getNode(ISD::TRUNCATE, dl, ChunkVT, Chunk);
+      Parts.push_back(Chunk);
+    }
+    if (Parts.empty())
----------------
RKSimon wrote:

Better to early out at the same time as the BestChunkWidth check and then just assert here:
```suggestion
    assert (!Parts.empty() && "Failed to split divisor into chunks");
```

https://github.com/llvm/llvm-project/pull/146238


More information about the llvm-commits mailing list