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

Side by Side Diff: src/compiler/simplified-lowering.cc

Issue 425003004: Implement representation selection as part of SimplifiedLowering. Representation selection also req… (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Added better tests for Load/Store of fields and elements, with both tagged and untagged bases. Created 6 years, 4 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 | Annotate | Revision Log
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/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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698