Bug Summary

File:out/../deps/v8/src/compiler/common-operator.cc
Warning:line 241, column 13
Assigned value is garbage or undefined

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name common-operator.cc -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/home/maurizio/node-v18.6.0/out -resource-dir /usr/local/lib/clang/16.0.0 -D _GLIBCXX_USE_CXX11_ABI=1 -D NODE_OPENSSL_CONF_NAME=nodejs_conf -D NODE_OPENSSL_HAS_QUIC -D V8_GYP_BUILD -D V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP=64 -D __STDC_FORMAT_MACROS -D OPENSSL_NO_PINSHARED -D OPENSSL_THREADS -D V8_TARGET_ARCH_X64 -D V8_HAVE_TARGET_OS -D V8_TARGET_OS_LINUX -D V8_EMBEDDER_STRING="-node.8" -D ENABLE_DISASSEMBLER -D V8_PROMISE_INTERNAL_FIELD_COUNT=1 -D V8_SHORT_BUILTIN_CALLS -D OBJECT_PRINT -D V8_INTL_SUPPORT -D V8_ATOMIC_OBJECT_FIELD_WRITES -D V8_ENABLE_LAZY_SOURCE_POSITIONS -D V8_USE_SIPHASH -D V8_SHARED_RO_HEAP -D V8_WIN64_UNWINDING_INFO -D V8_ENABLE_REGEXP_INTERPRETER_THREADED_DISPATCH -D V8_SNAPSHOT_COMPRESSION -D V8_ENABLE_WEBASSEMBLY -D V8_ENABLE_JAVASCRIPT_PROMISE_HOOKS -D V8_ALLOCATION_FOLDING -D V8_ALLOCATION_SITE_TRACKING -D V8_SCRIPTORMODULE_LEGACY_LIFETIME -D V8_ADVANCED_BIGINT_ALGORITHMS -D UCONFIG_NO_SERVICE=1 -D U_ENABLE_DYLOAD=0 -D U_STATIC_IMPLEMENTATION=1 -D U_HAVE_STD_STRING=1 -D UCONFIG_NO_BREAK_ITERATION=0 -I ../deps/v8 -I ../deps/v8/include -I /home/maurizio/node-v18.6.0/out/Release/obj/gen/generate-bytecode-output-root -I /home/maurizio/node-v18.6.0/out/Release/obj/gen -I ../deps/icu-small/source/i18n -I ../deps/icu-small/source/common -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8 -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/x86_64-redhat-linux -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/backward -internal-isystem /usr/local/lib/clang/16.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -Wno-unused-parameter -Wno-return-type -std=gnu++17 -fdeprecated-macro -fdebug-compilation-dir=/home/maurizio/node-v18.6.0/out -ferror-limit 19 -fno-rtti -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-08-22-142216-507842-1 -x c++ ../deps/v8/src/compiler/common-operator.cc

../deps/v8/src/compiler/common-operator.cc

1// Copyright 2014 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
5#include "src/compiler/common-operator.h"
6
7#include "src/base/lazy-instance.h"
8#include "src/compiler/linkage.h"
9#include "src/compiler/node.h"
10#include "src/compiler/opcodes.h"
11#include "src/compiler/operator.h"
12#include "src/handles/handles-inl.h"
13#include "src/zone/zone.h"
14
15namespace v8 {
16namespace internal {
17namespace compiler {
18
19std::ostream& operator<<(std::ostream& os, BranchHint hint) {
20 switch (hint) {
21 case BranchHint::kNone:
22 return os << "None";
23 case BranchHint::kTrue:
24 return os << "True";
25 case BranchHint::kFalse:
26 return os << "False";
27 }
28 UNREACHABLE()V8_Fatal("unreachable code");
29}
30
31std::ostream& operator<<(std::ostream& os, TrapId trap_id) {
32 switch (trap_id) {
33#define TRAP_CASE(Name) \
34 case TrapId::k##Name: \
35 return os << #Name;
36 FOREACH_WASM_TRAPREASON(TRAP_CASE)TRAP_CASE(TrapUnreachable) TRAP_CASE(TrapMemOutOfBounds) TRAP_CASE
(TrapUnalignedAccess) TRAP_CASE(TrapDivByZero) TRAP_CASE(TrapDivUnrepresentable
) TRAP_CASE(TrapRemByZero) TRAP_CASE(TrapFloatUnrepresentable
) TRAP_CASE(TrapFuncSigMismatch) TRAP_CASE(TrapDataSegmentOutOfBounds
) TRAP_CASE(TrapElemSegmentDropped) TRAP_CASE(TrapTableOutOfBounds
) TRAP_CASE(TrapRethrowNull) TRAP_CASE(TrapNullDereference) TRAP_CASE
(TrapIllegalCast) TRAP_CASE(TrapArrayOutOfBounds) TRAP_CASE(TrapArrayTooLarge
)
37#undef TRAP_CASE
38 case TrapId::kInvalid:
39 return os << "Invalid";
40 }
41 UNREACHABLE()V8_Fatal("unreachable code");
42}
43
44TrapId TrapIdOf(const Operator* const op) {
45 DCHECK(op->opcode() == IrOpcode::kTrapIf ||((void) 0)
46 op->opcode() == IrOpcode::kTrapUnless)((void) 0);
47 return OpParameter<TrapId>(op);
48}
49
50BranchHint BranchHintOf(const Operator* const op) {
51 switch (op->opcode()) {
52 case IrOpcode::kIfValue:
53 return IfValueParametersOf(op).hint();
54 case IrOpcode::kIfDefault:
55 case IrOpcode::kBranch:
56 return OpParameter<BranchHint>(op);
57 default:
58 UNREACHABLE()V8_Fatal("unreachable code");
59 }
60}
61
62int ValueInputCountOfReturn(Operator const* const op) {
63 DCHECK_EQ(IrOpcode::kReturn, op->opcode())((void) 0);
64 // Return nodes have a hidden input at index 0 which we ignore in the value
65 // input count.
66 return op->ValueInputCount() - 1;
67}
68
69bool operator==(DeoptimizeParameters lhs, DeoptimizeParameters rhs) {
70 return lhs.reason() == rhs.reason() && lhs.feedback() == rhs.feedback();
71}
72
73bool operator!=(DeoptimizeParameters lhs, DeoptimizeParameters rhs) {
74 return !(lhs == rhs);
75}
76
77size_t hash_value(DeoptimizeParameters p) {
78 FeedbackSource::Hash feebdack_hash;
79 return base::hash_combine(p.reason(), feebdack_hash(p.feedback()));
80}
81
82std::ostream& operator<<(std::ostream& os, DeoptimizeParameters p) {
83 return os << p.reason() << ", " << p.feedback();
84}
85
86DeoptimizeParameters const& DeoptimizeParametersOf(Operator const* const op) {
87 DCHECK(op->opcode() == IrOpcode::kDeoptimize ||((void) 0)
88 op->opcode() == IrOpcode::kDeoptimizeIf ||((void) 0)
89 op->opcode() == IrOpcode::kDeoptimizeUnless)((void) 0);
90 return OpParameter<DeoptimizeParameters>(op);
91}
92
93const Operator* CommonOperatorBuilder::DelayedStringConstant(
94 const StringConstantBase* str) {
95 return zone()->New<Operator1<const StringConstantBase*>>(
96 IrOpcode::kDelayedStringConstant, Operator::kPure,
97 "DelayedStringConstant", 0, 0, 0, 1, 0, 0, str);
98}
99
100bool operator==(SelectParameters const& lhs, SelectParameters const& rhs) {
101 return lhs.representation() == rhs.representation() &&
102 lhs.hint() == rhs.hint();
103}
104
105
106bool operator!=(SelectParameters const& lhs, SelectParameters const& rhs) {
107 return !(lhs == rhs);
108}
109
110
111size_t hash_value(SelectParameters const& p) {
112 return base::hash_combine(p.representation(), p.hint());
113}
114
115
116std::ostream& operator<<(std::ostream& os, SelectParameters const& p) {
117 return os << p.representation() << ", " << p.hint();
118}
119
120
121SelectParameters const& SelectParametersOf(const Operator* const op) {
122 DCHECK_EQ(IrOpcode::kSelect, op->opcode())((void) 0);
123 return OpParameter<SelectParameters>(op);
124}
125
126CallDescriptor const* CallDescriptorOf(const Operator* const op) {
127 DCHECK(op->opcode() == IrOpcode::kCall ||((void) 0)
128 op->opcode() == IrOpcode::kTailCall)((void) 0);
129 return OpParameter<CallDescriptor const*>(op);
130}
131
132size_t ProjectionIndexOf(const Operator* const op) {
133 DCHECK_EQ(IrOpcode::kProjection, op->opcode())((void) 0);
134 return OpParameter<size_t>(op);
135}
136
137
138MachineRepresentation PhiRepresentationOf(const Operator* const op) {
139 DCHECK_EQ(IrOpcode::kPhi, op->opcode())((void) 0);
140 return OpParameter<MachineRepresentation>(op);
141}
142
143MachineRepresentation LoopExitValueRepresentationOf(const Operator* const op) {
144 DCHECK_EQ(IrOpcode::kLoopExitValue, op->opcode())((void) 0);
145 return OpParameter<MachineRepresentation>(op);
146}
147
148int ParameterIndexOf(const Operator* const op) {
149 DCHECK_EQ(IrOpcode::kParameter, op->opcode())((void) 0);
150 return OpParameter<ParameterInfo>(op).index();
151}
152
153
154const ParameterInfo& ParameterInfoOf(const Operator* const op) {
155 DCHECK_EQ(IrOpcode::kParameter, op->opcode())((void) 0);
156 return OpParameter<ParameterInfo>(op);
157}
158
159
160bool operator==(ParameterInfo const& lhs, ParameterInfo const& rhs) {
161 return lhs.index() == rhs.index();
162}
163
164
165bool operator!=(ParameterInfo const& lhs, ParameterInfo const& rhs) {
166 return !(lhs == rhs);
167}
168
169
170size_t hash_value(ParameterInfo const& p) { return p.index(); }
171
172
173std::ostream& operator<<(std::ostream& os, ParameterInfo const& i) {
174 os << i.index();
175 if (i.debug_name()) os << ", debug name: " << i.debug_name();
176 return os;
177}
178
179std::ostream& operator<<(std::ostream& os, ObjectStateInfo const& i) {
180 return os << "id:" << i.object_id() << ", size:" << i.size();
181}
182
183size_t hash_value(ObjectStateInfo const& p) {
184 return base::hash_combine(p.object_id(), p.size());
185}
186
187std::ostream& operator<<(std::ostream& os, TypedObjectStateInfo const& i) {
188 return os << "id:" << i.object_id() << ", " << i.machine_types();
189}
190
191size_t hash_value(TypedObjectStateInfo const& p) {
192 return base::hash_combine(p.object_id(), p.machine_types());
193}
194
195bool operator==(RelocatablePtrConstantInfo const& lhs,
196 RelocatablePtrConstantInfo const& rhs) {
197 return lhs.rmode() == rhs.rmode() && lhs.value() == rhs.value() &&
198 lhs.type() == rhs.type();
199}
200
201bool operator!=(RelocatablePtrConstantInfo const& lhs,
202 RelocatablePtrConstantInfo const& rhs) {
203 return !(lhs == rhs);
204}
205
206size_t hash_value(RelocatablePtrConstantInfo const& p) {
207 return base::hash_combine(p.value(), int8_t{p.rmode()}, p.type());
208}
209
210std::ostream& operator<<(std::ostream& os,
211 RelocatablePtrConstantInfo const& p) {
212 return os << p.value() << ", " << static_cast<int>(p.rmode()) << ", "
213 << p.type();
214}
215
216SparseInputMask::InputIterator::InputIterator(
217 SparseInputMask::BitMaskType bit_mask, Node* parent)
218 : bit_mask_(bit_mask), parent_(parent), real_index_(0) {
219#if DEBUG
220 if (bit_mask_ != SparseInputMask::kDenseBitMask) {
221 DCHECK_EQ(base::bits::CountPopulation(bit_mask_) -((void) 0)
222 base::bits::CountPopulation(kEndMarker),((void) 0)
223 parent->InputCount())((void) 0);
224 }
225#endif
226}
227
228void SparseInputMask::InputIterator::Advance() {
229 DCHECK(!IsEnd())((void) 0);
230
231 if (IsReal()) {
232 ++real_index_;
233 }
234 bit_mask_ >>= 1;
235}
236
237size_t SparseInputMask::InputIterator::AdvanceToNextRealOrEnd() {
238 DCHECK_NE(bit_mask_, SparseInputMask::kDenseBitMask)((void) 0);
239
240 size_t count = base::bits::CountTrailingZeros(bit_mask_);
1
Calling 'CountTrailingZeros<unsigned int, 32U>'
5
Returning from 'CountTrailingZeros<unsigned int, 32U>'
6
'count' initialized to 32
241 bit_mask_ >>= count;
7
Assigned value is garbage or undefined
242 DCHECK(IsReal() || IsEnd())((void) 0);
243 return count;
244}
245
246Node* SparseInputMask::InputIterator::GetReal() const {
247 DCHECK(IsReal())((void) 0);
248 return parent_->InputAt(real_index_);
249}
250
251bool SparseInputMask::InputIterator::IsReal() const {
252 return bit_mask_ == SparseInputMask::kDenseBitMask ||
253 (bit_mask_ & kEntryMask);
254}
255
256bool SparseInputMask::InputIterator::IsEnd() const {
257 return (bit_mask_ == kEndMarker) ||
258 (bit_mask_ == SparseInputMask::kDenseBitMask &&
259 real_index_ >= parent_->InputCount());
260}
261
262int SparseInputMask::CountReal() const {
263 DCHECK(!IsDense())((void) 0);
264 return base::bits::CountPopulation(bit_mask_) -
265 base::bits::CountPopulation(kEndMarker);
266}
267
268SparseInputMask::InputIterator SparseInputMask::IterateOverInputs(Node* node) {
269 DCHECK(IsDense() || CountReal() == node->InputCount())((void) 0);
270 return InputIterator(bit_mask_, node);
271}
272
273bool operator==(SparseInputMask const& lhs, SparseInputMask const& rhs) {
274 return lhs.mask() == rhs.mask();
275}
276
277bool operator!=(SparseInputMask const& lhs, SparseInputMask const& rhs) {
278 return !(lhs == rhs);
279}
280
281size_t hash_value(SparseInputMask const& p) {
282 return base::hash_value(p.mask());
283}
284
285std::ostream& operator<<(std::ostream& os, SparseInputMask const& p) {
286 if (p.IsDense()) {
287 return os << "dense";
288 } else {
289 SparseInputMask::BitMaskType mask = p.mask();
290 DCHECK_NE(mask, SparseInputMask::kDenseBitMask)((void) 0);
291
292 os << "sparse:";
293
294 while (mask != SparseInputMask::kEndMarker) {
295 if (mask & SparseInputMask::kEntryMask) {
296 os << "^";
297 } else {
298 os << ".";
299 }
300 mask >>= 1;
301 }
302 return os;
303 }
304}
305
306bool operator==(TypedStateValueInfo const& lhs,
307 TypedStateValueInfo const& rhs) {
308 return lhs.machine_types() == rhs.machine_types() &&
309 lhs.sparse_input_mask() == rhs.sparse_input_mask();
310}
311
312bool operator!=(TypedStateValueInfo const& lhs,
313 TypedStateValueInfo const& rhs) {
314 return !(lhs == rhs);
315}
316
317size_t hash_value(TypedStateValueInfo const& p) {
318 return base::hash_combine(p.machine_types(), p.sparse_input_mask());
319}
320
321std::ostream& operator<<(std::ostream& os, TypedStateValueInfo const& p) {
322 return os << p.machine_types() << ", " << p.sparse_input_mask();
323}
324
325size_t hash_value(RegionObservability observability) {
326 return static_cast<size_t>(observability);
327}
328
329std::ostream& operator<<(std::ostream& os, RegionObservability observability) {
330 switch (observability) {
331 case RegionObservability::kObservable:
332 return os << "observable";
333 case RegionObservability::kNotObservable:
334 return os << "not-observable";
335 }
336 UNREACHABLE()V8_Fatal("unreachable code");
337}
338
339RegionObservability RegionObservabilityOf(Operator const* op) {
340 DCHECK_EQ(IrOpcode::kBeginRegion, op->opcode())((void) 0);
341 return OpParameter<RegionObservability>(op);
342}
343
344Type TypeGuardTypeOf(Operator const* op) {
345 DCHECK_EQ(IrOpcode::kTypeGuard, op->opcode())((void) 0);
346 return OpParameter<Type>(op);
347}
348
349std::ostream& operator<<(std::ostream& os,
350 const ZoneVector<MachineType>* types) {
351 // Print all the MachineTypes, separated by commas.
352 bool first = true;
353 for (MachineType elem : *types) {
354 if (!first) {
355 os << ", ";
356 }
357 first = false;
358 os << elem;
359 }
360 return os;
361}
362
363int OsrValueIndexOf(Operator const* op) {
364 DCHECK_EQ(IrOpcode::kOsrValue, op->opcode())((void) 0);
365 return OpParameter<int>(op);
366}
367
368SparseInputMask SparseInputMaskOf(Operator const* op) {
369 DCHECK(op->opcode() == IrOpcode::kStateValues ||((void) 0)
370 op->opcode() == IrOpcode::kTypedStateValues)((void) 0);
371
372 if (op->opcode() == IrOpcode::kTypedStateValues) {
373 return OpParameter<TypedStateValueInfo>(op).sparse_input_mask();
374 }
375 return OpParameter<SparseInputMask>(op);
376}
377
378ZoneVector<MachineType> const* MachineTypesOf(Operator const* op) {
379 DCHECK(op->opcode() == IrOpcode::kTypedObjectState ||((void) 0)
380 op->opcode() == IrOpcode::kTypedStateValues)((void) 0);
381
382 if (op->opcode() == IrOpcode::kTypedStateValues) {
383 return OpParameter<TypedStateValueInfo>(op).machine_types();
384 }
385 return OpParameter<TypedObjectStateInfo>(op).machine_types();
386}
387
388V8_EXPORT_PRIVATE bool operator==(IfValueParameters const& l,
389 IfValueParameters const& r) {
390 return l.value() == r.value() &&
391 l.comparison_order() == r.comparison_order() && l.hint() == r.hint();
392}
393
394size_t hash_value(IfValueParameters const& p) {
395 return base::hash_combine(p.value(), p.comparison_order(), p.hint());
396}
397
398V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& out,
399 IfValueParameters const& p) {
400 out << p.value() << " (order " << p.comparison_order() << ", hint "
401 << p.hint() << ")";
402 return out;
403}
404
405IfValueParameters const& IfValueParametersOf(const Operator* op) {
406 DCHECK(op->opcode() == IrOpcode::kIfValue)((void) 0);
407 return OpParameter<IfValueParameters>(op);
408}
409
410V8_EXPORT_PRIVATE bool operator==(const SLVerifierHintParameters& p1,
411 const SLVerifierHintParameters& p2) {
412 return p1.semantics() == p2.semantics() &&
413 p1.override_output_type() == p2.override_output_type();
414}
415
416size_t hash_value(const SLVerifierHintParameters& p) {
417 return base::hash_combine(
418 p.semantics(),
419 p.override_output_type() ? hash_value(*p.override_output_type()) : 0);
420}
421
422V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& out,
423 const SLVerifierHintParameters& p) {
424 if (p.semantics()) {
425 p.semantics()->PrintTo(out);
426 } else {
427 out << "nullptr";
428 }
429 out << ", ";
430 if (const auto& t = p.override_output_type()) {
431 t->PrintTo(out);
432 } else {
433 out << ", nullopt";
434 }
435 return out;
436}
437
438const SLVerifierHintParameters& SLVerifierHintParametersOf(const Operator* op) {
439 DCHECK_EQ(op->opcode(), IrOpcode::kSLVerifierHint)((void) 0);
440 return OpParameter<SLVerifierHintParameters>(op);
441}
442
443#define COMMON_CACHED_OP_LIST(V) \
444 V(Plug, Operator::kNoProperties, 0, 0, 0, 1, 0, 0) \
445 V(Dead, Operator::kFoldable, 0, 0, 0, 1, 1, 1) \
446 V(Unreachable, Operator::kFoldable, 0, 1, 1, 1, 1, 0) \
447 V(IfTrue, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
448 V(IfFalse, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
449 V(IfSuccess, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
450 V(IfException, Operator::kKontrol, 0, 1, 1, 1, 1, 1) \
451 V(Throw, Operator::kKontrol, 0, 1, 1, 0, 0, 1) \
452 V(Terminate, Operator::kKontrol, 0, 1, 1, 0, 0, 1) \
453 V(LoopExit, Operator::kKontrol, 0, 0, 2, 0, 0, 1) \
454 V(LoopExitEffect, Operator::kNoThrow, 0, 1, 1, 0, 1, 0) \
455 V(Checkpoint, Operator::kKontrol, 0, 1, 1, 0, 1, 0) \
456 V(FinishRegion, Operator::kKontrol, 1, 1, 0, 1, 1, 0) \
457 V(Retain, Operator::kKontrol, 1, 1, 0, 0, 1, 0)
458
459#define CACHED_LOOP_EXIT_VALUE_LIST(V)V(kTagged) V(kTagged)
460
461#define CACHED_BRANCH_LIST(V) \
462 V(None) \
463 V(True) \
464 V(False)
465
466#define CACHED_RETURN_LIST(V) \
467 V(1) \
468 V(2) \
469 V(3) \
470 V(4)
471
472#define CACHED_END_LIST(V) \
473 V(1) \
474 V(2) \
475 V(3) \
476 V(4) \
477 V(5) \
478 V(6) \
479 V(7) \
480 V(8)
481
482
483#define CACHED_EFFECT_PHI_LIST(V) \
484 V(1) \
485 V(2) \
486 V(3) \
487 V(4) \
488 V(5) \
489 V(6)
490
491#define CACHED_INDUCTION_VARIABLE_PHI_LIST(V) \
492 V(4) \
493 V(5) \
494 V(6) \
495 V(7)
496
497#define CACHED_LOOP_LIST(V) \
498 V(1) \
499 V(2)
500
501
502#define CACHED_MERGE_LIST(V) \
503 V(1) \
504 V(2) \
505 V(3) \
506 V(4) \
507 V(5) \
508 V(6) \
509 V(7) \
510 V(8)
511
512#define CACHED_DEOPTIMIZE_LIST(V) \
513 V(MinusZero) \
514 V(WrongMap) \
515 V(InsufficientTypeFeedbackForGenericKeyedAccess) \
516 V(InsufficientTypeFeedbackForGenericNamedAccess)
517
518#define CACHED_DEOPTIMIZE_IF_LIST(V) \
519 V(DivisionByZero) \
520 V(Hole) \
521 V(MinusZero) \
522 V(Overflow) \
523 V(Smi)
524
525#define CACHED_DEOPTIMIZE_UNLESS_LIST(V) \
526 V(LostPrecision) \
527 V(LostPrecisionOrNaN) \
528 V(NotAHeapNumber) \
529 V(NotANumberOrOddball) \
530 V(NotASmi) \
531 V(OutOfBounds) \
532 V(WrongInstanceType) \
533 V(WrongMap)
534
535#define CACHED_TRAP_IF_LIST(V) \
536 V(TrapDivUnrepresentable) \
537 V(TrapFloatUnrepresentable)
538
539// The reason for a trap.
540#define CACHED_TRAP_UNLESS_LIST(V) \
541 V(TrapUnreachable) \
542 V(TrapMemOutOfBounds) \
543 V(TrapDivByZero) \
544 V(TrapDivUnrepresentable) \
545 V(TrapRemByZero) \
546 V(TrapFloatUnrepresentable) \
547 V(TrapTableOutOfBounds) \
548 V(TrapFuncSigMismatch)
549
550#define CACHED_PARAMETER_LIST(V) \
551 V(0) \
552 V(1) \
553 V(2) \
554 V(3) \
555 V(4) \
556 V(5) \
557 V(6)
558
559
560#define CACHED_PHI_LIST(V) \
561 V(kTagged, 1) \
562 V(kTagged, 2) \
563 V(kTagged, 3) \
564 V(kTagged, 4) \
565 V(kTagged, 5) \
566 V(kTagged, 6) \
567 V(kBit, 2) \
568 V(kFloat64, 2) \
569 V(kWord32, 2)
570
571
572#define CACHED_PROJECTION_LIST(V) \
573 V(0) \
574 V(1)
575
576
577#define CACHED_STATE_VALUES_LIST(V) \
578 V(0) \
579 V(1) \
580 V(2) \
581 V(3) \
582 V(4) \
583 V(5) \
584 V(6) \
585 V(7) \
586 V(8) \
587 V(10) \
588 V(11) \
589 V(12) \
590 V(13) \
591 V(14)
592
593
594struct CommonOperatorGlobalCache final {
595#define CACHED(Name, properties, value_input_count, effect_input_count, \
596 control_input_count, value_output_count, effect_output_count, \
597 control_output_count) \
598 struct Name##Operator final : public Operator { \
599 Name##Operator() \
600 : Operator(IrOpcode::k##Name, properties, #Name, value_input_count, \
601 effect_input_count, control_input_count, \
602 value_output_count, effect_output_count, \
603 control_output_count) {} \
604 }; \
605 Name##Operator k##Name##Operator;
606 COMMON_CACHED_OP_LIST(CACHED)
607#undef CACHED
608
609 template <size_t kInputCount>
610 struct EndOperator final : public Operator {
611 EndOperator()
612 : Operator( // --
613 IrOpcode::kEnd, Operator::kKontrol, // opcode
614 "End", // name
615 0, 0, kInputCount, 0, 0, 0) {} // counts
616 };
617#define CACHED_END(input_count) \
618 EndOperator<input_count> kEnd##input_count##Operator;
619 CACHED_END_LIST(CACHED_END)
620#undef CACHED_END
621
622 template <size_t kValueInputCount>
623 struct ReturnOperator final : public Operator {
624 ReturnOperator()
625 : Operator( // --
626 IrOpcode::kReturn, Operator::kNoThrow, // opcode
627 "Return", // name
628 kValueInputCount + 1, 1, 1, 0, 0, 1) {} // counts
629 };
630#define CACHED_RETURN(value_input_count) \
631 ReturnOperator<value_input_count> kReturn##value_input_count##Operator;
632 CACHED_RETURN_LIST(CACHED_RETURN)
633#undef CACHED_RETURN
634
635 template <BranchHint hint>
636 struct BranchOperator final : public Operator1<BranchHint> {
637 BranchOperator()
638 : Operator1<BranchHint>( // --
639 IrOpcode::kBranch, Operator::kKontrol, // opcode
640 "Branch", // name
641 1, 0, 1, 0, 0, 2, // counts
642 hint) {} // parameter
643 };
644#define CACHED_BRANCH(Hint) \
645 BranchOperator<BranchHint::k##Hint> kBranch##Hint##Operator;
646 CACHED_BRANCH_LIST(CACHED_BRANCH)
647#undef CACHED_BRANCH
648
649 template <int kEffectInputCount>
650 struct EffectPhiOperator final : public Operator {
651 EffectPhiOperator()
652 : Operator( // --
653 IrOpcode::kEffectPhi, Operator::kKontrol, // opcode
654 "EffectPhi", // name
655 0, kEffectInputCount, 1, 0, 1, 0) {} // counts
656 };
657#define CACHED_EFFECT_PHI(input_count) \
658 EffectPhiOperator<input_count> kEffectPhi##input_count##Operator;
659 CACHED_EFFECT_PHI_LIST(CACHED_EFFECT_PHI)
660#undef CACHED_EFFECT_PHI
661
662 template <RegionObservability kRegionObservability>
663 struct BeginRegionOperator final : public Operator1<RegionObservability> {
664 BeginRegionOperator()
665 : Operator1<RegionObservability>( // --
666 IrOpcode::kBeginRegion, Operator::kKontrol, // opcode
667 "BeginRegion", // name
668 0, 1, 0, 0, 1, 0, // counts
669 kRegionObservability) {} // parameter
670 };
671 BeginRegionOperator<RegionObservability::kObservable>
672 kBeginRegionObservableOperator;
673 BeginRegionOperator<RegionObservability::kNotObservable>
674 kBeginRegionNotObservableOperator;
675
676 template <size_t kInputCount>
677 struct LoopOperator final : public Operator {
678 LoopOperator()
679 : Operator( // --
680 IrOpcode::kLoop, Operator::kKontrol, // opcode
681 "Loop", // name
682 0, 0, kInputCount, 0, 0, 1) {} // counts
683 };
684#define CACHED_LOOP(input_count) \
685 LoopOperator<input_count> kLoop##input_count##Operator;
686 CACHED_LOOP_LIST(CACHED_LOOP)
687#undef CACHED_LOOP
688
689 template <size_t kInputCount>
690 struct MergeOperator final : public Operator {
691 MergeOperator()
692 : Operator( // --
693 IrOpcode::kMerge, Operator::kKontrol, // opcode
694 "Merge", // name
695 0, 0, kInputCount, 0, 0, 1) {} // counts
696 };
697#define CACHED_MERGE(input_count) \
698 MergeOperator<input_count> kMerge##input_count##Operator;
699 CACHED_MERGE_LIST(CACHED_MERGE)
700#undef CACHED_MERGE
701
702 template <MachineRepresentation kRep>
703 struct LoopExitValueOperator final : public Operator1<MachineRepresentation> {
704 LoopExitValueOperator()
705 : Operator1<MachineRepresentation>(IrOpcode::kLoopExitValue,
706 Operator::kPure, "LoopExitValue", 1,
707 0, 1, 1, 0, 0, kRep) {}
708 };
709#define CACHED_LOOP_EXIT_VALUE(rep) \
710 LoopExitValueOperator<MachineRepresentation::rep> \
711 kLoopExitValue##rep##Operator;
712 CACHED_LOOP_EXIT_VALUE_LIST(CACHED_LOOP_EXIT_VALUE)CACHED_LOOP_EXIT_VALUE(kTagged)
713#undef CACHED_LOOP_EXIT_VALUE
714
715 template <DeoptimizeReason kReason>
716 struct DeoptimizeOperator final : public Operator1<DeoptimizeParameters> {
717 DeoptimizeOperator()
718 : Operator1<DeoptimizeParameters>( // --
719 IrOpcode::kDeoptimize, // opcode
720 Operator::kFoldable | Operator::kNoThrow, // properties
721 "Deoptimize", // name
722 1, 1, 1, 0, 0, 1, // counts
723 DeoptimizeParameters(kReason, FeedbackSource())) {}
724 };
725#define CACHED_DEOPTIMIZE(Reason) \
726 DeoptimizeOperator<DeoptimizeReason::k##Reason> kDeoptimize##Reason##Operator;
727 CACHED_DEOPTIMIZE_LIST(CACHED_DEOPTIMIZE)
728#undef CACHED_DEOPTIMIZE
729
730 template <DeoptimizeReason kReason>
731 struct DeoptimizeIfOperator final : public Operator1<DeoptimizeParameters> {
732 DeoptimizeIfOperator()
733 : Operator1<DeoptimizeParameters>( // --
734 IrOpcode::kDeoptimizeIf, // opcode
735 Operator::kFoldable | Operator::kNoThrow, // properties
736 "DeoptimizeIf", // name
737 2, 1, 1, 0, 1, 1, // counts
738 DeoptimizeParameters(kReason, FeedbackSource())) {}
739 };
740#define CACHED_DEOPTIMIZE_IF(Reason) \
741 DeoptimizeIfOperator<DeoptimizeReason::k##Reason> \
742 kDeoptimizeIf##Reason##Operator;
743 CACHED_DEOPTIMIZE_IF_LIST(CACHED_DEOPTIMIZE_IF)
744#undef CACHED_DEOPTIMIZE_IF
745
746 template <DeoptimizeReason kReason>
747 struct DeoptimizeUnlessOperator final
748 : public Operator1<DeoptimizeParameters> {
749 DeoptimizeUnlessOperator()
750 : Operator1<DeoptimizeParameters>( // --
751 IrOpcode::kDeoptimizeUnless, // opcode
752 Operator::kFoldable | Operator::kNoThrow, // properties
753 "DeoptimizeUnless", // name
754 2, 1, 1, 0, 1, 1, // counts
755 DeoptimizeParameters(kReason, FeedbackSource())) {}
756 };
757#define CACHED_DEOPTIMIZE_UNLESS(Reason) \
758 DeoptimizeUnlessOperator<DeoptimizeReason::k##Reason> \
759 kDeoptimizeUnless##Reason##Operator;
760 CACHED_DEOPTIMIZE_UNLESS_LIST(CACHED_DEOPTIMIZE_UNLESS)
761#undef CACHED_DEOPTIMIZE_UNLESS
762
763 template <TrapId trap_id>
764 struct TrapIfOperator final : public Operator1<TrapId> {
765 TrapIfOperator()
766 : Operator1<TrapId>( // --
767 IrOpcode::kTrapIf, // opcode
768 Operator::kFoldable | Operator::kNoThrow, // properties
769 "TrapIf", // name
770 1, 1, 1, 0, 0, 1, // counts
771 trap_id) {} // parameter
772 };
773#define CACHED_TRAP_IF(Trap) \
774 TrapIfOperator<TrapId::k##Trap> kTrapIf##Trap##Operator;
775 CACHED_TRAP_IF_LIST(CACHED_TRAP_IF)
776#undef CACHED_TRAP_IF
777
778 template <TrapId trap_id>
779 struct TrapUnlessOperator final : public Operator1<TrapId> {
780 TrapUnlessOperator()
781 : Operator1<TrapId>( // --
782 IrOpcode::kTrapUnless, // opcode
783 Operator::kFoldable | Operator::kNoThrow, // properties
784 "TrapUnless", // name
785 1, 1, 1, 0, 0, 1, // counts
786 trap_id) {} // parameter
787 };
788#define CACHED_TRAP_UNLESS(Trap) \
789 TrapUnlessOperator<TrapId::k##Trap> kTrapUnless##Trap##Operator;
790 CACHED_TRAP_UNLESS_LIST(CACHED_TRAP_UNLESS)
791#undef CACHED_TRAP_UNLESS
792
793 template <MachineRepresentation kRep, int kInputCount>
794 struct PhiOperator final : public Operator1<MachineRepresentation> {
795 PhiOperator()
796 : Operator1<MachineRepresentation>( //--
797 IrOpcode::kPhi, Operator::kPure, // opcode
798 "Phi", // name
799 kInputCount, 0, 1, 1, 0, 0, // counts
800 kRep) {} // parameter
801 };
802#define CACHED_PHI(rep, input_count) \
803 PhiOperator<MachineRepresentation::rep, input_count> \
804 kPhi##rep##input_count##Operator;
805 CACHED_PHI_LIST(CACHED_PHI)
806#undef CACHED_PHI
807
808 template <int kInputCount>
809 struct InductionVariablePhiOperator final : public Operator {
810 InductionVariablePhiOperator()
811 : Operator( //--
812 IrOpcode::kInductionVariablePhi, Operator::kPure, // opcode
813 "InductionVariablePhi", // name
814 kInputCount, 0, 1, 1, 0, 0) {} // counts
815 };
816#define CACHED_INDUCTION_VARIABLE_PHI(input_count) \
817 InductionVariablePhiOperator<input_count> \
818 kInductionVariablePhi##input_count##Operator;
819 CACHED_INDUCTION_VARIABLE_PHI_LIST(CACHED_INDUCTION_VARIABLE_PHI)
820#undef CACHED_INDUCTION_VARIABLE_PHI
821
822 template <int kIndex>
823 struct ParameterOperator final : public Operator1<ParameterInfo> {
824 ParameterOperator()
825 : Operator1<ParameterInfo>( // --
826 IrOpcode::kParameter, Operator::kPure, // opcode
827 "Parameter", // name
828 1, 0, 0, 1, 0, 0, // counts,
829 ParameterInfo(kIndex, nullptr)) {} // parameter and name
830 };
831#define CACHED_PARAMETER(index) \
832 ParameterOperator<index> kParameter##index##Operator;
833 CACHED_PARAMETER_LIST(CACHED_PARAMETER)
834#undef CACHED_PARAMETER
835
836 template <size_t kIndex>
837 struct ProjectionOperator final : public Operator1<size_t> {
838 ProjectionOperator()
839 : Operator1<size_t>( // --
840 IrOpcode::kProjection, // opcode
841 Operator::kPure, // flags
842 "Projection", // name
843 1, 0, 1, 1, 0, 0, // counts,
844 kIndex) {} // parameter
845 };
846#define CACHED_PROJECTION(index) \
847 ProjectionOperator<index> kProjection##index##Operator;
848 CACHED_PROJECTION_LIST(CACHED_PROJECTION)
849#undef CACHED_PROJECTION
850
851 template <int kInputCount>
852 struct StateValuesOperator final : public Operator1<SparseInputMask> {
853 StateValuesOperator()
854 : Operator1<SparseInputMask>( // --
855 IrOpcode::kStateValues, // opcode
856 Operator::kPure, // flags
857 "StateValues", // name
858 kInputCount, 0, 0, 1, 0, 0, // counts
859 SparseInputMask::Dense()) {} // parameter
860 };
861#define CACHED_STATE_VALUES(input_count) \
862 StateValuesOperator<input_count> kStateValues##input_count##Operator;
863 CACHED_STATE_VALUES_LIST(CACHED_STATE_VALUES)
864#undef CACHED_STATE_VALUES
865};
866
867namespace {
868DEFINE_LAZY_LEAKY_OBJECT_GETTER(CommonOperatorGlobalCache,CommonOperatorGlobalCache* GetCommonOperatorGlobalCache() { static
::v8::base::LeakyObject<CommonOperatorGlobalCache> object
{}; return object.get(); }
869 GetCommonOperatorGlobalCache)CommonOperatorGlobalCache* GetCommonOperatorGlobalCache() { static
::v8::base::LeakyObject<CommonOperatorGlobalCache> object
{}; return object.get(); }
870} // namespace
871
872CommonOperatorBuilder::CommonOperatorBuilder(Zone* zone)
873 : cache_(*GetCommonOperatorGlobalCache()), zone_(zone) {}
874
875#define CACHED(Name, properties, value_input_count, effect_input_count, \
876 control_input_count, value_output_count, effect_output_count, \
877 control_output_count) \
878 const Operator* CommonOperatorBuilder::Name() { \
879 return &cache_.k##Name##Operator; \
880 }
881COMMON_CACHED_OP_LIST(CACHED)
882#undef CACHED
883
884
885const Operator* CommonOperatorBuilder::End(size_t control_input_count) {
886 switch (control_input_count) {
887#define CACHED_END(input_count) \
888 case input_count: \
889 return &cache_.kEnd##input_count##Operator;
890 CACHED_END_LIST(CACHED_END)
891#undef CACHED_END
892 default:
893 break;
894 }
895 // Uncached.
896 return zone()->New<Operator>( //--
897 IrOpcode::kEnd, Operator::kKontrol, // opcode
898 "End", // name
899 0, 0, control_input_count, 0, 0, 0); // counts
900}
901
902const Operator* CommonOperatorBuilder::Return(int value_input_count) {
903 switch (value_input_count) {
904#define CACHED_RETURN(input_count) \
905 case input_count: \
906 return &cache_.kReturn##input_count##Operator;
907 CACHED_RETURN_LIST(CACHED_RETURN)
908#undef CACHED_RETURN
909 default:
910 break;
911 }
912 // Uncached.
913 return zone()->New<Operator>( //--
914 IrOpcode::kReturn, Operator::kNoThrow, // opcode
915 "Return", // name
916 value_input_count + 1, 1, 1, 0, 0, 1); // counts
917}
918
919const Operator* CommonOperatorBuilder::StaticAssert(const char* source) {
920 return zone()->New<Operator1<const char*>>(
921 IrOpcode::kStaticAssert, Operator::kFoldable, "StaticAssert", 1, 1, 0, 0,
922 1, 0, source);
923}
924
925const Operator* CommonOperatorBuilder::SLVerifierHint(
926 const Operator* semantics,
927 const base::Optional<Type>& override_output_type) {
928 return zone()->New<Operator1<SLVerifierHintParameters>>(
929 IrOpcode::kSLVerifierHint, Operator::kNoProperties, "SLVerifierHint", 1,
930 0, 0, 1, 0, 0, SLVerifierHintParameters(semantics, override_output_type));
931}
932
933const Operator* CommonOperatorBuilder::Branch(BranchHint hint) {
934#define CACHED_BRANCH(Hint) \
935 if (hint == BranchHint::k##Hint) { \
936 return &cache_.kBranch##Hint##Operator; \
937 }
938 CACHED_BRANCH_LIST(CACHED_BRANCH)
939#undef CACHED_BRANCH
940 UNREACHABLE()V8_Fatal("unreachable code");
941}
942
943const Operator* CommonOperatorBuilder::Deoptimize(
944 DeoptimizeReason reason, FeedbackSource const& feedback) {
945#define CACHED_DEOPTIMIZE(Reason) \
946 if (reason == DeoptimizeReason::k##Reason && !feedback.IsValid()) { \
947 return &cache_.kDeoptimize##Reason##Operator; \
948 }
949 CACHED_DEOPTIMIZE_LIST(CACHED_DEOPTIMIZE)
950#undef CACHED_DEOPTIMIZE
951 // Uncached
952 DeoptimizeParameters parameter(reason, feedback);
953 return zone()->New<Operator1<DeoptimizeParameters>>( // --
954 IrOpcode::kDeoptimize, // opcodes
955 Operator::kFoldable | Operator::kNoThrow, // properties
956 "Deoptimize", // name
957 1, 1, 1, 0, 0, 1, // counts
958 parameter); // parameter
959}
960
961const Operator* CommonOperatorBuilder::DeoptimizeIf(
962 DeoptimizeReason reason, FeedbackSource const& feedback) {
963#define CACHED_DEOPTIMIZE_IF(Reason) \
964 if (reason == DeoptimizeReason::k##Reason && !feedback.IsValid()) { \
965 return &cache_.kDeoptimizeIf##Reason##Operator; \
966 }
967 CACHED_DEOPTIMIZE_IF_LIST(CACHED_DEOPTIMIZE_IF)
968#undef CACHED_DEOPTIMIZE_IF
969 // Uncached
970 DeoptimizeParameters parameter(reason, feedback);
971 return zone()->New<Operator1<DeoptimizeParameters>>( // --
972 IrOpcode::kDeoptimizeIf, // opcode
973 Operator::kFoldable | Operator::kNoThrow, // properties
974 "DeoptimizeIf", // name
975 2, 1, 1, 0, 1, 1, // counts
976 parameter); // parameter
977}
978
979const Operator* CommonOperatorBuilder::DeoptimizeUnless(
980 DeoptimizeReason reason, FeedbackSource const& feedback) {
981#define CACHED_DEOPTIMIZE_UNLESS(Reason) \
982 if (reason == DeoptimizeReason::k##Reason && !feedback.IsValid()) { \
983 return &cache_.kDeoptimizeUnless##Reason##Operator; \
984 }
985 CACHED_DEOPTIMIZE_UNLESS_LIST(CACHED_DEOPTIMIZE_UNLESS)
986#undef CACHED_DEOPTIMIZE_UNLESS
987 // Uncached
988 DeoptimizeParameters parameter(reason, feedback);
989 return zone()->New<Operator1<DeoptimizeParameters>>( // --
990 IrOpcode::kDeoptimizeUnless, // opcode
991 Operator::kFoldable | Operator::kNoThrow, // properties
992 "DeoptimizeUnless", // name
993 2, 1, 1, 0, 1, 1, // counts
994 parameter); // parameter
995}
996
997const Operator* CommonOperatorBuilder::TrapIf(TrapId trap_id) {
998 switch (trap_id) {
999#define CACHED_TRAP_IF(Trap) \
1000 case TrapId::k##Trap: \
1001 return &cache_.kTrapIf##Trap##Operator;
1002 CACHED_TRAP_IF_LIST(CACHED_TRAP_IF)
1003#undef CACHED_TRAP_IF
1004 default:
1005 break;
1006 }
1007 // Uncached
1008 return zone()->New<Operator1<TrapId>>( // --
1009 IrOpcode::kTrapIf, // opcode
1010 Operator::kFoldable | Operator::kNoThrow, // properties
1011 "TrapIf", // name
1012 1, 1, 1, 0, 0, 1, // counts
1013 trap_id); // parameter
1014}
1015
1016const Operator* CommonOperatorBuilder::TrapUnless(TrapId trap_id) {
1017 switch (trap_id) {
1018#define CACHED_TRAP_UNLESS(Trap) \
1019 case TrapId::k##Trap: \
1020 return &cache_.kTrapUnless##Trap##Operator;
1021 CACHED_TRAP_UNLESS_LIST(CACHED_TRAP_UNLESS)
1022#undef CACHED_TRAP_UNLESS
1023 default:
1024 break;
1025 }
1026 // Uncached
1027 return zone()->New<Operator1<TrapId>>( // --
1028 IrOpcode::kTrapUnless, // opcode
1029 Operator::kFoldable | Operator::kNoThrow, // properties
1030 "TrapUnless", // name
1031 1, 1, 1, 0, 0, 1, // counts
1032 trap_id); // parameter
1033}
1034
1035const Operator* CommonOperatorBuilder::Switch(size_t control_output_count) {
1036 return zone()->New<Operator>( // --
1037 IrOpcode::kSwitch, Operator::kKontrol, // opcode
1038 "Switch", // name
1039 1, 0, 1, 0, 0, control_output_count); // counts
1040}
1041
1042const Operator* CommonOperatorBuilder::IfValue(int32_t index,
1043 int32_t comparison_order,
1044 BranchHint hint) {
1045 return zone()->New<Operator1<IfValueParameters>>( // --
1046 IrOpcode::kIfValue, Operator::kKontrol, // opcode
1047 "IfValue", // name
1048 0, 0, 1, 0, 0, 1, // counts
1049 IfValueParameters(index, comparison_order, hint)); // parameter
1050}
1051
1052const Operator* CommonOperatorBuilder::IfDefault(BranchHint hint) {
1053 return zone()->New<Operator1<BranchHint>>( // --
1054 IrOpcode::kIfDefault, Operator::kKontrol, // opcode
1055 "IfDefault", // name
1056 0, 0, 1, 0, 0, 1, // counts
1057 hint); // parameter
1058}
1059
1060const Operator* CommonOperatorBuilder::Start(int value_output_count) {
1061 return zone()->New<Operator>( // --
1062 IrOpcode::kStart, Operator::kFoldable | Operator::kNoThrow, // opcode
1063 "Start", // name
1064 0, 0, 0, value_output_count, 1, 1); // counts
1065}
1066
1067
1068const Operator* CommonOperatorBuilder::Loop(int control_input_count) {
1069 switch (control_input_count) {
1070#define CACHED_LOOP(input_count) \
1071 case input_count: \
1072 return &cache_.kLoop##input_count##Operator;
1073 CACHED_LOOP_LIST(CACHED_LOOP)
1074#undef CACHED_LOOP
1075 default:
1076 break;
1077 }
1078 // Uncached.
1079 return zone()->New<Operator>( // --
1080 IrOpcode::kLoop, Operator::kKontrol, // opcode
1081 "Loop", // name
1082 0, 0, control_input_count, 0, 0, 1); // counts
1083}
1084
1085
1086const Operator* CommonOperatorBuilder::Merge(int control_input_count) {
1087 switch (control_input_count) {
1088#define CACHED_MERGE(input_count) \
1089 case input_count: \
1090 return &cache_.kMerge##input_count##Operator;
1091 CACHED_MERGE_LIST(CACHED_MERGE)
1092#undef CACHED_MERGE
1093 default:
1094 break;
1095 }
1096 // Uncached.
1097 return zone()->New<Operator>( // --
1098 IrOpcode::kMerge, Operator::kKontrol, // opcode
1099 "Merge", // name
1100 0, 0, control_input_count, 0, 0, 1); // counts
1101}
1102
1103const Operator* CommonOperatorBuilder::LoopExitValue(
1104 MachineRepresentation rep) {
1105 switch (rep) {
1106#define CACHED_LOOP_EXIT_VALUE(kRep) \
1107 case MachineRepresentation::kRep: \
1108 return &cache_.kLoopExitValue##kRep##Operator;
1109
1110 CACHED_LOOP_EXIT_VALUE_LIST(CACHED_LOOP_EXIT_VALUE)CACHED_LOOP_EXIT_VALUE(kTagged)
1111#undef CACHED_LOOP_EXIT_VALUE
1112 default:
1113 // Uncached.
1114 return zone()->New<Operator1<MachineRepresentation>>( // --
1115 IrOpcode::kLoopExitValue, Operator::kPure, // opcode
1116 "LoopExitValue", // name
1117 1, 0, 1, 1, 0, 0, // counts
1118 rep); // parameter
1119 }
1120}
1121
1122const Operator* CommonOperatorBuilder::Parameter(int index,
1123 const char* debug_name) {
1124 if (!debug_name) {
1125 switch (index) {
1126#define CACHED_PARAMETER(index) \
1127 case index: \
1128 return &cache_.kParameter##index##Operator;
1129 CACHED_PARAMETER_LIST(CACHED_PARAMETER)
1130#undef CACHED_PARAMETER
1131 default:
1132 break;
1133 }
1134 }
1135 // Uncached.
1136 return zone()->New<Operator1<ParameterInfo>>( // --
1137 IrOpcode::kParameter, Operator::kPure, // opcode
1138 "Parameter", // name
1139 1, 0, 0, 1, 0, 0, // counts
1140 ParameterInfo(index, debug_name)); // parameter info
1141}
1142
1143const Operator* CommonOperatorBuilder::OsrValue(int index) {
1144 return zone()->New<Operator1<int>>( // --
1145 IrOpcode::kOsrValue, Operator::kNoProperties, // opcode
1146 "OsrValue", // name
1147 0, 0, 1, 1, 0, 0, // counts
1148 index); // parameter
1149}
1150
1151const Operator* CommonOperatorBuilder::Int32Constant(int32_t value) {
1152 return zone()->New<Operator1<int32_t>>( // --
1153 IrOpcode::kInt32Constant, Operator::kPure, // opcode
1154 "Int32Constant", // name
1155 0, 0, 0, 1, 0, 0, // counts
1156 value); // parameter
1157}
1158
1159
1160const Operator* CommonOperatorBuilder::Int64Constant(int64_t value) {
1161 return zone()->New<Operator1<int64_t>>( // --
1162 IrOpcode::kInt64Constant, Operator::kPure, // opcode
1163 "Int64Constant", // name
1164 0, 0, 0, 1, 0, 0, // counts
1165 value); // parameter
1166}
1167
1168const Operator* CommonOperatorBuilder::TaggedIndexConstant(int32_t value) {
1169 return zone()->New<Operator1<int32_t>>( // --
1170 IrOpcode::kTaggedIndexConstant, Operator::kPure, // opcode
1171 "TaggedIndexConstant", // name
1172 0, 0, 0, 1, 0, 0, // counts
1173 value); // parameter
1174}
1175
1176const Operator* CommonOperatorBuilder::Float32Constant(volatile float value) {
1177 return zone()->New<Operator1<float>>( // --
1178 IrOpcode::kFloat32Constant, Operator::kPure, // opcode
1179 "Float32Constant", // name
1180 0, 0, 0, 1, 0, 0, // counts
1181 value); // parameter
1182}
1183
1184
1185const Operator* CommonOperatorBuilder::Float64Constant(volatile double value) {
1186 return zone()->New<Operator1<double>>( // --
1187 IrOpcode::kFloat64Constant, Operator::kPure, // opcode
1188 "Float64Constant", // name
1189 0, 0, 0, 1, 0, 0, // counts
1190 value); // parameter
1191}
1192
1193
1194const Operator* CommonOperatorBuilder::ExternalConstant(
1195 const ExternalReference& value) {
1196 return zone()->New<Operator1<ExternalReference>>( // --
1197 IrOpcode::kExternalConstant, Operator::kPure, // opcode
1198 "ExternalConstant", // name
1199 0, 0, 0, 1, 0, 0, // counts
1200 value); // parameter
1201}
1202
1203
1204const Operator* CommonOperatorBuilder::NumberConstant(volatile double value) {
1205 return zone()->New<Operator1<double>>( // --
1206 IrOpcode::kNumberConstant, Operator::kPure, // opcode
1207 "NumberConstant", // name
1208 0, 0, 0, 1, 0, 0, // counts
1209 value); // parameter
1210}
1211
1212const Operator* CommonOperatorBuilder::PointerConstant(intptr_t value) {
1213 return zone()->New<Operator1<intptr_t>>( // --
1214 IrOpcode::kPointerConstant, Operator::kPure, // opcode
1215 "PointerConstant", // name
1216 0, 0, 0, 1, 0, 0, // counts
1217 value); // parameter
1218}
1219
1220const Operator* CommonOperatorBuilder::HeapConstant(
1221 const Handle<HeapObject>& value) {
1222 return zone()->New<Operator1<Handle<HeapObject>>>( // --
1223 IrOpcode::kHeapConstant, Operator::kPure, // opcode
1224 "HeapConstant", // name
1225 0, 0, 0, 1, 0, 0, // counts
1226 value); // parameter
1227}
1228
1229const Operator* CommonOperatorBuilder::CompressedHeapConstant(
1230 const Handle<HeapObject>& value) {
1231 return zone()->New<Operator1<Handle<HeapObject>>>( // --
1232 IrOpcode::kCompressedHeapConstant, Operator::kPure, // opcode
1233 "CompressedHeapConstant", // name
1234 0, 0, 0, 1, 0, 0, // counts
1235 value); // parameter
1236}
1237
1238Handle<HeapObject> HeapConstantOf(const Operator* op) {
1239 DCHECK(IrOpcode::kHeapConstant == op->opcode() ||((void) 0)
1240 IrOpcode::kCompressedHeapConstant == op->opcode())((void) 0);
1241 return OpParameter<Handle<HeapObject>>(op);
1242}
1243
1244const StringConstantBase* StringConstantBaseOf(const Operator* op) {
1245 DCHECK_EQ(IrOpcode::kDelayedStringConstant, op->opcode())((void) 0);
1246 return OpParameter<const StringConstantBase*>(op);
1247}
1248
1249const char* StaticAssertSourceOf(const Operator* op) {
1250 DCHECK_EQ(IrOpcode::kStaticAssert, op->opcode())((void) 0);
1251 return OpParameter<const char*>(op);
1252}
1253
1254const Operator* CommonOperatorBuilder::RelocatableInt32Constant(
1255 int32_t value, RelocInfo::Mode rmode) {
1256 return zone()->New<Operator1<RelocatablePtrConstantInfo>>( // --
1257 IrOpcode::kRelocatableInt32Constant, Operator::kPure, // opcode
1258 "RelocatableInt32Constant", // name
1259 0, 0, 0, 1, 0, 0, // counts
1260 RelocatablePtrConstantInfo(value, rmode)); // parameter
1261}
1262
1263const Operator* CommonOperatorBuilder::RelocatableInt64Constant(
1264 int64_t value, RelocInfo::Mode rmode) {
1265 return zone()->New<Operator1<RelocatablePtrConstantInfo>>( // --
1266 IrOpcode::kRelocatableInt64Constant, Operator::kPure, // opcode
1267 "RelocatableInt64Constant", // name
1268 0, 0, 0, 1, 0, 0, // counts
1269 RelocatablePtrConstantInfo(value, rmode)); // parameter
1270}
1271
1272const Operator* CommonOperatorBuilder::ObjectId(uint32_t object_id) {
1273 return zone()->New<Operator1<uint32_t>>( // --
1274 IrOpcode::kObjectId, Operator::kPure, // opcode
1275 "ObjectId", // name
1276 0, 0, 0, 1, 0, 0, // counts
1277 object_id); // parameter
1278}
1279
1280const Operator* CommonOperatorBuilder::Select(MachineRepresentation rep,
1281 BranchHint hint) {
1282 return zone()->New<Operator1<SelectParameters>>( // --
1283 IrOpcode::kSelect, Operator::kPure, // opcode
1284 "Select", // name
1285 3, 0, 0, 1, 0, 0, // counts
1286 SelectParameters(rep, hint)); // parameter
1287}
1288
1289
1290const Operator* CommonOperatorBuilder::Phi(MachineRepresentation rep,
1291 int value_input_count) {
1292 DCHECK_LT(0, value_input_count)((void) 0); // Disallow empty phis.
1293#define CACHED_PHI(kRep, kValueInputCount) \
1294 if (MachineRepresentation::kRep == rep && \
1295 kValueInputCount == value_input_count) { \
1296 return &cache_.kPhi##kRep##kValueInputCount##Operator; \
1297 }
1298 CACHED_PHI_LIST(CACHED_PHI)
1299#undef CACHED_PHI
1300 // Uncached.
1301 return zone()->New<Operator1<MachineRepresentation>>( // --
1302 IrOpcode::kPhi, Operator::kPure, // opcode
1303 "Phi", // name
1304 value_input_count, 0, 1, 1, 0, 0, // counts
1305 rep); // parameter
1306}
1307
1308const Operator* CommonOperatorBuilder::TypeGuard(Type type) {
1309 return zone()->New<Operator1<Type>>( // --
1310 IrOpcode::kTypeGuard, Operator::kPure, // opcode
1311 "TypeGuard", // name
1312 1, 1, 1, 1, 1, 0, // counts
1313 type); // parameter
1314}
1315
1316const Operator* CommonOperatorBuilder::FoldConstant() {
1317 return zone()->New<Operator>( // --
1318 IrOpcode::kFoldConstant, Operator::kPure, // opcode
1319 "FoldConstant", // name
1320 2, 0, 0, 1, 0, 0); // counts
1321}
1322
1323const Operator* CommonOperatorBuilder::EffectPhi(int effect_input_count) {
1324 DCHECK_LT(0, effect_input_count)((void) 0); // Disallow empty effect phis.
1325 switch (effect_input_count) {
1326#define CACHED_EFFECT_PHI(input_count) \
1327 case input_count: \
1328 return &cache_.kEffectPhi##input_count##Operator;
1329 CACHED_EFFECT_PHI_LIST(CACHED_EFFECT_PHI)
1330#undef CACHED_EFFECT_PHI
1331 default:
1332 break;
1333 }
1334 // Uncached.
1335 return zone()->New<Operator>( // --
1336 IrOpcode::kEffectPhi, Operator::kKontrol, // opcode
1337 "EffectPhi", // name
1338 0, effect_input_count, 1, 0, 1, 0); // counts
1339}
1340
1341const Operator* CommonOperatorBuilder::InductionVariablePhi(int input_count) {
1342 DCHECK_LE(4, input_count)((void) 0); // There must be always the entry, backedge,
1343 // increment and at least one bound.
1344 switch (input_count) {
1345#define CACHED_INDUCTION_VARIABLE_PHI(input_count) \
1346 case input_count: \
1347 return &cache_.kInductionVariablePhi##input_count##Operator;
1348 CACHED_INDUCTION_VARIABLE_PHI_LIST(CACHED_INDUCTION_VARIABLE_PHI)
1349#undef CACHED_INDUCTION_VARIABLE_PHI
1350 default:
1351 break;
1352 }
1353 // Uncached.
1354 return zone()->New<Operator>( // --
1355 IrOpcode::kInductionVariablePhi, Operator::kPure, // opcode
1356 "InductionVariablePhi", // name
1357 input_count, 0, 1, 1, 0, 0); // counts
1358}
1359
1360const Operator* CommonOperatorBuilder::BeginRegion(
1361 RegionObservability region_observability) {
1362 switch (region_observability) {
1363 case RegionObservability::kObservable:
1364 return &cache_.kBeginRegionObservableOperator;
1365 case RegionObservability::kNotObservable:
1366 return &cache_.kBeginRegionNotObservableOperator;
1367 }
1368 UNREACHABLE()V8_Fatal("unreachable code");
1369}
1370
1371const Operator* CommonOperatorBuilder::StateValues(int arguments,
1372 SparseInputMask bitmask) {
1373 if (bitmask.IsDense()) {
1374 switch (arguments) {
1375#define CACHED_STATE_VALUES(arguments) \
1376 case arguments: \
1377 return &cache_.kStateValues##arguments##Operator;
1378 CACHED_STATE_VALUES_LIST(CACHED_STATE_VALUES)
1379#undef CACHED_STATE_VALUES
1380 default:
1381 break;
1382 }
1383 }
1384
1385#if DEBUG
1386 DCHECK(bitmask.IsDense() || bitmask.CountReal() == arguments)((void) 0);
1387#endif
1388
1389 // Uncached.
1390 return zone()->New<Operator1<SparseInputMask>>( // --
1391 IrOpcode::kStateValues, Operator::kPure, // opcode
1392 "StateValues", // name
1393 arguments, 0, 0, 1, 0, 0, // counts
1394 bitmask); // parameter
1395}
1396
1397const Operator* CommonOperatorBuilder::TypedStateValues(
1398 const ZoneVector<MachineType>* types, SparseInputMask bitmask) {
1399#if DEBUG
1400 DCHECK(bitmask.IsDense() ||((void) 0)
1401 bitmask.CountReal() == static_cast<int>(types->size()))((void) 0);
1402#endif
1403
1404 return zone()->New<Operator1<TypedStateValueInfo>>( // --
1405 IrOpcode::kTypedStateValues, Operator::kPure, // opcode
1406 "TypedStateValues", // name
1407 static_cast<int>(types->size()), 0, 0, 1, 0, 0, // counts
1408 TypedStateValueInfo(types, bitmask)); // parameters
1409}
1410
1411const Operator* CommonOperatorBuilder::ArgumentsElementsState(
1412 ArgumentsStateType type) {
1413 return zone()->New<Operator1<ArgumentsStateType>>( // --
1414 IrOpcode::kArgumentsElementsState, Operator::kPure, // opcode
1415 "ArgumentsElementsState", // name
1416 0, 0, 0, 1, 0, 0, // counts
1417 type); // parameter
1418}
1419
1420const Operator* CommonOperatorBuilder::ArgumentsLengthState() {
1421 return zone()->New<Operator>( // --
1422 IrOpcode::kArgumentsLengthState, Operator::kPure, // opcode
1423 "ArgumentsLengthState", // name
1424 0, 0, 0, 1, 0, 0); // counts
1425}
1426
1427ArgumentsStateType ArgumentsStateTypeOf(Operator const* op) {
1428 DCHECK(op->opcode() == IrOpcode::kArgumentsElementsState)((void) 0);
1429 return OpParameter<ArgumentsStateType>(op);
1430}
1431
1432const Operator* CommonOperatorBuilder::ObjectState(uint32_t object_id,
1433 int pointer_slots) {
1434 return zone()->New<Operator1<ObjectStateInfo>>( // --
1435 IrOpcode::kObjectState, Operator::kPure, // opcode
1436 "ObjectState", // name
1437 pointer_slots, 0, 0, 1, 0, 0, // counts
1438 ObjectStateInfo{object_id, pointer_slots}); // parameter
1439}
1440
1441const Operator* CommonOperatorBuilder::TypedObjectState(
1442 uint32_t object_id, const ZoneVector<MachineType>* types) {
1443 return zone()->New<Operator1<TypedObjectStateInfo>>( // --
1444 IrOpcode::kTypedObjectState, Operator::kPure, // opcode
1445 "TypedObjectState", // name
1446 static_cast<int>(types->size()), 0, 0, 1, 0, 0, // counts
1447 TypedObjectStateInfo(object_id, types)); // parameter
1448}
1449
1450uint32_t ObjectIdOf(Operator const* op) {
1451 switch (op->opcode()) {
1452 case IrOpcode::kObjectState:
1453 return OpParameter<ObjectStateInfo>(op).object_id();
1454 case IrOpcode::kTypedObjectState:
1455 return OpParameter<TypedObjectStateInfo>(op).object_id();
1456 case IrOpcode::kObjectId:
1457 return OpParameter<uint32_t>(op);
1458 default:
1459 UNREACHABLE()V8_Fatal("unreachable code");
1460 }
1461}
1462
1463MachineRepresentation DeadValueRepresentationOf(Operator const* op) {
1464 DCHECK_EQ(IrOpcode::kDeadValue, op->opcode())((void) 0);
1465 return OpParameter<MachineRepresentation>(op);
1466}
1467
1468const Operator* CommonOperatorBuilder::FrameState(
1469 BytecodeOffset bailout_id, OutputFrameStateCombine state_combine,
1470 const FrameStateFunctionInfo* function_info) {
1471 FrameStateInfo state_info(bailout_id, state_combine, function_info);
1472 return zone()->New<Operator1<FrameStateInfo>>( // --
1473 IrOpcode::kFrameState, Operator::kPure, // opcode
1474 "FrameState", // name
1475 5, 0, 0, 1, 0, 0, // counts
1476 state_info); // parameter
1477}
1478
1479const Operator* CommonOperatorBuilder::Call(
1480 const CallDescriptor* call_descriptor) {
1481 class CallOperator final : public Operator1<const CallDescriptor*> {
1482 public:
1483 explicit CallOperator(const CallDescriptor* call_descriptor)
1484 : Operator1<const CallDescriptor*>(
1485 IrOpcode::kCall, call_descriptor->properties(), "Call",
1486 call_descriptor->InputCount() +
1487 call_descriptor->FrameStateCount(),
1488 Operator::ZeroIfPure(call_descriptor->properties()),
1489 Operator::ZeroIfEliminatable(call_descriptor->properties()),
1490 call_descriptor->ReturnCount(),
1491 Operator::ZeroIfPure(call_descriptor->properties()),
1492 Operator::ZeroIfNoThrow(call_descriptor->properties()),
1493 call_descriptor) {}
1494
1495 void PrintParameter(std::ostream& os,
1496 PrintVerbosity verbose) const override {
1497 os << "[" << *parameter() << "]";
1498 }
1499 };
1500 return zone()->New<CallOperator>(call_descriptor);
1501}
1502
1503const Operator* CommonOperatorBuilder::TailCall(
1504 const CallDescriptor* call_descriptor) {
1505 class TailCallOperator final : public Operator1<const CallDescriptor*> {
1506 public:
1507 explicit TailCallOperator(const CallDescriptor* call_descriptor)
1508 : Operator1<const CallDescriptor*>(
1509 IrOpcode::kTailCall,
1510 call_descriptor->properties() | Operator::kNoThrow, "TailCall",
1511 call_descriptor->InputCount() +
1512 call_descriptor->FrameStateCount(),
1513 1, 1, 0, 0, 1, call_descriptor) {}
1514
1515 void PrintParameter(std::ostream& os,
1516 PrintVerbosity verbose) const override {
1517 os << "[" << *parameter() << "]";
1518 }
1519 };
1520 return zone()->New<TailCallOperator>(call_descriptor);
1521}
1522
1523const Operator* CommonOperatorBuilder::Projection(size_t index) {
1524 switch (index) {
1525#define CACHED_PROJECTION(index) \
1526 case index: \
1527 return &cache_.kProjection##index##Operator;
1528 CACHED_PROJECTION_LIST(CACHED_PROJECTION)
1529#undef CACHED_PROJECTION
1530 default:
1531 break;
1532 }
1533 // Uncached.
1534 return zone()->New<Operator1<size_t>>( // --
1535 IrOpcode::kProjection, // opcode
1536 Operator::kPure, // flags
1537 "Projection", // name
1538 1, 0, 1, 1, 0, 0, // counts
1539 index); // parameter
1540}
1541
1542
1543const Operator* CommonOperatorBuilder::ResizeMergeOrPhi(const Operator* op,
1544 int size) {
1545 if (op->opcode() == IrOpcode::kPhi) {
1546 return Phi(PhiRepresentationOf(op), size);
1547 } else if (op->opcode() == IrOpcode::kEffectPhi) {
1548 return EffectPhi(size);
1549 } else if (op->opcode() == IrOpcode::kMerge) {
1550 return Merge(size);
1551 } else if (op->opcode() == IrOpcode::kLoop) {
1552 return Loop(size);
1553 } else {
1554 UNREACHABLE()V8_Fatal("unreachable code");
1555 }
1556}
1557
1558const FrameStateFunctionInfo*
1559CommonOperatorBuilder::CreateFrameStateFunctionInfo(
1560 FrameStateType type, int parameter_count, int local_count,
1561 Handle<SharedFunctionInfo> shared_info) {
1562 return zone()->New<FrameStateFunctionInfo>(type, parameter_count, local_count,
1563 shared_info);
1564}
1565
1566#if V8_ENABLE_WEBASSEMBLY1
1567const FrameStateFunctionInfo*
1568CommonOperatorBuilder::CreateJSToWasmFrameStateFunctionInfo(
1569 FrameStateType type, int parameter_count, int local_count,
1570 Handle<SharedFunctionInfo> shared_info,
1571 const wasm::FunctionSig* signature) {
1572 DCHECK_EQ(type, FrameStateType::kJSToWasmBuiltinContinuation)((void) 0);
1573 DCHECK_NOT_NULL(signature)((void) 0);
1574 return zone()->New<JSToWasmFrameStateFunctionInfo>(
1575 type, parameter_count, local_count, shared_info, signature);
1576}
1577#endif // V8_ENABLE_WEBASSEMBLY
1578
1579const Operator* CommonOperatorBuilder::DeadValue(MachineRepresentation rep) {
1580 return zone()->New<Operator1<MachineRepresentation>>( // --
1581 IrOpcode::kDeadValue, Operator::kPure, // opcode
1582 "DeadValue", // name
1583 1, 0, 0, 1, 0, 0, // counts
1584 rep); // parameter
1585}
1586
1587const FrameStateInfo& FrameStateInfoOf(const Operator* op) {
1588 DCHECK_EQ(IrOpcode::kFrameState, op->opcode())((void) 0);
1589 return OpParameter<FrameStateInfo>(op);
1590}
1591
1592#undef COMMON_CACHED_OP_LIST
1593#undef CACHED_BRANCH_LIST
1594#undef CACHED_RETURN_LIST
1595#undef CACHED_END_LIST
1596#undef CACHED_EFFECT_PHI_LIST
1597#undef CACHED_INDUCTION_VARIABLE_PHI_LIST
1598#undef CACHED_LOOP_LIST
1599#undef CACHED_MERGE_LIST
1600#undef CACHED_DEOPTIMIZE_LIST
1601#undef CACHED_DEOPTIMIZE_IF_LIST
1602#undef CACHED_DEOPTIMIZE_UNLESS_LIST
1603#undef CACHED_TRAP_IF_LIST
1604#undef CACHED_TRAP_UNLESS_LIST
1605#undef CACHED_PARAMETER_LIST
1606#undef CACHED_PHI_LIST
1607#undef CACHED_PROJECTION_LIST
1608#undef CACHED_STATE_VALUES_LIST
1609
1610} // namespace compiler
1611} // namespace internal
1612} // namespace v8

../deps/v8/src/base/bits.h

1// Copyright 2014 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
5#ifndef V8_BASE_BITS_H_
6#define V8_BASE_BITS_H_
7
8#include <stdint.h>
9#include <type_traits>
10
11#include "src/base/base-export.h"
12#include "src/base/macros.h"
13#if V8_CC_MSVC
14#include <intrin.h>
15#endif
16#if V8_OS_WIN32
17#include "src/base/win32-headers.h"
18#endif
19
20namespace v8 {
21namespace base {
22namespace bits {
23
24// CountPopulation(value) returns the number of bits set in |value|.
25template <typename T>
26constexpr inline
27 typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) <= 8,
28 unsigned>::type
29 CountPopulation(T value) {
30 STATIC_ASSERT(sizeof(T) <= 8)static_assert(sizeof(T) <= 8, "sizeof(T) <= 8");
31#if V8_HAS_BUILTIN_POPCOUNT(1)
32 return sizeof(T) == 8 ? __builtin_popcountll(static_cast<uint64_t>(value))
33 : __builtin_popcount(static_cast<uint32_t>(value));
34#else
35 // Fall back to divide-and-conquer popcount (see "Hacker's Delight" by Henry
36 // S. Warren, Jr.), chapter 5-1.
37 constexpr uint64_t mask[] = {0x5555555555555555, 0x3333333333333333,
38 0x0f0f0f0f0f0f0f0f};
39 // Start with 64 buckets of 1 bits, holding values from [0,1].
40 value = ((value >> 1) & mask[0]) + (value & mask[0]);
41 // Having 32 buckets of 2 bits, holding values from [0,2] now.
42 value = ((value >> 2) & mask[1]) + (value & mask[1]);
43 // Having 16 buckets of 4 bits, holding values from [0,4] now.
44 value = ((value >> 4) & mask[2]) + (value & mask[2]);
45 // Having 8 buckets of 8 bits, holding values from [0,8] now.
46 // From this point on, the buckets are bigger than the number of bits
47 // required to hold the values, and the buckets are bigger the maximum
48 // result, so there's no need to mask value anymore, since there's no
49 // more risk of overflow between buckets.
50 if (sizeof(T) > 1) value = (value >> (sizeof(T) > 1 ? 8 : 0)) + value;
51 // Having 4 buckets of 16 bits, holding values from [0,16] now.
52 if (sizeof(T) > 2) value = (value >> (sizeof(T) > 2 ? 16 : 0)) + value;
53 // Having 2 buckets of 32 bits, holding values from [0,32] now.
54 if (sizeof(T) > 4) value = (value >> (sizeof(T) > 4 ? 32 : 0)) + value;
55 // Having 1 buckets of 64 bits, holding values from [0,64] now.
56 return static_cast<unsigned>(value & 0xff);
57#endif
58}
59
60// ReverseBits(value) returns |value| in reverse bit order.
61template <typename T>
62T ReverseBits(T value) {
63 STATIC_ASSERT((sizeof(value) == 1) || (sizeof(value) == 2) ||static_assert((sizeof(value) == 1) || (sizeof(value) == 2) ||
(sizeof(value) == 4) || (sizeof(value) == 8), "(sizeof(value) == 1) || (sizeof(value) == 2) || (sizeof(value) == 4) || (sizeof(value) == 8)"
)
64 (sizeof(value) == 4) || (sizeof(value) == 8))static_assert((sizeof(value) == 1) || (sizeof(value) == 2) ||
(sizeof(value) == 4) || (sizeof(value) == 8), "(sizeof(value) == 1) || (sizeof(value) == 2) || (sizeof(value) == 4) || (sizeof(value) == 8)"
)
;
65 T result = 0;
66 for (unsigned i = 0; i < (sizeof(value) * 8); i++) {
67 result = (result << 1) | (value & 1);
68 value >>= 1;
69 }
70 return result;
71}
72
73// CountLeadingZeros(value) returns the number of zero bits following the most
74// significant 1 bit in |value| if |value| is non-zero, otherwise it returns
75// {sizeof(T) * 8}.
76template <typename T, unsigned bits = sizeof(T) * 8>
77inline constexpr
78 typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) <= 8,
79 unsigned>::type
80 CountLeadingZeros(T value) {
81 static_assert(bits > 0, "invalid instantiation");
82#if V8_HAS_BUILTIN_CLZ(1)
83 return value == 0
84 ? bits
85 : bits == 64
86 ? __builtin_clzll(static_cast<uint64_t>(value))
87 : __builtin_clz(static_cast<uint32_t>(value)) - (32 - bits);
88#else
89 // Binary search algorithm taken from "Hacker's Delight" (by Henry S. Warren,
90 // Jr.), figures 5-11 and 5-12.
91 if (bits == 1) return static_cast<unsigned>(value) ^ 1;
92 T upper_half = value >> (bits / 2);
93 T next_value = upper_half != 0 ? upper_half : value;
94 unsigned add = upper_half != 0 ? 0 : bits / 2;
95 constexpr unsigned next_bits = bits == 1 ? 1 : bits / 2;
96 return CountLeadingZeros<T, next_bits>(next_value) + add;
97#endif
98}
99
100inline constexpr unsigned CountLeadingZeros32(uint32_t value) {
101 return CountLeadingZeros(value);
102}
103inline constexpr unsigned CountLeadingZeros64(uint64_t value) {
104 return CountLeadingZeros(value);
105}
106
107// CountTrailingZeros(value) returns the number of zero bits preceding the
108// least significant 1 bit in |value| if |value| is non-zero, otherwise it
109// returns {sizeof(T) * 8}.
110// See CountTrailingZerosNonZero for an optimized version for the case that
111// |value| is guaranteed to be non-zero.
112template <typename T, unsigned bits = sizeof(T) * 8>
113inline constexpr
114 typename std::enable_if<std::is_integral<T>::value && sizeof(T) <= 8,
115 unsigned>::type
116 CountTrailingZeros(T value) {
117#if V8_HAS_BUILTIN_CTZ(1)
118 return value == 0 ? bits
2
Assuming 'value' is equal to 0
3
'?' condition is true
4
Returning the value 32
119 : bits == 64 ? __builtin_ctzll(static_cast<uint64_t>(value))
120 : __builtin_ctz(static_cast<uint32_t>(value));
121#else
122 // Fall back to popcount (see "Hacker's Delight" by Henry S. Warren, Jr.),
123 // chapter 5-4. On x64, since is faster than counting in a loop and faster
124 // than doing binary search.
125 using U = typename std::make_unsigned<T>::type;
126 U u = value;
127 return CountPopulation(static_cast<U>(~u & (u - 1u)));
128#endif
129}
130
131inline constexpr unsigned CountTrailingZeros32(uint32_t value) {
132 return CountTrailingZeros(value);
133}
134inline constexpr unsigned CountTrailingZeros64(uint64_t value) {
135 return CountTrailingZeros(value);
136}
137
138// CountTrailingZerosNonZero(value) returns the number of zero bits preceding
139// the least significant 1 bit in |value| if |value| is non-zero, otherwise the
140// behavior is undefined.
141// See CountTrailingZeros for an alternative version that allows |value| == 0.
142template <typename T, unsigned bits = sizeof(T) * 8>
143inline constexpr
144 typename std::enable_if<std::is_integral<T>::value && sizeof(T) <= 8,
145 unsigned>::type
146 CountTrailingZerosNonZero(T value) {
147 DCHECK_NE(0, value)((void) 0);
148#if V8_HAS_BUILTIN_CTZ(1)
149 return bits == 64 ? __builtin_ctzll(static_cast<uint64_t>(value))
150 : __builtin_ctz(static_cast<uint32_t>(value));
151#else
152 return CountTrailingZeros<T, bits>(value);
153#endif
154}
155
156// Returns true iff |value| is a power of 2.
157template <typename T,
158 typename = typename std::enable_if<std::is_integral<T>::value ||
159 std::is_enum<T>::value>::type>
160constexpr inline bool IsPowerOfTwo(T value) {
161 return value > 0 && (value & (value - 1)) == 0;
162}
163
164// Identical to {CountTrailingZeros}, but only works for powers of 2.
165template <typename T,
166 typename = typename std::enable_if<std::is_integral<T>::value>::type>
167inline constexpr int WhichPowerOfTwo(T value) {
168 DCHECK(IsPowerOfTwo(value))((void) 0);
169#if V8_HAS_BUILTIN_CTZ(1)
170 STATIC_ASSERT(sizeof(T) <= 8)static_assert(sizeof(T) <= 8, "sizeof(T) <= 8");
171 return sizeof(T) == 8 ? __builtin_ctzll(static_cast<uint64_t>(value))
172 : __builtin_ctz(static_cast<uint32_t>(value));
173#else
174 // Fall back to popcount (see "Hacker's Delight" by Henry S. Warren, Jr.),
175 // chapter 5-4. On x64, since is faster than counting in a loop and faster
176 // than doing binary search.
177 using U = typename std::make_unsigned<T>::type;
178 U u = value;
179 return CountPopulation(static_cast<U>(u - 1));
180#endif
181}
182
183// RoundUpToPowerOfTwo32(value) returns the smallest power of two which is
184// greater than or equal to |value|. If you pass in a |value| that is already a
185// power of two, it is returned as is. |value| must be less than or equal to
186// 0x80000000u. Uses computation based on leading zeros if we have compiler
187// support for that. Falls back to the implementation from "Hacker's Delight" by
188// Henry S. Warren, Jr., figure 3-3, page 48, where the function is called clp2.
189V8_BASE_EXPORT uint32_t RoundUpToPowerOfTwo32(uint32_t value);
190// Same for 64 bit integers. |value| must be <= 2^63
191V8_BASE_EXPORT uint64_t RoundUpToPowerOfTwo64(uint64_t value);
192// Same for size_t integers.
193inline size_t RoundUpToPowerOfTwo(size_t value) {
194 if (sizeof(size_t) == sizeof(uint64_t)) {
195 return RoundUpToPowerOfTwo64(value);
196 } else {
197 // Without windows.h included this line triggers a truncation warning on
198 // 64-bit builds. Presumably windows.h disables the relevant warning.
199 return RoundUpToPowerOfTwo32(static_cast<uint32_t>(value));
200 }
201}
202
203// RoundDownToPowerOfTwo32(value) returns the greatest power of two which is
204// less than or equal to |value|. If you pass in a |value| that is already a
205// power of two, it is returned as is.
206inline uint32_t RoundDownToPowerOfTwo32(uint32_t value) {
207 if (value > 0x80000000u) return 0x80000000u;
208 uint32_t result = RoundUpToPowerOfTwo32(value);
209 if (result > value) result >>= 1;
210 return result;
211}
212
213
214// Precondition: 0 <= shift < 32
215inline constexpr uint32_t RotateRight32(uint32_t value, uint32_t shift) {
216 return (value >> shift) | (value << ((32 - shift) & 31));
217}
218
219// Precondition: 0 <= shift < 32
220inline constexpr uint32_t RotateLeft32(uint32_t value, uint32_t shift) {
221 return (value << shift) | (value >> ((32 - shift) & 31));
222}
223
224// Precondition: 0 <= shift < 64
225inline constexpr uint64_t RotateRight64(uint64_t value, uint64_t shift) {
226 return (value >> shift) | (value << ((64 - shift) & 63));
227}
228
229// Precondition: 0 <= shift < 64
230inline constexpr uint64_t RotateLeft64(uint64_t value, uint64_t shift) {
231 return (value << shift) | (value >> ((64 - shift) & 63));
232}
233
234// SignedAddOverflow32(lhs,rhs,val) performs a signed summation of |lhs| and
235// |rhs| and stores the result into the variable pointed to by |val| and
236// returns true if the signed summation resulted in an overflow.
237inline bool SignedAddOverflow32(int32_t lhs, int32_t rhs, int32_t* val) {
238#if V8_HAS_BUILTIN_SADD_OVERFLOW(1)
239 return __builtin_sadd_overflow(lhs, rhs, val);
240#else
241 uint32_t res = static_cast<uint32_t>(lhs) + static_cast<uint32_t>(rhs);
242 *val = bit_cast<int32_t>(res);
243 return ((res ^ lhs) & (res ^ rhs) & (1U << 31)) != 0;
244#endif
245}
246
247
248// SignedSubOverflow32(lhs,rhs,val) performs a signed subtraction of |lhs| and
249// |rhs| and stores the result into the variable pointed to by |val| and
250// returns true if the signed subtraction resulted in an overflow.
251inline bool SignedSubOverflow32(int32_t lhs, int32_t rhs, int32_t* val) {
252#if V8_HAS_BUILTIN_SSUB_OVERFLOW(1)
253 return __builtin_ssub_overflow(lhs, rhs, val);
254#else
255 uint32_t res = static_cast<uint32_t>(lhs) - static_cast<uint32_t>(rhs);
256 *val = bit_cast<int32_t>(res);
257 return ((res ^ lhs) & (res ^ ~rhs) & (1U << 31)) != 0;
258#endif
259}
260
261// SignedMulOverflow32(lhs,rhs,val) performs a signed multiplication of |lhs|
262// and |rhs| and stores the result into the variable pointed to by |val| and
263// returns true if the signed multiplication resulted in an overflow.
264V8_BASE_EXPORT bool SignedMulOverflow32(int32_t lhs, int32_t rhs, int32_t* val);
265
266// SignedAddOverflow64(lhs,rhs,val) performs a signed summation of |lhs| and
267// |rhs| and stores the result into the variable pointed to by |val| and
268// returns true if the signed summation resulted in an overflow.
269inline bool SignedAddOverflow64(int64_t lhs, int64_t rhs, int64_t* val) {
270 uint64_t res = static_cast<uint64_t>(lhs) + static_cast<uint64_t>(rhs);
271 *val = bit_cast<int64_t>(res);
272 return ((res ^ lhs) & (res ^ rhs) & (1ULL << 63)) != 0;
273}
274
275
276// SignedSubOverflow64(lhs,rhs,val) performs a signed subtraction of |lhs| and
277// |rhs| and stores the result into the variable pointed to by |val| and
278// returns true if the signed subtraction resulted in an overflow.
279inline bool SignedSubOverflow64(int64_t lhs, int64_t rhs, int64_t* val) {
280 uint64_t res = static_cast<uint64_t>(lhs) - static_cast<uint64_t>(rhs);
281 *val = bit_cast<int64_t>(res);
282 return ((res ^ lhs) & (res ^ ~rhs) & (1ULL << 63)) != 0;
283}
284
285// SignedMulHigh32(lhs, rhs) multiplies two signed 32-bit values |lhs| and
286// |rhs|, extracts the most significant 32 bits of the result, and returns
287// those.
288V8_BASE_EXPORT int32_t SignedMulHigh32(int32_t lhs, int32_t rhs);
289
290// SignedMulHighAndAdd32(lhs, rhs, acc) multiplies two signed 32-bit values
291// |lhs| and |rhs|, extracts the most significant 32 bits of the result, and
292// adds the accumulate value |acc|.
293V8_BASE_EXPORT int32_t SignedMulHighAndAdd32(int32_t lhs, int32_t rhs,
294 int32_t acc);
295
296// SignedDiv32(lhs, rhs) divides |lhs| by |rhs| and returns the quotient
297// truncated to int32. If |rhs| is zero, then zero is returned. If |lhs|
298// is minint and |rhs| is -1, it returns minint.
299V8_BASE_EXPORT int32_t SignedDiv32(int32_t lhs, int32_t rhs);
300
301// SignedMod32(lhs, rhs) divides |lhs| by |rhs| and returns the remainder
302// truncated to int32. If either |rhs| is zero or |lhs| is minint and |rhs|
303// is -1, it returns zero.
304V8_BASE_EXPORT int32_t SignedMod32(int32_t lhs, int32_t rhs);
305
306// UnsignedAddOverflow32(lhs,rhs,val) performs an unsigned summation of |lhs|
307// and |rhs| and stores the result into the variable pointed to by |val| and
308// returns true if the unsigned summation resulted in an overflow.
309inline bool UnsignedAddOverflow32(uint32_t lhs, uint32_t rhs, uint32_t* val) {
310#if V8_HAS_BUILTIN_SADD_OVERFLOW(1)
311 return __builtin_uadd_overflow(lhs, rhs, val);
312#else
313 *val = lhs + rhs;
314 return *val < (lhs | rhs);
315#endif
316}
317
318
319// UnsignedDiv32(lhs, rhs) divides |lhs| by |rhs| and returns the quotient
320// truncated to uint32. If |rhs| is zero, then zero is returned.
321inline uint32_t UnsignedDiv32(uint32_t lhs, uint32_t rhs) {
322 return rhs ? lhs / rhs : 0u;
323}
324
325
326// UnsignedMod32(lhs, rhs) divides |lhs| by |rhs| and returns the remainder
327// truncated to uint32. If |rhs| is zero, then zero is returned.
328inline uint32_t UnsignedMod32(uint32_t lhs, uint32_t rhs) {
329 return rhs ? lhs % rhs : 0u;
330}
331
332// Wraparound integer arithmetic without undefined behavior.
333
334inline int32_t WraparoundAdd32(int32_t lhs, int32_t rhs) {
335 return static_cast<int32_t>(static_cast<uint32_t>(lhs) +
336 static_cast<uint32_t>(rhs));
337}
338
339inline int32_t WraparoundNeg32(int32_t x) {
340 return static_cast<int32_t>(-static_cast<uint32_t>(x));
341}
342
343// SignedSaturatedAdd64(lhs, rhs) adds |lhs| and |rhs|,
344// checks and returns the result.
345V8_BASE_EXPORT int64_t SignedSaturatedAdd64(int64_t lhs, int64_t rhs);
346
347// SignedSaturatedSub64(lhs, rhs) subtracts |lhs| by |rhs|,
348// checks and returns the result.
349V8_BASE_EXPORT int64_t SignedSaturatedSub64(int64_t lhs, int64_t rhs);
350
351} // namespace bits
352} // namespace base
353} // namespace v8
354
355#endif // V8_BASE_BITS_H_