1*0fca6ea1SDimitry Andric //===- SlowDynamicAPInt.cpp - SlowDynamicAPInt Implementation -------------===// 2*0fca6ea1SDimitry Andric // 3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0fca6ea1SDimitry Andric // 7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 8*0fca6ea1SDimitry Andric 9*0fca6ea1SDimitry Andric #include "llvm/ADT/SlowDynamicAPInt.h" 10*0fca6ea1SDimitry Andric #include "llvm/ADT/Hashing.h" 11*0fca6ea1SDimitry Andric #include "llvm/Support/Debug.h" 12*0fca6ea1SDimitry Andric #include "llvm/Support/raw_ostream.h" 13*0fca6ea1SDimitry Andric 14*0fca6ea1SDimitry Andric using namespace llvm; 15*0fca6ea1SDimitry Andric using namespace detail; 16*0fca6ea1SDimitry Andric 17*0fca6ea1SDimitry Andric SlowDynamicAPInt::SlowDynamicAPInt(int64_t Val) 18*0fca6ea1SDimitry Andric : Val(64, Val, /*isSigned=*/true) {} 19*0fca6ea1SDimitry Andric SlowDynamicAPInt::SlowDynamicAPInt() : SlowDynamicAPInt(0) {} 20*0fca6ea1SDimitry Andric SlowDynamicAPInt::SlowDynamicAPInt(const APInt &Val) : Val(Val) {} 21*0fca6ea1SDimitry Andric SlowDynamicAPInt &SlowDynamicAPInt::operator=(int64_t Val) { 22*0fca6ea1SDimitry Andric return *this = SlowDynamicAPInt(Val); 23*0fca6ea1SDimitry Andric } 24*0fca6ea1SDimitry Andric SlowDynamicAPInt::operator int64_t() const { return Val.getSExtValue(); } 25*0fca6ea1SDimitry Andric 26*0fca6ea1SDimitry Andric hash_code detail::hash_value(const SlowDynamicAPInt &X) { 27*0fca6ea1SDimitry Andric return hash_value(X.Val); 28*0fca6ea1SDimitry Andric } 29*0fca6ea1SDimitry Andric 30*0fca6ea1SDimitry Andric /// --------------------------------------------------------------------------- 31*0fca6ea1SDimitry Andric /// Convenience operator overloads for int64_t. 32*0fca6ea1SDimitry Andric /// --------------------------------------------------------------------------- 33*0fca6ea1SDimitry Andric SlowDynamicAPInt &detail::operator+=(SlowDynamicAPInt &A, int64_t B) { 34*0fca6ea1SDimitry Andric return A += SlowDynamicAPInt(B); 35*0fca6ea1SDimitry Andric } 36*0fca6ea1SDimitry Andric SlowDynamicAPInt &detail::operator-=(SlowDynamicAPInt &A, int64_t B) { 37*0fca6ea1SDimitry Andric return A -= SlowDynamicAPInt(B); 38*0fca6ea1SDimitry Andric } 39*0fca6ea1SDimitry Andric SlowDynamicAPInt &detail::operator*=(SlowDynamicAPInt &A, int64_t B) { 40*0fca6ea1SDimitry Andric return A *= SlowDynamicAPInt(B); 41*0fca6ea1SDimitry Andric } 42*0fca6ea1SDimitry Andric SlowDynamicAPInt &detail::operator/=(SlowDynamicAPInt &A, int64_t B) { 43*0fca6ea1SDimitry Andric return A /= SlowDynamicAPInt(B); 44*0fca6ea1SDimitry Andric } 45*0fca6ea1SDimitry Andric SlowDynamicAPInt &detail::operator%=(SlowDynamicAPInt &A, int64_t B) { 46*0fca6ea1SDimitry Andric return A %= SlowDynamicAPInt(B); 47*0fca6ea1SDimitry Andric } 48*0fca6ea1SDimitry Andric 49*0fca6ea1SDimitry Andric bool detail::operator==(const SlowDynamicAPInt &A, int64_t B) { 50*0fca6ea1SDimitry Andric return A == SlowDynamicAPInt(B); 51*0fca6ea1SDimitry Andric } 52*0fca6ea1SDimitry Andric bool detail::operator!=(const SlowDynamicAPInt &A, int64_t B) { 53*0fca6ea1SDimitry Andric return A != SlowDynamicAPInt(B); 54*0fca6ea1SDimitry Andric } 55*0fca6ea1SDimitry Andric bool detail::operator>(const SlowDynamicAPInt &A, int64_t B) { 56*0fca6ea1SDimitry Andric return A > SlowDynamicAPInt(B); 57*0fca6ea1SDimitry Andric } 58*0fca6ea1SDimitry Andric bool detail::operator<(const SlowDynamicAPInt &A, int64_t B) { 59*0fca6ea1SDimitry Andric return A < SlowDynamicAPInt(B); 60*0fca6ea1SDimitry Andric } 61*0fca6ea1SDimitry Andric bool detail::operator<=(const SlowDynamicAPInt &A, int64_t B) { 62*0fca6ea1SDimitry Andric return A <= SlowDynamicAPInt(B); 63*0fca6ea1SDimitry Andric } 64*0fca6ea1SDimitry Andric bool detail::operator>=(const SlowDynamicAPInt &A, int64_t B) { 65*0fca6ea1SDimitry Andric return A >= SlowDynamicAPInt(B); 66*0fca6ea1SDimitry Andric } 67*0fca6ea1SDimitry Andric SlowDynamicAPInt detail::operator+(const SlowDynamicAPInt &A, int64_t B) { 68*0fca6ea1SDimitry Andric return A + SlowDynamicAPInt(B); 69*0fca6ea1SDimitry Andric } 70*0fca6ea1SDimitry Andric SlowDynamicAPInt detail::operator-(const SlowDynamicAPInt &A, int64_t B) { 71*0fca6ea1SDimitry Andric return A - SlowDynamicAPInt(B); 72*0fca6ea1SDimitry Andric } 73*0fca6ea1SDimitry Andric SlowDynamicAPInt detail::operator*(const SlowDynamicAPInt &A, int64_t B) { 74*0fca6ea1SDimitry Andric return A * SlowDynamicAPInt(B); 75*0fca6ea1SDimitry Andric } 76*0fca6ea1SDimitry Andric SlowDynamicAPInt detail::operator/(const SlowDynamicAPInt &A, int64_t B) { 77*0fca6ea1SDimitry Andric return A / SlowDynamicAPInt(B); 78*0fca6ea1SDimitry Andric } 79*0fca6ea1SDimitry Andric SlowDynamicAPInt detail::operator%(const SlowDynamicAPInt &A, int64_t B) { 80*0fca6ea1SDimitry Andric return A % SlowDynamicAPInt(B); 81*0fca6ea1SDimitry Andric } 82*0fca6ea1SDimitry Andric 83*0fca6ea1SDimitry Andric bool detail::operator==(int64_t A, const SlowDynamicAPInt &B) { 84*0fca6ea1SDimitry Andric return SlowDynamicAPInt(A) == B; 85*0fca6ea1SDimitry Andric } 86*0fca6ea1SDimitry Andric bool detail::operator!=(int64_t A, const SlowDynamicAPInt &B) { 87*0fca6ea1SDimitry Andric return SlowDynamicAPInt(A) != B; 88*0fca6ea1SDimitry Andric } 89*0fca6ea1SDimitry Andric bool detail::operator>(int64_t A, const SlowDynamicAPInt &B) { 90*0fca6ea1SDimitry Andric return SlowDynamicAPInt(A) > B; 91*0fca6ea1SDimitry Andric } 92*0fca6ea1SDimitry Andric bool detail::operator<(int64_t A, const SlowDynamicAPInt &B) { 93*0fca6ea1SDimitry Andric return SlowDynamicAPInt(A) < B; 94*0fca6ea1SDimitry Andric } 95*0fca6ea1SDimitry Andric bool detail::operator<=(int64_t A, const SlowDynamicAPInt &B) { 96*0fca6ea1SDimitry Andric return SlowDynamicAPInt(A) <= B; 97*0fca6ea1SDimitry Andric } 98*0fca6ea1SDimitry Andric bool detail::operator>=(int64_t A, const SlowDynamicAPInt &B) { 99*0fca6ea1SDimitry Andric return SlowDynamicAPInt(A) >= B; 100*0fca6ea1SDimitry Andric } 101*0fca6ea1SDimitry Andric SlowDynamicAPInt detail::operator+(int64_t A, const SlowDynamicAPInt &B) { 102*0fca6ea1SDimitry Andric return SlowDynamicAPInt(A) + B; 103*0fca6ea1SDimitry Andric } 104*0fca6ea1SDimitry Andric SlowDynamicAPInt detail::operator-(int64_t A, const SlowDynamicAPInt &B) { 105*0fca6ea1SDimitry Andric return SlowDynamicAPInt(A) - B; 106*0fca6ea1SDimitry Andric } 107*0fca6ea1SDimitry Andric SlowDynamicAPInt detail::operator*(int64_t A, const SlowDynamicAPInt &B) { 108*0fca6ea1SDimitry Andric return SlowDynamicAPInt(A) * B; 109*0fca6ea1SDimitry Andric } 110*0fca6ea1SDimitry Andric SlowDynamicAPInt detail::operator/(int64_t A, const SlowDynamicAPInt &B) { 111*0fca6ea1SDimitry Andric return SlowDynamicAPInt(A) / B; 112*0fca6ea1SDimitry Andric } 113*0fca6ea1SDimitry Andric SlowDynamicAPInt detail::operator%(int64_t A, const SlowDynamicAPInt &B) { 114*0fca6ea1SDimitry Andric return SlowDynamicAPInt(A) % B; 115*0fca6ea1SDimitry Andric } 116*0fca6ea1SDimitry Andric 117*0fca6ea1SDimitry Andric static unsigned getMaxWidth(const APInt &A, const APInt &B) { 118*0fca6ea1SDimitry Andric return std::max(A.getBitWidth(), B.getBitWidth()); 119*0fca6ea1SDimitry Andric } 120*0fca6ea1SDimitry Andric 121*0fca6ea1SDimitry Andric /// --------------------------------------------------------------------------- 122*0fca6ea1SDimitry Andric /// Comparison operators. 123*0fca6ea1SDimitry Andric /// --------------------------------------------------------------------------- 124*0fca6ea1SDimitry Andric 125*0fca6ea1SDimitry Andric // TODO: consider instead making APInt::compare available and using that. 126*0fca6ea1SDimitry Andric bool SlowDynamicAPInt::operator==(const SlowDynamicAPInt &O) const { 127*0fca6ea1SDimitry Andric unsigned Width = getMaxWidth(Val, O.Val); 128*0fca6ea1SDimitry Andric return Val.sext(Width) == O.Val.sext(Width); 129*0fca6ea1SDimitry Andric } 130*0fca6ea1SDimitry Andric bool SlowDynamicAPInt::operator!=(const SlowDynamicAPInt &O) const { 131*0fca6ea1SDimitry Andric unsigned Width = getMaxWidth(Val, O.Val); 132*0fca6ea1SDimitry Andric return Val.sext(Width) != O.Val.sext(Width); 133*0fca6ea1SDimitry Andric } 134*0fca6ea1SDimitry Andric bool SlowDynamicAPInt::operator>(const SlowDynamicAPInt &O) const { 135*0fca6ea1SDimitry Andric unsigned Width = getMaxWidth(Val, O.Val); 136*0fca6ea1SDimitry Andric return Val.sext(Width).sgt(O.Val.sext(Width)); 137*0fca6ea1SDimitry Andric } 138*0fca6ea1SDimitry Andric bool SlowDynamicAPInt::operator<(const SlowDynamicAPInt &O) const { 139*0fca6ea1SDimitry Andric unsigned Width = getMaxWidth(Val, O.Val); 140*0fca6ea1SDimitry Andric return Val.sext(Width).slt(O.Val.sext(Width)); 141*0fca6ea1SDimitry Andric } 142*0fca6ea1SDimitry Andric bool SlowDynamicAPInt::operator<=(const SlowDynamicAPInt &O) const { 143*0fca6ea1SDimitry Andric unsigned Width = getMaxWidth(Val, O.Val); 144*0fca6ea1SDimitry Andric return Val.sext(Width).sle(O.Val.sext(Width)); 145*0fca6ea1SDimitry Andric } 146*0fca6ea1SDimitry Andric bool SlowDynamicAPInt::operator>=(const SlowDynamicAPInt &O) const { 147*0fca6ea1SDimitry Andric unsigned Width = getMaxWidth(Val, O.Val); 148*0fca6ea1SDimitry Andric return Val.sext(Width).sge(O.Val.sext(Width)); 149*0fca6ea1SDimitry Andric } 150*0fca6ea1SDimitry Andric 151*0fca6ea1SDimitry Andric /// --------------------------------------------------------------------------- 152*0fca6ea1SDimitry Andric /// Arithmetic operators. 153*0fca6ea1SDimitry Andric /// --------------------------------------------------------------------------- 154*0fca6ea1SDimitry Andric 155*0fca6ea1SDimitry Andric /// Bring a and b to have the same width and then call op(a, b, overflow). 156*0fca6ea1SDimitry Andric /// If the overflow bit becomes set, resize a and b to double the width and 157*0fca6ea1SDimitry Andric /// call op(a, b, overflow), returning its result. The operation with double 158*0fca6ea1SDimitry Andric /// widths should not also overflow. 159*0fca6ea1SDimitry Andric APInt runOpWithExpandOnOverflow( 160*0fca6ea1SDimitry Andric const APInt &A, const APInt &B, 161*0fca6ea1SDimitry Andric function_ref<APInt(const APInt &, const APInt &, bool &Overflow)> Op) { 162*0fca6ea1SDimitry Andric bool Overflow; 163*0fca6ea1SDimitry Andric unsigned Width = getMaxWidth(A, B); 164*0fca6ea1SDimitry Andric APInt Ret = Op(A.sext(Width), B.sext(Width), Overflow); 165*0fca6ea1SDimitry Andric if (!Overflow) 166*0fca6ea1SDimitry Andric return Ret; 167*0fca6ea1SDimitry Andric 168*0fca6ea1SDimitry Andric Width *= 2; 169*0fca6ea1SDimitry Andric Ret = Op(A.sext(Width), B.sext(Width), Overflow); 170*0fca6ea1SDimitry Andric assert(!Overflow && "double width should be sufficient to avoid overflow!"); 171*0fca6ea1SDimitry Andric return Ret; 172*0fca6ea1SDimitry Andric } 173*0fca6ea1SDimitry Andric 174*0fca6ea1SDimitry Andric SlowDynamicAPInt SlowDynamicAPInt::operator+(const SlowDynamicAPInt &O) const { 175*0fca6ea1SDimitry Andric return SlowDynamicAPInt( 176*0fca6ea1SDimitry Andric runOpWithExpandOnOverflow(Val, O.Val, std::mem_fn(&APInt::sadd_ov))); 177*0fca6ea1SDimitry Andric } 178*0fca6ea1SDimitry Andric SlowDynamicAPInt SlowDynamicAPInt::operator-(const SlowDynamicAPInt &O) const { 179*0fca6ea1SDimitry Andric return SlowDynamicAPInt( 180*0fca6ea1SDimitry Andric runOpWithExpandOnOverflow(Val, O.Val, std::mem_fn(&APInt::ssub_ov))); 181*0fca6ea1SDimitry Andric } 182*0fca6ea1SDimitry Andric SlowDynamicAPInt SlowDynamicAPInt::operator*(const SlowDynamicAPInt &O) const { 183*0fca6ea1SDimitry Andric return SlowDynamicAPInt( 184*0fca6ea1SDimitry Andric runOpWithExpandOnOverflow(Val, O.Val, std::mem_fn(&APInt::smul_ov))); 185*0fca6ea1SDimitry Andric } 186*0fca6ea1SDimitry Andric SlowDynamicAPInt SlowDynamicAPInt::operator/(const SlowDynamicAPInt &O) const { 187*0fca6ea1SDimitry Andric return SlowDynamicAPInt( 188*0fca6ea1SDimitry Andric runOpWithExpandOnOverflow(Val, O.Val, std::mem_fn(&APInt::sdiv_ov))); 189*0fca6ea1SDimitry Andric } 190*0fca6ea1SDimitry Andric SlowDynamicAPInt detail::abs(const SlowDynamicAPInt &X) { 191*0fca6ea1SDimitry Andric return X >= 0 ? X : -X; 192*0fca6ea1SDimitry Andric } 193*0fca6ea1SDimitry Andric SlowDynamicAPInt detail::ceilDiv(const SlowDynamicAPInt &LHS, 194*0fca6ea1SDimitry Andric const SlowDynamicAPInt &RHS) { 195*0fca6ea1SDimitry Andric if (RHS == -1) 196*0fca6ea1SDimitry Andric return -LHS; 197*0fca6ea1SDimitry Andric unsigned Width = getMaxWidth(LHS.Val, RHS.Val); 198*0fca6ea1SDimitry Andric return SlowDynamicAPInt(APIntOps::RoundingSDiv( 199*0fca6ea1SDimitry Andric LHS.Val.sext(Width), RHS.Val.sext(Width), APInt::Rounding::UP)); 200*0fca6ea1SDimitry Andric } 201*0fca6ea1SDimitry Andric SlowDynamicAPInt detail::floorDiv(const SlowDynamicAPInt &LHS, 202*0fca6ea1SDimitry Andric const SlowDynamicAPInt &RHS) { 203*0fca6ea1SDimitry Andric if (RHS == -1) 204*0fca6ea1SDimitry Andric return -LHS; 205*0fca6ea1SDimitry Andric unsigned Width = getMaxWidth(LHS.Val, RHS.Val); 206*0fca6ea1SDimitry Andric return SlowDynamicAPInt(APIntOps::RoundingSDiv( 207*0fca6ea1SDimitry Andric LHS.Val.sext(Width), RHS.Val.sext(Width), APInt::Rounding::DOWN)); 208*0fca6ea1SDimitry Andric } 209*0fca6ea1SDimitry Andric // The RHS is always expected to be positive, and the result 210*0fca6ea1SDimitry Andric /// is always non-negative. 211*0fca6ea1SDimitry Andric SlowDynamicAPInt detail::mod(const SlowDynamicAPInt &LHS, 212*0fca6ea1SDimitry Andric const SlowDynamicAPInt &RHS) { 213*0fca6ea1SDimitry Andric assert(RHS >= 1 && "mod is only supported for positive divisors!"); 214*0fca6ea1SDimitry Andric return LHS % RHS < 0 ? LHS % RHS + RHS : LHS % RHS; 215*0fca6ea1SDimitry Andric } 216*0fca6ea1SDimitry Andric 217*0fca6ea1SDimitry Andric SlowDynamicAPInt detail::gcd(const SlowDynamicAPInt &A, 218*0fca6ea1SDimitry Andric const SlowDynamicAPInt &B) { 219*0fca6ea1SDimitry Andric assert(A >= 0 && B >= 0 && "operands must be non-negative!"); 220*0fca6ea1SDimitry Andric unsigned Width = getMaxWidth(A.Val, B.Val); 221*0fca6ea1SDimitry Andric return SlowDynamicAPInt( 222*0fca6ea1SDimitry Andric APIntOps::GreatestCommonDivisor(A.Val.sext(Width), B.Val.sext(Width))); 223*0fca6ea1SDimitry Andric } 224*0fca6ea1SDimitry Andric 225*0fca6ea1SDimitry Andric /// Returns the least common multiple of A and B. 226*0fca6ea1SDimitry Andric SlowDynamicAPInt detail::lcm(const SlowDynamicAPInt &A, 227*0fca6ea1SDimitry Andric const SlowDynamicAPInt &B) { 228*0fca6ea1SDimitry Andric SlowDynamicAPInt X = abs(A); 229*0fca6ea1SDimitry Andric SlowDynamicAPInt Y = abs(B); 230*0fca6ea1SDimitry Andric return (X * Y) / gcd(X, Y); 231*0fca6ea1SDimitry Andric } 232*0fca6ea1SDimitry Andric 233*0fca6ea1SDimitry Andric /// This operation cannot overflow. 234*0fca6ea1SDimitry Andric SlowDynamicAPInt SlowDynamicAPInt::operator%(const SlowDynamicAPInt &O) const { 235*0fca6ea1SDimitry Andric unsigned Width = std::max(Val.getBitWidth(), O.Val.getBitWidth()); 236*0fca6ea1SDimitry Andric return SlowDynamicAPInt(Val.sext(Width).srem(O.Val.sext(Width))); 237*0fca6ea1SDimitry Andric } 238*0fca6ea1SDimitry Andric 239*0fca6ea1SDimitry Andric SlowDynamicAPInt SlowDynamicAPInt::operator-() const { 240*0fca6ea1SDimitry Andric if (Val.isMinSignedValue()) { 241*0fca6ea1SDimitry Andric /// Overflow only occurs when the value is the minimum possible value. 242*0fca6ea1SDimitry Andric APInt Ret = Val.sext(2 * Val.getBitWidth()); 243*0fca6ea1SDimitry Andric return SlowDynamicAPInt(-Ret); 244*0fca6ea1SDimitry Andric } 245*0fca6ea1SDimitry Andric return SlowDynamicAPInt(-Val); 246*0fca6ea1SDimitry Andric } 247*0fca6ea1SDimitry Andric 248*0fca6ea1SDimitry Andric /// --------------------------------------------------------------------------- 249*0fca6ea1SDimitry Andric /// Assignment operators, preincrement, predecrement. 250*0fca6ea1SDimitry Andric /// --------------------------------------------------------------------------- 251*0fca6ea1SDimitry Andric SlowDynamicAPInt &SlowDynamicAPInt::operator+=(const SlowDynamicAPInt &O) { 252*0fca6ea1SDimitry Andric *this = *this + O; 253*0fca6ea1SDimitry Andric return *this; 254*0fca6ea1SDimitry Andric } 255*0fca6ea1SDimitry Andric SlowDynamicAPInt &SlowDynamicAPInt::operator-=(const SlowDynamicAPInt &O) { 256*0fca6ea1SDimitry Andric *this = *this - O; 257*0fca6ea1SDimitry Andric return *this; 258*0fca6ea1SDimitry Andric } 259*0fca6ea1SDimitry Andric SlowDynamicAPInt &SlowDynamicAPInt::operator*=(const SlowDynamicAPInt &O) { 260*0fca6ea1SDimitry Andric *this = *this * O; 261*0fca6ea1SDimitry Andric return *this; 262*0fca6ea1SDimitry Andric } 263*0fca6ea1SDimitry Andric SlowDynamicAPInt &SlowDynamicAPInt::operator/=(const SlowDynamicAPInt &O) { 264*0fca6ea1SDimitry Andric *this = *this / O; 265*0fca6ea1SDimitry Andric return *this; 266*0fca6ea1SDimitry Andric } 267*0fca6ea1SDimitry Andric SlowDynamicAPInt &SlowDynamicAPInt::operator%=(const SlowDynamicAPInt &O) { 268*0fca6ea1SDimitry Andric *this = *this % O; 269*0fca6ea1SDimitry Andric return *this; 270*0fca6ea1SDimitry Andric } 271*0fca6ea1SDimitry Andric SlowDynamicAPInt &SlowDynamicAPInt::operator++() { 272*0fca6ea1SDimitry Andric *this += 1; 273*0fca6ea1SDimitry Andric return *this; 274*0fca6ea1SDimitry Andric } 275*0fca6ea1SDimitry Andric 276*0fca6ea1SDimitry Andric SlowDynamicAPInt &SlowDynamicAPInt::operator--() { 277*0fca6ea1SDimitry Andric *this -= 1; 278*0fca6ea1SDimitry Andric return *this; 279*0fca6ea1SDimitry Andric } 280*0fca6ea1SDimitry Andric 281*0fca6ea1SDimitry Andric /// --------------------------------------------------------------------------- 282*0fca6ea1SDimitry Andric /// Printing. 283*0fca6ea1SDimitry Andric /// --------------------------------------------------------------------------- 284*0fca6ea1SDimitry Andric void SlowDynamicAPInt::print(raw_ostream &OS) const { OS << Val; } 285*0fca6ea1SDimitry Andric 286*0fca6ea1SDimitry Andric void SlowDynamicAPInt::dump() const { print(dbgs()); } 287