LLZK 0.1.0
Veridise's ZK Language IR
Loading...
Searching...
No Matches
DynamicAPIntHelper.cpp
Go to the documentation of this file.
1//===-- DynamicAPIntHelper.cpp ----------------------------------*- C++ -*-===//
2//
3// Part of the LLZK Project, under the Apache License v2.0.
4// See LICENSE.txt for license information.
5// Copyright 2025 Veridise Inc.
6// SPDX-License-Identifier: Apache-2.0
7//
8//===----------------------------------------------------------------------===//
9
11
12#include <llvm/ADT/ArrayRef.h>
13#include <llvm/Support/raw_ostream.h>
14
15#include <limits>
16
17using namespace llvm;
18using namespace std;
19
20static DynamicAPInt po2(const DynamicAPInt &e) {
21 // Ensure parameter is not negative and that it can be safely cast to unsigned.
22 assert(e >= 0);
23 assert(e <= std::numeric_limits<unsigned>::max() /* upcast from unsigned -> int64_t */);
24 unsigned shiftAmt = llzk::toAPSInt(e).getZExtValue();
25 APSInt p = APSInt::get(1) << shiftAmt;
26 return llzk::toDynamicAPInt(p);
27}
28
29static DynamicAPInt fromBigEndian(const std::vector<bool> &bits) {
30 APSInt rawInt(bits.size(), /* isUnsigned */ false);
31 for (unsigned i = 0; i < bits.size(); ++i) {
32 rawInt.setBitVal(i, bits[i]);
33 }
34 return llzk::toDynamicAPInt(rawInt);
35}
36
37static DynamicAPInt
38binaryBitOp(const DynamicAPInt &lhs, const DynamicAPInt &rhs, function_ref<bool(bool, bool)> fn) {
39 DynamicAPInt a = lhs, b = rhs;
40 std::vector<bool> bits;
41 while (a != 0 || b != 0) {
42 // bits are sign extended
43 bool abit = a != 0 ? bool(int64_t(a % 2)) : lhs < 0;
44 bool bbit = b != 0 ? bool(int64_t(b % 2)) : rhs < 0;
45 bits.push_back(fn(abit, bbit));
46 a /= 2;
47 b /= 2;
48 }
49 // Insert final sign bit, as the above will ignore 0 sign bits. This is also
50 // acceptable when both numbers are signed, as it acts as a sign extension.
51 bits.push_back(fn(lhs < 0, rhs < 0));
52 return fromBigEndian(bits);
53}
54
55namespace llzk {
56
57DynamicAPInt operator&(const DynamicAPInt &lhs, const DynamicAPInt &rhs) {
58 auto fn = [](bool a, bool b) { return a && b; };
59 return binaryBitOp(lhs, rhs, fn);
60}
61
62DynamicAPInt operator|(const DynamicAPInt &lhs, const DynamicAPInt &rhs) {
63 auto fn = [](bool a, bool b) { return a || b; };
64 return binaryBitOp(lhs, rhs, fn);
65}
66
67DynamicAPInt operator^(const DynamicAPInt &lhs, const DynamicAPInt &rhs) {
68 auto fn = [](bool a, bool b) { return a ^ b; };
69 return binaryBitOp(lhs, rhs, fn);
70}
71
72DynamicAPInt operator<<(const DynamicAPInt &lhs, const DynamicAPInt &rhs) { return lhs * po2(rhs); }
73
74DynamicAPInt operator>>(const DynamicAPInt &lhs, const DynamicAPInt &rhs) {
75 if (lhs >= 0) {
76 return lhs / po2(rhs);
77 } else {
78 // round towards negative infinity
79 DynamicAPInt divisor = po2(rhs);
80 if (lhs % divisor == 0) {
81 return lhs / divisor;
82 } else {
83 return (lhs - (divisor - 1)) / divisor;
84 }
85 }
86}
87
88DynamicAPInt toDynamicAPInt(StringRef str) {
89 APSInt parsedInt(str);
90 return toDynamicAPInt(parsedInt);
91}
92
93DynamicAPInt toDynamicAPInt(const APSInt &i) {
94 if (i.getBitWidth() <= 64) {
95 // Fast path for smaller values, just use the int64_t conversion
96 return DynamicAPInt(i.isNegative() ? i.getSExtValue() : i.getZExtValue());
97 }
98
99 DynamicAPInt res(0), po2(1);
100 // Since LLVM 20 doesn't have a direct APInt to DynamicAPInt constructor, we
101 // manually construct the DynamicAPInt from bits of the input.
102 // We use the positive representation so our negation works at the end.
103 APSInt raw = i < 0 ? -i : i;
104 for (unsigned b = 0; b < raw.getActiveBits(); b++) {
105 DynamicAPInt bitSet(raw[b]);
106 res += (bitSet * po2);
107 po2 *= 2;
108 }
109 if (i.isNegative() && res > 0) {
110 res = -res;
111 }
112 return res;
113}
114
115APSInt toAPSInt(const DynamicAPInt &i) {
116 if (numeric_limits<int64_t>::min() <= i && i <= numeric_limits<int64_t>::max()) {
117 // Fast path for smaller values, just use the int64_t conversion
118 return APSInt::get(int64_t(i));
119 }
120
121 // Else, convert to string and parse back as an APSInt.
122 // This may not be the most efficient implementation, but it is the cleanest
123 // due to the lack of direct conversions between DynamicAPInt and APInts.
124 std::string repr;
125 llvm::raw_string_ostream ss(repr);
126 ss << i;
127
128 APSInt res(repr);
129 // For consistency, we add a bit and mark these as signed integers, since
130 // DynamicAPInts are inherently signed.
131 res = res.extend(res.getBitWidth() + 1);
132 res.setIsSigned(true);
133
134 return res;
135}
136
137} // namespace llzk
This file implements helper methods for constructing DynamicAPInts.
DynamicAPInt toDynamicAPInt(StringRef str)
Interval operator<<(const Interval &lhs, const Interval &rhs)
DynamicAPInt operator|(const DynamicAPInt &lhs, const DynamicAPInt &rhs)
Interval operator>>(const Interval &lhs, const Interval &rhs)
Interval operator&(const Interval &lhs, const Interval &rhs)
APSInt toAPSInt(const DynamicAPInt &i)
DynamicAPInt operator^(const DynamicAPInt &lhs, const DynamicAPInt &rhs)