1 // Copyright 2013 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_COMPILER_OPERATOR_PROPERTIES_INL_H_
6 #define V8_COMPILER_OPERATOR_PROPERTIES_INL_H_
7 
8 #include "src/compiler/common-operator.h"
9 #include "src/compiler/js-operator.h"
10 #include "src/compiler/opcodes.h"
11 #include "src/compiler/operator-properties.h"
12 
13 namespace v8 {
14 namespace internal {
15 namespace compiler {
16 
HasValueInput(const Operator * op)17 inline bool OperatorProperties::HasValueInput(const Operator* op) {
18   return OperatorProperties::GetValueInputCount(op) > 0;
19 }
20 
HasContextInput(const Operator * op)21 inline bool OperatorProperties::HasContextInput(const Operator* op) {
22   IrOpcode::Value opcode = static_cast<IrOpcode::Value>(op->opcode());
23   return IrOpcode::IsJsOpcode(opcode);
24 }
25 
HasEffectInput(const Operator * op)26 inline bool OperatorProperties::HasEffectInput(const Operator* op) {
27   return OperatorProperties::GetEffectInputCount(op) > 0;
28 }
29 
HasControlInput(const Operator * op)30 inline bool OperatorProperties::HasControlInput(const Operator* op) {
31   return OperatorProperties::GetControlInputCount(op) > 0;
32 }
33 
HasFrameStateInput(const Operator * op)34 inline bool OperatorProperties::HasFrameStateInput(const Operator* op) {
35   if (!FLAG_turbo_deoptimization) {
36     return false;
37   }
38 
39   switch (op->opcode()) {
40     case IrOpcode::kFrameState:
41       return true;
42     case IrOpcode::kJSCallRuntime: {
43       Runtime::FunctionId function = OpParameter<Runtime::FunctionId>(op);
44       return Linkage::NeedsFrameState(function);
45     }
46 
47     // Strict equality cannot lazily deoptimize.
48     case IrOpcode::kJSStrictEqual:
49     case IrOpcode::kJSStrictNotEqual:
50       return false;
51 
52     // Calls
53     case IrOpcode::kJSCallFunction:
54     case IrOpcode::kJSCallConstruct:
55 
56     // Compare operations
57     case IrOpcode::kJSEqual:
58     case IrOpcode::kJSNotEqual:
59     case IrOpcode::kJSLessThan:
60     case IrOpcode::kJSGreaterThan:
61     case IrOpcode::kJSLessThanOrEqual:
62     case IrOpcode::kJSGreaterThanOrEqual:
63 
64     // Binary operations
65     case IrOpcode::kJSBitwiseOr:
66     case IrOpcode::kJSBitwiseXor:
67     case IrOpcode::kJSBitwiseAnd:
68     case IrOpcode::kJSShiftLeft:
69     case IrOpcode::kJSShiftRight:
70     case IrOpcode::kJSShiftRightLogical:
71     case IrOpcode::kJSAdd:
72     case IrOpcode::kJSSubtract:
73     case IrOpcode::kJSMultiply:
74     case IrOpcode::kJSDivide:
75     case IrOpcode::kJSModulus:
76     case IrOpcode::kJSLoadProperty:
77     case IrOpcode::kJSStoreProperty:
78     case IrOpcode::kJSLoadNamed:
79     case IrOpcode::kJSStoreNamed:
80       return true;
81 
82     default:
83       return false;
84   }
85 }
86 
GetValueInputCount(const Operator * op)87 inline int OperatorProperties::GetValueInputCount(const Operator* op) {
88   return op->InputCount();
89 }
90 
GetContextInputCount(const Operator * op)91 inline int OperatorProperties::GetContextInputCount(const Operator* op) {
92   return OperatorProperties::HasContextInput(op) ? 1 : 0;
93 }
94 
GetFrameStateInputCount(const Operator * op)95 inline int OperatorProperties::GetFrameStateInputCount(const Operator* op) {
96   return OperatorProperties::HasFrameStateInput(op) ? 1 : 0;
97 }
98 
GetEffectInputCount(const Operator * op)99 inline int OperatorProperties::GetEffectInputCount(const Operator* op) {
100   if (op->opcode() == IrOpcode::kEffectPhi ||
101       op->opcode() == IrOpcode::kFinish) {
102     return OpParameter<int>(op);
103   }
104   if (op->HasProperty(Operator::kNoRead) && op->HasProperty(Operator::kNoWrite))
105     return 0;  // no effects.
106   return 1;
107 }
108 
GetControlInputCount(const Operator * op)109 inline int OperatorProperties::GetControlInputCount(const Operator* op) {
110   switch (op->opcode()) {
111     case IrOpcode::kPhi:
112     case IrOpcode::kEffectPhi:
113     case IrOpcode::kControlEffect:
114       return 1;
115 #define OPCODE_CASE(x) case IrOpcode::k##x:
116       CONTROL_OP_LIST(OPCODE_CASE)
117 #undef OPCODE_CASE
118       // Control operators are Operator1<int>.
119       return OpParameter<int>(op);
120     default:
121       // Operators that have write effects must have a control
122       // dependency. Effect dependencies only ensure the correct order of
123       // write/read operations without consideration of control flow. Without an
124       // explicit control dependency writes can be float in the schedule too
125       // early along a path that shouldn't generate a side-effect.
126       return op->HasProperty(Operator::kNoWrite) ? 0 : 1;
127   }
128   return 0;
129 }
130 
GetTotalInputCount(const Operator * op)131 inline int OperatorProperties::GetTotalInputCount(const Operator* op) {
132   return GetValueInputCount(op) + GetContextInputCount(op) +
133          GetFrameStateInputCount(op) + GetEffectInputCount(op) +
134          GetControlInputCount(op);
135 }
136 
137 // -----------------------------------------------------------------------------
138 // Output properties.
139 
HasValueOutput(const Operator * op)140 inline bool OperatorProperties::HasValueOutput(const Operator* op) {
141   return GetValueOutputCount(op) > 0;
142 }
143 
HasEffectOutput(const Operator * op)144 inline bool OperatorProperties::HasEffectOutput(const Operator* op) {
145   return op->opcode() == IrOpcode::kStart ||
146          op->opcode() == IrOpcode::kControlEffect ||
147          op->opcode() == IrOpcode::kValueEffect ||
148          (op->opcode() != IrOpcode::kFinish && GetEffectInputCount(op) > 0);
149 }
150 
HasControlOutput(const Operator * op)151 inline bool OperatorProperties::HasControlOutput(const Operator* op) {
152   IrOpcode::Value opcode = static_cast<IrOpcode::Value>(op->opcode());
153   return (opcode != IrOpcode::kEnd && IrOpcode::IsControlOpcode(opcode));
154 }
155 
156 
GetValueOutputCount(const Operator * op)157 inline int OperatorProperties::GetValueOutputCount(const Operator* op) {
158   return op->OutputCount();
159 }
160 
GetEffectOutputCount(const Operator * op)161 inline int OperatorProperties::GetEffectOutputCount(const Operator* op) {
162   return HasEffectOutput(op) ? 1 : 0;
163 }
164 
GetControlOutputCount(const Operator * node)165 inline int OperatorProperties::GetControlOutputCount(const Operator* node) {
166   return node->opcode() == IrOpcode::kBranch ? 2 : HasControlOutput(node) ? 1
167                                                                           : 0;
168 }
169 
170 
IsBasicBlockBegin(const Operator * op)171 inline bool OperatorProperties::IsBasicBlockBegin(const Operator* op) {
172   uint8_t opcode = op->opcode();
173   return opcode == IrOpcode::kStart || opcode == IrOpcode::kEnd ||
174          opcode == IrOpcode::kDead || opcode == IrOpcode::kLoop ||
175          opcode == IrOpcode::kMerge || opcode == IrOpcode::kIfTrue ||
176          opcode == IrOpcode::kIfFalse;
177 }
178 
179 }  // namespace compiler
180 }  // namespace internal
181 }  // namespace v8
182 
183 #endif  // V8_COMPILER_OPERATOR_PROPERTIES_INL_H_
184