|  | //===- llvm/unittest/Support/DivisionByConstantTest.cpp -------------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/ADT/APInt.h" | 
|  | #include "llvm/Support/DivisionByConstantInfo.h" | 
|  | #include "gtest/gtest.h" | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | template <typename Fn> static void EnumerateAPInts(unsigned Bits, Fn TestFn) { | 
|  | APInt N(Bits, 0); | 
|  | do { | 
|  | TestFn(N); | 
|  | } while (++N != 0); | 
|  | } | 
|  |  | 
|  | APInt MULHS(APInt X, APInt Y) { | 
|  | unsigned Bits = X.getBitWidth(); | 
|  | unsigned WideBits = 2 * Bits; | 
|  | return (X.sext(WideBits) * Y.sext(WideBits)).lshr(Bits).trunc(Bits); | 
|  | } | 
|  |  | 
|  | APInt SignedDivideUsingMagic(APInt Numerator, APInt Divisor, | 
|  | SignedDivisionByConstantInfo Magics) { | 
|  | unsigned Bits = Numerator.getBitWidth(); | 
|  |  | 
|  | APInt Factor(Bits, 0); | 
|  | APInt ShiftMask(Bits, -1, true); | 
|  | if (Divisor.isOne() || Divisor.isAllOnes()) { | 
|  | // If d is +1/-1, we just multiply the numerator by +1/-1. | 
|  | Factor = Divisor.getSExtValue(); | 
|  | Magics.Magic = 0; | 
|  | Magics.ShiftAmount = 0; | 
|  | ShiftMask = 0; | 
|  | } else if (Divisor.isStrictlyPositive() && Magics.Magic.isNegative()) { | 
|  | // If d > 0 and m < 0, add the numerator. | 
|  | Factor = 1; | 
|  | } else if (Divisor.isNegative() && Magics.Magic.isStrictlyPositive()) { | 
|  | // If d < 0 and m > 0, subtract the numerator. | 
|  | Factor = -1; | 
|  | } | 
|  |  | 
|  | // Multiply the numerator by the magic value. | 
|  | APInt Q = MULHS(Numerator, Magics.Magic); | 
|  |  | 
|  | // (Optionally) Add/subtract the numerator using Factor. | 
|  | Factor = Numerator * Factor; | 
|  | Q = Q + Factor; | 
|  |  | 
|  | // Shift right algebraic by shift value. | 
|  | Q = Q.ashr(Magics.ShiftAmount); | 
|  |  | 
|  | // Extract the sign bit, mask it and add it to the quotient. | 
|  | unsigned SignShift = Bits - 1; | 
|  | APInt T = Q.lshr(SignShift); | 
|  | T = T & ShiftMask; | 
|  | return Q + T; | 
|  | } | 
|  |  | 
|  | TEST(SignedDivisionByConstantTest, Test) { | 
|  | for (unsigned Bits = 1; Bits <= 32; ++Bits) { | 
|  | if (Bits < 3) | 
|  | continue; // Not supported by `SignedDivisionByConstantInfo::get()`. | 
|  | if (Bits > 12) | 
|  | continue; // Unreasonably slow. | 
|  | EnumerateAPInts(Bits, [Bits](const APInt &Divisor) { | 
|  | if (Divisor.isZero()) | 
|  | return; // Division by zero is undefined behavior. | 
|  | SignedDivisionByConstantInfo Magics; | 
|  | if (!(Divisor.isOne() || Divisor.isAllOnes())) | 
|  | Magics = SignedDivisionByConstantInfo::get(Divisor); | 
|  | EnumerateAPInts(Bits, [Divisor, Magics, Bits](const APInt &Numerator) { | 
|  | if (Numerator.isMinSignedValue() && Divisor.isAllOnes()) | 
|  | return; // Overflow is undefined behavior. | 
|  | APInt NativeResult = Numerator.sdiv(Divisor); | 
|  | APInt MagicResult = SignedDivideUsingMagic(Numerator, Divisor, Magics); | 
|  | ASSERT_EQ(MagicResult, NativeResult) | 
|  | << " ... given the operation:  srem i" << Bits << " " << Numerator | 
|  | << ", " << Divisor; | 
|  | }); | 
|  | }); | 
|  | } | 
|  | } | 
|  |  | 
|  | APInt MULHU(APInt X, APInt Y) { | 
|  | unsigned Bits = X.getBitWidth(); | 
|  | unsigned WideBits = 2 * Bits; | 
|  | return (X.zext(WideBits) * Y.zext(WideBits)).lshr(Bits).trunc(Bits); | 
|  | } | 
|  |  | 
|  | APInt UnsignedDivideUsingMagic(const APInt &Numerator, const APInt &Divisor, | 
|  | bool LZOptimization, | 
|  | bool AllowEvenDivisorOptimization, bool ForceNPQ, | 
|  | UnsignedDivisionByConstantInfo Magics) { | 
|  | assert(!Divisor.isOne() && "Division by 1 is not supported using Magic."); | 
|  |  | 
|  | unsigned Bits = Numerator.getBitWidth(); | 
|  |  | 
|  | if (LZOptimization) { | 
|  | unsigned LeadingZeros = Numerator.countl_zero(); | 
|  | // Clip to the number of leading zeros in the divisor. | 
|  | LeadingZeros = std::min(LeadingZeros, Divisor.countl_zero()); | 
|  | if (LeadingZeros > 0) { | 
|  | Magics = UnsignedDivisionByConstantInfo::get( | 
|  | Divisor, LeadingZeros, AllowEvenDivisorOptimization); | 
|  | assert(!Magics.IsAdd && "Should use cheap fixup now"); | 
|  | } | 
|  | } | 
|  |  | 
|  | assert(Magics.PreShift < Divisor.getBitWidth() && | 
|  | "We shouldn't generate an undefined shift!"); | 
|  | assert(Magics.PostShift < Divisor.getBitWidth() && | 
|  | "We shouldn't generate an undefined shift!"); | 
|  | assert((!Magics.IsAdd || Magics.PreShift == 0) && "Unexpected pre-shift"); | 
|  | unsigned PreShift = Magics.PreShift; | 
|  | unsigned PostShift = Magics.PostShift; | 
|  | bool UseNPQ = Magics.IsAdd; | 
|  |  | 
|  | APInt NPQFactor = | 
|  | UseNPQ ? APInt::getSignedMinValue(Bits) : APInt::getZero(Bits); | 
|  |  | 
|  | APInt Q = Numerator.lshr(PreShift); | 
|  |  | 
|  | // Multiply the numerator by the magic value. | 
|  | Q = MULHU(Q, Magics.Magic); | 
|  |  | 
|  | if (UseNPQ || ForceNPQ) { | 
|  | APInt NPQ = Numerator - Q; | 
|  |  | 
|  | // For vectors we might have a mix of non-NPQ/NPQ paths, so use | 
|  | // MULHU to act as a SRL-by-1 for NPQ, else multiply by zero. | 
|  | APInt NPQ_Scalar = NPQ.lshr(1); | 
|  | (void)NPQ_Scalar; | 
|  | NPQ = MULHU(NPQ, NPQFactor); | 
|  | assert(!UseNPQ || NPQ == NPQ_Scalar); | 
|  |  | 
|  | Q = NPQ + Q; | 
|  | } | 
|  |  | 
|  | Q = Q.lshr(PostShift); | 
|  |  | 
|  | return Q; | 
|  | } | 
|  |  | 
|  | TEST(UnsignedDivisionByConstantTest, Test) { | 
|  | for (unsigned Bits = 1; Bits <= 32; ++Bits) { | 
|  | if (Bits < 2) | 
|  | continue; // Not supported by `UnsignedDivisionByConstantInfo::get()`. | 
|  | if (Bits > 10) | 
|  | continue; // Unreasonably slow. | 
|  | EnumerateAPInts(Bits, [Bits](const APInt &Divisor) { | 
|  | if (Divisor.isZero()) | 
|  | return; // Division by zero is undefined behavior. | 
|  | if (Divisor.isOne()) | 
|  | return; // Division by one is the numerator. | 
|  |  | 
|  | const UnsignedDivisionByConstantInfo Magics = | 
|  | UnsignedDivisionByConstantInfo::get(Divisor); | 
|  | EnumerateAPInts(Bits, [Divisor, Magics, Bits](const APInt &Numerator) { | 
|  | APInt NativeResult = Numerator.udiv(Divisor); | 
|  | for (bool LZOptimization : {true, false}) { | 
|  | for (bool AllowEvenDivisorOptimization : {true, false}) { | 
|  | for (bool ForceNPQ : {false, true}) { | 
|  | APInt MagicResult = UnsignedDivideUsingMagic( | 
|  | Numerator, Divisor, LZOptimization, | 
|  | AllowEvenDivisorOptimization, ForceNPQ, Magics); | 
|  | ASSERT_EQ(MagicResult, NativeResult) | 
|  | << " ... given the operation:  urem i" << Bits << " " | 
|  | << Numerator << ", " << Divisor | 
|  | << " (allow LZ optimization = " | 
|  | << LZOptimization << ", allow even divisior optimization = " | 
|  | << AllowEvenDivisorOptimization << ", force NPQ = " | 
|  | << ForceNPQ << ")"; | 
|  | } | 
|  | } | 
|  | } | 
|  | }); | 
|  | }); | 
|  | } | 
|  | } | 
|  |  | 
|  | } // end anonymous namespace |