xref: /llvm-project/llvm/lib/Support/DivisionByConstantInfo.cpp (revision 13ed3b472b6209ef6f7c5b0ee1eb91e563e01cbc)
1a55ff6aaSCraig Topper //===----- DivisionByConstantInfo.cpp - division by constant -*- C++ -*----===//
23077bc90SChristopher Tetreault //
33077bc90SChristopher Tetreault // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43077bc90SChristopher Tetreault // See https://llvm.org/LICENSE.txt for license information.
53077bc90SChristopher Tetreault // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63077bc90SChristopher Tetreault //
73077bc90SChristopher Tetreault //===----------------------------------------------------------------------===//
83077bc90SChristopher Tetreault ///
93077bc90SChristopher Tetreault /// This file implements support for optimizing divisions by a constant
103077bc90SChristopher Tetreault ///
113077bc90SChristopher Tetreault //===----------------------------------------------------------------------===//
123077bc90SChristopher Tetreault 
133077bc90SChristopher Tetreault #include "llvm/Support/DivisionByConstantInfo.h"
143077bc90SChristopher Tetreault 
153077bc90SChristopher Tetreault using namespace llvm;
163077bc90SChristopher Tetreault 
173077bc90SChristopher Tetreault /// Calculate the magic numbers required to implement a signed integer division
183077bc90SChristopher Tetreault /// by a constant as a sequence of multiplies, adds and shifts.  Requires that
193077bc90SChristopher Tetreault /// the divisor not be 0, 1, or -1.  Taken from "Hacker's Delight", Henry S.
203077bc90SChristopher Tetreault /// Warren, Jr., Chapter 10.
get(const APInt & D)213077bc90SChristopher Tetreault SignedDivisionByConstantInfo SignedDivisionByConstantInfo::get(const APInt &D) {
22066b492bSRoman Lebedev   assert(!D.isZero() && "Precondition violation.");
23066b492bSRoman Lebedev 
24066b492bSRoman Lebedev   // We'd be endlessly stuck in the loop.
25066b492bSRoman Lebedev   assert(D.getBitWidth() >= 3 && "Does not work at smaller bitwidths.");
26066b492bSRoman Lebedev 
271a6310bfSCraig Topper   APInt Delta;
283077bc90SChristopher Tetreault   APInt SignedMin = APInt::getSignedMinValue(D.getBitWidth());
293077bc90SChristopher Tetreault   struct SignedDivisionByConstantInfo Retval;
303077bc90SChristopher Tetreault 
311a6310bfSCraig Topper   APInt AD = D.abs();
321a6310bfSCraig Topper   APInt T = SignedMin + (D.lshr(D.getBitWidth() - 1));
331a6310bfSCraig Topper   APInt ANC = T - 1 - T.urem(AD);   // absolute value of NC
341a6310bfSCraig Topper   unsigned P = D.getBitWidth() - 1; // initialize P
35e3774304SCraig Topper   APInt Q1, R1, Q2, R2;
36e3774304SCraig Topper   // initialize Q1 = 2P/abs(NC); R1 = rem(2P,abs(NC))
37e3774304SCraig Topper   APInt::udivrem(SignedMin, ANC, Q1, R1);
38e3774304SCraig Topper   // initialize Q2 = 2P/abs(D); R2 = rem(2P,abs(D))
39e3774304SCraig Topper   APInt::udivrem(SignedMin, AD, Q2, R2);
403077bc90SChristopher Tetreault   do {
413077bc90SChristopher Tetreault     P = P + 1;
421cc48a76SCraig Topper     Q1 <<= 1;      // update Q1 = 2P/abs(NC)
431cc48a76SCraig Topper     R1 <<= 1;      // update R1 = rem(2P/abs(NC))
443077bc90SChristopher Tetreault     if (R1.uge(ANC)) { // must be unsigned comparison
451cc48a76SCraig Topper       ++Q1;
461cc48a76SCraig Topper       R1 -= ANC;
473077bc90SChristopher Tetreault     }
481cc48a76SCraig Topper     Q2 <<= 1;     // update Q2 = 2P/abs(D)
491cc48a76SCraig Topper     R2 <<= 1;     // update R2 = rem(2P/abs(D))
503077bc90SChristopher Tetreault     if (R2.uge(AD)) { // must be unsigned comparison
511cc48a76SCraig Topper       ++Q2;
521cc48a76SCraig Topper       R2 -= AD;
533077bc90SChristopher Tetreault     }
541cc48a76SCraig Topper     // Delta = AD - R2
551cc48a76SCraig Topper     Delta = AD;
561cc48a76SCraig Topper     Delta -= R2;
571cc48a76SCraig Topper   } while (Q1.ult(Delta) || (Q1 == Delta && R1.isZero()));
583077bc90SChristopher Tetreault 
591cc48a76SCraig Topper   Retval.Magic = std::move(Q2);
601cc48a76SCraig Topper   ++Retval.Magic;
613077bc90SChristopher Tetreault   if (D.isNegative())
621cc48a76SCraig Topper     Retval.Magic.negate();                  // resulting magic number
633077bc90SChristopher Tetreault   Retval.ShiftAmount = P - D.getBitWidth(); // resulting shift
643077bc90SChristopher Tetreault   return Retval;
653077bc90SChristopher Tetreault }
663077bc90SChristopher Tetreault 
673077bc90SChristopher Tetreault /// Calculate the magic numbers required to implement an unsigned integer
683077bc90SChristopher Tetreault /// division by a constant as a sequence of multiplies, adds and shifts.
693077bc90SChristopher Tetreault /// Requires that the divisor not be 0.  Taken from "Hacker's Delight", Henry
703077bc90SChristopher Tetreault /// S. Warren, Jr., chapter 10.
713077bc90SChristopher Tetreault /// LeadingZeros can be used to simplify the calculation if the upper bits
723077bc90SChristopher Tetreault /// of the divided value are known zero.
73a55ff6aaSCraig Topper UnsignedDivisionByConstantInfo
get(const APInt & D,unsigned LeadingZeros,bool AllowEvenDivisorOptimization)7484daed7fSCraig Topper UnsignedDivisionByConstantInfo::get(const APInt &D, unsigned LeadingZeros,
7584daed7fSCraig Topper                                     bool AllowEvenDivisorOptimization) {
768bca60fbSCraig Topper   assert(!D.isZero() && !D.isOne() && "Precondition violation.");
77066b492bSRoman Lebedev   assert(D.getBitWidth() > 1 && "Does not work at smaller bitwidths.");
78066b492bSRoman Lebedev 
791a6310bfSCraig Topper   APInt Delta;
80a55ff6aaSCraig Topper   struct UnsignedDivisionByConstantInfo Retval;
812aed0813SKazu Hirata   Retval.IsAdd = false; // initialize "add" indicator
82*13ed3b47SCraig Topper   APInt AllOnes =
83*13ed3b47SCraig Topper       APInt::getLowBitsSet(D.getBitWidth(), D.getBitWidth() - LeadingZeros);
843077bc90SChristopher Tetreault   APInt SignedMin = APInt::getSignedMinValue(D.getBitWidth());
853077bc90SChristopher Tetreault   APInt SignedMax = APInt::getSignedMaxValue(D.getBitWidth());
863077bc90SChristopher Tetreault 
871490796dSCraig Topper   // Calculate NC, the largest dividend such that NC.urem(D) == D-1.
881490796dSCraig Topper   APInt NC = AllOnes - (AllOnes + 1 - D).urem(D);
891490796dSCraig Topper   assert(NC.urem(D) == D - 1 && "Unexpected NC value");
901a6310bfSCraig Topper   unsigned P = D.getBitWidth() - 1; // initialize P
91e3774304SCraig Topper   APInt Q1, R1, Q2, R2;
92e3774304SCraig Topper   // initialize Q1 = 2P/NC; R1 = rem(2P,NC)
93e3774304SCraig Topper   APInt::udivrem(SignedMin, NC, Q1, R1);
94e3774304SCraig Topper   // initialize Q2 = (2P-1)/D; R2 = rem((2P-1),D)
95e3774304SCraig Topper   APInt::udivrem(SignedMax, D, Q2, R2);
963077bc90SChristopher Tetreault   do {
973077bc90SChristopher Tetreault     P = P + 1;
983077bc90SChristopher Tetreault     if (R1.uge(NC - R1)) {
991cc48a76SCraig Topper       // update Q1
1001cc48a76SCraig Topper       Q1 <<= 1;
1011cc48a76SCraig Topper       ++Q1;
1021cc48a76SCraig Topper       // update R1
1031cc48a76SCraig Topper       R1 <<= 1;
1041cc48a76SCraig Topper       R1 -= NC;
1053077bc90SChristopher Tetreault     } else {
1061cc48a76SCraig Topper       Q1 <<= 1; // update Q1
1071cc48a76SCraig Topper       R1 <<= 1; // update R1
1083077bc90SChristopher Tetreault     }
1093077bc90SChristopher Tetreault     if ((R2 + 1).uge(D - R2)) {
1103077bc90SChristopher Tetreault       if (Q2.uge(SignedMax))
1112aed0813SKazu Hirata         Retval.IsAdd = true;
1121cc48a76SCraig Topper       // update Q2
1131cc48a76SCraig Topper       Q2 <<= 1;
1141cc48a76SCraig Topper       ++Q2;
1151cc48a76SCraig Topper       // update R2
1161cc48a76SCraig Topper       R2 <<= 1;
1171cc48a76SCraig Topper       ++R2;
1181cc48a76SCraig Topper       R2 -= D;
1193077bc90SChristopher Tetreault     } else {
1203077bc90SChristopher Tetreault       if (Q2.uge(SignedMin))
1212aed0813SKazu Hirata         Retval.IsAdd = true;
1221cc48a76SCraig Topper       // update Q2
1231cc48a76SCraig Topper       Q2 <<= 1;
1241cc48a76SCraig Topper       // update R2
1251cc48a76SCraig Topper       R2 <<= 1;
1261cc48a76SCraig Topper       ++R2;
1273077bc90SChristopher Tetreault     }
1281cc48a76SCraig Topper     // Delta = D - 1 - R2
1291cc48a76SCraig Topper     Delta = D;
1301cc48a76SCraig Topper     --Delta;
1311cc48a76SCraig Topper     Delta -= R2;
1323077bc90SChristopher Tetreault   } while (P < D.getBitWidth() * 2 &&
1331cc48a76SCraig Topper            (Q1.ult(Delta) || (Q1 == Delta && R1.isZero())));
13484daed7fSCraig Topper 
13584daed7fSCraig Topper   if (Retval.IsAdd && !D[0] && AllowEvenDivisorOptimization) {
136f8f3db27SKazu Hirata     unsigned PreShift = D.countr_zero();
13784daed7fSCraig Topper     APInt ShiftedD = D.lshr(PreShift);
13884daed7fSCraig Topper     Retval =
13984daed7fSCraig Topper         UnsignedDivisionByConstantInfo::get(ShiftedD, LeadingZeros + PreShift);
14084daed7fSCraig Topper     assert(Retval.IsAdd == 0 && Retval.PreShift == 0);
14184daed7fSCraig Topper     Retval.PreShift = PreShift;
14284daed7fSCraig Topper     return Retval;
14384daed7fSCraig Topper   }
14484daed7fSCraig Topper 
1451cc48a76SCraig Topper   Retval.Magic = std::move(Q2);             // resulting magic number
1461cc48a76SCraig Topper   ++Retval.Magic;
1473f749a5dSCraig Topper   Retval.PostShift = P - D.getBitWidth(); // resulting shift
1483f749a5dSCraig Topper   // Reduce shift amount for IsAdd.
1493f749a5dSCraig Topper   if (Retval.IsAdd) {
1503f749a5dSCraig Topper     assert(Retval.PostShift > 0 && "Unexpected shift");
1513f749a5dSCraig Topper     Retval.PostShift -= 1;
1523f749a5dSCraig Topper   }
15384daed7fSCraig Topper   Retval.PreShift = 0;
1543077bc90SChristopher Tetreault   return Retval;
1553077bc90SChristopher Tetreault }
156