[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;
----------------
RKSimon wrote:
Is there not a cheaper bit twiddling we can do for this?
https://github.com/llvm/llvm-project/pull/146238
More information about the llvm-commits
mailing list