14#include <llvm/ADT/ArrayRef.h>
15#include <llvm/ADT/SmallString.h>
16#include <llvm/Support/Compiler.h>
17#include <llvm/Support/ErrorHandling.h>
18#include <llvm/Support/raw_ostream.h>
27static DynamicAPInt binaryBitOp(
28 const DynamicAPInt &lhs,
const DynamicAPInt &rhs,
29 function_ref<APInt(
const APInt &,
const APInt &)> fn
32 unsigned width = std::max(a.getBitWidth(), b.getBitWidth());
33 return DynamicAPInt(fn(a.sext(width), b.sext(width)));
40 return DynamicAPInt(0);
42 if (parts.size() <= std::numeric_limits<unsigned>::max() / 64) {
43 return DynamicAPInt(APInt(
static_cast<unsigned>(parts.size()) * 64, parts));
45 llvm::report_fatal_error(
"part array exceeds APInt's maximum bit width");
49 StringRef digits = str;
50 bool negative = digits.consume_front(
"-");
52 if (digits.getAsInteger(10, magnitude)) {
53 return createStringError(inconvertibleErrorCode(),
"expected signed decimal integer");
56 return negative ? -value : value;
61 return llvm::hash_value(bits.trunc(bits.getSignificantBits()));
64Expected<APInt>
checkedToAPInt(
const DynamicAPInt &value,
unsigned bitWidth,
bool isSigned) {
66 bool fits = bitWidth != 0 &&
67 (isSigned ? bits.isSignedIntN(bitWidth) : value >= 0 && bits.isIntN(bitWidth));
69 return createStringError(inconvertibleErrorCode(),
"integer does not fit requested width");
71 return isSigned ? bits.sextOrTrunc(bitWidth) : bits.zextOrTrunc(bitWidth);
75 if (value < numeric_limits<int64_t>::min() || value > numeric_limits<int64_t>::max()) {
76 return createStringError(inconvertibleErrorCode(),
"integer does not fit requested width");
78 return static_cast<int64_t
>(value);
84 return bits.takeError();
86 return bits->getZExtValue();
89Expected<size_t>
checkedToSize(
const DynamicAPInt &value,
const Twine &context) {
91 return createStringError(inconvertibleErrorCode(), context +
" would underflow size_t");
93 constexpr size_t sizeMax = std::numeric_limits<size_t>::max();
94 if (value <= std::numeric_limits<int64_t>::max()) {
95 auto native =
static_cast<uint64_t
>(
static_cast<int64_t
>(value));
96 if (native > sizeMax) {
97 return createStringError(inconvertibleErrorCode(), context +
" would overflow size_t");
99 return static_cast<size_t>(native);
103 if (value > maxValue) {
104 return createStringError(inconvertibleErrorCode(), context +
" would overflow size_t");
108 auto distance =
static_cast<int64_t
>(maxValue - value);
109 return sizeMax -
static_cast<size_t>(distance);
112DynamicAPInt
operator&(
const DynamicAPInt &lhs,
const DynamicAPInt &rhs) {
113 return binaryBitOp(lhs, rhs, [](
const APInt &a,
const APInt &b) {
return a & b; });
116DynamicAPInt
operator|(
const DynamicAPInt &lhs,
const DynamicAPInt &rhs) {
117 return binaryBitOp(lhs, rhs, [](
const APInt &a,
const APInt &b) {
return a | b; });
120DynamicAPInt
operator^(
const DynamicAPInt &lhs,
const DynamicAPInt &rhs) {
121 return binaryBitOp(lhs, rhs, [](
const APInt &a,
const APInt &b) {
return a ^ b; });
124DynamicAPInt
operator<<(
const DynamicAPInt &lhs,
const DynamicAPInt &rhs) {
125 if (rhs < numeric_limits<int64_t>::min() || rhs > numeric_limits<int64_t>::max()) {
126 llvm::report_fatal_error(
"invalid or unrepresentable left shift");
128 return lhs << static_cast<int64_t>(rhs);
131DynamicAPInt
operator<<(
const DynamicAPInt &lhs, int64_t rhs) {
133 unsigned width = bits.getSignificantBits();
134 if (rhs < 0 ||
static_cast<uint64_t
>(rhs) > numeric_limits<unsigned>::max() - width) {
135 llvm::report_fatal_error(
"invalid or unrepresentable left shift");
138 return DynamicAPInt(0);
141 return DynamicAPInt(bits.sextOrTrunc(width + amount).shl(amount));
144DynamicAPInt
operator>>(
const DynamicAPInt &lhs,
const DynamicAPInt &rhs) {
145 if (rhs < numeric_limits<int64_t>::min()) {
146 llvm::report_fatal_error(
"negative right shift");
148 if (rhs > numeric_limits<int64_t>::max()) {
149 return DynamicAPInt(lhs < 0 ? -1 : 0);
152 return lhs >>
static_cast<int64_t
>(rhs);
155DynamicAPInt
operator>>(
const DynamicAPInt &lhs, int64_t rhs) {
157 llvm::report_fatal_error(
"negative right shift");
160 if (
static_cast<uint64_t
>(rhs) >= bits.getSignificantBits()) {
161 return DynamicAPInt(lhs < 0 ? -1 : 0);
171 if (i.isUnsigned() && i.isSignBitSet()) {
172 return DynamicAPInt(i.zext(i.getBitWidth() + 1));
174 return DynamicAPInt(i);
179 if (i.isSignBitSet()) {
180 return DynamicAPInt(i.zext(i.getBitWidth() + 1));
182 return DynamicAPInt(i);
189static LLVM_ATTRIBUTE_NOINLINE APSInt toAPSIntSlow(
const DynamicAPInt &i) {
192 SmallString<96> repr;
193 raw_svector_ostream(repr) << i;
199 size_t digits = repr.size() - (repr.front() ==
'-');
200 constexpr uint64_t maxDigits = ((uint64_t(numeric_limits<unsigned>::max()) - 2) * 19) / 64;
202 if (digits > maxDigits) {
203 llvm::report_fatal_error(
"decimal integer exceeds APInt's maximum parse width");
205 unsigned parseWidth =
static_cast<unsigned>((uint64_t(digits) * 64) / 19 + 2);
206 APInt bits(parseWidth, repr, 10);
209 unsigned minWidth = bits.getSignificantBits();
210 if (APInt::getNumWords(minWidth) < bits.getNumWords()) {
211 bits = bits.trunc(minWidth);
213 return APSInt(std::move(bits),
false);
217 if (numeric_limits<int64_t>::min() <= i && i <= numeric_limits<int64_t>::max()) {
219 return APSInt::get(int64_t(i));
221 return toAPSIntSlow(i);
224DynamicAPInt
modExp(
const DynamicAPInt &base,
const DynamicAPInt &exp,
const DynamicAPInt &
mod) {
225 if (exp < 0 ||
mod <= 0) {
226 llvm::report_fatal_error(
227 "modular exponentiation requires a nonnegative exponent and positive modulus"
230 DynamicAPInt result(
mod == 1 ? 0 : 1);
231 DynamicAPInt b = llvm::mod(base,
mod);
232 DynamicAPInt e = exp;
236 result = (result * b) %
mod;
246 assert(f != 0 &&
"0 has no inverse");
248 DynamicAPInt exp = p - 2;
249 DynamicAPInt result =
modExp(f, exp, p);
250 assert(llvm::mod(f * result, p) == 1 &&
"inverse is incorrect");
This file implements helpers for DynamicAPInt operations and conversions that LLVM does not provide.
ExpressionValue mod(const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
Expected< size_t > checkedToSize(const DynamicAPInt &value, const Twine &context)
Interval operator|(const Interval &lhs, const Interval &rhs)
hash_code hashDynamicAPInt(const DynamicAPInt &value)
Interval operator^(const Interval &lhs, const Interval &rhs)
DynamicAPInt toDynamicAPInt(StringRef str)
Expected< DynamicAPInt > parseDynamicAPInt(StringRef str)
Interval operator<<(const Interval &lhs, const Interval &rhs)
constexpr T checkedCast(U u) noexcept
Expected< uint64_t > checkedToUInt64(const DynamicAPInt &value)
Interval operator>>(const Interval &lhs, const Interval &rhs)
Interval operator&(const Interval &lhs, const Interval &rhs)
Expected< int64_t > checkedToInt64(const DynamicAPInt &value)
DynamicAPInt toSignedDynamicAPInt(ArrayRef< uint64_t > parts)
DynamicAPInt modInversePrime(const DynamicAPInt &f, const DynamicAPInt &p)
APSInt toAPSInt(const DynamicAPInt &i)
Expected< APInt > checkedToAPInt(const DynamicAPInt &value, unsigned bitWidth, bool isSigned)
DynamicAPInt modExp(const DynamicAPInt &base, const DynamicAPInt &exp, const DynamicAPInt &mod)