Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(66)

Side by Side Diff: src/compiler/js-typed-lowering.cc

Issue 985713003: [turbofan] Fix lazy deopt for JSToNumber conversions in binary operations. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@multiple-framestates
Patch Set: Fixes, rebase Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/compiler/js-typed-lowering.h ('k') | test/cctest/cctest.status » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/compiler/js-typed-lowering.h ('k') | test/cctest/cctest.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698