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/simplified-lowering.h" | 5 #include "src/compiler/simplified-lowering.h" |
6 | 6 |
7 #include <deque> | |
8 #include <queue> | |
9 | |
10 #include "src/compiler/common-operator.h" | |
7 #include "src/compiler/graph-inl.h" | 11 #include "src/compiler/graph-inl.h" |
8 #include "src/compiler/node-properties-inl.h" | 12 #include "src/compiler/node-properties-inl.h" |
13 #include "src/compiler/representation-change.h" | |
14 #include "src/compiler/simplified-lowering.h" | |
15 #include "src/compiler/simplified-operator.h" | |
9 #include "src/objects.h" | 16 #include "src/objects.h" |
10 | 17 |
11 namespace v8 { | 18 namespace v8 { |
12 namespace internal { | 19 namespace internal { |
13 namespace compiler { | 20 namespace compiler { |
14 | 21 |
22 // Macro for outputting trace information from representation inference. | |
23 #define TRACE(x) \ | |
24 if (FLAG_trace_representation) PrintF x | |
25 | |
26 // Representation selection and lowering of {Simplified} operators to machine | |
27 // operators are interwined. We use a fixpoint calculation to compute both the | |
28 // output representation and the best possible lowering for {Simplified} nodes. | |
29 // Representation change insertion ensures that all values are in the correct | |
30 // machine representation after this phase, as dictated by the machine | |
31 // operators themselves. | |
32 enum Phase { | |
rossberg
2014/08/06 13:04:07
I wish we could somehow factor this using some for
titzer
2014/08/08 09:16:13
As discussed, the virtual method thing is going to
| |
33 // 1.) PROPAGATE: Traverse the graph from the end, pushing usage information | |
34 // backwards from uses to definitions, around cycles in phis, according | |
35 // to local rules for each operator. | |
36 // During this phase, the usage information for a node determines the best | |
37 // possible lowering for each operator so far, and that in turn determines | |
38 // the output representation. | |
39 // Therefore, to be correct, this phase must iterate to a fixpoint before | |
40 // the next phase can begin. | |
41 PROPAGATE, | |
42 | |
43 // 2.) LOWER: perform lowering for all {Simplified} nodes by replacing some | |
44 // operators for some nodes, expanding some nodes to multiple nodes, or | |
45 // removing some (redundant) nodes. | |
46 // During this phase, use the {RepresentationChanger} to insert | |
47 // representation changes between uses that demand a particular | |
48 // representation and nodes that produce a different representation. | |
49 LOWER | |
50 }; | |
51 | |
52 | |
53 class RepresentationSelector { | |
54 public: | |
55 // Information for each node tracked during the fixpoint. | |
56 struct NodeInfo { | |
57 RepTypeUnion use : 14; // Union of all usages for the node. | |
58 bool queued : 1; // Bookkeeping for the traversal. | |
59 bool visited : 1; // Bookkeeping for the traversal. | |
60 RepTypeUnion output : 16; // Output type of the node. | |
rossberg
2014/08/06 13:04:07
Why is this bitset larger than the other?
titzer
2014/08/08 09:16:13
Done.
| |
61 }; | |
62 | |
63 RepresentationSelector(JSGraph* jsgraph, Zone* zone, | |
64 RepresentationChanger* changer) | |
65 : jsgraph_(jsgraph), | |
66 zone_(zone), | |
67 count_(jsgraph->graph()->NodeCount()), | |
68 info_(zone->NewArray<NodeInfo>(count_)), | |
69 nodes_(NodeVector::allocator_type(zone)), | |
70 contains_js_nodes_(false), | |
71 phase_(PROPAGATE), | |
72 changer_(changer), | |
73 queue_(std::deque<Node*, NodePtrZoneAllocator>( | |
74 NodePtrZoneAllocator(zone))) { | |
75 memset(info_, 0, sizeof(NodeInfo) * count_); | |
76 } | |
77 | |
78 void Run(SimplifiedLowering* lowering) { | |
79 // Run propagation phase to a fixpoint. | |
80 TRACE(("--{Propagation phase}--\n")); | |
81 phase_ = PROPAGATE; | |
82 Enqueue(jsgraph_->graph()->end()); | |
83 // Process nodes from the queue until it is empty. | |
84 while (!queue_.empty()) { | |
85 Node* node = queue_.front(); | |
86 NodeInfo* info = GetInfo(node); | |
87 queue_.pop(); | |
88 info->queued = false; | |
89 TRACE((" visit #%d: %s\n", node->id(), node->op()->mnemonic())); | |
90 VisitNode(node, info->use, NULL); | |
91 TRACE((" ==> output ")); | |
92 PrintInfo(info->output); | |
93 TRACE(("\n")); | |
94 } | |
95 | |
96 // Run lowering and change insertion phase. | |
97 TRACE(("--{Simplified lowering phase}--\n")); | |
98 phase_ = LOWER; | |
99 // Process nodes from the collected {nodes_} vector. | |
100 for (NodeVector::iterator i = nodes_.begin(); i != nodes_.end(); ++i) { | |
101 Node* node = *i; | |
102 TRACE((" visit #%d: %s\n", node->id(), node->op()->mnemonic())); | |
103 // Reuse {VisitNode()} so the representation rules are in one place. | |
104 VisitNode(node, GetUseInfo(node), lowering); | |
105 } | |
106 } | |
107 | |
108 // Enqueue {node} if the {use} contains new information for that node. | |
109 // Add {node} to {nodes_} if this is the first time it's been visited. | |
110 void Enqueue(Node* node, RepTypeUnion use = 0) { | |
111 if (phase_ != PROPAGATE) return; | |
112 NodeInfo* info = GetInfo(node); | |
113 if (!info->visited) { | |
114 // First visit of this node. | |
115 info->visited = true; | |
116 info->queued = true; | |
117 nodes_.push_back(node); | |
118 queue_.push(node); | |
119 TRACE((" initial: ")); | |
120 info->use |= use; | |
121 PrintUseInfo(node); | |
122 return; | |
123 } | |
124 TRACE((" queue?: ")); | |
125 PrintUseInfo(node); | |
126 if ((info->use & use) != use) { | |
127 // New usage information for the node is available. | |
128 if (!info->queued) { | |
129 queue_.push(node); | |
130 info->queued = true; | |
131 TRACE((" added: ")); | |
132 } else { | |
133 TRACE((" inqueue: ")); | |
134 } | |
135 info->use |= use; | |
136 PrintUseInfo(node); | |
137 } | |
138 } | |
139 | |
140 bool lower() { return phase_ == LOWER; } | |
141 | |
142 void Enqueue(Node* node, RepType use) { | |
143 Enqueue(node, static_cast<RepTypeUnion>(use)); | |
144 } | |
145 | |
146 void SetOutput(Node* node, RepTypeUnion output) { | |
147 // Every node should have at most one output representation. Note that | |
148 // phis can have 0, if they have not been used in a representation-inducing | |
149 // instruction. | |
150 DCHECK((output & rMask) == 0 || IsPowerOf2(output & rMask)); | |
151 GetInfo(node)->output = output; | |
152 } | |
153 | |
154 bool BothInputsAre(Node* node, Type* type) { | |
155 DCHECK_EQ(2, node->InputCount()); | |
156 return NodeProperties::GetBounds(node->InputAt(0)).upper->Is(type) && | |
157 NodeProperties::GetBounds(node->InputAt(1)).upper->Is(type); | |
158 } | |
159 | |
160 void ProcessInput(Node* node, int index, RepTypeUnion use) { | |
161 Node* input = node->InputAt(index); | |
162 if (phase_ == PROPAGATE) { | |
163 // In the propagate phase, propagate the usage information backward. | |
164 Enqueue(input, use); | |
165 } else { | |
166 // In the change phase, insert a change before the use if necessary. | |
167 RepTypeUnion output = GetInfo(input)->output; | |
168 if ((output & rMask & use) == 0) { | |
169 // Output representation doesn't match usage. | |
170 TRACE((" change: #%d:%s(@%d #%d:%s) ", node->id(), | |
171 node->op()->mnemonic(), index, input->id(), | |
172 input->op()->mnemonic())); | |
173 TRACE((" from ")); | |
174 PrintInfo(output); | |
175 TRACE((" to ")); | |
176 PrintInfo(use); | |
177 TRACE(("\n")); | |
178 Node* n = changer_->GetRepresentationFor(input, output, use); | |
179 node->ReplaceInput(index, n); | |
180 } | |
181 } | |
182 } | |
183 | |
184 static const RepTypeUnion kFloat64 = rFloat64 | tNumber; | |
185 static const RepTypeUnion kInt32 = rWord32 | tInt32; | |
186 static const RepTypeUnion kUint32 = rWord32 | tUint32; | |
187 static const RepTypeUnion kInt64 = rWord64 | tInt64; | |
188 static const RepTypeUnion kUint64 = rWord64 | tUint64; | |
189 static const RepTypeUnion kAnyTagged = rTagged | tAny; | |
190 | |
191 // The default, most general visitation case. For {node}, process all value, | |
192 // context, effect, and control inputs, assuming that value inputs should have | |
193 // {rTagged} representation and can observe all output values {tAny}. | |
194 void VisitInputs(Node* node) { | |
195 InputIter i = node->inputs().begin(); | |
196 for (int j = NodeProperties::GetValueInputCount(node); j > 0; ++i, j--) { | |
197 ProcessInput(node, i.index(), kAnyTagged); // Value inputs | |
198 } | |
199 for (int j = NodeProperties::GetContextInputCount(node); j > 0; ++i, j--) { | |
200 ProcessInput(node, i.index(), kAnyTagged); // Context inputs | |
201 } | |
202 for (int j = NodeProperties::GetEffectInputCount(node); j > 0; ++i, j--) { | |
203 Enqueue(*i); // Effect inputs: just visit | |
204 } | |
205 for (int j = NodeProperties::GetControlInputCount(node); j > 0; ++i, j--) { | |
206 Enqueue(*i); // Control inputs: just visit | |
207 } | |
208 SetOutput(node, kAnyTagged); | |
209 } | |
210 | |
211 // Helper for binops of the I x I -> O variety. | |
212 void VisitBinop(Node* node, RepTypeUnion input_use, RepTypeUnion output) { | |
213 DCHECK_EQ(2, node->InputCount()); | |
214 ProcessInput(node, 0, input_use); | |
215 ProcessInput(node, 1, input_use); | |
216 SetOutput(node, output); | |
217 } | |
218 | |
219 // Helper for unops of the I -> O variety. | |
220 void VisitUnop(Node* node, RepTypeUnion input_use, RepTypeUnion output) { | |
221 DCHECK_EQ(1, node->InputCount()); | |
222 ProcessInput(node, 0, input_use); | |
223 SetOutput(node, output); | |
224 } | |
225 | |
226 // Helper for leaf nodes. | |
227 void VisitLeaf(Node* node, RepType output) { | |
228 DCHECK_EQ(0, node->InputCount()); | |
229 SetOutput(node, output); | |
230 } | |
231 | |
232 // Helpers for specific types of binops. | |
rossberg
2014/08/06 13:04:07
Nit: not sure these are worth it, but I leave it u
| |
233 void VisitFloat64Binop(Node* node) { VisitBinop(node, kFloat64, kFloat64); } | |
234 void VisitInt32Binop(Node* node) { VisitBinop(node, kInt32, kInt32); } | |
235 void VisitUint32Binop(Node* node) { VisitBinop(node, kUint32, kUint32); } | |
236 void VisitInt64Binop(Node* node) { VisitBinop(node, kInt64, kInt64); } | |
237 void VisitUint64Binop(Node* node) { VisitBinop(node, kUint64, kUint64); } | |
238 void VisitFloat64Cmp(Node* node) { VisitBinop(node, kFloat64, rBit); } | |
239 void VisitInt32Cmp(Node* node) { VisitBinop(node, kInt32, rBit); } | |
240 void VisitUint32Cmp(Node* node) { VisitBinop(node, kUint32, rBit); } | |
241 void VisitInt64Cmp(Node* node) { VisitBinop(node, kInt64, rBit); } | |
242 void VisitUint64Cmp(Node* node) { VisitBinop(node, kUint64, rBit); } | |
243 | |
244 // Helper for handling phis. | |
245 void VisitPhi(Node* node, RepTypeUnion use) { | |
246 // First, propagate the usage information to inputs of the phi. | |
247 int values = node->op()->InputCount(); | |
rossberg
2014/08/06 13:04:07
Doesn't this include non-values?
| |
248 Node::Inputs inputs = node->inputs(); | |
249 for (Node::Inputs::iterator iter(inputs.begin()); iter != inputs.end(); | |
250 ++iter, --values) { | |
251 // Propagate {use} of the phi to value inputs, and 0 to control. | |
252 ProcessInput(node, iter.index(), values > 0 ? use : 0); | |
rossberg
2014/08/06 13:04:07
Oh, this breaks the node properties abstraction qu
| |
253 } | |
254 // Phis adapt to whatever output representation their uses demand. | |
255 RepTypeUnion use_rep = GetUseInfo(node) & rMask; | |
256 RepTypeUnion use_type = GetUseInfo(node) & tMask; | |
257 RepTypeUnion rep = 0; | |
258 if (use_rep & rTagged) { | |
259 rep = rTagged; // Tagged overrides everything. | |
260 } else if (use_rep & rFloat64) { | |
261 rep = rFloat64; | |
262 } else if (use_rep & rWord64) { | |
263 rep = rWord64; | |
264 } else if (use_rep & rWord32) { | |
265 rep = rWord32; | |
266 } else if (use_rep & rBit) { | |
267 rep = rBit; | |
268 } else { | |
269 // There was no representation associated with any of the uses of this | |
270 // phi. | |
271 // Select the best one based on the usage type. | |
272 if (use_type & tAny) { | |
273 rep = rTagged; | |
274 } else if (use_rep & tNumber) { | |
275 rep = rFloat64; | |
276 } else if (use_rep & tInt64 || use_rep & tUint64) { | |
277 rep = rWord64; | |
278 } else if (use_rep & tInt32 || use_rep & tUint32) { | |
279 rep = rWord32; | |
280 } else if (use_rep & tBool) { | |
281 rep = rBit; | |
282 } else { | |
283 UNREACHABLE(); // should have at least a usage type! | |
284 } | |
285 } | |
286 // Preserve the usage type, but set the representation. | |
287 SetOutput(node, rep | use_type); | |
288 } | |
289 | |
290 Operator* Int32Op(Node* node) { | |
291 return changer_->Int32OperatorFor(node->opcode()); | |
292 } | |
293 | |
294 Operator* Uint32Op(Node* node) { | |
295 return changer_->Uint32OperatorFor(node->opcode()); | |
296 } | |
297 | |
298 Operator* Float64Op(Node* node) { | |
299 return changer_->Float64OperatorFor(node->opcode()); | |
300 } | |
301 | |
302 // Dispatching routine for visiting the node {node} with the usage {use}. | |
303 // Depending on the operator, propagate new usage info to the inputs. | |
304 void VisitNode(Node* node, RepTypeUnion use, SimplifiedLowering* lowering) { | |
305 switch (node->opcode()) { | |
306 //------------------------------------------------------------------ | |
307 // Common operators. | |
308 //------------------------------------------------------------------ | |
309 case IrOpcode::kStart: | |
310 return VisitLeaf(node, rBit); | |
rossberg
2014/08/06 13:04:07
Nit: could combine these two cases.
| |
311 case IrOpcode::kDead: | |
312 return VisitLeaf(node, rBit); | |
rossberg
2014/08/06 13:04:07
Why rBit?
| |
313 case IrOpcode::kParameter: | |
314 return VisitLeaf(node, rTagged); | |
315 case IrOpcode::kInt32Constant: | |
316 return VisitLeaf(node, rWord32); | |
317 case IrOpcode::kInt64Constant: | |
318 return VisitLeaf(node, rWord64); | |
319 case IrOpcode::kFloat64Constant: | |
320 return VisitLeaf(node, rFloat64); | |
321 case IrOpcode::kExternalConstant: | |
322 return VisitLeaf(node, rPtr); | |
323 case IrOpcode::kNumberConstant: | |
324 return VisitLeaf(node, rTagged); | |
325 case IrOpcode::kHeapConstant: | |
326 return VisitLeaf(node, rTagged); | |
327 | |
328 case IrOpcode::kEnd: | |
329 case IrOpcode::kIfTrue: | |
330 case IrOpcode::kIfFalse: | |
331 case IrOpcode::kReturn: | |
332 case IrOpcode::kMerge: | |
333 case IrOpcode::kThrow: | |
334 return VisitInputs(node); // default visit for all node inputs. | |
335 | |
336 case IrOpcode::kBranch: | |
337 ProcessInput(node, 0, rBit); | |
338 Enqueue(NodeProperties::GetControlInput(node, 0)); | |
339 break; | |
340 case IrOpcode::kPhi: | |
341 return VisitPhi(node, use); | |
342 | |
343 //------------------------------------------------------------------ | |
rossberg
2014/08/06 13:04:07
Nit: weird indentation
titzer
2014/08/08 09:16:13
clang-format keeps putting it back, so I'll just l
| |
344 // JavaScript operators. | |
345 //------------------------------------------------------------------ | |
346 // For now, we assume that all JS operators were too complex to lower | |
347 // to Simplified and that they will always require tagged value inputs and | |
348 // produce tagged value outputs. | |
349 // TODO(turbofan): it might be possible to lower some JSOperators here, | |
350 // but that responsibility really lies in the typed lowering phase. | |
351 #define DEFINE_JS_CASE(x) case IrOpcode::k##x: | |
352 JS_OP_LIST(DEFINE_JS_CASE) | |
353 #undef DEFINE_JS_CASE | |
354 contains_js_nodes_ = true; | |
355 VisitInputs(node); | |
356 return SetOutput(node, rTagged); | |
357 | |
358 //------------------------------------------------------------------ | |
359 // Simplified operators. | |
360 //------------------------------------------------------------------ | |
361 case IrOpcode::kBooleanNot: { | |
362 if (lower()) { | |
363 RepTypeUnion input = GetInfo(node->InputAt(0))->output; | |
364 if (input & rBit) { | |
365 // BooleanNot(x: rBit) => WordEqual(x, #0) | |
366 node->set_op(lowering->machine()->WordEqual()); | |
367 node->AppendInput(jsgraph_->zone(), jsgraph_->Int32Constant(0)); | |
368 } else { | |
369 // BooleanNot(x: rTagged) => WordEqual(x, #false) | |
rossberg
2014/08/06 13:04:07
Wait, why is BooleanNot overloaded on JS Booleans?
| |
370 node->set_op(lowering->machine()->WordEqual()); | |
371 node->AppendInput(jsgraph_->zone(), jsgraph_->FalseConstant()); | |
372 } | |
373 } else { | |
374 // No representation requirement, since we handle both during | |
375 // lowering. | |
376 ProcessInput(node, 0, tBool); | |
377 SetOutput(node, rBit); | |
378 } | |
379 break; | |
380 } | |
381 case IrOpcode::kNumberEqual: | |
382 case IrOpcode::kNumberLessThan: | |
383 case IrOpcode::kNumberLessThanOrEqual: { | |
384 // Number comparisons reduce to integer comparisons for integer inputs. | |
385 if (BothInputsAre(node, Type::Signed32())) { | |
386 // => signed Int32Cmp | |
387 VisitInt32Cmp(node); | |
388 if (lower()) node->set_op(Int32Op(node)); | |
389 } else if (BothInputsAre(node, Type::Unsigned32())) { | |
390 // => unsigned Int32Cmp | |
391 VisitUint32Cmp(node); | |
392 if (lower()) node->set_op(Uint32Op(node)); | |
393 } else { | |
394 // => Float64Cmp | |
395 VisitFloat64Cmp(node); | |
396 if (lower()) node->set_op(Float64Op(node)); | |
397 } | |
398 break; | |
399 } | |
400 case IrOpcode::kNumberAdd: | |
401 case IrOpcode::kNumberSubtract: { | |
402 // Add and subtract reduce to Int32Add/Sub if the inputs | |
403 // are already integers and all uses are truncating. | |
404 if (BothInputsAre(node, Type::Signed32()) && | |
405 (use & (tUint32 | tNumber | tAny)) == 0) { | |
406 // => signed Int32Add/Sub | |
407 VisitInt32Binop(node); | |
408 if (lower()) node->set_op(Int32Op(node)); | |
409 } else if (BothInputsAre(node, Type::Unsigned32()) && | |
410 (use & (tInt32 | tNumber | tAny)) == 0) { | |
411 // => unsigned Int32Add/Sub | |
412 VisitUint32Binop(node); | |
413 if (lower()) node->set_op(Uint32Op(node)); | |
414 } else { | |
415 // => Float64Add/Sub | |
416 VisitFloat64Binop(node); | |
417 if (lower()) node->set_op(Float64Op(node)); | |
418 } | |
419 break; | |
420 } | |
421 case IrOpcode::kNumberMultiply: | |
422 case IrOpcode::kNumberDivide: | |
423 case IrOpcode::kNumberModulus: { | |
424 // Float64Mul/Div/Mod | |
425 VisitFloat64Binop(node); | |
426 if (lower()) node->set_op(Float64Op(node)); | |
427 break; | |
428 } | |
429 case IrOpcode::kNumberToInt32: { | |
430 if (lower()) { | |
431 RepTypeUnion in = GetInfo(node->InputAt(0))->output; | |
432 if ((in & rMask) == rWord32) { | |
433 // Input is already represented as a word32. This is a nop. | |
434 DeferReplacement(node, node->InputAt(0)); | |
435 } else if ((in & tMask) == tInt32) { | |
436 // The input has type int32, just change representation. | |
437 VisitUnop(node, tInt32 | rWord32, tInt32 | rWord32); | |
438 DeferReplacement(node, node->InputAt(0)); | |
439 } else { | |
440 // Require the input in float64 format and perform conversion. | |
441 // TODO(turbofan): could also avoid the conversion with a tag check. | |
442 VisitUnop(node, tInt32 | rFloat64, tInt32 | rWord32); | |
443 node->set_op(lowering->machine()->ChangeFloat64ToInt32()); | |
444 } | |
445 } else { | |
446 // Propage a type to the input, but not a representation. | |
rossberg
2014/08/06 13:04:07
Typo: Propagate
| |
447 VisitUnop(node, tInt32, tInt32 | rWord32); | |
448 } | |
449 break; | |
450 } | |
451 case IrOpcode::kNumberToUint32: { | |
452 if (lower()) { | |
453 RepTypeUnion in = GetInfo(node->InputAt(0))->output; | |
454 if ((in & rMask) == rWord32) { | |
455 // Input is already represented as a word32. This is a nop. | |
456 DeferReplacement(node, node->InputAt(0)); | |
457 } else if ((in & tMask) == tUint32) { | |
458 // The input has type int32, just change representation. | |
459 VisitUnop(node, tUint32 | rWord32, tUint32 | rWord32); | |
460 DeferReplacement(node, node->InputAt(0)); | |
461 } else { | |
462 // Require the input in float64 format and perform conversion. | |
463 VisitUnop(node, tUint32 | rFloat64, tUint32 | rWord32); | |
464 node->set_op(lowering->machine()->ChangeFloat64ToInt32()); | |
465 } | |
466 } else { | |
467 // Propage a type to the input, but not a representation. | |
468 VisitUnop(node, tUint32, tUint32 | rWord32); | |
469 } | |
470 break; | |
471 } | |
472 case IrOpcode::kReferenceEqual: { | |
473 VisitUnop(node, kAnyTagged, rBit); | |
474 if (lower()) node->set_op(lowering->machine()->WordEqual()); | |
475 } | |
476 case IrOpcode::kStringEqual: { | |
477 VisitBinop(node, kAnyTagged, rBit); | |
478 // TODO(titzer): lower StringEqual to stub/runtime call. | |
479 break; | |
480 } | |
481 case IrOpcode::kStringLessThan: { | |
482 VisitBinop(node, kAnyTagged, rBit); | |
483 // TODO(titzer): lower StringLessThan to stub/runtime call. | |
484 break; | |
485 } | |
486 case IrOpcode::kStringLessThanOrEqual: { | |
487 VisitBinop(node, kAnyTagged, rBit); | |
488 // TODO(titzer): lower StringLessThanOrEqual to stub/runtime call. | |
489 break; | |
490 } | |
491 case IrOpcode::kStringAdd: { | |
492 VisitBinop(node, kAnyTagged, kAnyTagged); | |
493 // TODO(titzer): lower StringAdd to stub/runtime call. | |
494 break; | |
495 } | |
496 case IrOpcode::kLoadField: { | |
497 FieldAccess access = FieldAccessOf(node->op()); | |
498 ProcessInput(node, 0, changer_->TypeForBasePointer(access)); | |
499 SetOutput(node, changer_->TypeForField(access)); | |
500 if (lower()) lowering->DoLoadField(node); | |
501 break; | |
502 } | |
503 case IrOpcode::kStoreField: { | |
504 FieldAccess access = FieldAccessOf(node->op()); | |
505 ProcessInput(node, 0, changer_->TypeForBasePointer(access)); | |
506 ProcessInput(node, 1, changer_->TypeForField(access)); | |
507 SetOutput(node, 0); | |
508 if (lower()) lowering->DoStoreField(node); | |
509 break; | |
510 } | |
511 case IrOpcode::kLoadElement: { | |
512 ElementAccess access = ElementAccessOf(node->op()); | |
513 ProcessInput(node, 0, changer_->TypeForBasePointer(access)); | |
514 ProcessInput(node, 1, kInt32); // element index | |
515 SetOutput(node, changer_->TypeForElement(access)); | |
516 if (lower()) lowering->DoLoadElement(node); | |
517 break; | |
518 } | |
519 case IrOpcode::kStoreElement: { | |
520 ElementAccess access = ElementAccessOf(node->op()); | |
521 ProcessInput(node, 0, changer_->TypeForBasePointer(access)); | |
522 ProcessInput(node, 1, kInt32); // element index | |
523 ProcessInput(node, 2, changer_->TypeForElement(access)); | |
524 SetOutput(node, 0); | |
525 if (lower()) lowering->DoStoreElement(node); | |
526 break; | |
527 } | |
528 | |
529 //------------------------------------------------------------------ | |
530 // Machine-level operators. | |
531 //------------------------------------------------------------------ | |
532 case IrOpcode::kLoad: { | |
533 // TODO(titzer): machine loads/stores need to know BaseTaggedness!? | |
534 RepType tBase = rTagged; | |
535 MachineRepresentation rep = OpParameter<MachineRepresentation>(node); | |
536 ProcessInput(node, 0, tBase); // pointer or object | |
537 ProcessInput(node, 1, kInt32); // index | |
538 SetOutput(node, changer_->TypeForMachineRepresentation(rep)); | |
539 break; | |
540 } | |
541 case IrOpcode::kStore: { | |
542 // TODO(titzer): machine loads/stores need to know BaseTaggedness!? | |
543 RepType tBase = rTagged; | |
544 StoreRepresentation rep = OpParameter<StoreRepresentation>(node); | |
545 ProcessInput(node, 0, tBase); // pointer or object | |
546 ProcessInput(node, 1, kInt32); // index | |
547 ProcessInput(node, 2, changer_->TypeForMachineRepresentation(rep.rep)); | |
548 SetOutput(node, 0); | |
549 break; | |
550 } | |
551 case IrOpcode::kWord32Shr: | |
552 // We use unsigned int32 as the output type for shift right, though | |
rossberg
2014/08/06 13:04:07
This comment is confusing. Unsigned seems adequate
| |
553 // technically it doesn't have a sign. Because JavaScript. | |
554 return VisitBinop(node, rWord32, rWord32 | tUint32); | |
555 case IrOpcode::kWord32And: | |
556 case IrOpcode::kWord32Or: | |
557 case IrOpcode::kWord32Xor: | |
558 case IrOpcode::kWord32Shl: | |
559 case IrOpcode::kWord32Sar: | |
560 // We use signed int32 as the output type for these word32 operations, | |
561 // though technically they don't have a sign. Because JavaScript. | |
562 return VisitBinop(node, rWord32, rWord32 | tInt32); | |
563 case IrOpcode::kWord32Equal: | |
564 return VisitBinop(node, rWord32, rBit); | |
565 | |
566 case IrOpcode::kInt32Add: | |
567 case IrOpcode::kInt32Sub: | |
568 case IrOpcode::kInt32Mul: | |
569 case IrOpcode::kInt32Div: | |
570 case IrOpcode::kInt32Mod: | |
571 return VisitInt32Binop(node); | |
572 case IrOpcode::kInt32UDiv: | |
573 case IrOpcode::kInt32UMod: | |
574 return VisitUint32Binop(node); | |
575 case IrOpcode::kInt32LessThan: | |
576 case IrOpcode::kInt32LessThanOrEqual: | |
577 return VisitInt32Cmp(node); | |
578 | |
579 case IrOpcode::kUint32LessThan: | |
580 case IrOpcode::kUint32LessThanOrEqual: | |
581 return VisitUint32Cmp(node); | |
582 | |
583 case IrOpcode::kInt64Add: | |
584 case IrOpcode::kInt64Sub: | |
585 case IrOpcode::kInt64Mul: | |
586 case IrOpcode::kInt64Div: | |
587 case IrOpcode::kInt64Mod: | |
588 return VisitInt64Binop(node); | |
589 case IrOpcode::kInt64LessThan: | |
590 case IrOpcode::kInt64LessThanOrEqual: | |
591 return VisitInt64Cmp(node); | |
592 | |
593 case IrOpcode::kInt64UDiv: | |
594 case IrOpcode::kInt64UMod: | |
595 return VisitUint64Binop(node); | |
596 | |
597 case IrOpcode::kWord64And: | |
598 case IrOpcode::kWord64Or: | |
599 case IrOpcode::kWord64Xor: | |
600 case IrOpcode::kWord64Shl: | |
601 case IrOpcode::kWord64Shr: | |
602 case IrOpcode::kWord64Sar: | |
603 return VisitBinop(node, rWord64, rWord64); | |
604 case IrOpcode::kWord64Equal: | |
605 return VisitBinop(node, rWord64, rBit); | |
606 | |
607 case IrOpcode::kConvertInt32ToInt64: | |
608 return VisitUnop(node, tInt32 | rWord32, tInt32 | rWord64); | |
609 case IrOpcode::kConvertInt64ToInt32: | |
610 return VisitUnop(node, tInt64 | rWord64, tInt32 | rWord32); | |
611 | |
612 case IrOpcode::kChangeInt32ToFloat64: | |
613 return VisitUnop(node, tInt32 | rWord32, tInt32 | rFloat64); | |
614 case IrOpcode::kChangeUint32ToFloat64: | |
615 return VisitUnop(node, tUint32 | rWord32, tUint32 | rFloat64); | |
616 case IrOpcode::kChangeFloat64ToInt32: | |
617 return VisitUnop(node, tInt32 | rFloat64, tInt32 | rWord32); | |
618 case IrOpcode::kChangeFloat64ToUint32: | |
619 return VisitUnop(node, tUint32 | rFloat64, tUint32 | rWord32); | |
620 | |
621 case IrOpcode::kFloat64Add: | |
622 case IrOpcode::kFloat64Sub: | |
623 case IrOpcode::kFloat64Mul: | |
624 case IrOpcode::kFloat64Div: | |
625 case IrOpcode::kFloat64Mod: | |
626 return VisitFloat64Binop(node); | |
627 case IrOpcode::kFloat64Equal: | |
628 case IrOpcode::kFloat64LessThan: | |
629 case IrOpcode::kFloat64LessThanOrEqual: | |
630 return VisitFloat64Cmp(node); | |
631 default: | |
632 VisitInputs(node); | |
633 break; | |
634 } | |
635 } | |
636 | |
637 void DeferReplacement(Node* node, Node* replacement) { | |
638 if (replacement->id() < count_) { | |
639 // Replace with a previously existing node eagerly. | |
640 node->ReplaceUses(replacement); | |
641 } else { | |
642 // Otherwise, we are replacing a node with a representation change. | |
643 // Such a substitution must be done after all lowering is done, because | |
644 // new nodes do not have {NodeInfo} entries, and that would confuse | |
645 // the representation change insertion for uses of it. | |
646 // TODO(titzer): replace these after lowering. | |
647 } | |
648 node->RemoveAllInputs(); // Node is now dead. | |
649 } | |
650 | |
651 void PrintUseInfo(Node* node) { | |
652 TRACE(("#%d:%-20s ", node->id(), node->op()->mnemonic())); | |
653 PrintInfo(GetUseInfo(node)); | |
654 TRACE(("\n")); | |
655 } | |
656 | |
657 void PrintInfo(RepTypeUnion info) { | |
658 if (FLAG_trace_representation) { | |
659 char buf[REP_TYPE_STRLEN]; | |
660 RenderRepTypeUnion(buf, info); | |
661 TRACE(("%s", buf)); | |
662 } | |
663 } | |
664 | |
665 private: | |
666 JSGraph* jsgraph_; | |
667 Zone* zone_; | |
668 int count_; // number of nodes in the graph | |
669 NodeInfo* info_; // node id -> usage information | |
670 NodeVector nodes_; // collected nodes | |
671 bool contains_js_nodes_; // {true} if a JS operator was seen | |
672 Phase phase_; // current phase of algorithm | |
673 RepresentationChanger* changer_; // for inserting representation changes | |
674 | |
675 std::queue<Node*, std::deque<Node*, NodePtrZoneAllocator> > queue_; | |
676 | |
677 NodeInfo* GetInfo(Node* node) { | |
678 DCHECK(node->id() >= 0); | |
679 DCHECK(node->id() < count_); | |
680 return &info_[node->id()]; | |
681 } | |
682 | |
683 RepTypeUnion GetUseInfo(Node* node) { return GetInfo(node)->use; } | |
684 }; | |
685 | |
686 | |
15 Node* SimplifiedLowering::IsTagged(Node* node) { | 687 Node* SimplifiedLowering::IsTagged(Node* node) { |
16 // TODO(titzer): factor this out to a TaggingScheme abstraction. | 688 // TODO(titzer): factor this out to a TaggingScheme abstraction. |
17 STATIC_ASSERT(kSmiTagMask == 1); // Only works if tag is the low bit. | 689 STATIC_ASSERT(kSmiTagMask == 1); // Only works if tag is the low bit. |
18 return graph()->NewNode(machine()->WordAnd(), node, | 690 return graph()->NewNode(machine()->WordAnd(), node, |
19 jsgraph()->Int32Constant(kSmiTagMask)); | 691 jsgraph()->Int32Constant(kSmiTagMask)); |
20 } | 692 } |
21 | 693 |
22 | 694 |
695 void SimplifiedLowering::LowerAllNodes() { | |
696 SimplifiedOperatorBuilder simplified(graph()->zone()); | |
697 RepresentationChanger changer(jsgraph(), &simplified, machine(), | |
698 graph()->zone()->isolate()); | |
699 RepresentationSelector selector(jsgraph(), zone(), &changer); | |
700 selector.Run(this); | |
701 | |
702 LoweringBuilder::LowerAllNodes(); | |
703 } | |
704 | |
705 | |
23 Node* SimplifiedLowering::Untag(Node* node) { | 706 Node* SimplifiedLowering::Untag(Node* node) { |
24 // TODO(titzer): factor this out to a TaggingScheme abstraction. | 707 // TODO(titzer): factor this out to a TaggingScheme abstraction. |
25 Node* shift_amount = jsgraph()->Int32Constant(kSmiTagSize + kSmiShiftSize); | 708 Node* shift_amount = jsgraph()->Int32Constant(kSmiTagSize + kSmiShiftSize); |
26 return graph()->NewNode(machine()->WordSar(), node, shift_amount); | 709 return graph()->NewNode(machine()->WordSar(), node, shift_amount); |
27 } | 710 } |
28 | 711 |
29 | 712 |
30 Node* SimplifiedLowering::SmiTag(Node* node) { | 713 Node* SimplifiedLowering::SmiTag(Node* node) { |
31 // TODO(titzer): factor this out to a TaggingScheme abstraction. | 714 // TODO(titzer): factor this out to a TaggingScheme abstraction. |
32 Node* shift_amount = jsgraph()->Int32Constant(kSmiTagSize + kSmiShiftSize); | 715 Node* shift_amount = jsgraph()->Int32Constant(kSmiTagSize + kSmiShiftSize); |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
158 | 841 |
159 | 842 |
160 void SimplifiedLowering::DoChangeFloat64ToTagged(Node* node, Node* effect, | 843 void SimplifiedLowering::DoChangeFloat64ToTagged(Node* node, Node* effect, |
161 Node* control) { | 844 Node* control) { |
162 return; // TODO(titzer): need to call runtime to allocate in one branch | 845 return; // TODO(titzer): need to call runtime to allocate in one branch |
163 } | 846 } |
164 | 847 |
165 | 848 |
166 void SimplifiedLowering::DoChangeBoolToBit(Node* node, Node* effect, | 849 void SimplifiedLowering::DoChangeBoolToBit(Node* node, Node* effect, |
167 Node* control) { | 850 Node* control) { |
168 Node* val = node->InputAt(0); | 851 Node* cmp = graph()->NewNode(machine()->WordEqual(), node->InputAt(0), |
169 Operator* op = | 852 jsgraph()->TrueConstant()); |
170 kPointerSize == 8 ? machine()->Word64Equal() : machine()->Word32Equal(); | |
171 Node* cmp = graph()->NewNode(op, val, jsgraph()->TrueConstant()); | |
172 node->ReplaceUses(cmp); | 853 node->ReplaceUses(cmp); |
173 } | 854 } |
174 | 855 |
175 | 856 |
176 void SimplifiedLowering::DoChangeBitToBool(Node* node, Node* effect, | 857 void SimplifiedLowering::DoChangeBitToBool(Node* node, Node* effect, |
177 Node* control) { | 858 Node* control) { |
178 Node* val = node->InputAt(0); | 859 Node* val = node->InputAt(0); |
179 Node* branch = graph()->NewNode(common()->Branch(), val, control); | 860 Node* branch = graph()->NewNode(common()->Branch(), val, control); |
180 | 861 |
181 // true branch. | 862 // true branch. |
(...skipping 15 matching lines...) Expand all Loading... | |
197 Type* type) { | 878 Type* type) { |
198 // TODO(turbofan): skip write barriers for Smis, etc. | 879 // TODO(turbofan): skip write barriers for Smis, etc. |
199 if (base_is_tagged == kTaggedBase && representation == kMachineTagged) { | 880 if (base_is_tagged == kTaggedBase && representation == kMachineTagged) { |
200 // Write barriers are only for writes into heap objects (i.e. tagged base). | 881 // Write barriers are only for writes into heap objects (i.e. tagged base). |
201 return kFullWriteBarrier; | 882 return kFullWriteBarrier; |
202 } | 883 } |
203 return kNoWriteBarrier; | 884 return kNoWriteBarrier; |
204 } | 885 } |
205 | 886 |
206 | 887 |
207 void SimplifiedLowering::DoLoadField(Node* node, Node* effect, Node* control) { | 888 void SimplifiedLowering::DoLoadField(Node* node) { |
208 const FieldAccess& access = FieldAccessOf(node->op()); | 889 const FieldAccess& access = FieldAccessOf(node->op()); |
209 node->set_op(machine_.Load(access.representation)); | 890 node->set_op(machine_.Load(access.representation)); |
210 Node* offset = jsgraph()->Int32Constant(access.offset - access.tag()); | 891 Node* offset = jsgraph()->Int32Constant(access.offset - access.tag()); |
211 node->InsertInput(zone(), 1, offset); | 892 node->InsertInput(zone(), 1, offset); |
212 } | 893 } |
213 | 894 |
214 | 895 |
215 void SimplifiedLowering::DoStoreField(Node* node, Node* effect, Node* control) { | 896 void SimplifiedLowering::DoStoreField(Node* node) { |
216 const FieldAccess& access = FieldAccessOf(node->op()); | 897 const FieldAccess& access = FieldAccessOf(node->op()); |
217 WriteBarrierKind kind = ComputeWriteBarrierKind( | 898 WriteBarrierKind kind = ComputeWriteBarrierKind( |
218 access.base_is_tagged, access.representation, access.type); | 899 access.base_is_tagged, access.representation, access.type); |
219 node->set_op(machine_.Store(access.representation, kind)); | 900 node->set_op(machine_.Store(access.representation, kind)); |
220 Node* offset = jsgraph()->Int32Constant(access.offset - access.tag()); | 901 Node* offset = jsgraph()->Int32Constant(access.offset - access.tag()); |
221 node->InsertInput(zone(), 1, offset); | 902 node->InsertInput(zone(), 1, offset); |
222 } | 903 } |
223 | 904 |
224 | 905 |
225 Node* SimplifiedLowering::ComputeIndex(const ElementAccess& access, | 906 Node* SimplifiedLowering::ComputeIndex(const ElementAccess& access, |
(...skipping 24 matching lines...) Expand all Loading... | |
250 index = graph()->NewNode(machine()->Int32Mul(), | 931 index = graph()->NewNode(machine()->Int32Mul(), |
251 jsgraph()->Int32Constant(element_size), index); | 932 jsgraph()->Int32Constant(element_size), index); |
252 } | 933 } |
253 int fixed_offset = access.header_size - access.tag(); | 934 int fixed_offset = access.header_size - access.tag(); |
254 if (fixed_offset == 0) return index; | 935 if (fixed_offset == 0) return index; |
255 return graph()->NewNode(machine()->Int32Add(), | 936 return graph()->NewNode(machine()->Int32Add(), |
256 jsgraph()->Int32Constant(fixed_offset), index); | 937 jsgraph()->Int32Constant(fixed_offset), index); |
257 } | 938 } |
258 | 939 |
259 | 940 |
260 void SimplifiedLowering::DoLoadElement(Node* node, Node* effect, | 941 void SimplifiedLowering::DoLoadElement(Node* node) { |
261 Node* control) { | |
262 const ElementAccess& access = ElementAccessOf(node->op()); | 942 const ElementAccess& access = ElementAccessOf(node->op()); |
263 node->set_op(machine_.Load(access.representation)); | 943 node->set_op(machine_.Load(access.representation)); |
264 node->ReplaceInput(1, ComputeIndex(access, node->InputAt(1))); | 944 node->ReplaceInput(1, ComputeIndex(access, node->InputAt(1))); |
265 } | 945 } |
266 | 946 |
267 | 947 |
268 void SimplifiedLowering::DoStoreElement(Node* node, Node* effect, | 948 void SimplifiedLowering::DoStoreElement(Node* node) { |
269 Node* control) { | |
270 const ElementAccess& access = ElementAccessOf(node->op()); | 949 const ElementAccess& access = ElementAccessOf(node->op()); |
271 WriteBarrierKind kind = ComputeWriteBarrierKind( | 950 WriteBarrierKind kind = ComputeWriteBarrierKind( |
272 access.base_is_tagged, access.representation, access.type); | 951 access.base_is_tagged, access.representation, access.type); |
273 node->set_op(machine_.Store(access.representation, kind)); | 952 node->set_op(machine_.Store(access.representation, kind)); |
274 node->ReplaceInput(1, ComputeIndex(access, node->InputAt(1))); | 953 node->ReplaceInput(1, ComputeIndex(access, node->InputAt(1))); |
275 } | 954 } |
276 | 955 |
277 | 956 |
278 void SimplifiedLowering::Lower(Node* node) { | 957 void SimplifiedLowering::Lower(Node* node) {} |
rossberg
2014/08/06 13:04:07
What's this still good for?
| |
279 Node* start = graph()->start(); | 958 |
959 | |
960 void SimplifiedLowering::LowerChange(Node* node, Node* effect, Node* control) { | |
280 switch (node->opcode()) { | 961 switch (node->opcode()) { |
281 case IrOpcode::kBooleanNot: | |
282 case IrOpcode::kNumberEqual: | |
283 case IrOpcode::kNumberLessThan: | |
284 case IrOpcode::kNumberLessThanOrEqual: | |
285 case IrOpcode::kNumberAdd: | |
286 case IrOpcode::kNumberSubtract: | |
287 case IrOpcode::kNumberMultiply: | |
288 case IrOpcode::kNumberDivide: | |
289 case IrOpcode::kNumberModulus: | |
290 case IrOpcode::kNumberToInt32: | |
291 case IrOpcode::kNumberToUint32: | |
292 case IrOpcode::kReferenceEqual: | |
293 case IrOpcode::kStringEqual: | |
294 case IrOpcode::kStringLessThan: | |
295 case IrOpcode::kStringLessThanOrEqual: | |
296 case IrOpcode::kStringAdd: | |
297 break; | |
298 case IrOpcode::kChangeTaggedToInt32: | 962 case IrOpcode::kChangeTaggedToInt32: |
299 DoChangeTaggedToUI32(node, start, start, true); | 963 DoChangeTaggedToUI32(node, effect, control, true); |
300 break; | 964 break; |
301 case IrOpcode::kChangeTaggedToUint32: | 965 case IrOpcode::kChangeTaggedToUint32: |
302 DoChangeTaggedToUI32(node, start, start, false); | 966 DoChangeTaggedToUI32(node, effect, control, false); |
303 break; | 967 break; |
304 case IrOpcode::kChangeTaggedToFloat64: | 968 case IrOpcode::kChangeTaggedToFloat64: |
305 DoChangeTaggedToFloat64(node, start, start); | 969 DoChangeTaggedToFloat64(node, effect, control); |
306 break; | 970 break; |
307 case IrOpcode::kChangeInt32ToTagged: | 971 case IrOpcode::kChangeInt32ToTagged: |
308 DoChangeUI32ToTagged(node, start, start, true); | 972 DoChangeUI32ToTagged(node, effect, control, true); |
309 break; | 973 break; |
310 case IrOpcode::kChangeUint32ToTagged: | 974 case IrOpcode::kChangeUint32ToTagged: |
311 DoChangeUI32ToTagged(node, start, start, false); | 975 DoChangeUI32ToTagged(node, effect, control, false); |
312 break; | 976 break; |
313 case IrOpcode::kChangeFloat64ToTagged: | 977 case IrOpcode::kChangeFloat64ToTagged: |
314 DoChangeFloat64ToTagged(node, start, start); | 978 DoChangeFloat64ToTagged(node, effect, control); |
315 break; | 979 break; |
316 case IrOpcode::kChangeBoolToBit: | 980 case IrOpcode::kChangeBoolToBit: |
317 DoChangeBoolToBit(node, start, start); | 981 DoChangeBoolToBit(node, effect, control); |
318 break; | 982 break; |
319 case IrOpcode::kChangeBitToBool: | 983 case IrOpcode::kChangeBitToBool: |
320 DoChangeBitToBool(node, start, start); | 984 DoChangeBitToBool(node, effect, control); |
321 break; | |
322 case IrOpcode::kLoadField: | |
rossberg
2014/08/06 13:04:07
Why did these cases disappear?
| |
323 DoLoadField(node, start, start); | |
324 break; | |
325 case IrOpcode::kStoreField: | |
326 DoStoreField(node, start, start); | |
327 break; | |
328 case IrOpcode::kLoadElement: | |
329 DoLoadElement(node, start, start); | |
330 break; | |
331 case IrOpcode::kStoreElement: | |
332 DoStoreElement(node, start, start); | |
333 break; | 985 break; |
334 default: | 986 default: |
987 UNREACHABLE(); | |
335 break; | 988 break; |
336 } | 989 } |
337 } | 990 } |
338 | 991 |
339 } // namespace compiler | 992 } // namespace compiler |
340 } // namespace internal | 993 } // namespace internal |
341 } // namespace v8 | 994 } // namespace v8 |
OLD | NEW |