File: | out/../deps/v8/src/compiler/common-operator.cc |
Warning: | line 241, column 13 Assigned value is garbage or undefined |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | ||||
15 | namespace v8 { | |||
16 | namespace internal { | |||
17 | namespace compiler { | |||
18 | ||||
19 | std::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 | ||||
31 | std::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 | ||||
44 | TrapId 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 | ||||
50 | BranchHint 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 | ||||
62 | int 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 | ||||
69 | bool operator==(DeoptimizeParameters lhs, DeoptimizeParameters rhs) { | |||
70 | return lhs.reason() == rhs.reason() && lhs.feedback() == rhs.feedback(); | |||
71 | } | |||
72 | ||||
73 | bool operator!=(DeoptimizeParameters lhs, DeoptimizeParameters rhs) { | |||
74 | return !(lhs == rhs); | |||
75 | } | |||
76 | ||||
77 | size_t hash_value(DeoptimizeParameters p) { | |||
78 | FeedbackSource::Hash feebdack_hash; | |||
79 | return base::hash_combine(p.reason(), feebdack_hash(p.feedback())); | |||
80 | } | |||
81 | ||||
82 | std::ostream& operator<<(std::ostream& os, DeoptimizeParameters p) { | |||
83 | return os << p.reason() << ", " << p.feedback(); | |||
84 | } | |||
85 | ||||
86 | DeoptimizeParameters 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 | ||||
93 | const 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 | ||||
100 | bool operator==(SelectParameters const& lhs, SelectParameters const& rhs) { | |||
101 | return lhs.representation() == rhs.representation() && | |||
102 | lhs.hint() == rhs.hint(); | |||
103 | } | |||
104 | ||||
105 | ||||
106 | bool operator!=(SelectParameters const& lhs, SelectParameters const& rhs) { | |||
107 | return !(lhs == rhs); | |||
108 | } | |||
109 | ||||
110 | ||||
111 | size_t hash_value(SelectParameters const& p) { | |||
112 | return base::hash_combine(p.representation(), p.hint()); | |||
113 | } | |||
114 | ||||
115 | ||||
116 | std::ostream& operator<<(std::ostream& os, SelectParameters const& p) { | |||
117 | return os << p.representation() << ", " << p.hint(); | |||
118 | } | |||
119 | ||||
120 | ||||
121 | SelectParameters const& SelectParametersOf(const Operator* const op) { | |||
122 | DCHECK_EQ(IrOpcode::kSelect, op->opcode())((void) 0); | |||
123 | return OpParameter<SelectParameters>(op); | |||
124 | } | |||
125 | ||||
126 | CallDescriptor 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 | ||||
132 | size_t ProjectionIndexOf(const Operator* const op) { | |||
133 | DCHECK_EQ(IrOpcode::kProjection, op->opcode())((void) 0); | |||
134 | return OpParameter<size_t>(op); | |||
135 | } | |||
136 | ||||
137 | ||||
138 | MachineRepresentation PhiRepresentationOf(const Operator* const op) { | |||
139 | DCHECK_EQ(IrOpcode::kPhi, op->opcode())((void) 0); | |||
140 | return OpParameter<MachineRepresentation>(op); | |||
141 | } | |||
142 | ||||
143 | MachineRepresentation LoopExitValueRepresentationOf(const Operator* const op) { | |||
144 | DCHECK_EQ(IrOpcode::kLoopExitValue, op->opcode())((void) 0); | |||
145 | return OpParameter<MachineRepresentation>(op); | |||
146 | } | |||
147 | ||||
148 | int ParameterIndexOf(const Operator* const op) { | |||
149 | DCHECK_EQ(IrOpcode::kParameter, op->opcode())((void) 0); | |||
150 | return OpParameter<ParameterInfo>(op).index(); | |||
151 | } | |||
152 | ||||
153 | ||||
154 | const ParameterInfo& ParameterInfoOf(const Operator* const op) { | |||
155 | DCHECK_EQ(IrOpcode::kParameter, op->opcode())((void) 0); | |||
156 | return OpParameter<ParameterInfo>(op); | |||
157 | } | |||
158 | ||||
159 | ||||
160 | bool operator==(ParameterInfo const& lhs, ParameterInfo const& rhs) { | |||
161 | return lhs.index() == rhs.index(); | |||
162 | } | |||
163 | ||||
164 | ||||
165 | bool operator!=(ParameterInfo const& lhs, ParameterInfo const& rhs) { | |||
166 | return !(lhs == rhs); | |||
167 | } | |||
168 | ||||
169 | ||||
170 | size_t hash_value(ParameterInfo const& p) { return p.index(); } | |||
171 | ||||
172 | ||||
173 | std::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 | ||||
179 | std::ostream& operator<<(std::ostream& os, ObjectStateInfo const& i) { | |||
180 | return os << "id:" << i.object_id() << ", size:" << i.size(); | |||
181 | } | |||
182 | ||||
183 | size_t hash_value(ObjectStateInfo const& p) { | |||
184 | return base::hash_combine(p.object_id(), p.size()); | |||
185 | } | |||
186 | ||||
187 | std::ostream& operator<<(std::ostream& os, TypedObjectStateInfo const& i) { | |||
188 | return os << "id:" << i.object_id() << ", " << i.machine_types(); | |||
189 | } | |||
190 | ||||
191 | size_t hash_value(TypedObjectStateInfo const& p) { | |||
192 | return base::hash_combine(p.object_id(), p.machine_types()); | |||
193 | } | |||
194 | ||||
195 | bool 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 | ||||
201 | bool operator!=(RelocatablePtrConstantInfo const& lhs, | |||
202 | RelocatablePtrConstantInfo const& rhs) { | |||
203 | return !(lhs == rhs); | |||
204 | } | |||
205 | ||||
206 | size_t hash_value(RelocatablePtrConstantInfo const& p) { | |||
207 | return base::hash_combine(p.value(), int8_t{p.rmode()}, p.type()); | |||
208 | } | |||
209 | ||||
210 | std::ostream& operator<<(std::ostream& os, | |||
211 | RelocatablePtrConstantInfo const& p) { | |||
212 | return os << p.value() << ", " << static_cast<int>(p.rmode()) << ", " | |||
213 | << p.type(); | |||
214 | } | |||
215 | ||||
216 | SparseInputMask::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 | ||||
228 | void SparseInputMask::InputIterator::Advance() { | |||
229 | DCHECK(!IsEnd())((void) 0); | |||
230 | ||||
231 | if (IsReal()) { | |||
232 | ++real_index_; | |||
233 | } | |||
234 | bit_mask_ >>= 1; | |||
235 | } | |||
236 | ||||
237 | size_t SparseInputMask::InputIterator::AdvanceToNextRealOrEnd() { | |||
238 | DCHECK_NE(bit_mask_, SparseInputMask::kDenseBitMask)((void) 0); | |||
239 | ||||
240 | size_t count = base::bits::CountTrailingZeros(bit_mask_); | |||
| ||||
241 | bit_mask_ >>= count; | |||
| ||||
242 | DCHECK(IsReal() || IsEnd())((void) 0); | |||
243 | return count; | |||
244 | } | |||
245 | ||||
246 | Node* SparseInputMask::InputIterator::GetReal() const { | |||
247 | DCHECK(IsReal())((void) 0); | |||
248 | return parent_->InputAt(real_index_); | |||
249 | } | |||
250 | ||||
251 | bool SparseInputMask::InputIterator::IsReal() const { | |||
252 | return bit_mask_ == SparseInputMask::kDenseBitMask || | |||
253 | (bit_mask_ & kEntryMask); | |||
254 | } | |||
255 | ||||
256 | bool SparseInputMask::InputIterator::IsEnd() const { | |||
257 | return (bit_mask_ == kEndMarker) || | |||
258 | (bit_mask_ == SparseInputMask::kDenseBitMask && | |||
259 | real_index_ >= parent_->InputCount()); | |||
260 | } | |||
261 | ||||
262 | int SparseInputMask::CountReal() const { | |||
263 | DCHECK(!IsDense())((void) 0); | |||
264 | return base::bits::CountPopulation(bit_mask_) - | |||
265 | base::bits::CountPopulation(kEndMarker); | |||
266 | } | |||
267 | ||||
268 | SparseInputMask::InputIterator SparseInputMask::IterateOverInputs(Node* node) { | |||
269 | DCHECK(IsDense() || CountReal() == node->InputCount())((void) 0); | |||
270 | return InputIterator(bit_mask_, node); | |||
271 | } | |||
272 | ||||
273 | bool operator==(SparseInputMask const& lhs, SparseInputMask const& rhs) { | |||
274 | return lhs.mask() == rhs.mask(); | |||
275 | } | |||
276 | ||||
277 | bool operator!=(SparseInputMask const& lhs, SparseInputMask const& rhs) { | |||
278 | return !(lhs == rhs); | |||
279 | } | |||
280 | ||||
281 | size_t hash_value(SparseInputMask const& p) { | |||
282 | return base::hash_value(p.mask()); | |||
283 | } | |||
284 | ||||
285 | std::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 | ||||
306 | bool 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 | ||||
312 | bool operator!=(TypedStateValueInfo const& lhs, | |||
313 | TypedStateValueInfo const& rhs) { | |||
314 | return !(lhs == rhs); | |||
315 | } | |||
316 | ||||
317 | size_t hash_value(TypedStateValueInfo const& p) { | |||
318 | return base::hash_combine(p.machine_types(), p.sparse_input_mask()); | |||
319 | } | |||
320 | ||||
321 | std::ostream& operator<<(std::ostream& os, TypedStateValueInfo const& p) { | |||
322 | return os << p.machine_types() << ", " << p.sparse_input_mask(); | |||
323 | } | |||
324 | ||||
325 | size_t hash_value(RegionObservability observability) { | |||
326 | return static_cast<size_t>(observability); | |||
327 | } | |||
328 | ||||
329 | std::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 | ||||
339 | RegionObservability RegionObservabilityOf(Operator const* op) { | |||
340 | DCHECK_EQ(IrOpcode::kBeginRegion, op->opcode())((void) 0); | |||
341 | return OpParameter<RegionObservability>(op); | |||
342 | } | |||
343 | ||||
344 | Type TypeGuardTypeOf(Operator const* op) { | |||
345 | DCHECK_EQ(IrOpcode::kTypeGuard, op->opcode())((void) 0); | |||
346 | return OpParameter<Type>(op); | |||
347 | } | |||
348 | ||||
349 | std::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 | ||||
363 | int OsrValueIndexOf(Operator const* op) { | |||
364 | DCHECK_EQ(IrOpcode::kOsrValue, op->opcode())((void) 0); | |||
365 | return OpParameter<int>(op); | |||
366 | } | |||
367 | ||||
368 | SparseInputMask 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 | ||||
378 | ZoneVector<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 | ||||
388 | V8_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 | ||||
394 | size_t hash_value(IfValueParameters const& p) { | |||
395 | return base::hash_combine(p.value(), p.comparison_order(), p.hint()); | |||
396 | } | |||
397 | ||||
398 | V8_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 | ||||
405 | IfValueParameters const& IfValueParametersOf(const Operator* op) { | |||
406 | DCHECK(op->opcode() == IrOpcode::kIfValue)((void) 0); | |||
407 | return OpParameter<IfValueParameters>(op); | |||
408 | } | |||
409 | ||||
410 | V8_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 | ||||
416 | size_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 | ||||
422 | V8_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 | ||||
438 | const 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 | ||||
594 | struct 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 | ||||
867 | namespace { | |||
868 | DEFINE_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 | ||||
872 | CommonOperatorBuilder::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 | } | |||
881 | COMMON_CACHED_OP_LIST(CACHED) | |||
882 | #undef CACHED | |||
883 | ||||
884 | ||||
885 | const 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 | ||||
902 | const 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 | ||||
919 | const 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 | ||||
925 | const 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 | ||||
933 | const 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 | ||||
943 | const 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 | ||||
961 | const 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 | ||||
979 | const 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 | ||||
997 | const 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 | ||||
1016 | const 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 | ||||
1035 | const 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 | ||||
1042 | const 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 | ||||
1052 | const 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 | ||||
1060 | const 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 | ||||
1068 | const 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 | ||||
1086 | const 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 | ||||
1103 | const 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 | ||||
1122 | const 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 | ||||
1143 | const 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 | ||||
1151 | const 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 | ||||
1160 | const 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 | ||||
1168 | const 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 | ||||
1176 | const 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 | ||||
1185 | const 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 | ||||
1194 | const 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 | ||||
1204 | const 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 | ||||
1212 | const 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 | ||||
1220 | const 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 | ||||
1229 | const 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 | ||||
1238 | Handle<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 | ||||
1244 | const StringConstantBase* StringConstantBaseOf(const Operator* op) { | |||
1245 | DCHECK_EQ(IrOpcode::kDelayedStringConstant, op->opcode())((void) 0); | |||
1246 | return OpParameter<const StringConstantBase*>(op); | |||
1247 | } | |||
1248 | ||||
1249 | const char* StaticAssertSourceOf(const Operator* op) { | |||
1250 | DCHECK_EQ(IrOpcode::kStaticAssert, op->opcode())((void) 0); | |||
1251 | return OpParameter<const char*>(op); | |||
1252 | } | |||
1253 | ||||
1254 | const 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 | ||||
1263 | const 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 | ||||
1272 | const 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 | ||||
1280 | const 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 | ||||
1290 | const 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 | ||||
1308 | const 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 | ||||
1316 | const 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 | ||||
1323 | const 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 | ||||
1341 | const 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 | ||||
1360 | const 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 | ||||
1371 | const 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 | ||||
1397 | const 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 | ||||
1411 | const 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 | ||||
1420 | const 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 | ||||
1427 | ArgumentsStateType ArgumentsStateTypeOf(Operator const* op) { | |||
1428 | DCHECK(op->opcode() == IrOpcode::kArgumentsElementsState)((void) 0); | |||
1429 | return OpParameter<ArgumentsStateType>(op); | |||
1430 | } | |||
1431 | ||||
1432 | const 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 | ||||
1441 | const 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 | ||||
1450 | uint32_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 | ||||
1463 | MachineRepresentation DeadValueRepresentationOf(Operator const* op) { | |||
1464 | DCHECK_EQ(IrOpcode::kDeadValue, op->opcode())((void) 0); | |||
1465 | return OpParameter<MachineRepresentation>(op); | |||
1466 | } | |||
1467 | ||||
1468 | const 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 | ||||
1479 | const 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 | ||||
1503 | const 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 | ||||
1523 | const 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 | ||||
1543 | const 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 | ||||
1558 | const FrameStateFunctionInfo* | |||
1559 | CommonOperatorBuilder::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 | |||
1567 | const FrameStateFunctionInfo* | |||
1568 | CommonOperatorBuilder::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 | ||||
1579 | const 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 | ||||
1587 | const 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 |
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 | |
20 | namespace v8 { |
21 | namespace base { |
22 | namespace bits { |
23 | |
24 | // CountPopulation(value) returns the number of bits set in |value|. |
25 | template <typename T> |
26 | constexpr 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. |
61 | template <typename T> |
62 | T 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}. |
76 | template <typename T, unsigned bits = sizeof(T) * 8> |
77 | inline 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 | |
100 | inline constexpr unsigned CountLeadingZeros32(uint32_t value) { |
101 | return CountLeadingZeros(value); |
102 | } |
103 | inline 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. |
112 | template <typename T, unsigned bits = sizeof(T) * 8> |
113 | inline 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 |
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 | |
131 | inline constexpr unsigned CountTrailingZeros32(uint32_t value) { |
132 | return CountTrailingZeros(value); |
133 | } |
134 | inline 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. |
142 | template <typename T, unsigned bits = sizeof(T) * 8> |
143 | inline 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. |
157 | template <typename T, |
158 | typename = typename std::enable_if<std::is_integral<T>::value || |
159 | std::is_enum<T>::value>::type> |
160 | constexpr 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. |
165 | template <typename T, |
166 | typename = typename std::enable_if<std::is_integral<T>::value>::type> |
167 | inline 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. |
189 | V8_BASE_EXPORT uint32_t RoundUpToPowerOfTwo32(uint32_t value); |
190 | // Same for 64 bit integers. |value| must be <= 2^63 |
191 | V8_BASE_EXPORT uint64_t RoundUpToPowerOfTwo64(uint64_t value); |
192 | // Same for size_t integers. |
193 | inline 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. |
206 | inline 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 |
215 | inline 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 |
220 | inline 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 |
225 | inline 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 |
230 | inline 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. |
237 | inline 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. |
251 | inline 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. |
264 | V8_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. |
269 | inline 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. |
279 | inline 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. |
288 | V8_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|. |
293 | V8_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. |
299 | V8_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. |
304 | V8_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. |
309 | inline 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. |
321 | inline 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. |
328 | inline 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 | |
334 | inline 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 | |
339 | inline 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. |
345 | V8_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. |
349 | V8_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_ |