OLD | NEW |
---|---|
1 // Copyright 2014 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/access-builder.h" | 5 #include "src/compiler/access-builder.h" |
6 #include "src/compiler/js-graph.h" | 6 #include "src/compiler/js-graph.h" |
7 #include "src/compiler/js-typed-lowering.h" | 7 #include "src/compiler/js-typed-lowering.h" |
8 #include "src/compiler/node-matchers.h" | 8 #include "src/compiler/node-matchers.h" |
9 #include "src/compiler/node-properties.h" | 9 #include "src/compiler/node-properties.h" |
10 #include "src/compiler/operator-properties.h" | 10 #include "src/compiler/operator-properties.h" |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
55 } | 55 } |
56 | 56 |
57 | 57 |
58 // A helper class to simplify the process of reducing a single binop node with a | 58 // A helper class to simplify the process of reducing a single binop node with a |
59 // JSOperator. This class manages the rewriting of context, control, and effect | 59 // JSOperator. This class manages the rewriting of context, control, and effect |
60 // dependencies during lowering of a binop and contains numerous helper | 60 // dependencies during lowering of a binop and contains numerous helper |
61 // functions for matching the types of inputs to an operation. | 61 // functions for matching the types of inputs to an operation. |
62 class JSBinopReduction FINAL { | 62 class JSBinopReduction FINAL { |
63 public: | 63 public: |
64 JSBinopReduction(JSTypedLowering* lowering, Node* node) | 64 JSBinopReduction(JSTypedLowering* lowering, Node* node) |
65 : lowering_(lowering), | 65 : lowering_(lowering), node_(node) {} |
66 node_(node), | |
67 left_type_(NodeProperties::GetBounds(node->InputAt(0)).upper), | |
68 right_type_(NodeProperties::GetBounds(node->InputAt(1)).upper) {} | |
69 | 66 |
70 void ConvertInputsToNumber() { | 67 void ConvertPrimitiveInputsToNumber() { |
71 node_->ReplaceInput(0, ConvertToNumber(left())); | 68 node_->ReplaceInput(0, ConvertPrimitiveToNumber(left())); |
72 node_->ReplaceInput(1, ConvertToNumber(right())); | 69 node_->ReplaceInput(1, ConvertPrimitiveToNumber(right())); |
70 } | |
71 | |
72 void ConvertInputsToNumber(Node* frame_state) { | |
73 // To convert the inputs to numbers, we have to provide frame states | |
74 // for lazy bailouts in the ToNumber conversions. | |
75 // We use a little hack here: we take the frame state before the binary | |
76 // operation and use it to construct the frame states for the conversion | |
77 // so that after the deoptimization, the binary operation IC gets | |
78 // already converted values from full code. This way we are sure that we | |
79 // will not re-do any of the side effects. | |
80 | |
81 Node* left_input = | |
82 left_type()->Is(Type::PlainPrimitive()) | |
83 ? ConvertPrimitiveToNumber(left()) | |
84 : ConvertToNumber(left(), | |
85 CreateFrameStateForLeftInput(frame_state)); | |
86 | |
87 Node* right_input = | |
88 right_type()->Is(Type::PlainPrimitive()) | |
89 ? ConvertPrimitiveToNumber(right()) | |
90 : ConvertToNumber(right(), CreateFrameStateForRightInput( | |
91 frame_state, left_input)); | |
92 | |
93 node_->ReplaceInput(0, left_input); | |
94 node_->ReplaceInput(1, right_input); | |
73 } | 95 } |
74 | 96 |
75 void ConvertInputsToUI32(Signedness left_signedness, | 97 void ConvertInputsToUI32(Signedness left_signedness, |
76 Signedness right_signedness) { | 98 Signedness right_signedness) { |
77 node_->ReplaceInput(0, ConvertToUI32(left(), left_signedness)); | 99 node_->ReplaceInput(0, ConvertToUI32(left(), left_signedness)); |
78 node_->ReplaceInput(1, ConvertToUI32(right(), right_signedness)); | 100 node_->ReplaceInput(1, ConvertToUI32(right(), right_signedness)); |
79 } | 101 } |
80 | 102 |
81 void ConvertInputsToString() { | 103 void ConvertInputsToString() { |
82 node_->ReplaceInput(0, ConvertToString(left())); | 104 node_->ReplaceInput(0, ConvertToString(left())); |
83 node_->ReplaceInput(1, ConvertToString(right())); | 105 node_->ReplaceInput(1, ConvertToString(right())); |
84 } | 106 } |
85 | 107 |
86 // Convert inputs for bitwise shift operation (ES5 spec 11.7). | 108 // Convert inputs for bitwise shift operation (ES5 spec 11.7). |
87 void ConvertInputsForShift(Signedness left_signedness) { | 109 void ConvertInputsForShift(Signedness left_signedness) { |
88 node_->ReplaceInput(0, ConvertToUI32(left(), left_signedness)); | 110 node_->ReplaceInput( |
89 Node* rnum = ConvertToUI32(right(), kUnsigned); | 111 0, ConvertToUI32(ConvertPrimitiveToNumber(left()), left_signedness)); |
112 Node* rnum = ConvertToUI32(ConvertPrimitiveToNumber(right()), kUnsigned); | |
90 Type* rnum_type = NodeProperties::GetBounds(rnum).upper; | 113 Type* rnum_type = NodeProperties::GetBounds(rnum).upper; |
91 if (!rnum_type->Is(lowering_->zero_thirtyone_range_)) { | 114 if (!rnum_type->Is(lowering_->zero_thirtyone_range_)) { |
92 rnum = graph()->NewNode(machine()->Word32And(), rnum, | 115 rnum = graph()->NewNode(machine()->Word32And(), rnum, |
93 jsgraph()->Int32Constant(0x1F)); | 116 jsgraph()->Int32Constant(0x1F)); |
94 } | 117 } |
95 node_->ReplaceInput(1, rnum); | 118 node_->ReplaceInput(1, rnum); |
96 } | 119 } |
97 | 120 |
98 void SwapInputs() { | 121 void SwapInputs() { |
99 Node* l = left(); | 122 Node* l = left(); |
100 Node* r = right(); | 123 Node* r = right(); |
101 node_->ReplaceInput(0, r); | 124 node_->ReplaceInput(0, r); |
102 node_->ReplaceInput(1, l); | 125 node_->ReplaceInput(1, l); |
103 std::swap(left_type_, right_type_); | |
104 } | 126 } |
105 | 127 |
106 // Remove all effect and control inputs and outputs to this node and change | 128 // Remove all effect and control inputs and outputs to this node and change |
107 // to the pure operator {op}, possibly inserting a boolean inversion. | 129 // to the pure operator {op}, possibly inserting a boolean inversion. |
108 Reduction ChangeToPureOperator(const Operator* op, bool invert = false, | 130 Reduction ChangeToPureOperator(const Operator* op, bool invert = false, |
109 Type* type = Type::Any()) { | 131 Type* type = Type::Any()) { |
110 DCHECK_EQ(0, op->EffectInputCount()); | 132 DCHECK_EQ(0, op->EffectInputCount()); |
111 DCHECK_EQ(false, OperatorProperties::HasContextInput(op)); | 133 DCHECK_EQ(false, OperatorProperties::HasContextInput(op)); |
112 DCHECK_EQ(0, op->ControlInputCount()); | 134 DCHECK_EQ(0, op->ControlInputCount()); |
113 DCHECK_EQ(2, op->ValueInputCount()); | 135 DCHECK_EQ(2, op->ValueInputCount()); |
(...skipping 20 matching lines...) Expand all Loading... | |
134 value->ReplaceInput(0, node_); | 156 value->ReplaceInput(0, node_); |
135 return lowering_->Replace(value); | 157 return lowering_->Replace(value); |
136 } | 158 } |
137 return lowering_->Changed(node_); | 159 return lowering_->Changed(node_); |
138 } | 160 } |
139 | 161 |
140 Reduction ChangeToPureOperator(const Operator* op, Type* type) { | 162 Reduction ChangeToPureOperator(const Operator* op, Type* type) { |
141 return ChangeToPureOperator(op, false, type); | 163 return ChangeToPureOperator(op, false, type); |
142 } | 164 } |
143 | 165 |
144 bool OneInputIs(Type* t) { return left_type_->Is(t) || right_type_->Is(t); } | 166 bool OneInputIs(Type* t) { return left_type()->Is(t) || right_type()->Is(t); } |
145 | 167 |
146 bool BothInputsAre(Type* t) { | 168 bool BothInputsAre(Type* t) { |
147 return left_type_->Is(t) && right_type_->Is(t); | 169 return left_type()->Is(t) && right_type()->Is(t); |
148 } | 170 } |
149 | 171 |
150 bool OneInputCannotBe(Type* t) { | 172 bool OneInputCannotBe(Type* t) { |
151 return !left_type_->Maybe(t) || !right_type_->Maybe(t); | 173 return !left_type()->Maybe(t) || !right_type()->Maybe(t); |
152 } | 174 } |
153 | 175 |
154 bool NeitherInputCanBe(Type* t) { | 176 bool NeitherInputCanBe(Type* t) { |
155 return !left_type_->Maybe(t) && !right_type_->Maybe(t); | 177 return !left_type()->Maybe(t) && !right_type()->Maybe(t); |
156 } | 178 } |
157 | 179 |
158 Node* effect() { return NodeProperties::GetEffectInput(node_); } | 180 Node* effect() { return NodeProperties::GetEffectInput(node_); } |
159 Node* control() { return NodeProperties::GetControlInput(node_); } | 181 Node* control() { return NodeProperties::GetControlInput(node_); } |
160 Node* context() { return NodeProperties::GetContextInput(node_); } | 182 Node* context() { return NodeProperties::GetContextInput(node_); } |
161 Node* left() { return NodeProperties::GetValueInput(node_, 0); } | 183 Node* left() { return NodeProperties::GetValueInput(node_, 0); } |
162 Node* right() { return NodeProperties::GetValueInput(node_, 1); } | 184 Node* right() { return NodeProperties::GetValueInput(node_, 1); } |
163 Type* left_type() { return left_type_; } | 185 Type* left_type() { |
164 Type* right_type() { return right_type_; } | 186 return NodeProperties::GetBounds(node_->InputAt(0)).upper; |
187 } | |
188 Type* right_type() { | |
189 return NodeProperties::GetBounds(node_->InputAt(1)).upper; | |
190 } | |
165 | 191 |
166 SimplifiedOperatorBuilder* simplified() { return lowering_->simplified(); } | 192 SimplifiedOperatorBuilder* simplified() { return lowering_->simplified(); } |
167 Graph* graph() const { return lowering_->graph(); } | 193 Graph* graph() const { return lowering_->graph(); } |
168 JSGraph* jsgraph() { return lowering_->jsgraph(); } | 194 JSGraph* jsgraph() { return lowering_->jsgraph(); } |
169 JSOperatorBuilder* javascript() { return lowering_->javascript(); } | 195 JSOperatorBuilder* javascript() { return lowering_->javascript(); } |
170 MachineOperatorBuilder* machine() { return lowering_->machine(); } | 196 MachineOperatorBuilder* machine() { return lowering_->machine(); } |
171 Zone* zone() const { return graph()->zone(); } | 197 Zone* zone() const { return graph()->zone(); } |
172 | 198 |
173 private: | 199 private: |
174 JSTypedLowering* lowering_; // The containing lowering instance. | 200 JSTypedLowering* lowering_; // The containing lowering instance. |
175 Node* node_; // The original node. | 201 Node* node_; // The original node. |
176 Type* left_type_; // Cache of the left input's type. | |
177 Type* right_type_; // Cache of the right input's type. | |
178 | 202 |
179 Node* ConvertToString(Node* node) { | 203 Node* ConvertToString(Node* node) { |
180 // Avoid introducing too many eager ToString() operations. | 204 // Avoid introducing too many eager ToString() operations. |
181 Reduction reduced = lowering_->ReduceJSToStringInput(node); | 205 Reduction reduced = lowering_->ReduceJSToStringInput(node); |
182 if (reduced.Changed()) return reduced.replacement(); | 206 if (reduced.Changed()) return reduced.replacement(); |
183 Node* n = graph()->NewNode(javascript()->ToString(), node, context(), | 207 Node* n = graph()->NewNode(javascript()->ToString(), node, context(), |
184 effect(), control()); | 208 effect(), control()); |
185 update_effect(n); | 209 update_effect(n); |
186 return n; | 210 return n; |
187 } | 211 } |
188 | 212 |
189 Node* ConvertToNumber(Node* node) { | 213 Node* CreateFrameStateForLeftInput(Node* frame_state) { |
214 if (!FLAG_turbo_deoptimization) return nullptr; | |
215 | |
216 FrameStateCallInfo state_info = | |
217 OpParameter<FrameStateCallInfo>(frame_state); | |
218 // If the frame state is already the right one, just return it. | |
219 if (state_info.state_combine().kind() == OutputFrameStateCombine::kPokeAt && | |
220 state_info.state_combine().GetOffsetToPokeAt() == 1) { | |
221 return frame_state; | |
222 } | |
223 | |
224 // Here, we smash the result of the conversion into the slot just below | |
225 // the stack top. This is the slot that full code uses to store the | |
226 // left operand. | |
227 const Operator* op = jsgraph()->common()->FrameState( | |
228 state_info.type(), state_info.bailout_id(), | |
229 OutputFrameStateCombine::PokeAt(1)); | |
230 | |
231 return graph()->NewNode(op, frame_state->InputAt(0), | |
Benedikt Meurer
2015/03/09 09:57:29
As discussed offline, please add something like No
| |
232 frame_state->InputAt(1), frame_state->InputAt(2), | |
233 frame_state->InputAt(3), frame_state->InputAt(4)); | |
234 } | |
235 | |
236 Node* CreateFrameStateForRightInput(Node* frame_state, Node* converted_left) { | |
237 if (!FLAG_turbo_deoptimization) return nullptr; | |
238 | |
239 FrameStateCallInfo state_info = | |
240 OpParameter<FrameStateCallInfo>(frame_state); | |
241 | |
242 if (state_info.bailout_id() == BailoutId::None()) { | |
243 // Dummy frame state => just leave it as is. | |
244 return frame_state; | |
245 } | |
246 | |
247 // Create a frame state that stores the result of the operation to the | |
248 // top of the stack (i.e., the slot used for the right operand). | |
249 const Operator* op = jsgraph()->common()->FrameState( | |
250 state_info.type(), state_info.bailout_id(), | |
251 OutputFrameStateCombine::PokeAt(0)); | |
252 | |
253 // Change the left operand {converted_left} on the expression stack. | |
254 Node* stack = frame_state->InputAt(2); | |
255 DCHECK_EQ(stack->opcode(), IrOpcode::kStateValues); | |
256 DCHECK_GE(stack->InputCount(), 2); | |
257 | |
258 // TODO(jarin) Allocate in a local zone or a reusable buffer. | |
259 NodeVector new_values(stack->InputCount(), zone()); | |
260 for (int i = 0; i < stack->InputCount(); i++) { | |
261 if (i == stack->InputCount() - 2) { | |
262 new_values[i] = converted_left; | |
263 } else { | |
264 new_values[i] = stack->InputAt(i); | |
265 } | |
266 } | |
267 Node* new_stack = | |
268 graph()->NewNode(stack->op(), stack->InputCount(), &new_values.front()); | |
269 | |
270 return graph()->NewNode(op, frame_state->InputAt(0), | |
Benedikt Meurer
2015/03/09 09:57:29
As discussed offline, please add something like No
| |
271 frame_state->InputAt(1), new_stack, | |
272 frame_state->InputAt(3), frame_state->InputAt(4)); | |
273 } | |
274 | |
275 Node* ConvertPrimitiveToNumber(Node* node) { | |
276 return lowering_->ConvertPrimitiveToNumber(node); | |
277 } | |
278 | |
279 Node* ConvertToNumber(Node* node, Node* frame_state) { | |
190 if (NodeProperties::GetBounds(node).upper->Is(Type::PlainPrimitive())) { | 280 if (NodeProperties::GetBounds(node).upper->Is(Type::PlainPrimitive())) { |
191 return lowering_->ConvertToNumber(node); | 281 return ConvertPrimitiveToNumber(node); |
282 } else if (!FLAG_turbo_deoptimization) { | |
283 // We cannot use ConvertToPrimitiveNumber here because we need context | |
284 // for converting general values. | |
285 Node* const n = graph()->NewNode(javascript()->ToNumber(), node, | |
286 context(), effect(), control()); | |
287 update_effect(n); | |
288 return n; | |
289 } else { | |
290 Node* const n = | |
291 graph()->NewNode(javascript()->ToNumber(), node, context(), | |
292 frame_state, effect(), control()); | |
293 update_effect(n); | |
294 return n; | |
192 } | 295 } |
193 // TODO(jarin) This ToNumber conversion can deoptimize, but we do not really | |
194 // have a frame state to deoptimize to. Either we provide such a frame state | |
195 // or we exclude the values that could lead to deoptimization (e.g., by | |
196 // triggering eager deopt if the value is not plain). | |
197 Node* const n = FLAG_turbo_deoptimization | |
198 ? graph()->NewNode( | |
199 javascript()->ToNumber(), node, context(), | |
200 jsgraph()->EmptyFrameState(), effect(), control()) | |
201 : graph()->NewNode(javascript()->ToNumber(), node, | |
202 context(), effect(), control()); | |
203 update_effect(n); | |
204 return n; | |
205 } | 296 } |
206 | 297 |
207 Node* ConvertToUI32(Node* node, Signedness signedness) { | 298 Node* ConvertToUI32(Node* node, Signedness signedness) { |
208 // Avoid introducing too many eager NumberToXXnt32() operations. | 299 // Avoid introducing too many eager NumberToXXnt32() operations. |
209 node = ConvertToNumber(node); | |
210 Type* type = NodeProperties::GetBounds(node).upper; | 300 Type* type = NodeProperties::GetBounds(node).upper; |
211 if (signedness == kSigned) { | 301 if (signedness == kSigned) { |
212 if (!type->Is(Type::Signed32())) { | 302 if (!type->Is(Type::Signed32())) { |
213 node = graph()->NewNode(simplified()->NumberToInt32(), node); | 303 node = graph()->NewNode(simplified()->NumberToInt32(), node); |
214 } | 304 } |
215 } else { | 305 } else { |
216 DCHECK_EQ(kUnsigned, signedness); | 306 DCHECK_EQ(kUnsigned, signedness); |
217 if (!type->Is(Type::Unsigned32())) { | 307 if (!type->Is(Type::Unsigned32())) { |
218 node = graph()->NewNode(simplified()->NumberToUint32(), node); | 308 node = graph()->NewNode(simplified()->NumberToUint32(), node); |
219 } | 309 } |
220 } | 310 } |
221 return node; | 311 return node; |
222 } | 312 } |
223 | 313 |
224 void update_effect(Node* effect) { | 314 void update_effect(Node* effect) { |
225 NodeProperties::ReplaceEffectInput(node_, effect); | 315 NodeProperties::ReplaceEffectInput(node_, effect); |
226 } | 316 } |
227 }; | 317 }; |
228 | 318 |
229 | 319 |
230 Reduction JSTypedLowering::ReduceJSAdd(Node* node) { | 320 Reduction JSTypedLowering::ReduceJSAdd(Node* node) { |
231 JSBinopReduction r(this, node); | 321 JSBinopReduction r(this, node); |
232 if (r.BothInputsAre(Type::Number())) { | 322 if (r.BothInputsAre(Type::Number())) { |
233 // JSAdd(x:number, y:number) => NumberAdd(x, y) | 323 // JSAdd(x:number, y:number) => NumberAdd(x, y) |
234 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number()); | 324 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number()); |
235 } | 325 } |
236 if (r.BothInputsAre(Type::Primitive()) && | 326 if (r.NeitherInputCanBe(Type::StringOrReceiver())) { |
237 r.NeitherInputCanBe(Type::StringOrReceiver())) { | |
238 // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y)) | 327 // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y)) |
239 r.ConvertInputsToNumber(); | 328 Node* frame_state = FLAG_turbo_deoptimization |
329 ? NodeProperties::GetFrameStateInput(node, 1) | |
330 : nullptr; | |
331 r.ConvertInputsToNumber(frame_state); | |
240 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number()); | 332 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number()); |
241 } | 333 } |
242 #if 0 | 334 #if 0 |
243 // TODO(turbofan): General ToNumber disabled for now because: | |
244 // a) The inserted ToNumber operation screws up observability of valueOf. | |
245 // b) Deoptimization at ToNumber doesn't have corresponding bailout id. | |
246 Type* maybe_string = Type::Union(Type::String(), Type::Receiver(), zone()); | |
247 if (r.NeitherInputCanBe(maybe_string)) { | |
248 ... | |
249 } | |
250 #endif | |
251 #if 0 | |
252 // TODO(turbofan): Lowering of StringAdd is disabled for now because: | 335 // TODO(turbofan): Lowering of StringAdd is disabled for now because: |
253 // a) The inserted ToString operation screws up valueOf vs. toString order. | 336 // a) The inserted ToString operation screws up valueOf vs. toString order. |
254 // b) Deoptimization at ToString doesn't have corresponding bailout id. | 337 // b) Deoptimization at ToString doesn't have corresponding bailout id. |
255 // c) Our current StringAddStub is actually non-pure and requires context. | 338 // c) Our current StringAddStub is actually non-pure and requires context. |
256 if (r.OneInputIs(Type::String())) { | 339 if (r.OneInputIs(Type::String())) { |
257 // JSAdd(x:string, y:string) => StringAdd(x, y) | 340 // JSAdd(x:string, y:string) => StringAdd(x, y) |
258 // JSAdd(x:string, y) => StringAdd(x, ToString(y)) | 341 // JSAdd(x:string, y) => StringAdd(x, ToString(y)) |
259 // JSAdd(x, y:string) => StringAdd(ToString(x), y) | 342 // JSAdd(x, y:string) => StringAdd(ToString(x), y) |
260 r.ConvertInputsToString(); | 343 r.ConvertInputsToString(); |
261 return r.ChangeToPureOperator(simplified()->StringAdd()); | 344 return r.ChangeToPureOperator(simplified()->StringAdd()); |
262 } | 345 } |
263 #endif | 346 #endif |
264 return NoChange(); | 347 return NoChange(); |
265 } | 348 } |
266 | 349 |
267 | 350 |
268 Reduction JSTypedLowering::ReduceJSBitwiseOr(Node* node) { | |
269 JSBinopReduction r(this, node); | |
270 | |
271 // We can only reduce to Word32Or if we are sure the to-number conversions | |
272 // cannot lazily deoptimize. | |
273 bool shortcut_or_zero = | |
274 !FLAG_turbo_deoptimization && r.OneInputIs(zero_range_); | |
275 if (r.BothInputsAre(Type::Primitive()) || shortcut_or_zero) { | |
276 // TODO(titzer): some Smi bitwise operations don't really require going | |
277 // all the way to int32, which can save tagging/untagging for some | |
278 // operations on some platforms. | |
279 // TODO(turbofan): make this heuristic configurable for code size. | |
280 r.ConvertInputsToUI32(kSigned, kSigned); | |
281 return r.ChangeToPureOperator(machine()->Word32Or(), Type::Integral32()); | |
282 } | |
283 return NoChange(); | |
284 } | |
285 | |
286 | |
287 Reduction JSTypedLowering::ReduceJSMultiply(Node* node) { | |
288 JSBinopReduction r(this, node); | |
289 | |
290 // We can only reduce to NumberMultiply if we are sure the to-number | |
291 // conversions cannot lazily deoptimize. | |
292 bool shortcut_multiply_one = | |
293 !FLAG_turbo_deoptimization && r.OneInputIs(one_range_); | |
294 | |
295 if (r.BothInputsAre(Type::Primitive()) || shortcut_multiply_one) { | |
296 r.ConvertInputsToNumber(); | |
297 return r.ChangeToPureOperator(simplified()->NumberMultiply(), | |
298 Type::Number()); | |
299 } | |
300 // TODO(turbofan): relax/remove the effects of this operator in other cases. | |
301 return NoChange(); | |
302 } | |
303 | |
304 | |
305 Reduction JSTypedLowering::ReduceNumberBinop(Node* node, | 351 Reduction JSTypedLowering::ReduceNumberBinop(Node* node, |
306 const Operator* numberOp) { | 352 const Operator* numberOp) { |
307 JSBinopReduction r(this, node); | 353 JSBinopReduction r(this, node); |
308 if (r.BothInputsAre(Type::Primitive())) { | 354 Node* frame_state = FLAG_turbo_deoptimization |
309 r.ConvertInputsToNumber(); | 355 ? NodeProperties::GetFrameStateInput(node, 1) |
310 return r.ChangeToPureOperator(numberOp, Type::Number()); | 356 : nullptr; |
311 } | 357 r.ConvertInputsToNumber(frame_state); |
312 #if 0 | 358 return r.ChangeToPureOperator(numberOp, Type::Number()); |
313 // TODO(turbofan): General ToNumber disabled for now because: | |
314 // a) The inserted ToNumber operation screws up observability of valueOf. | |
315 // b) Deoptimization at ToNumber doesn't have corresponding bailout id. | |
316 if (r.OneInputIs(Type::Primitive())) { | |
317 // If at least one input is a primitive, then insert appropriate conversions | |
318 // to number and reduce this operator to the given numeric one. | |
319 // TODO(turbofan): make this heuristic configurable for code size. | |
320 r.ConvertInputsToNumber(); | |
321 return r.ChangeToPureOperator(numberOp); | |
322 } | |
323 #endif | |
324 // TODO(turbofan): relax/remove the effects of this operator in other cases. | |
325 return NoChange(); | |
326 } | 359 } |
327 | 360 |
328 | 361 |
329 Reduction JSTypedLowering::ReduceInt32Binop(Node* node, const Operator* intOp) { | 362 Reduction JSTypedLowering::ReduceInt32Binop(Node* node, const Operator* intOp) { |
330 JSBinopReduction r(this, node); | 363 JSBinopReduction r(this, node); |
331 if (r.BothInputsAre(Type::Primitive())) { | 364 Node* frame_state = FLAG_turbo_deoptimization |
332 // TODO(titzer): some Smi bitwise operations don't really require going | 365 ? NodeProperties::GetFrameStateInput(node, 1) |
333 // all the way to int32, which can save tagging/untagging for some | 366 : nullptr; |
334 // operations | 367 r.ConvertInputsToNumber(frame_state); |
335 // on some platforms. | 368 r.ConvertInputsToUI32(kSigned, kSigned); |
336 // TODO(turbofan): make this heuristic configurable for code size. | 369 return r.ChangeToPureOperator(intOp, Type::Integral32()); |
337 r.ConvertInputsToUI32(kSigned, kSigned); | |
338 return r.ChangeToPureOperator(intOp, Type::Integral32()); | |
339 } | |
340 return NoChange(); | |
341 } | 370 } |
342 | 371 |
343 | 372 |
344 Reduction JSTypedLowering::ReduceUI32Shift(Node* node, | 373 Reduction JSTypedLowering::ReduceUI32Shift(Node* node, |
345 Signedness left_signedness, | 374 Signedness left_signedness, |
346 const Operator* shift_op) { | 375 const Operator* shift_op) { |
347 JSBinopReduction r(this, node); | 376 JSBinopReduction r(this, node); |
348 if (r.BothInputsAre(Type::Primitive())) { | 377 if (r.BothInputsAre(Type::Primitive())) { |
349 r.ConvertInputsForShift(left_signedness); | 378 r.ConvertInputsForShift(left_signedness); |
350 return r.ChangeToPureOperator(shift_op, Type::Integral32()); | 379 return r.ChangeToPureOperator(shift_op, Type::Integral32()); |
(...skipping 30 matching lines...) Expand all Loading... | |
381 #if 0 | 410 #if 0 |
382 // TODO(turbofan): General ToNumber disabled for now because: | 411 // TODO(turbofan): General ToNumber disabled for now because: |
383 // a) The inserted ToNumber operation screws up observability of valueOf. | 412 // a) The inserted ToNumber operation screws up observability of valueOf. |
384 // b) Deoptimization at ToNumber doesn't have corresponding bailout id. | 413 // b) Deoptimization at ToNumber doesn't have corresponding bailout id. |
385 Type* maybe_string = Type::Union(Type::String(), Type::Receiver(), zone()); | 414 Type* maybe_string = Type::Union(Type::String(), Type::Receiver(), zone()); |
386 if (r.OneInputCannotBe(maybe_string)) { | 415 if (r.OneInputCannotBe(maybe_string)) { |
387 // If one input cannot be a string, then emit a number comparison. | 416 // If one input cannot be a string, then emit a number comparison. |
388 ... | 417 ... |
389 } | 418 } |
390 #endif | 419 #endif |
391 if (r.BothInputsAre(Type::Primitive()) && | 420 if (r.BothInputsAre(Type::PlainPrimitive()) && |
392 r.OneInputCannotBe(Type::StringOrReceiver())) { | 421 r.OneInputCannotBe(Type::StringOrReceiver())) { |
393 const Operator* less_than; | 422 const Operator* less_than; |
394 const Operator* less_than_or_equal; | 423 const Operator* less_than_or_equal; |
395 if (r.BothInputsAre(Type::Unsigned32())) { | 424 if (r.BothInputsAre(Type::Unsigned32())) { |
396 less_than = machine()->Uint32LessThan(); | 425 less_than = machine()->Uint32LessThan(); |
397 less_than_or_equal = machine()->Uint32LessThanOrEqual(); | 426 less_than_or_equal = machine()->Uint32LessThanOrEqual(); |
398 } else if (r.BothInputsAre(Type::Signed32())) { | 427 } else if (r.BothInputsAre(Type::Signed32())) { |
399 less_than = machine()->Int32LessThan(); | 428 less_than = machine()->Int32LessThan(); |
400 less_than_or_equal = machine()->Int32LessThanOrEqual(); | 429 less_than_or_equal = machine()->Int32LessThanOrEqual(); |
401 } else { | 430 } else { |
402 // TODO(turbofan): mixed signed/unsigned int32 comparisons. | 431 // TODO(turbofan): mixed signed/unsigned int32 comparisons. |
403 r.ConvertInputsToNumber(); | 432 r.ConvertPrimitiveInputsToNumber(); |
404 less_than = simplified()->NumberLessThan(); | 433 less_than = simplified()->NumberLessThan(); |
405 less_than_or_equal = simplified()->NumberLessThanOrEqual(); | 434 less_than_or_equal = simplified()->NumberLessThanOrEqual(); |
406 } | 435 } |
407 const Operator* comparison; | 436 const Operator* comparison; |
408 switch (node->opcode()) { | 437 switch (node->opcode()) { |
409 case IrOpcode::kJSLessThan: | 438 case IrOpcode::kJSLessThan: |
410 comparison = less_than; | 439 comparison = less_than; |
411 break; | 440 break; |
412 case IrOpcode::kJSGreaterThan: | 441 case IrOpcode::kJSGreaterThan: |
413 comparison = less_than; | 442 comparison = less_than; |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
588 DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Number())); | 617 DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Number())); |
589 RelaxEffectsAndControls(node); | 618 RelaxEffectsAndControls(node); |
590 node->set_op(common()->Phi(kMachAnyTagged, input_count)); | 619 node->set_op(common()->Phi(kMachAnyTagged, input_count)); |
591 for (int i = 0; i < input_count; ++i) { | 620 for (int i = 0; i < input_count; ++i) { |
592 // We must be very careful not to introduce cycles when pushing | 621 // We must be very careful not to introduce cycles when pushing |
593 // operations into phis. It is safe for {value}, since it appears | 622 // operations into phis. It is safe for {value}, since it appears |
594 // as input to the phi that we are replacing, but it's not safe | 623 // as input to the phi that we are replacing, but it's not safe |
595 // to simply reuse the context of the {node}. However, ToNumber() | 624 // to simply reuse the context of the {node}. However, ToNumber() |
596 // does not require a context anyways, so it's safe to discard it | 625 // does not require a context anyways, so it's safe to discard it |
597 // here and pass the dummy context. | 626 // here and pass the dummy context. |
598 Node* const value = ConvertToNumber(input->InputAt(i)); | 627 Node* const value = ConvertPrimitiveToNumber(input->InputAt(i)); |
599 if (i < node->InputCount()) { | 628 if (i < node->InputCount()) { |
600 node->ReplaceInput(i, value); | 629 node->ReplaceInput(i, value); |
601 } else { | 630 } else { |
602 node->AppendInput(graph()->zone(), value); | 631 node->AppendInput(graph()->zone(), value); |
603 } | 632 } |
604 } | 633 } |
605 if (input_count < node->InputCount()) { | 634 if (input_count < node->InputCount()) { |
606 node->ReplaceInput(input_count, control); | 635 node->ReplaceInput(input_count, control); |
607 } else { | 636 } else { |
608 node->AppendInput(graph()->zone(), control); | 637 node->AppendInput(graph()->zone(), control); |
(...skipping 12 matching lines...) Expand all Loading... | |
621 RelaxEffectsAndControls(node); | 650 RelaxEffectsAndControls(node); |
622 node->set_op(common()->Select(kMachAnyTagged, input_hint)); | 651 node->set_op(common()->Select(kMachAnyTagged, input_hint)); |
623 node->ReplaceInput(0, input->InputAt(0)); | 652 node->ReplaceInput(0, input->InputAt(0)); |
624 for (int i = 1; i < input_count; ++i) { | 653 for (int i = 1; i < input_count; ++i) { |
625 // We must be very careful not to introduce cycles when pushing | 654 // We must be very careful not to introduce cycles when pushing |
626 // operations into selects. It is safe for {value}, since it appears | 655 // operations into selects. It is safe for {value}, since it appears |
627 // as input to the select that we are replacing, but it's not safe | 656 // as input to the select that we are replacing, but it's not safe |
628 // to simply reuse the context of the {node}. However, ToNumber() | 657 // to simply reuse the context of the {node}. However, ToNumber() |
629 // does not require a context anyways, so it's safe to discard it | 658 // does not require a context anyways, so it's safe to discard it |
630 // here and pass the dummy context. | 659 // here and pass the dummy context. |
631 Node* const value = ConvertToNumber(input->InputAt(i)); | 660 Node* const value = ConvertPrimitiveToNumber(input->InputAt(i)); |
632 node->ReplaceInput(i, value); | 661 node->ReplaceInput(i, value); |
633 } | 662 } |
634 node->TrimInputCount(input_count); | 663 node->TrimInputCount(input_count); |
635 return Changed(node); | 664 return Changed(node); |
636 } | 665 } |
637 // Remember this conversion. | 666 // Remember this conversion. |
638 InsertConversion(node); | 667 InsertConversion(node); |
639 if (NodeProperties::GetContextInput(node) != | 668 if (NodeProperties::GetContextInput(node) != |
640 jsgraph()->NoContextConstant() || | 669 jsgraph()->NoContextConstant() || |
641 NodeProperties::GetEffectInput(node) != graph()->start() || | 670 NodeProperties::GetEffectInput(node) != graph()->start() || |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
904 case IrOpcode::kJSStrictEqual: | 933 case IrOpcode::kJSStrictEqual: |
905 return ReduceJSStrictEqual(node, false); | 934 return ReduceJSStrictEqual(node, false); |
906 case IrOpcode::kJSStrictNotEqual: | 935 case IrOpcode::kJSStrictNotEqual: |
907 return ReduceJSStrictEqual(node, true); | 936 return ReduceJSStrictEqual(node, true); |
908 case IrOpcode::kJSLessThan: // fall through | 937 case IrOpcode::kJSLessThan: // fall through |
909 case IrOpcode::kJSGreaterThan: // fall through | 938 case IrOpcode::kJSGreaterThan: // fall through |
910 case IrOpcode::kJSLessThanOrEqual: // fall through | 939 case IrOpcode::kJSLessThanOrEqual: // fall through |
911 case IrOpcode::kJSGreaterThanOrEqual: | 940 case IrOpcode::kJSGreaterThanOrEqual: |
912 return ReduceJSComparison(node); | 941 return ReduceJSComparison(node); |
913 case IrOpcode::kJSBitwiseOr: | 942 case IrOpcode::kJSBitwiseOr: |
914 return ReduceJSBitwiseOr(node); | 943 return ReduceInt32Binop(node, machine()->Word32Or()); |
915 case IrOpcode::kJSBitwiseXor: | 944 case IrOpcode::kJSBitwiseXor: |
916 return ReduceInt32Binop(node, machine()->Word32Xor()); | 945 return ReduceInt32Binop(node, machine()->Word32Xor()); |
917 case IrOpcode::kJSBitwiseAnd: | 946 case IrOpcode::kJSBitwiseAnd: |
918 return ReduceInt32Binop(node, machine()->Word32And()); | 947 return ReduceInt32Binop(node, machine()->Word32And()); |
919 case IrOpcode::kJSShiftLeft: | 948 case IrOpcode::kJSShiftLeft: |
920 return ReduceUI32Shift(node, kSigned, machine()->Word32Shl()); | 949 return ReduceUI32Shift(node, kSigned, machine()->Word32Shl()); |
921 case IrOpcode::kJSShiftRight: | 950 case IrOpcode::kJSShiftRight: |
922 return ReduceUI32Shift(node, kSigned, machine()->Word32Sar()); | 951 return ReduceUI32Shift(node, kSigned, machine()->Word32Sar()); |
923 case IrOpcode::kJSShiftRightLogical: | 952 case IrOpcode::kJSShiftRightLogical: |
924 return ReduceUI32Shift(node, kUnsigned, machine()->Word32Shr()); | 953 return ReduceUI32Shift(node, kUnsigned, machine()->Word32Shr()); |
925 case IrOpcode::kJSAdd: | 954 case IrOpcode::kJSAdd: |
926 return ReduceJSAdd(node); | 955 return ReduceJSAdd(node); |
927 case IrOpcode::kJSSubtract: | 956 case IrOpcode::kJSSubtract: |
928 return ReduceNumberBinop(node, simplified()->NumberSubtract()); | 957 return ReduceNumberBinop(node, simplified()->NumberSubtract()); |
929 case IrOpcode::kJSMultiply: | 958 case IrOpcode::kJSMultiply: |
930 return ReduceJSMultiply(node); | 959 return ReduceNumberBinop(node, simplified()->NumberMultiply()); |
931 case IrOpcode::kJSDivide: | 960 case IrOpcode::kJSDivide: |
932 return ReduceNumberBinop(node, simplified()->NumberDivide()); | 961 return ReduceNumberBinop(node, simplified()->NumberDivide()); |
933 case IrOpcode::kJSModulus: | 962 case IrOpcode::kJSModulus: |
934 return ReduceNumberBinop(node, simplified()->NumberModulus()); | 963 return ReduceNumberBinop(node, simplified()->NumberModulus()); |
935 case IrOpcode::kJSUnaryNot: | 964 case IrOpcode::kJSUnaryNot: |
936 return ReduceJSUnaryNot(node); | 965 return ReduceJSUnaryNot(node); |
937 case IrOpcode::kJSToBoolean: | 966 case IrOpcode::kJSToBoolean: |
938 return ReduceJSToBoolean(node); | 967 return ReduceJSToBoolean(node); |
939 case IrOpcode::kJSToNumber: | 968 case IrOpcode::kJSToNumber: |
940 return ReduceJSToNumber(node); | 969 return ReduceJSToNumber(node); |
941 case IrOpcode::kJSToString: | 970 case IrOpcode::kJSToString: |
942 return ReduceJSToString(node); | 971 return ReduceJSToString(node); |
943 case IrOpcode::kJSLoadProperty: | 972 case IrOpcode::kJSLoadProperty: |
944 return ReduceJSLoadProperty(node); | 973 return ReduceJSLoadProperty(node); |
945 case IrOpcode::kJSStoreProperty: | 974 case IrOpcode::kJSStoreProperty: |
946 return ReduceJSStoreProperty(node); | 975 return ReduceJSStoreProperty(node); |
947 case IrOpcode::kJSLoadContext: | 976 case IrOpcode::kJSLoadContext: |
948 return ReduceJSLoadContext(node); | 977 return ReduceJSLoadContext(node); |
949 case IrOpcode::kJSStoreContext: | 978 case IrOpcode::kJSStoreContext: |
950 return ReduceJSStoreContext(node); | 979 return ReduceJSStoreContext(node); |
951 default: | 980 default: |
952 break; | 981 break; |
953 } | 982 } |
954 return NoChange(); | 983 return NoChange(); |
955 } | 984 } |
956 | 985 |
957 | 986 |
958 Node* JSTypedLowering::ConvertToNumber(Node* input) { | 987 Node* JSTypedLowering::ConvertPrimitiveToNumber(Node* input) { |
959 DCHECK(NodeProperties::GetBounds(input).upper->Is(Type::PlainPrimitive())); | 988 DCHECK(NodeProperties::GetBounds(input).upper->Is(Type::PlainPrimitive())); |
960 // Avoid inserting too many eager ToNumber() operations. | 989 // Avoid inserting too many eager ToNumber() operations. |
961 Reduction const reduction = ReduceJSToNumberInput(input); | 990 Reduction const reduction = ReduceJSToNumberInput(input); |
962 if (reduction.Changed()) return reduction.replacement(); | 991 if (reduction.Changed()) return reduction.replacement(); |
963 // TODO(jarin) Use PlainPrimitiveToNumber once we have it. | 992 // TODO(jarin) Use PlainPrimitiveToNumber once we have it. |
964 Node* const conversion = | 993 Node* const conversion = |
965 FLAG_turbo_deoptimization | 994 FLAG_turbo_deoptimization |
966 ? graph()->NewNode(javascript()->ToNumber(), input, | 995 ? graph()->NewNode(javascript()->ToNumber(), input, |
967 jsgraph()->NoContextConstant(), | 996 jsgraph()->NoContextConstant(), |
968 jsgraph()->EmptyFrameState(), graph()->start(), | 997 jsgraph()->EmptyFrameState(), graph()->start(), |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1021 } | 1050 } |
1022 | 1051 |
1023 | 1052 |
1024 MachineOperatorBuilder* JSTypedLowering::machine() const { | 1053 MachineOperatorBuilder* JSTypedLowering::machine() const { |
1025 return jsgraph()->machine(); | 1054 return jsgraph()->machine(); |
1026 } | 1055 } |
1027 | 1056 |
1028 } // namespace compiler | 1057 } // namespace compiler |
1029 } // namespace internal | 1058 } // namespace internal |
1030 } // namespace v8 | 1059 } // namespace v8 |
OLD | NEW |