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.
5 #include "src/compiler/common-operator.h"
7 #include "src/assembler.h"
8 #include "src/base/lazy-instance.h"
9 #include "src/compiler/linkage.h"
10 #include "src/compiler/opcodes.h"
11 #include "src/compiler/operator.h"
12 #include "src/unique.h"
19 std::ostream& operator<<(std::ostream& os, BranchHint hint) {
21 case BranchHint::kNone:
23 case BranchHint::kTrue:
25 case BranchHint::kFalse:
33 BranchHint BranchHintOf(const Operator* const op) {
34 DCHECK_EQ(IrOpcode::kBranch, op->opcode());
35 return OpParameter<BranchHint>(op);
39 bool operator==(SelectParameters const& lhs, SelectParameters const& rhs) {
40 return lhs.type() == rhs.type() && lhs.hint() == rhs.hint();
44 bool operator!=(SelectParameters const& lhs, SelectParameters const& rhs) {
49 size_t hash_value(SelectParameters const& p) {
50 return base::hash_combine(p.type(), p.hint());
54 std::ostream& operator<<(std::ostream& os, SelectParameters const& p) {
55 return os << p.type() << "|" << p.hint();
59 SelectParameters const& SelectParametersOf(const Operator* const op) {
60 DCHECK_EQ(IrOpcode::kSelect, op->opcode());
61 return OpParameter<SelectParameters>(op);
65 size_t hash_value(OutputFrameStateCombine const& sc) {
66 return base::hash_combine(sc.kind_, sc.parameter_);
70 std::ostream& operator<<(std::ostream& os, OutputFrameStateCombine const& sc) {
72 case OutputFrameStateCombine::kPushOutput:
73 if (sc.parameter_ == 0) return os << "Ignore";
74 return os << "Push(" << sc.parameter_ << ")";
75 case OutputFrameStateCombine::kPokeAt:
76 return os << "PokeAt(" << sc.parameter_ << ")";
83 bool operator==(FrameStateCallInfo const& lhs, FrameStateCallInfo const& rhs) {
84 return lhs.type() == rhs.type() && lhs.bailout_id() == rhs.bailout_id() &&
85 lhs.state_combine() == rhs.state_combine();
89 bool operator!=(FrameStateCallInfo const& lhs, FrameStateCallInfo const& rhs) {
94 size_t hash_value(FrameStateCallInfo const& info) {
95 return base::hash_combine(info.type(), info.bailout_id(),
96 info.state_combine());
100 std::ostream& operator<<(std::ostream& os, FrameStateCallInfo const& info) {
101 return os << info.type() << ", " << info.bailout_id() << ", "
102 << info.state_combine();
106 size_t ProjectionIndexOf(const Operator* const op) {
107 DCHECK_EQ(IrOpcode::kProjection, op->opcode());
108 return OpParameter<size_t>(op);
112 #define CACHED_OP_LIST(V) \
113 V(Always, Operator::kPure, 0, 0, 0, 1, 0, 0) \
114 V(Dead, Operator::kFoldable, 0, 0, 0, 0, 0, 1) \
115 V(End, Operator::kKontrol, 0, 0, 1, 0, 0, 0) \
116 V(IfTrue, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
117 V(IfFalse, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
118 V(IfSuccess, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
119 V(IfException, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
120 V(IfDefault, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
121 V(Throw, Operator::kFoldable, 1, 1, 1, 0, 0, 1) \
122 V(Deoptimize, Operator::kNoThrow, 1, 1, 1, 0, 0, 1) \
123 V(Return, Operator::kNoThrow, 1, 1, 1, 0, 0, 1) \
124 V(OsrNormalEntry, Operator::kFoldable, 0, 1, 1, 0, 1, 1) \
125 V(OsrLoopEntry, Operator::kFoldable, 0, 1, 1, 0, 1, 1)
128 #define CACHED_EFFECT_PHI_LIST(V) \
137 #define CACHED_LOOP_LIST(V) \
142 #define CACHED_MERGE_LIST(V) \
153 #define CACHED_PARAMETER_LIST(V) \
163 #define CACHED_PHI_LIST(V) \
164 V(kMachAnyTagged, 1) \
165 V(kMachAnyTagged, 2) \
166 V(kMachAnyTagged, 3) \
167 V(kMachAnyTagged, 4) \
168 V(kMachAnyTagged, 5) \
169 V(kMachAnyTagged, 6) \
175 #define CACHED_PROJECTION_LIST(V) \
180 #define CACHED_STATE_VALUES_LIST(V) \
197 struct CommonOperatorGlobalCache FINAL {
198 #define CACHED(Name, properties, value_input_count, effect_input_count, \
199 control_input_count, value_output_count, effect_output_count, \
200 control_output_count) \
201 struct Name##Operator FINAL : public Operator { \
203 : Operator(IrOpcode::k##Name, properties, #Name, value_input_count, \
204 effect_input_count, control_input_count, \
205 value_output_count, effect_output_count, \
206 control_output_count) {} \
208 Name##Operator k##Name##Operator;
209 CACHED_OP_LIST(CACHED)
212 template <BranchHint kBranchHint>
213 struct BranchOperator FINAL : public Operator1<BranchHint> {
215 : Operator1<BranchHint>( // --
216 IrOpcode::kBranch, Operator::kKontrol, // opcode
218 1, 0, 1, 0, 0, 2, // counts
219 kBranchHint) {} // parameter
221 BranchOperator<BranchHint::kNone> kBranchNoneOperator;
222 BranchOperator<BranchHint::kTrue> kBranchTrueOperator;
223 BranchOperator<BranchHint::kFalse> kBranchFalseOperator;
225 template <int kEffectInputCount>
226 struct EffectPhiOperator FINAL : public Operator {
229 IrOpcode::kEffectPhi, Operator::kPure, // opcode
231 0, kEffectInputCount, 1, 0, 1, 0) {} // counts
233 #define CACHED_EFFECT_PHI(input_count) \
234 EffectPhiOperator<input_count> kEffectPhi##input_count##Operator;
235 CACHED_EFFECT_PHI_LIST(CACHED_EFFECT_PHI)
236 #undef CACHED_EFFECT_PHI
238 template <size_t kInputCount>
239 struct LoopOperator FINAL : public Operator {
242 IrOpcode::kLoop, Operator::kKontrol, // opcode
244 0, 0, kInputCount, 0, 0, 1) {} // counts
246 #define CACHED_LOOP(input_count) \
247 LoopOperator<input_count> kLoop##input_count##Operator;
248 CACHED_LOOP_LIST(CACHED_LOOP)
251 template <size_t kInputCount>
252 struct MergeOperator FINAL : public Operator {
255 IrOpcode::kMerge, Operator::kKontrol, // opcode
257 0, 0, kInputCount, 0, 0, 1) {} // counts
259 #define CACHED_MERGE(input_count) \
260 MergeOperator<input_count> kMerge##input_count##Operator;
261 CACHED_MERGE_LIST(CACHED_MERGE)
264 template <MachineType kType, int kInputCount>
265 struct PhiOperator FINAL : public Operator1<MachineType> {
267 : Operator1<MachineType>( //--
268 IrOpcode::kPhi, Operator::kPure, // opcode
270 kInputCount, 0, 1, 1, 0, 0, // counts
271 kType) {} // parameter
273 #define CACHED_PHI(type, input_count) \
274 PhiOperator<type, input_count> kPhi##type##input_count##Operator;
275 CACHED_PHI_LIST(CACHED_PHI)
278 template <int kIndex>
279 struct ParameterOperator FINAL : public Operator1<int> {
281 : Operator1<int>( // --
282 IrOpcode::kParameter, Operator::kPure, // opcode
284 1, 0, 0, 1, 0, 0, // counts,
285 kIndex) {} // parameter
287 #define CACHED_PARAMETER(index) \
288 ParameterOperator<index> kParameter##index##Operator;
289 CACHED_PARAMETER_LIST(CACHED_PARAMETER)
290 #undef CACHED_PARAMETER
292 template <size_t kIndex>
293 struct ProjectionOperator FINAL : public Operator1<size_t> {
295 : Operator1<size_t>( // --
296 IrOpcode::kProjection, // opcode
297 Operator::kPure, // flags
298 "Projection", // name
299 1, 0, 0, 1, 0, 0, // counts,
300 kIndex) {} // parameter
302 #define CACHED_PROJECTION(index) \
303 ProjectionOperator<index> kProjection##index##Operator;
304 CACHED_PROJECTION_LIST(CACHED_PROJECTION)
305 #undef CACHED_PROJECTION
307 template <int kInputCount>
308 struct StateValuesOperator FINAL : public Operator {
309 StateValuesOperator()
311 IrOpcode::kStateValues, // opcode
312 Operator::kPure, // flags
313 "StateValues", // name
314 kInputCount, 0, 0, 1, 0, 0) {} // counts
316 #define CACHED_STATE_VALUES(input_count) \
317 StateValuesOperator<input_count> kStateValues##input_count##Operator;
318 CACHED_STATE_VALUES_LIST(CACHED_STATE_VALUES)
319 #undef CACHED_STATE_VALUES
323 static base::LazyInstance<CommonOperatorGlobalCache>::type kCache =
324 LAZY_INSTANCE_INITIALIZER;
327 CommonOperatorBuilder::CommonOperatorBuilder(Zone* zone)
328 : cache_(kCache.Get()), zone_(zone) {}
331 #define CACHED(Name, properties, value_input_count, effect_input_count, \
332 control_input_count, value_output_count, effect_output_count, \
333 control_output_count) \
334 const Operator* CommonOperatorBuilder::Name() { \
335 return &cache_.k##Name##Operator; \
337 CACHED_OP_LIST(CACHED)
341 const Operator* CommonOperatorBuilder::Branch(BranchHint hint) {
343 case BranchHint::kNone:
344 return &cache_.kBranchNoneOperator;
345 case BranchHint::kTrue:
346 return &cache_.kBranchTrueOperator;
347 case BranchHint::kFalse:
348 return &cache_.kBranchFalseOperator;
355 const Operator* CommonOperatorBuilder::Switch(size_t control_output_count) {
356 DCHECK_GE(control_output_count, 3u); // Disallow trivial switches.
357 return new (zone()) Operator( // --
358 IrOpcode::kSwitch, Operator::kKontrol, // opcode
360 1, 0, 1, 0, 0, control_output_count); // counts
364 const Operator* CommonOperatorBuilder::IfValue(int32_t index) {
365 return new (zone()) Operator1<int32_t>( // --
366 IrOpcode::kIfValue, Operator::kKontrol, // opcode
368 0, 0, 1, 0, 0, 1, // counts
373 const Operator* CommonOperatorBuilder::Start(int num_formal_parameters) {
374 // Outputs are formal parameters, plus context, receiver, and JSFunction.
375 const int value_output_count = num_formal_parameters + 3;
376 return new (zone()) Operator( // --
377 IrOpcode::kStart, Operator::kFoldable, // opcode
379 0, 0, 0, value_output_count, 1, 1); // counts
383 const Operator* CommonOperatorBuilder::Loop(int control_input_count) {
384 switch (control_input_count) {
385 #define CACHED_LOOP(input_count) \
387 return &cache_.kLoop##input_count##Operator;
388 CACHED_LOOP_LIST(CACHED_LOOP)
394 return new (zone()) Operator( // --
395 IrOpcode::kLoop, Operator::kKontrol, // opcode
397 0, 0, control_input_count, 0, 0, 1); // counts
401 const Operator* CommonOperatorBuilder::Merge(int control_input_count) {
402 switch (control_input_count) {
403 #define CACHED_MERGE(input_count) \
405 return &cache_.kMerge##input_count##Operator;
406 CACHED_MERGE_LIST(CACHED_MERGE)
412 return new (zone()) Operator( // --
413 IrOpcode::kMerge, Operator::kKontrol, // opcode
415 0, 0, control_input_count, 0, 0, 1); // counts
419 const Operator* CommonOperatorBuilder::Parameter(int index) {
421 #define CACHED_PARAMETER(index) \
423 return &cache_.kParameter##index##Operator;
424 CACHED_PARAMETER_LIST(CACHED_PARAMETER)
425 #undef CACHED_PARAMETER
430 return new (zone()) Operator1<int>( // --
431 IrOpcode::kParameter, Operator::kPure, // opcode
433 1, 0, 0, 1, 0, 0, // counts
438 const Operator* CommonOperatorBuilder::OsrValue(int index) {
439 return new (zone()) Operator1<int>( // --
440 IrOpcode::kOsrValue, Operator::kNoProperties, // opcode
442 0, 0, 1, 1, 0, 0, // counts
447 const Operator* CommonOperatorBuilder::Int32Constant(int32_t value) {
448 return new (zone()) Operator1<int32_t>( // --
449 IrOpcode::kInt32Constant, Operator::kPure, // opcode
450 "Int32Constant", // name
451 0, 0, 0, 1, 0, 0, // counts
456 const Operator* CommonOperatorBuilder::Int64Constant(int64_t value) {
457 return new (zone()) Operator1<int64_t>( // --
458 IrOpcode::kInt64Constant, Operator::kPure, // opcode
459 "Int64Constant", // name
460 0, 0, 0, 1, 0, 0, // counts
465 const Operator* CommonOperatorBuilder::Float32Constant(volatile float value) {
467 Operator1<float, base::bit_equal_to<float>, base::bit_hash<float>>( // --
468 IrOpcode::kFloat32Constant, Operator::kPure, // opcode
469 "Float32Constant", // name
470 0, 0, 0, 1, 0, 0, // counts
475 const Operator* CommonOperatorBuilder::Float64Constant(volatile double value) {
476 return new (zone()) Operator1<double, base::bit_equal_to<double>,
477 base::bit_hash<double>>( // --
478 IrOpcode::kFloat64Constant, Operator::kPure, // opcode
479 "Float64Constant", // name
480 0, 0, 0, 1, 0, 0, // counts
485 const Operator* CommonOperatorBuilder::ExternalConstant(
486 const ExternalReference& value) {
487 return new (zone()) Operator1<ExternalReference>( // --
488 IrOpcode::kExternalConstant, Operator::kPure, // opcode
489 "ExternalConstant", // name
490 0, 0, 0, 1, 0, 0, // counts
495 const Operator* CommonOperatorBuilder::NumberConstant(volatile double value) {
496 return new (zone()) Operator1<double, base::bit_equal_to<double>,
497 base::bit_hash<double>>( // --
498 IrOpcode::kNumberConstant, Operator::kPure, // opcode
499 "NumberConstant", // name
500 0, 0, 0, 1, 0, 0, // counts
505 const Operator* CommonOperatorBuilder::HeapConstant(
506 const Unique<HeapObject>& value) {
507 return new (zone()) Operator1<Unique<HeapObject>>( // --
508 IrOpcode::kHeapConstant, Operator::kPure, // opcode
509 "HeapConstant", // name
510 0, 0, 0, 1, 0, 0, // counts
515 const Operator* CommonOperatorBuilder::Select(MachineType type,
517 return new (zone()) Operator1<SelectParameters>( // --
518 IrOpcode::kSelect, Operator::kPure, // opcode
520 3, 0, 0, 1, 0, 0, // counts
521 SelectParameters(type, hint)); // parameter
525 const Operator* CommonOperatorBuilder::Phi(MachineType type,
526 int value_input_count) {
527 DCHECK(value_input_count > 0); // Disallow empty phis.
528 #define CACHED_PHI(kType, kValueInputCount) \
529 if (kType == type && kValueInputCount == value_input_count) { \
530 return &cache_.kPhi##kType##kValueInputCount##Operator; \
532 CACHED_PHI_LIST(CACHED_PHI)
535 return new (zone()) Operator1<MachineType>( // --
536 IrOpcode::kPhi, Operator::kPure, // opcode
538 value_input_count, 0, 1, 1, 0, 0, // counts
543 const Operator* CommonOperatorBuilder::EffectPhi(int effect_input_count) {
544 DCHECK(effect_input_count > 0); // Disallow empty effect phis.
545 switch (effect_input_count) {
546 #define CACHED_EFFECT_PHI(input_count) \
548 return &cache_.kEffectPhi##input_count##Operator;
549 CACHED_EFFECT_PHI_LIST(CACHED_EFFECT_PHI)
550 #undef CACHED_EFFECT_PHI
555 return new (zone()) Operator( // --
556 IrOpcode::kEffectPhi, Operator::kPure, // opcode
558 0, effect_input_count, 1, 0, 1, 0); // counts
562 const Operator* CommonOperatorBuilder::EffectSet(int arguments) {
563 DCHECK(arguments > 1); // Disallow empty/singleton sets.
564 return new (zone()) Operator( // --
565 IrOpcode::kEffectSet, Operator::kPure, // opcode
567 0, arguments, 0, 0, 1, 0); // counts
571 const Operator* CommonOperatorBuilder::ValueEffect(int arguments) {
572 DCHECK(arguments > 0); // Disallow empty value effects.
573 return new (zone()) Operator( // --
574 IrOpcode::kValueEffect, Operator::kPure, // opcode
575 "ValueEffect", // name
576 arguments, 0, 0, 0, 1, 0); // counts
580 const Operator* CommonOperatorBuilder::Finish(int arguments) {
581 DCHECK(arguments > 0); // Disallow empty finishes.
582 return new (zone()) Operator( // --
583 IrOpcode::kFinish, Operator::kPure, // opcode
585 1, arguments, 0, 1, 0, 0); // counts
589 const Operator* CommonOperatorBuilder::StateValues(int arguments) {
591 #define CACHED_STATE_VALUES(arguments) \
593 return &cache_.kStateValues##arguments##Operator;
594 CACHED_STATE_VALUES_LIST(CACHED_STATE_VALUES)
595 #undef CACHED_STATE_VALUES
600 return new (zone()) Operator( // --
601 IrOpcode::kStateValues, Operator::kPure, // opcode
602 "StateValues", // name
603 arguments, 0, 0, 1, 0, 0); // counts
607 const Operator* CommonOperatorBuilder::TypedStateValues(
608 const ZoneVector<MachineType>* types) {
609 return new (zone()) Operator1<const ZoneVector<MachineType>*>( // --
610 IrOpcode::kTypedStateValues, Operator::kPure, // opcode
611 "TypedStateValues", // name
612 static_cast<int>(types->size()), 0, 0, 1, 0, 0, types); // counts
616 const Operator* CommonOperatorBuilder::FrameState(
617 FrameStateType type, BailoutId bailout_id,
618 OutputFrameStateCombine state_combine, MaybeHandle<JSFunction> jsfunction) {
619 return new (zone()) Operator1<FrameStateCallInfo>( // --
620 IrOpcode::kFrameState, Operator::kPure, // opcode
621 "FrameState", // name
622 4, 0, 0, 1, 0, 0, // counts
623 FrameStateCallInfo(type, bailout_id, state_combine, jsfunction));
627 const Operator* CommonOperatorBuilder::Call(const CallDescriptor* descriptor) {
628 class CallOperator FINAL : public Operator1<const CallDescriptor*> {
630 CallOperator(const CallDescriptor* descriptor, const char* mnemonic)
631 : Operator1<const CallDescriptor*>(
632 IrOpcode::kCall, descriptor->properties(), mnemonic,
633 descriptor->InputCount() + descriptor->FrameStateCount(),
634 Operator::ZeroIfPure(descriptor->properties()),
635 Operator::ZeroIfEliminatable(descriptor->properties()),
636 descriptor->ReturnCount(),
637 Operator::ZeroIfPure(descriptor->properties()),
638 Operator::ZeroIfNoThrow(descriptor->properties()), descriptor) {}
640 void PrintParameter(std::ostream& os) const OVERRIDE {
641 os << "[" << *parameter() << "]";
644 return new (zone()) CallOperator(descriptor, "Call");
648 const Operator* CommonOperatorBuilder::Projection(size_t index) {
650 #define CACHED_PROJECTION(index) \
652 return &cache_.kProjection##index##Operator;
653 CACHED_PROJECTION_LIST(CACHED_PROJECTION)
654 #undef CACHED_PROJECTION
659 return new (zone()) Operator1<size_t>( // --
660 IrOpcode::kProjection, // opcode
661 Operator::kFoldable | Operator::kNoThrow, // flags
662 "Projection", // name
663 1, 0, 0, 1, 0, 0, // counts
668 const Operator* CommonOperatorBuilder::ResizeMergeOrPhi(const Operator* op,
670 if (op->opcode() == IrOpcode::kPhi) {
671 return Phi(OpParameter<MachineType>(op), size);
672 } else if (op->opcode() == IrOpcode::kEffectPhi) {
673 return EffectPhi(size);
674 } else if (op->opcode() == IrOpcode::kMerge) {
676 } else if (op->opcode() == IrOpcode::kLoop) {
685 } // namespace compiler
686 } // namespace internal