v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
bitwise.cc
Go to the documentation of this file.
1// Copyright 2021 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
7#include "src/bigint/util.h"
9
10namespace v8 {
11namespace bigint {
12
14 int pairs = std::min(X.len(), Y.len());
15 DCHECK(Z.len() >= pairs);
16 int i = 0;
17 for (; i < pairs; i++) Z[i] = X[i] & Y[i];
18 for (; i < Z.len(); i++) Z[i] = 0;
19}
20
22 // (-x) & (-y) == ~(x-1) & ~(y-1)
23 // == ~((x-1) | (y-1))
24 // == -(((x-1) | (y-1)) + 1)
25 int pairs = std::min(X.len(), Y.len());
26 digit_t x_borrow = 1;
27 digit_t y_borrow = 1;
28 int i = 0;
29 for (; i < pairs; i++) {
30 Z[i] = digit_sub(X[i], x_borrow, &x_borrow) |
31 digit_sub(Y[i], y_borrow, &y_borrow);
32 }
33 // (At least) one of the next two loops will perform zero iterations:
34 for (; i < X.len(); i++) Z[i] = digit_sub(X[i], x_borrow, &x_borrow);
35 for (; i < Y.len(); i++) Z[i] = digit_sub(Y[i], y_borrow, &y_borrow);
36 DCHECK(x_borrow == 0);
37 DCHECK(y_borrow == 0);
38 for (; i < Z.len(); i++) Z[i] = 0;
39 Add(Z, 1);
40}
41
43 // x & (-y) == x & ~(y-1)
44 int pairs = std::min(X.len(), Y.len());
45 digit_t borrow = 1;
46 int i = 0;
47 for (; i < pairs; i++) Z[i] = X[i] & ~digit_sub(Y[i], borrow, &borrow);
48 for (; i < X.len(); i++) Z[i] = X[i];
49 for (; i < Z.len(); i++) Z[i] = 0;
50}
51
53 int pairs = std::min(X.len(), Y.len());
54 int i = 0;
55 for (; i < pairs; i++) Z[i] = X[i] | Y[i];
56 // (At least) one of the next two loops will perform zero iterations:
57 for (; i < X.len(); i++) Z[i] = X[i];
58 for (; i < Y.len(); i++) Z[i] = Y[i];
59 for (; i < Z.len(); i++) Z[i] = 0;
60}
61
63 // (-x) | (-y) == ~(x-1) | ~(y-1)
64 // == ~((x-1) & (y-1))
65 // == -(((x-1) & (y-1)) + 1)
66 int pairs = std::min(X.len(), Y.len());
67 digit_t x_borrow = 1;
68 digit_t y_borrow = 1;
69 int i = 0;
70 for (; i < pairs; i++) {
71 Z[i] = digit_sub(X[i], x_borrow, &x_borrow) &
72 digit_sub(Y[i], y_borrow, &y_borrow);
73 }
74 // Any leftover borrows don't matter, the '&' would drop them anyway.
75 for (; i < Z.len(); i++) Z[i] = 0;
76 Add(Z, 1);
77}
78
80 // x | (-y) == x | ~(y-1) == ~((y-1) &~ x) == -(((y-1) &~ x) + 1)
81 int pairs = std::min(X.len(), Y.len());
82 digit_t borrow = 1;
83 int i = 0;
84 for (; i < pairs; i++) Z[i] = digit_sub(Y[i], borrow, &borrow) & ~X[i];
85 for (; i < Y.len(); i++) Z[i] = digit_sub(Y[i], borrow, &borrow);
86 DCHECK(borrow == 0);
87 for (; i < Z.len(); i++) Z[i] = 0;
88 Add(Z, 1);
89}
90
92 int pairs = X.len();
93 if (Y.len() < X.len()) {
94 std::swap(X, Y);
95 pairs = X.len();
96 }
97 DCHECK(X.len() <= Y.len());
98 int i = 0;
99 for (; i < pairs; i++) Z[i] = X[i] ^ Y[i];
100 for (; i < Y.len(); i++) Z[i] = Y[i];
101 for (; i < Z.len(); i++) Z[i] = 0;
102}
103
105 // (-x) ^ (-y) == ~(x-1) ^ ~(y-1) == (x-1) ^ (y-1)
106 int pairs = std::min(X.len(), Y.len());
107 digit_t x_borrow = 1;
108 digit_t y_borrow = 1;
109 int i = 0;
110 for (; i < pairs; i++) {
111 Z[i] = digit_sub(X[i], x_borrow, &x_borrow) ^
112 digit_sub(Y[i], y_borrow, &y_borrow);
113 }
114 // (At least) one of the next two loops will perform zero iterations:
115 for (; i < X.len(); i++) Z[i] = digit_sub(X[i], x_borrow, &x_borrow);
116 for (; i < Y.len(); i++) Z[i] = digit_sub(Y[i], y_borrow, &y_borrow);
117 DCHECK(x_borrow == 0);
118 DCHECK(y_borrow == 0);
119 for (; i < Z.len(); i++) Z[i] = 0;
120}
121
123 // x ^ (-y) == x ^ ~(y-1) == ~(x ^ (y-1)) == -((x ^ (y-1)) + 1)
124 int pairs = std::min(X.len(), Y.len());
125 digit_t borrow = 1;
126 int i = 0;
127 for (; i < pairs; i++) Z[i] = X[i] ^ digit_sub(Y[i], borrow, &borrow);
128 // (At least) one of the next two loops will perform zero iterations:
129 for (; i < X.len(); i++) Z[i] = X[i];
130 for (; i < Y.len(); i++) Z[i] = digit_sub(Y[i], borrow, &borrow);
131 DCHECK(borrow == 0);
132 for (; i < Z.len(); i++) Z[i] = 0;
133 Add(Z, 1);
134}
135
137 int digit_shift = static_cast<int>(shift / kDigitBits);
138 int bits_shift = static_cast<int>(shift % kDigitBits);
139
140 int i = 0;
141 for (; i < digit_shift; ++i) Z[i] = 0;
142 if (bits_shift == 0) {
143 for (; i < X.len() + digit_shift; ++i) Z[i] = X[i - digit_shift];
144 for (; i < Z.len(); ++i) Z[i] = 0;
145 } else {
146 digit_t carry = 0;
147 for (; i < X.len() + digit_shift; ++i) {
148 digit_t d = X[i - digit_shift];
149 Z[i] = (d << bits_shift) | carry;
150 carry = d >> (kDigitBits - bits_shift);
151 }
152 if (carry != 0) Z[i++] = carry;
153 for (; i < Z.len(); ++i) Z[i] = 0;
154 }
155}
156
157int RightShift_ResultLength(Digits X, bool x_sign, digit_t shift,
158 RightShiftState* state) {
159 int digit_shift = static_cast<int>(shift / kDigitBits);
160 int bits_shift = static_cast<int>(shift % kDigitBits);
161 int result_length = X.len() - digit_shift;
162 if (result_length <= 0) return 0;
163
164 // For negative numbers, round down if any bit was shifted out (so that e.g.
165 // -5n >> 1n == -3n and not -2n). Check now whether this will happen and
166 // whether it can cause overflow into a new digit.
167 bool must_round_down = false;
168 if (x_sign) {
169 const digit_t mask = (static_cast<digit_t>(1) << bits_shift) - 1;
170 if ((X[digit_shift] & mask) != 0) {
171 must_round_down = true;
172 } else {
173 for (int i = 0; i < digit_shift; i++) {
174 if (X[i] != 0) {
175 must_round_down = true;
176 break;
177 }
178 }
179 }
180 }
181 // If bits_shift is non-zero, it frees up bits, preventing overflow.
182 if (must_round_down && bits_shift == 0) {
183 // Overflow cannot happen if the most significant digit has unset bits.
184 const bool rounding_can_overflow = digit_ismax(X.msd());
185 if (rounding_can_overflow) ++result_length;
186 }
187
188 if (state) {
189 DCHECK(!must_round_down || x_sign);
190 state->must_round_down = must_round_down;
191 }
192 return result_length;
193}
194
196 const RightShiftState& state) {
197 int digit_shift = static_cast<int>(shift / kDigitBits);
198 int bits_shift = static_cast<int>(shift % kDigitBits);
199
200 int i = 0;
201 if (bits_shift == 0) {
202 for (; i < X.len() - digit_shift; ++i) Z[i] = X[i + digit_shift];
203 } else {
204 digit_t carry = X[digit_shift] >> bits_shift;
205 for (; i < X.len() - digit_shift - 1; ++i) {
206 digit_t d = X[i + digit_shift + 1];
207 Z[i] = (d << (kDigitBits - bits_shift)) | carry;
208 carry = d >> bits_shift;
209 }
210 Z[i++] = carry;
211 }
212 for (; i < Z.len(); ++i) Z[i] = 0;
213
214 if (state.must_round_down) {
215 // Rounding down (a negative value) means adding one to
216 // its absolute value. This cannot overflow.
217 Add(Z, 1);
218 }
219}
220
221namespace {
222
223// Z := (least significant n bits of X).
224void TruncateToNBits(RWDigits Z, Digits X, int n) {
225 int digits = DIV_CEIL(n, kDigitBits);
226 int bits = n % kDigitBits;
227 // Copy all digits except the MSD.
228 int last = digits - 1;
229 for (int i = 0; i < last; i++) {
230 Z[i] = X[i];
231 }
232 // The MSD might contain extra bits that we don't want.
233 digit_t msd = X[last];
234 if (bits != 0) {
235 int drop = kDigitBits - bits;
236 msd = (msd << drop) >> drop;
237 }
238 Z[last] = msd;
239}
240
241// Z := 2**n - (least significant n bits of X).
242void TruncateAndSubFromPowerOfTwo(RWDigits Z, Digits X, int n) {
243 int digits = DIV_CEIL(n, kDigitBits);
244 int bits = n % kDigitBits;
245 // Process all digits except the MSD. Take X's digits, then simulate leading
246 // zeroes.
247 int last = digits - 1;
248 int have_x = std::min(last, X.len());
249 digit_t borrow = 0;
250 int i = 0;
251 for (; i < have_x; i++) Z[i] = digit_sub2(0, X[i], borrow, &borrow);
252 for (; i < last; i++) Z[i] = digit_sub(0, borrow, &borrow);
253
254 // The MSD might contain extra bits that we don't want.
255 digit_t msd = last < X.len() ? X[last] : 0;
256 if (bits == 0) {
257 Z[last] = digit_sub2(0, msd, borrow, &borrow);
258 } else {
259 int drop = kDigitBits - bits;
260 msd = (msd << drop) >> drop;
261 digit_t minuend_msd = static_cast<digit_t>(1) << bits;
262 digit_t result_msd = digit_sub2(minuend_msd, msd, borrow, &borrow);
263 DCHECK(borrow == 0); // result < 2^n.
264 // If all subtracted bits were zero, we have to get rid of the
265 // materialized minuend_msd again.
266 Z[last] = result_msd & (minuend_msd - 1);
267 }
268}
269
270} // namespace
271
272// Returns -1 when the operation would return X unchanged.
273int AsIntNResultLength(Digits X, bool x_negative, int n) {
274 int needed_digits = DIV_CEIL(n, kDigitBits);
275 // Generally: decide based on number of digits, and bits in the top digit.
276 if (X.len() < needed_digits) return -1;
277 if (X.len() > needed_digits) return needed_digits;
278 digit_t top_digit = X[needed_digits - 1];
279 digit_t compare_digit = digit_t{1} << ((n - 1) % kDigitBits);
280 if (top_digit < compare_digit) return -1;
281 if (top_digit > compare_digit) return needed_digits;
282 // Special case: if X == -2**(n-1), truncation is a no-op.
283 if (!x_negative) return needed_digits;
284 for (int i = needed_digits - 2; i >= 0; i--) {
285 if (X[i] != 0) return needed_digits;
286 }
287 return -1;
288}
289
290bool AsIntN(RWDigits Z, Digits X, bool x_negative, int n) {
291 DCHECK(X.len() > 0);
292 DCHECK(n > 0);
293 DCHECK(AsIntNResultLength(X, x_negative, n) > 0);
294 int needed_digits = DIV_CEIL(n, kDigitBits);
295 digit_t top_digit = X[needed_digits - 1];
296 digit_t compare_digit = digit_t{1} << ((n - 1) % kDigitBits);
297 // The canonical algorithm would be: convert negative numbers to two's
298 // complement representation, truncate, convert back to sign+magnitude. To
299 // avoid the conversions, we predict what the result would be:
300 // When the (n-1)th bit is not set:
301 // - truncate the absolute value
302 // - preserve the sign.
303 // When the (n-1)th bit is set:
304 // - subtract the truncated absolute value from 2**n to simulate two's
305 // complement representation
306 // - flip the sign, unless it's the special case where the input is negative
307 // and the result is the minimum n-bit integer. E.g. asIntN(3, -12) => -4.
308 bool has_bit = (top_digit & compare_digit) == compare_digit;
309 if (!has_bit) {
310 TruncateToNBits(Z, X, n);
311 return x_negative;
312 }
313 TruncateAndSubFromPowerOfTwo(Z, X, n);
314 if (!x_negative) return true; // Result is negative.
315 // Scan for the special case (see above): if all bits below the (n-1)th
316 // digit are zero, the result is negative.
317 if ((top_digit & (compare_digit - 1)) != 0) return false;
318 for (int i = needed_digits - 2; i >= 0; i--) {
319 if (X[i] != 0) return false;
320 }
321 return true;
322}
323
324// Returns -1 when the operation would return X unchanged.
326 int needed_digits = DIV_CEIL(n, kDigitBits);
327 if (X.len() < needed_digits) return -1;
328 if (X.len() > needed_digits) return needed_digits;
329 int bits_in_top_digit = n % kDigitBits;
330 if (bits_in_top_digit == 0) return -1;
331 digit_t top_digit = X[needed_digits - 1];
332 if ((top_digit >> bits_in_top_digit) == 0) return -1;
333 return needed_digits;
334}
335
336void AsUintN_Pos(RWDigits Z, Digits X, int n) {
338 TruncateToNBits(Z, X, n);
339}
340
341void AsUintN_Neg(RWDigits Z, Digits X, int n) {
342 TruncateAndSubFromPowerOfTwo(Z, X, n);
343}
344
345} // namespace bigint
346} // namespace v8
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in allocation gc speed threshold for starting incremental marking via a task in percent of available threshold for starting incremental marking immediately in percent of available Use a single schedule for determining a marking schedule between JS and C objects schedules the minor GC task with kUserVisible priority max worker number of concurrent for NumberOfWorkerThreads start background threads that allocate memory concurrent_array_buffer_sweeping use parallel threads to clear weak refs in the atomic pause trace progress of the incremental marking trace object counts and memory usage report a tick only when allocated zone memory changes by this amount TracingFlags::gc_stats TracingFlags::gc_stats track native contexts that are expected to be garbage collected verify heap pointers before and after GC memory reducer runs GC with ReduceMemoryFootprint flag Maximum number of memory reducer GCs scheduled Old gen GC speed is computed directly from gc tracer counters Perform compaction on full GCs based on V8 s default heuristics Perform compaction on every full GC Perform code space compaction when finalizing a full GC with stack Stress GC compaction to flush out bugs with moving objects flush of baseline code when it has not been executed recently Use time base code flushing instead of age Use a progress bar to scan large objects in increments when incremental marking is active force incremental marking for small heaps and run it more often force marking at random points between and X(inclusive) percent " "of the regular marking start limit") DEFINE_INT(stress_scavenge
std::vector< PatternMap > pairs
uint32_t const mask
void BitwiseXor_NegNeg(RWDigits Z, Digits X, Digits Y)
Definition bitwise.cc:104
bool AsIntN(RWDigits Z, Digits X, bool x_negative, int n)
Definition bitwise.cc:290
void BitwiseAnd_PosPos(RWDigits Z, Digits X, Digits Y)
Definition bitwise.cc:13
void BitwiseOr_PosNeg(RWDigits Z, Digits X, Digits Y)
Definition bitwise.cc:79
int RightShift_ResultLength(Digits X, bool x_sign, digit_t shift, RightShiftState *state)
Definition bitwise.cc:157
void BitwiseXor_PosPos(RWDigits Z, Digits X, Digits Y)
Definition bitwise.cc:91
void LeftShift(RWDigits Z, Digits X, digit_t shift)
Definition bitwise.cc:136
void BitwiseOr_PosPos(RWDigits Z, Digits X, Digits Y)
Definition bitwise.cc:52
static constexpr int kDigitBits
Definition bigint.h:51
void BitwiseAnd_NegNeg(RWDigits Z, Digits X, Digits Y)
Definition bitwise.cc:21
int AsIntNResultLength(Digits X, bool x_negative, int n)
Definition bitwise.cc:273
void Add(RWDigits Z, Digits X, Digits Y)
void AsUintN_Neg(RWDigits Z, Digits X, int n)
Definition bitwise.cc:341
digit_t digit_sub2(digit_t a, digit_t b, digit_t borrow_in, digit_t *borrow_out)
void BitwiseOr_NegNeg(RWDigits Z, Digits X, Digits Y)
Definition bitwise.cc:62
void RightShift(RWDigits Z, Digits X, digit_t shift, const RightShiftState &state)
Definition bitwise.cc:195
digit_t digit_sub(digit_t a, digit_t b, digit_t *borrow)
constexpr bool digit_ismax(digit_t x)
void BitwiseXor_PosNeg(RWDigits Z, Digits X, Digits Y)
Definition bitwise.cc:122
uintptr_t digit_t
Definition bigint.h:34
int AsUintN_Pos_ResultLength(Digits X, int n)
Definition bitwise.cc:325
void BitwiseAnd_PosNeg(RWDigits Z, Digits X, Digits Y)
Definition bitwise.cc:42
void AsUintN_Pos(RWDigits Z, Digits X, int n)
Definition bitwise.cc:336
#define DCHECK(condition)
Definition logging.h:482
#define DIV_CEIL(x, y)
Definition util.h:19