1 | //===----- DivisionByConstantInfo.cpp - division by constant -*- C++ -*----===// |
2 | // |
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 |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | /// |
9 | /// This file implements support for optimizing divisions by a constant |
10 | /// |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "llvm/Support/DivisionByConstantInfo.h" |
14 | |
15 | using namespace llvm; |
16 | |
17 | /// Calculate the magic numbers required to implement a signed integer division |
18 | /// by a constant as a sequence of multiplies, adds and shifts. Requires that |
19 | /// the divisor not be 0, 1, or -1. Taken from "Hacker's Delight", Henry S. |
20 | /// Warren, Jr., Chapter 10. |
21 | SignedDivisionByConstantInfo SignedDivisionByConstantInfo::get(const APInt &D) { |
22 | assert(!D.isZero() && "Precondition violation." ); |
23 | |
24 | // We'd be endlessly stuck in the loop. |
25 | assert(D.getBitWidth() >= 3 && "Does not work at smaller bitwidths." ); |
26 | |
27 | APInt Delta; |
28 | APInt SignedMin = APInt::getSignedMinValue(numBits: D.getBitWidth()); |
29 | struct SignedDivisionByConstantInfo Retval; |
30 | |
31 | APInt AD = D.abs(); |
32 | APInt T = SignedMin + (D.lshr(shiftAmt: D.getBitWidth() - 1)); |
33 | APInt ANC = T - 1 - T.urem(RHS: AD); // absolute value of NC |
34 | unsigned P = D.getBitWidth() - 1; // initialize P |
35 | APInt Q1, R1, Q2, R2; |
36 | // initialize Q1 = 2P/abs(NC); R1 = rem(2P,abs(NC)) |
37 | APInt::udivrem(LHS: SignedMin, RHS: ANC, Quotient&: Q1, Remainder&: R1); |
38 | // initialize Q2 = 2P/abs(D); R2 = rem(2P,abs(D)) |
39 | APInt::udivrem(LHS: SignedMin, RHS: AD, Quotient&: Q2, Remainder&: R2); |
40 | do { |
41 | P = P + 1; |
42 | Q1 <<= 1; // update Q1 = 2P/abs(NC) |
43 | R1 <<= 1; // update R1 = rem(2P/abs(NC)) |
44 | if (R1.uge(RHS: ANC)) { // must be unsigned comparison |
45 | ++Q1; |
46 | R1 -= ANC; |
47 | } |
48 | Q2 <<= 1; // update Q2 = 2P/abs(D) |
49 | R2 <<= 1; // update R2 = rem(2P/abs(D)) |
50 | if (R2.uge(RHS: AD)) { // must be unsigned comparison |
51 | ++Q2; |
52 | R2 -= AD; |
53 | } |
54 | // Delta = AD - R2 |
55 | Delta = AD; |
56 | Delta -= R2; |
57 | } while (Q1.ult(RHS: Delta) || (Q1 == Delta && R1.isZero())); |
58 | |
59 | Retval.Magic = std::move(Q2); |
60 | ++Retval.Magic; |
61 | if (D.isNegative()) |
62 | Retval.Magic.negate(); // resulting magic number |
63 | Retval.ShiftAmount = P - D.getBitWidth(); // resulting shift |
64 | return Retval; |
65 | } |
66 | |
67 | /// Calculate the magic numbers required to implement an unsigned integer |
68 | /// division by a constant as a sequence of multiplies, adds and shifts. |
69 | /// Requires that the divisor not be 0. Taken from "Hacker's Delight", Henry |
70 | /// S. Warren, Jr., chapter 10. |
71 | /// LeadingZeros can be used to simplify the calculation if the upper bits |
72 | /// of the divided value are known zero. |
73 | UnsignedDivisionByConstantInfo |
74 | UnsignedDivisionByConstantInfo::get(const APInt &D, unsigned LeadingZeros, |
75 | bool AllowEvenDivisorOptimization) { |
76 | assert(!D.isZero() && !D.isOne() && "Precondition violation." ); |
77 | assert(D.getBitWidth() > 1 && "Does not work at smaller bitwidths." ); |
78 | |
79 | APInt Delta; |
80 | struct UnsignedDivisionByConstantInfo Retval; |
81 | Retval.IsAdd = false; // initialize "add" indicator |
82 | APInt AllOnes = |
83 | APInt::getLowBitsSet(numBits: D.getBitWidth(), loBitsSet: D.getBitWidth() - LeadingZeros); |
84 | APInt SignedMin = APInt::getSignedMinValue(numBits: D.getBitWidth()); |
85 | APInt SignedMax = APInt::getSignedMaxValue(numBits: D.getBitWidth()); |
86 | |
87 | // Calculate NC, the largest dividend such that NC.urem(D) == D-1. |
88 | APInt NC = AllOnes - (AllOnes + 1 - D).urem(RHS: D); |
89 | assert(NC.urem(D) == D - 1 && "Unexpected NC value" ); |
90 | unsigned P = D.getBitWidth() - 1; // initialize P |
91 | APInt Q1, R1, Q2, R2; |
92 | // initialize Q1 = 2P/NC; R1 = rem(2P,NC) |
93 | APInt::udivrem(LHS: SignedMin, RHS: NC, Quotient&: Q1, Remainder&: R1); |
94 | // initialize Q2 = (2P-1)/D; R2 = rem((2P-1),D) |
95 | APInt::udivrem(LHS: SignedMax, RHS: D, Quotient&: Q2, Remainder&: R2); |
96 | do { |
97 | P = P + 1; |
98 | if (R1.uge(RHS: NC - R1)) { |
99 | // update Q1 |
100 | Q1 <<= 1; |
101 | ++Q1; |
102 | // update R1 |
103 | R1 <<= 1; |
104 | R1 -= NC; |
105 | } else { |
106 | Q1 <<= 1; // update Q1 |
107 | R1 <<= 1; // update R1 |
108 | } |
109 | if ((R2 + 1).uge(RHS: D - R2)) { |
110 | if (Q2.uge(RHS: SignedMax)) |
111 | Retval.IsAdd = true; |
112 | // update Q2 |
113 | Q2 <<= 1; |
114 | ++Q2; |
115 | // update R2 |
116 | R2 <<= 1; |
117 | ++R2; |
118 | R2 -= D; |
119 | } else { |
120 | if (Q2.uge(RHS: SignedMin)) |
121 | Retval.IsAdd = true; |
122 | // update Q2 |
123 | Q2 <<= 1; |
124 | // update R2 |
125 | R2 <<= 1; |
126 | ++R2; |
127 | } |
128 | // Delta = D - 1 - R2 |
129 | Delta = D; |
130 | --Delta; |
131 | Delta -= R2; |
132 | } while (P < D.getBitWidth() * 2 && |
133 | (Q1.ult(RHS: Delta) || (Q1 == Delta && R1.isZero()))); |
134 | |
135 | if (Retval.IsAdd && !D[0] && AllowEvenDivisorOptimization) { |
136 | unsigned PreShift = D.countr_zero(); |
137 | APInt ShiftedD = D.lshr(shiftAmt: PreShift); |
138 | Retval = |
139 | UnsignedDivisionByConstantInfo::get(D: ShiftedD, LeadingZeros: LeadingZeros + PreShift); |
140 | assert(Retval.IsAdd == 0 && Retval.PreShift == 0); |
141 | Retval.PreShift = PreShift; |
142 | return Retval; |
143 | } |
144 | |
145 | Retval.Magic = std::move(Q2); // resulting magic number |
146 | ++Retval.Magic; |
147 | Retval.PostShift = P - D.getBitWidth(); // resulting shift |
148 | // Reduce shift amount for IsAdd. |
149 | if (Retval.IsAdd) { |
150 | assert(Retval.PostShift > 0 && "Unexpected shift" ); |
151 | Retval.PostShift -= 1; |
152 | } |
153 | Retval.PreShift = 0; |
154 | return Retval; |
155 | } |
156 | |