1 //===- llvm/unittest/Support/DivisionByConstantTest.cpp -------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "llvm/ADT/APInt.h"
10 #include "llvm/Support/DivisionByConstantInfo.h"
11 #include "gtest/gtest.h"
17 template <typename Fn
> static void EnumerateAPInts(unsigned Bits
, Fn TestFn
) {
24 APInt
MULHS(APInt X
, APInt Y
) {
25 unsigned Bits
= X
.getBitWidth();
26 unsigned WideBits
= 2 * Bits
;
27 return (X
.sext(WideBits
) * Y
.sext(WideBits
)).lshr(Bits
).trunc(Bits
);
30 APInt
SignedDivideUsingMagic(APInt Numerator
, APInt Divisor
,
31 SignedDivisionByConstantInfo Magics
) {
32 unsigned Bits
= Numerator
.getBitWidth();
34 APInt
Factor(Bits
, 0);
35 APInt
ShiftMask(Bits
, -1);
36 if (Divisor
.isOne() || Divisor
.isAllOnes()) {
37 // If d is +1/-1, we just multiply the numerator by +1/-1.
38 Factor
= Divisor
.getSExtValue();
40 Magics
.ShiftAmount
= 0;
42 } else if (Divisor
.isStrictlyPositive() && Magics
.Magic
.isNegative()) {
43 // If d > 0 and m < 0, add the numerator.
45 } else if (Divisor
.isNegative() && Magics
.Magic
.isStrictlyPositive()) {
46 // If d < 0 and m > 0, subtract the numerator.
50 // Multiply the numerator by the magic value.
51 APInt Q
= MULHS(Numerator
, Magics
.Magic
);
53 // (Optionally) Add/subtract the numerator using Factor.
54 Factor
= Numerator
* Factor
;
57 // Shift right algebraic by shift value.
58 Q
= Q
.ashr(Magics
.ShiftAmount
);
60 // Extract the sign bit, mask it and add it to the quotient.
61 unsigned SignShift
= Bits
- 1;
62 APInt T
= Q
.lshr(SignShift
);
67 TEST(SignedDivisionByConstantTest
, Test
) {
68 for (unsigned Bits
= 1; Bits
<= 32; ++Bits
) {
70 continue; // Not supported by `SignedDivisionByConstantInfo::get()`.
72 continue; // Unreasonably slow.
73 EnumerateAPInts(Bits
, [Bits
](const APInt
&Divisor
) {
75 return; // Division by zero is undefined behavior.
76 SignedDivisionByConstantInfo Magics
;
77 if (!(Divisor
.isOne() || Divisor
.isAllOnes()))
78 Magics
= SignedDivisionByConstantInfo::get(Divisor
);
79 EnumerateAPInts(Bits
, [Divisor
, Magics
, Bits
](const APInt
&Numerator
) {
80 if (Numerator
.isMinSignedValue() && Divisor
.isAllOnes())
81 return; // Overflow is undefined behavior.
82 APInt NativeResult
= Numerator
.sdiv(Divisor
);
83 APInt MagicResult
= SignedDivideUsingMagic(Numerator
, Divisor
, Magics
);
84 ASSERT_EQ(MagicResult
, NativeResult
)
85 << " ... given the operation: srem i" << Bits
<< " " << Numerator
92 APInt
MULHU(APInt X
, APInt Y
) {
93 unsigned Bits
= X
.getBitWidth();
94 unsigned WideBits
= 2 * Bits
;
95 return (X
.zext(WideBits
) * Y
.zext(WideBits
)).lshr(Bits
).trunc(Bits
);
98 APInt
UnsignedDivideUsingMagic(const APInt
&Numerator
, const APInt
&Divisor
,
100 bool AllowEvenDivisorOptimization
, bool ForceNPQ
,
101 UnsignedDivisionByConstantInfo Magics
) {
102 assert(!Divisor
.isOne() && "Division by 1 is not supported using Magic.");
104 unsigned Bits
= Numerator
.getBitWidth();
106 if (LZOptimization
) {
107 unsigned LeadingZeros
= Numerator
.countl_zero();
108 // Clip to the number of leading zeros in the divisor.
109 LeadingZeros
= std::min(LeadingZeros
, Divisor
.countl_zero());
110 if (LeadingZeros
> 0) {
111 Magics
= UnsignedDivisionByConstantInfo::get(
112 Divisor
, LeadingZeros
, AllowEvenDivisorOptimization
);
113 assert(!Magics
.IsAdd
&& "Should use cheap fixup now");
117 assert(Magics
.PreShift
< Divisor
.getBitWidth() &&
118 "We shouldn't generate an undefined shift!");
119 assert(Magics
.PostShift
< Divisor
.getBitWidth() &&
120 "We shouldn't generate an undefined shift!");
121 assert((!Magics
.IsAdd
|| Magics
.PreShift
== 0) && "Unexpected pre-shift");
122 unsigned PreShift
= Magics
.PreShift
;
123 unsigned PostShift
= Magics
.PostShift
;
124 bool UseNPQ
= Magics
.IsAdd
;
127 UseNPQ
? APInt::getSignedMinValue(Bits
) : APInt::getZero(Bits
);
129 APInt Q
= Numerator
.lshr(PreShift
);
131 // Multiply the numerator by the magic value.
132 Q
= MULHU(Q
, Magics
.Magic
);
134 if (UseNPQ
|| ForceNPQ
) {
135 APInt NPQ
= Numerator
- Q
;
137 // For vectors we might have a mix of non-NPQ/NPQ paths, so use
138 // MULHU to act as a SRL-by-1 for NPQ, else multiply by zero.
139 APInt NPQ_Scalar
= NPQ
.lshr(1);
141 NPQ
= MULHU(NPQ
, NPQFactor
);
142 assert(!UseNPQ
|| NPQ
== NPQ_Scalar
);
147 Q
= Q
.lshr(PostShift
);
152 TEST(UnsignedDivisionByConstantTest
, Test
) {
153 for (unsigned Bits
= 1; Bits
<= 32; ++Bits
) {
155 continue; // Not supported by `UnsignedDivisionByConstantInfo::get()`.
157 continue; // Unreasonably slow.
158 EnumerateAPInts(Bits
, [Bits
](const APInt
&Divisor
) {
159 if (Divisor
.isZero())
160 return; // Division by zero is undefined behavior.
162 return; // Division by one is the numerator.
164 const UnsignedDivisionByConstantInfo Magics
=
165 UnsignedDivisionByConstantInfo::get(Divisor
);
166 EnumerateAPInts(Bits
, [Divisor
, Magics
, Bits
](const APInt
&Numerator
) {
167 APInt NativeResult
= Numerator
.udiv(Divisor
);
168 for (bool LZOptimization
: {true, false}) {
169 for (bool AllowEvenDivisorOptimization
: {true, false}) {
170 for (bool ForceNPQ
: {false, true}) {
171 APInt MagicResult
= UnsignedDivideUsingMagic(
172 Numerator
, Divisor
, LZOptimization
,
173 AllowEvenDivisorOptimization
, ForceNPQ
, Magics
);
174 ASSERT_EQ(MagicResult
, NativeResult
)
175 << " ... given the operation: urem i" << Bits
<< " "
176 << Numerator
<< ", " << Divisor
177 << " (allow LZ optimization = "
178 << LZOptimization
<< ", allow even divisior optimization = "
179 << AllowEvenDivisorOptimization
<< ", force NPQ = "
189 } // end anonymous namespace