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
3 // found in the LICENSE file.
4
5 #include "src/compiler/instruction-selector.h"
6
7 #include "src/compiler/instruction-selector-impl.h"
8 #include "src/compiler/node-matchers.h"
9 #include "src/compiler/node-properties-inl.h"
10 #include "src/compiler/pipeline.h"
11
12 namespace v8 {
13 namespace internal {
14 namespace compiler {
15
InstructionSelector(InstructionSequence * sequence,SourcePositionTable * source_positions,Features features)16 InstructionSelector::InstructionSelector(InstructionSequence* sequence,
17 SourcePositionTable* source_positions,
18 Features features)
19 : zone_(sequence->isolate()),
20 sequence_(sequence),
21 source_positions_(source_positions),
22 features_(features),
23 current_block_(NULL),
24 instructions_(zone()),
25 defined_(graph()->NodeCount(), false, zone()),
26 used_(graph()->NodeCount(), false, zone()) {}
27
28
SelectInstructions()29 void InstructionSelector::SelectInstructions() {
30 // Mark the inputs of all phis in loop headers as used.
31 BasicBlockVector* blocks = schedule()->rpo_order();
32 for (BasicBlockVectorIter i = blocks->begin(); i != blocks->end(); ++i) {
33 BasicBlock* block = *i;
34 if (!block->IsLoopHeader()) continue;
35 DCHECK_NE(0, block->PredecessorCount());
36 DCHECK_NE(1, block->PredecessorCount());
37 for (BasicBlock::const_iterator j = block->begin(); j != block->end();
38 ++j) {
39 Node* phi = *j;
40 if (phi->opcode() != IrOpcode::kPhi) continue;
41
42 // Mark all inputs as used.
43 Node::Inputs inputs = phi->inputs();
44 for (InputIter k = inputs.begin(); k != inputs.end(); ++k) {
45 MarkAsUsed(*k);
46 }
47 }
48 }
49
50 // Visit each basic block in post order.
51 for (BasicBlockVectorRIter i = blocks->rbegin(); i != blocks->rend(); ++i) {
52 VisitBlock(*i);
53 }
54
55 // Schedule the selected instructions.
56 for (BasicBlockVectorIter i = blocks->begin(); i != blocks->end(); ++i) {
57 BasicBlock* block = *i;
58 size_t end = block->code_end_;
59 size_t start = block->code_start_;
60 sequence()->StartBlock(block);
61 while (start-- > end) {
62 sequence()->AddInstruction(instructions_[start], block);
63 }
64 sequence()->EndBlock(block);
65 }
66 }
67
68
Emit(InstructionCode opcode,InstructionOperand * output,size_t temp_count,InstructionOperand ** temps)69 Instruction* InstructionSelector::Emit(InstructionCode opcode,
70 InstructionOperand* output,
71 size_t temp_count,
72 InstructionOperand** temps) {
73 size_t output_count = output == NULL ? 0 : 1;
74 return Emit(opcode, output_count, &output, 0, NULL, temp_count, temps);
75 }
76
77
Emit(InstructionCode opcode,InstructionOperand * output,InstructionOperand * a,size_t temp_count,InstructionOperand ** temps)78 Instruction* InstructionSelector::Emit(InstructionCode opcode,
79 InstructionOperand* output,
80 InstructionOperand* a, size_t temp_count,
81 InstructionOperand** temps) {
82 size_t output_count = output == NULL ? 0 : 1;
83 return Emit(opcode, output_count, &output, 1, &a, temp_count, temps);
84 }
85
86
Emit(InstructionCode opcode,InstructionOperand * output,InstructionOperand * a,InstructionOperand * b,size_t temp_count,InstructionOperand ** temps)87 Instruction* InstructionSelector::Emit(InstructionCode opcode,
88 InstructionOperand* output,
89 InstructionOperand* a,
90 InstructionOperand* b, size_t temp_count,
91 InstructionOperand** temps) {
92 size_t output_count = output == NULL ? 0 : 1;
93 InstructionOperand* inputs[] = {a, b};
94 size_t input_count = arraysize(inputs);
95 return Emit(opcode, output_count, &output, input_count, inputs, temp_count,
96 temps);
97 }
98
99
Emit(InstructionCode opcode,InstructionOperand * output,InstructionOperand * a,InstructionOperand * b,InstructionOperand * c,size_t temp_count,InstructionOperand ** temps)100 Instruction* InstructionSelector::Emit(InstructionCode opcode,
101 InstructionOperand* output,
102 InstructionOperand* a,
103 InstructionOperand* b,
104 InstructionOperand* c, size_t temp_count,
105 InstructionOperand** temps) {
106 size_t output_count = output == NULL ? 0 : 1;
107 InstructionOperand* inputs[] = {a, b, c};
108 size_t input_count = arraysize(inputs);
109 return Emit(opcode, output_count, &output, input_count, inputs, temp_count,
110 temps);
111 }
112
113
Emit(InstructionCode opcode,InstructionOperand * output,InstructionOperand * a,InstructionOperand * b,InstructionOperand * c,InstructionOperand * d,size_t temp_count,InstructionOperand ** temps)114 Instruction* InstructionSelector::Emit(
115 InstructionCode opcode, InstructionOperand* output, InstructionOperand* a,
116 InstructionOperand* b, InstructionOperand* c, InstructionOperand* d,
117 size_t temp_count, InstructionOperand** temps) {
118 size_t output_count = output == NULL ? 0 : 1;
119 InstructionOperand* inputs[] = {a, b, c, d};
120 size_t input_count = arraysize(inputs);
121 return Emit(opcode, output_count, &output, input_count, inputs, temp_count,
122 temps);
123 }
124
125
Emit(InstructionCode opcode,size_t output_count,InstructionOperand ** outputs,size_t input_count,InstructionOperand ** inputs,size_t temp_count,InstructionOperand ** temps)126 Instruction* InstructionSelector::Emit(
127 InstructionCode opcode, size_t output_count, InstructionOperand** outputs,
128 size_t input_count, InstructionOperand** inputs, size_t temp_count,
129 InstructionOperand** temps) {
130 Instruction* instr =
131 Instruction::New(instruction_zone(), opcode, output_count, outputs,
132 input_count, inputs, temp_count, temps);
133 return Emit(instr);
134 }
135
136
Emit(Instruction * instr)137 Instruction* InstructionSelector::Emit(Instruction* instr) {
138 instructions_.push_back(instr);
139 return instr;
140 }
141
142
IsNextInAssemblyOrder(const BasicBlock * block) const143 bool InstructionSelector::IsNextInAssemblyOrder(const BasicBlock* block) const {
144 return block->rpo_number_ == (current_block_->rpo_number_ + 1) &&
145 block->deferred_ == current_block_->deferred_;
146 }
147
148
CanCover(Node * user,Node * node) const149 bool InstructionSelector::CanCover(Node* user, Node* node) const {
150 return node->OwnedBy(user) &&
151 schedule()->block(node) == schedule()->block(user);
152 }
153
154
IsDefined(Node * node) const155 bool InstructionSelector::IsDefined(Node* node) const {
156 DCHECK_NOT_NULL(node);
157 NodeId id = node->id();
158 DCHECK(id >= 0);
159 DCHECK(id < static_cast<NodeId>(defined_.size()));
160 return defined_[id];
161 }
162
163
MarkAsDefined(Node * node)164 void InstructionSelector::MarkAsDefined(Node* node) {
165 DCHECK_NOT_NULL(node);
166 NodeId id = node->id();
167 DCHECK(id >= 0);
168 DCHECK(id < static_cast<NodeId>(defined_.size()));
169 defined_[id] = true;
170 }
171
172
IsUsed(Node * node) const173 bool InstructionSelector::IsUsed(Node* node) const {
174 if (!node->op()->HasProperty(Operator::kEliminatable)) return true;
175 NodeId id = node->id();
176 DCHECK(id >= 0);
177 DCHECK(id < static_cast<NodeId>(used_.size()));
178 return used_[id];
179 }
180
181
MarkAsUsed(Node * node)182 void InstructionSelector::MarkAsUsed(Node* node) {
183 DCHECK_NOT_NULL(node);
184 NodeId id = node->id();
185 DCHECK(id >= 0);
186 DCHECK(id < static_cast<NodeId>(used_.size()));
187 used_[id] = true;
188 }
189
190
IsDouble(const Node * node) const191 bool InstructionSelector::IsDouble(const Node* node) const {
192 DCHECK_NOT_NULL(node);
193 return sequence()->IsDouble(node->id());
194 }
195
196
MarkAsDouble(Node * node)197 void InstructionSelector::MarkAsDouble(Node* node) {
198 DCHECK_NOT_NULL(node);
199 DCHECK(!IsReference(node));
200 sequence()->MarkAsDouble(node->id());
201 }
202
203
IsReference(const Node * node) const204 bool InstructionSelector::IsReference(const Node* node) const {
205 DCHECK_NOT_NULL(node);
206 return sequence()->IsReference(node->id());
207 }
208
209
MarkAsReference(Node * node)210 void InstructionSelector::MarkAsReference(Node* node) {
211 DCHECK_NOT_NULL(node);
212 DCHECK(!IsDouble(node));
213 sequence()->MarkAsReference(node->id());
214 }
215
216
MarkAsRepresentation(MachineType rep,Node * node)217 void InstructionSelector::MarkAsRepresentation(MachineType rep, Node* node) {
218 DCHECK_NOT_NULL(node);
219 switch (RepresentationOf(rep)) {
220 case kRepFloat32:
221 case kRepFloat64:
222 MarkAsDouble(node);
223 break;
224 case kRepTagged:
225 MarkAsReference(node);
226 break;
227 default:
228 break;
229 }
230 }
231
232
233 // TODO(bmeurer): Get rid of the CallBuffer business and make
234 // InstructionSelector::VisitCall platform independent instead.
CallBuffer(Zone * zone,CallDescriptor * d,FrameStateDescriptor * frame_desc)235 CallBuffer::CallBuffer(Zone* zone, CallDescriptor* d,
236 FrameStateDescriptor* frame_desc)
237 : descriptor(d),
238 frame_state_descriptor(frame_desc),
239 output_nodes(zone),
240 outputs(zone),
241 instruction_args(zone),
242 pushed_nodes(zone) {
243 output_nodes.reserve(d->ReturnCount());
244 outputs.reserve(d->ReturnCount());
245 pushed_nodes.reserve(input_count());
246 instruction_args.reserve(input_count() + frame_state_value_count());
247 }
248
249
250 // TODO(bmeurer): Get rid of the CallBuffer business and make
251 // InstructionSelector::VisitCall platform independent instead.
InitializeCallBuffer(Node * call,CallBuffer * buffer,bool call_code_immediate,bool call_address_immediate)252 void InstructionSelector::InitializeCallBuffer(Node* call, CallBuffer* buffer,
253 bool call_code_immediate,
254 bool call_address_immediate) {
255 OperandGenerator g(this);
256 DCHECK_EQ(call->op()->OutputCount(), buffer->descriptor->ReturnCount());
257 DCHECK_EQ(OperatorProperties::GetValueInputCount(call->op()),
258 buffer->input_count() + buffer->frame_state_count());
259
260 if (buffer->descriptor->ReturnCount() > 0) {
261 // Collect the projections that represent multiple outputs from this call.
262 if (buffer->descriptor->ReturnCount() == 1) {
263 buffer->output_nodes.push_back(call);
264 } else {
265 buffer->output_nodes.resize(buffer->descriptor->ReturnCount(), NULL);
266 call->CollectProjections(&buffer->output_nodes);
267 }
268
269 // Filter out the outputs that aren't live because no projection uses them.
270 for (size_t i = 0; i < buffer->output_nodes.size(); i++) {
271 if (buffer->output_nodes[i] != NULL) {
272 Node* output = buffer->output_nodes[i];
273 MachineType type =
274 buffer->descriptor->GetReturnType(static_cast<int>(i));
275 LinkageLocation location =
276 buffer->descriptor->GetReturnLocation(static_cast<int>(i));
277 MarkAsRepresentation(type, output);
278 buffer->outputs.push_back(g.DefineAsLocation(output, location, type));
279 }
280 }
281 }
282
283 // The first argument is always the callee code.
284 Node* callee = call->InputAt(0);
285 switch (buffer->descriptor->kind()) {
286 case CallDescriptor::kCallCodeObject:
287 buffer->instruction_args.push_back(
288 (call_code_immediate && callee->opcode() == IrOpcode::kHeapConstant)
289 ? g.UseImmediate(callee)
290 : g.UseRegister(callee));
291 break;
292 case CallDescriptor::kCallAddress:
293 buffer->instruction_args.push_back(
294 (call_address_immediate &&
295 (callee->opcode() == IrOpcode::kInt32Constant ||
296 callee->opcode() == IrOpcode::kInt64Constant))
297 ? g.UseImmediate(callee)
298 : g.UseRegister(callee));
299 break;
300 case CallDescriptor::kCallJSFunction:
301 buffer->instruction_args.push_back(
302 g.UseLocation(callee, buffer->descriptor->GetInputLocation(0),
303 buffer->descriptor->GetInputType(0)));
304 break;
305 }
306 DCHECK_EQ(1, buffer->instruction_args.size());
307
308 // If the call needs a frame state, we insert the state information as
309 // follows (n is the number of value inputs to the frame state):
310 // arg 1 : deoptimization id.
311 // arg 2 - arg (n + 1) : value inputs to the frame state.
312 if (buffer->frame_state_descriptor != NULL) {
313 InstructionSequence::StateId state_id =
314 sequence()->AddFrameStateDescriptor(buffer->frame_state_descriptor);
315 buffer->instruction_args.push_back(g.TempImmediate(state_id.ToInt()));
316
317 Node* frame_state =
318 call->InputAt(static_cast<int>(buffer->descriptor->InputCount()));
319 AddFrameStateInputs(frame_state, &buffer->instruction_args,
320 buffer->frame_state_descriptor);
321 }
322 DCHECK(1 + buffer->frame_state_value_count() ==
323 buffer->instruction_args.size());
324
325 size_t input_count = static_cast<size_t>(buffer->input_count());
326
327 // Split the arguments into pushed_nodes and instruction_args. Pushed
328 // arguments require an explicit push instruction before the call and do
329 // not appear as arguments to the call. Everything else ends up
330 // as an InstructionOperand argument to the call.
331 InputIter iter(call->inputs().begin());
332 int pushed_count = 0;
333 for (size_t index = 0; index < input_count; ++iter, ++index) {
334 DCHECK(iter != call->inputs().end());
335 DCHECK(index == static_cast<size_t>(iter.index()));
336 DCHECK((*iter)->op()->opcode() != IrOpcode::kFrameState);
337 if (index == 0) continue; // The first argument (callee) is already done.
338 InstructionOperand* op =
339 g.UseLocation(*iter, buffer->descriptor->GetInputLocation(index),
340 buffer->descriptor->GetInputType(index));
341 if (UnallocatedOperand::cast(op)->HasFixedSlotPolicy()) {
342 int stack_index = -UnallocatedOperand::cast(op)->fixed_slot_index() - 1;
343 if (static_cast<size_t>(stack_index) >= buffer->pushed_nodes.size()) {
344 buffer->pushed_nodes.resize(stack_index + 1, NULL);
345 }
346 DCHECK_EQ(NULL, buffer->pushed_nodes[stack_index]);
347 buffer->pushed_nodes[stack_index] = *iter;
348 pushed_count++;
349 } else {
350 buffer->instruction_args.push_back(op);
351 }
352 }
353 CHECK_EQ(pushed_count, static_cast<int>(buffer->pushed_nodes.size()));
354 DCHECK(static_cast<size_t>(input_count) ==
355 (buffer->instruction_args.size() + buffer->pushed_nodes.size() -
356 buffer->frame_state_value_count()));
357 }
358
359
VisitBlock(BasicBlock * block)360 void InstructionSelector::VisitBlock(BasicBlock* block) {
361 DCHECK_EQ(NULL, current_block_);
362 current_block_ = block;
363 int current_block_end = static_cast<int>(instructions_.size());
364
365 // Generate code for the block control "top down", but schedule the code
366 // "bottom up".
367 VisitControl(block);
368 std::reverse(instructions_.begin() + current_block_end, instructions_.end());
369
370 // Visit code in reverse control flow order, because architecture-specific
371 // matching may cover more than one node at a time.
372 for (BasicBlock::reverse_iterator i = block->rbegin(); i != block->rend();
373 ++i) {
374 Node* node = *i;
375 // Skip nodes that are unused or already defined.
376 if (!IsUsed(node) || IsDefined(node)) continue;
377 // Generate code for this node "top down", but schedule the code "bottom
378 // up".
379 size_t current_node_end = instructions_.size();
380 VisitNode(node);
381 std::reverse(instructions_.begin() + current_node_end, instructions_.end());
382 }
383
384 // We're done with the block.
385 // TODO(bmeurer): We should not mutate the schedule.
386 block->code_end_ = current_block_end;
387 block->code_start_ = static_cast<int>(instructions_.size());
388
389 current_block_ = NULL;
390 }
391
392
CheckNoPhis(const BasicBlock * block)393 static inline void CheckNoPhis(const BasicBlock* block) {
394 #ifdef DEBUG
395 // Branch targets should not have phis.
396 for (BasicBlock::const_iterator i = block->begin(); i != block->end(); ++i) {
397 const Node* node = *i;
398 CHECK_NE(IrOpcode::kPhi, node->opcode());
399 }
400 #endif
401 }
402
403
VisitControl(BasicBlock * block)404 void InstructionSelector::VisitControl(BasicBlock* block) {
405 Node* input = block->control_input_;
406 switch (block->control_) {
407 case BasicBlockData::kGoto:
408 return VisitGoto(block->SuccessorAt(0));
409 case BasicBlockData::kBranch: {
410 DCHECK_EQ(IrOpcode::kBranch, input->opcode());
411 BasicBlock* tbranch = block->SuccessorAt(0);
412 BasicBlock* fbranch = block->SuccessorAt(1);
413 // SSA deconstruction requires targets of branches not to have phis.
414 // Edge split form guarantees this property, but is more strict.
415 CheckNoPhis(tbranch);
416 CheckNoPhis(fbranch);
417 if (tbranch == fbranch) return VisitGoto(tbranch);
418 return VisitBranch(input, tbranch, fbranch);
419 }
420 case BasicBlockData::kReturn: {
421 // If the result itself is a return, return its input.
422 Node* value = (input != NULL && input->opcode() == IrOpcode::kReturn)
423 ? input->InputAt(0)
424 : input;
425 return VisitReturn(value);
426 }
427 case BasicBlockData::kThrow:
428 return VisitThrow(input);
429 case BasicBlockData::kNone: {
430 // TODO(titzer): exit block doesn't have control.
431 DCHECK(input == NULL);
432 break;
433 }
434 default:
435 UNREACHABLE();
436 break;
437 }
438 }
439
440
VisitNode(Node * node)441 void InstructionSelector::VisitNode(Node* node) {
442 DCHECK_NOT_NULL(schedule()->block(node)); // should only use scheduled nodes.
443 SourcePosition source_position = source_positions_->GetSourcePosition(node);
444 if (!source_position.IsUnknown()) {
445 DCHECK(!source_position.IsInvalid());
446 if (FLAG_turbo_source_positions || node->opcode() == IrOpcode::kCall) {
447 Emit(SourcePositionInstruction::New(instruction_zone(), source_position));
448 }
449 }
450 switch (node->opcode()) {
451 case IrOpcode::kStart:
452 case IrOpcode::kLoop:
453 case IrOpcode::kEnd:
454 case IrOpcode::kBranch:
455 case IrOpcode::kIfTrue:
456 case IrOpcode::kIfFalse:
457 case IrOpcode::kEffectPhi:
458 case IrOpcode::kMerge:
459 // No code needed for these graph artifacts.
460 return;
461 case IrOpcode::kFinish:
462 return MarkAsReference(node), VisitFinish(node);
463 case IrOpcode::kParameter: {
464 MachineType type = linkage()->GetParameterType(OpParameter<int>(node));
465 MarkAsRepresentation(type, node);
466 return VisitParameter(node);
467 }
468 case IrOpcode::kPhi: {
469 MachineType type = OpParameter<MachineType>(node);
470 MarkAsRepresentation(type, node);
471 return VisitPhi(node);
472 }
473 case IrOpcode::kProjection:
474 return VisitProjection(node);
475 case IrOpcode::kInt32Constant:
476 case IrOpcode::kInt64Constant:
477 case IrOpcode::kExternalConstant:
478 return VisitConstant(node);
479 case IrOpcode::kFloat64Constant:
480 return MarkAsDouble(node), VisitConstant(node);
481 case IrOpcode::kHeapConstant:
482 case IrOpcode::kNumberConstant:
483 // TODO(turbofan): only mark non-smis as references.
484 return MarkAsReference(node), VisitConstant(node);
485 case IrOpcode::kCall:
486 return VisitCall(node, NULL, NULL);
487 case IrOpcode::kFrameState:
488 case IrOpcode::kStateValues:
489 return;
490 case IrOpcode::kLoad: {
491 LoadRepresentation rep = OpParameter<LoadRepresentation>(node);
492 MarkAsRepresentation(rep, node);
493 return VisitLoad(node);
494 }
495 case IrOpcode::kStore:
496 return VisitStore(node);
497 case IrOpcode::kWord32And:
498 return VisitWord32And(node);
499 case IrOpcode::kWord32Or:
500 return VisitWord32Or(node);
501 case IrOpcode::kWord32Xor:
502 return VisitWord32Xor(node);
503 case IrOpcode::kWord32Shl:
504 return VisitWord32Shl(node);
505 case IrOpcode::kWord32Shr:
506 return VisitWord32Shr(node);
507 case IrOpcode::kWord32Sar:
508 return VisitWord32Sar(node);
509 case IrOpcode::kWord32Ror:
510 return VisitWord32Ror(node);
511 case IrOpcode::kWord32Equal:
512 return VisitWord32Equal(node);
513 case IrOpcode::kWord64And:
514 return VisitWord64And(node);
515 case IrOpcode::kWord64Or:
516 return VisitWord64Or(node);
517 case IrOpcode::kWord64Xor:
518 return VisitWord64Xor(node);
519 case IrOpcode::kWord64Shl:
520 return VisitWord64Shl(node);
521 case IrOpcode::kWord64Shr:
522 return VisitWord64Shr(node);
523 case IrOpcode::kWord64Sar:
524 return VisitWord64Sar(node);
525 case IrOpcode::kWord64Ror:
526 return VisitWord64Ror(node);
527 case IrOpcode::kWord64Equal:
528 return VisitWord64Equal(node);
529 case IrOpcode::kInt32Add:
530 return VisitInt32Add(node);
531 case IrOpcode::kInt32AddWithOverflow:
532 return VisitInt32AddWithOverflow(node);
533 case IrOpcode::kInt32Sub:
534 return VisitInt32Sub(node);
535 case IrOpcode::kInt32SubWithOverflow:
536 return VisitInt32SubWithOverflow(node);
537 case IrOpcode::kInt32Mul:
538 return VisitInt32Mul(node);
539 case IrOpcode::kInt32Div:
540 return VisitInt32Div(node);
541 case IrOpcode::kInt32UDiv:
542 return VisitInt32UDiv(node);
543 case IrOpcode::kInt32Mod:
544 return VisitInt32Mod(node);
545 case IrOpcode::kInt32UMod:
546 return VisitInt32UMod(node);
547 case IrOpcode::kInt32LessThan:
548 return VisitInt32LessThan(node);
549 case IrOpcode::kInt32LessThanOrEqual:
550 return VisitInt32LessThanOrEqual(node);
551 case IrOpcode::kUint32LessThan:
552 return VisitUint32LessThan(node);
553 case IrOpcode::kUint32LessThanOrEqual:
554 return VisitUint32LessThanOrEqual(node);
555 case IrOpcode::kInt64Add:
556 return VisitInt64Add(node);
557 case IrOpcode::kInt64Sub:
558 return VisitInt64Sub(node);
559 case IrOpcode::kInt64Mul:
560 return VisitInt64Mul(node);
561 case IrOpcode::kInt64Div:
562 return VisitInt64Div(node);
563 case IrOpcode::kInt64UDiv:
564 return VisitInt64UDiv(node);
565 case IrOpcode::kInt64Mod:
566 return VisitInt64Mod(node);
567 case IrOpcode::kInt64UMod:
568 return VisitInt64UMod(node);
569 case IrOpcode::kInt64LessThan:
570 return VisitInt64LessThan(node);
571 case IrOpcode::kInt64LessThanOrEqual:
572 return VisitInt64LessThanOrEqual(node);
573 case IrOpcode::kChangeInt32ToFloat64:
574 return MarkAsDouble(node), VisitChangeInt32ToFloat64(node);
575 case IrOpcode::kChangeUint32ToFloat64:
576 return MarkAsDouble(node), VisitChangeUint32ToFloat64(node);
577 case IrOpcode::kChangeFloat64ToInt32:
578 return VisitChangeFloat64ToInt32(node);
579 case IrOpcode::kChangeFloat64ToUint32:
580 return VisitChangeFloat64ToUint32(node);
581 case IrOpcode::kChangeInt32ToInt64:
582 return VisitChangeInt32ToInt64(node);
583 case IrOpcode::kChangeUint32ToUint64:
584 return VisitChangeUint32ToUint64(node);
585 case IrOpcode::kTruncateFloat64ToInt32:
586 return VisitTruncateFloat64ToInt32(node);
587 case IrOpcode::kTruncateInt64ToInt32:
588 return VisitTruncateInt64ToInt32(node);
589 case IrOpcode::kFloat64Add:
590 return MarkAsDouble(node), VisitFloat64Add(node);
591 case IrOpcode::kFloat64Sub:
592 return MarkAsDouble(node), VisitFloat64Sub(node);
593 case IrOpcode::kFloat64Mul:
594 return MarkAsDouble(node), VisitFloat64Mul(node);
595 case IrOpcode::kFloat64Div:
596 return MarkAsDouble(node), VisitFloat64Div(node);
597 case IrOpcode::kFloat64Mod:
598 return MarkAsDouble(node), VisitFloat64Mod(node);
599 case IrOpcode::kFloat64Sqrt:
600 return MarkAsDouble(node), VisitFloat64Sqrt(node);
601 case IrOpcode::kFloat64Equal:
602 return VisitFloat64Equal(node);
603 case IrOpcode::kFloat64LessThan:
604 return VisitFloat64LessThan(node);
605 case IrOpcode::kFloat64LessThanOrEqual:
606 return VisitFloat64LessThanOrEqual(node);
607 default:
608 V8_Fatal(__FILE__, __LINE__, "Unexpected operator #%d:%s @ node #%d",
609 node->opcode(), node->op()->mnemonic(), node->id());
610 }
611 }
612
613
614 #if V8_TURBOFAN_BACKEND
615
VisitWord32Equal(Node * node)616 void InstructionSelector::VisitWord32Equal(Node* node) {
617 FlagsContinuation cont(kEqual, node);
618 Int32BinopMatcher m(node);
619 if (m.right().Is(0)) {
620 return VisitWord32Test(m.left().node(), &cont);
621 }
622 VisitWord32Compare(node, &cont);
623 }
624
625
VisitInt32LessThan(Node * node)626 void InstructionSelector::VisitInt32LessThan(Node* node) {
627 FlagsContinuation cont(kSignedLessThan, node);
628 VisitWord32Compare(node, &cont);
629 }
630
631
VisitInt32LessThanOrEqual(Node * node)632 void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
633 FlagsContinuation cont(kSignedLessThanOrEqual, node);
634 VisitWord32Compare(node, &cont);
635 }
636
637
VisitUint32LessThan(Node * node)638 void InstructionSelector::VisitUint32LessThan(Node* node) {
639 FlagsContinuation cont(kUnsignedLessThan, node);
640 VisitWord32Compare(node, &cont);
641 }
642
643
VisitUint32LessThanOrEqual(Node * node)644 void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
645 FlagsContinuation cont(kUnsignedLessThanOrEqual, node);
646 VisitWord32Compare(node, &cont);
647 }
648
649
VisitWord64Equal(Node * node)650 void InstructionSelector::VisitWord64Equal(Node* node) {
651 FlagsContinuation cont(kEqual, node);
652 Int64BinopMatcher m(node);
653 if (m.right().Is(0)) {
654 return VisitWord64Test(m.left().node(), &cont);
655 }
656 VisitWord64Compare(node, &cont);
657 }
658
659
VisitInt32AddWithOverflow(Node * node)660 void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
661 if (Node* ovf = node->FindProjection(1)) {
662 FlagsContinuation cont(kOverflow, ovf);
663 return VisitInt32AddWithOverflow(node, &cont);
664 }
665 FlagsContinuation cont;
666 VisitInt32AddWithOverflow(node, &cont);
667 }
668
669
VisitInt32SubWithOverflow(Node * node)670 void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
671 if (Node* ovf = node->FindProjection(1)) {
672 FlagsContinuation cont(kOverflow, ovf);
673 return VisitInt32SubWithOverflow(node, &cont);
674 }
675 FlagsContinuation cont;
676 VisitInt32SubWithOverflow(node, &cont);
677 }
678
679
VisitInt64LessThan(Node * node)680 void InstructionSelector::VisitInt64LessThan(Node* node) {
681 FlagsContinuation cont(kSignedLessThan, node);
682 VisitWord64Compare(node, &cont);
683 }
684
685
VisitInt64LessThanOrEqual(Node * node)686 void InstructionSelector::VisitInt64LessThanOrEqual(Node* node) {
687 FlagsContinuation cont(kSignedLessThanOrEqual, node);
688 VisitWord64Compare(node, &cont);
689 }
690
691
VisitTruncateFloat64ToInt32(Node * node)692 void InstructionSelector::VisitTruncateFloat64ToInt32(Node* node) {
693 OperandGenerator g(this);
694 Emit(kArchTruncateDoubleToI, g.DefineAsRegister(node),
695 g.UseRegister(node->InputAt(0)));
696 }
697
698
VisitFloat64Equal(Node * node)699 void InstructionSelector::VisitFloat64Equal(Node* node) {
700 FlagsContinuation cont(kUnorderedEqual, node);
701 VisitFloat64Compare(node, &cont);
702 }
703
704
VisitFloat64LessThan(Node * node)705 void InstructionSelector::VisitFloat64LessThan(Node* node) {
706 FlagsContinuation cont(kUnorderedLessThan, node);
707 VisitFloat64Compare(node, &cont);
708 }
709
710
VisitFloat64LessThanOrEqual(Node * node)711 void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
712 FlagsContinuation cont(kUnorderedLessThanOrEqual, node);
713 VisitFloat64Compare(node, &cont);
714 }
715
716 #endif // V8_TURBOFAN_BACKEND
717
718 // 32 bit targets do not implement the following instructions.
719 #if V8_TARGET_ARCH_32_BIT && V8_TURBOFAN_BACKEND
720
VisitWord64And(Node * node)721 void InstructionSelector::VisitWord64And(Node* node) { UNIMPLEMENTED(); }
722
723
VisitWord64Or(Node * node)724 void InstructionSelector::VisitWord64Or(Node* node) { UNIMPLEMENTED(); }
725
726
VisitWord64Xor(Node * node)727 void InstructionSelector::VisitWord64Xor(Node* node) { UNIMPLEMENTED(); }
728
729
VisitWord64Shl(Node * node)730 void InstructionSelector::VisitWord64Shl(Node* node) { UNIMPLEMENTED(); }
731
732
VisitWord64Shr(Node * node)733 void InstructionSelector::VisitWord64Shr(Node* node) { UNIMPLEMENTED(); }
734
735
VisitWord64Sar(Node * node)736 void InstructionSelector::VisitWord64Sar(Node* node) { UNIMPLEMENTED(); }
737
738
VisitWord64Ror(Node * node)739 void InstructionSelector::VisitWord64Ror(Node* node) { UNIMPLEMENTED(); }
740
741
VisitInt64Add(Node * node)742 void InstructionSelector::VisitInt64Add(Node* node) { UNIMPLEMENTED(); }
743
744
VisitInt64Sub(Node * node)745 void InstructionSelector::VisitInt64Sub(Node* node) { UNIMPLEMENTED(); }
746
747
VisitInt64Mul(Node * node)748 void InstructionSelector::VisitInt64Mul(Node* node) { UNIMPLEMENTED(); }
749
750
VisitInt64Div(Node * node)751 void InstructionSelector::VisitInt64Div(Node* node) { UNIMPLEMENTED(); }
752
753
VisitInt64UDiv(Node * node)754 void InstructionSelector::VisitInt64UDiv(Node* node) { UNIMPLEMENTED(); }
755
756
VisitInt64Mod(Node * node)757 void InstructionSelector::VisitInt64Mod(Node* node) { UNIMPLEMENTED(); }
758
759
VisitInt64UMod(Node * node)760 void InstructionSelector::VisitInt64UMod(Node* node) { UNIMPLEMENTED(); }
761
762
VisitChangeInt32ToInt64(Node * node)763 void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
764 UNIMPLEMENTED();
765 }
766
767
VisitChangeUint32ToUint64(Node * node)768 void InstructionSelector::VisitChangeUint32ToUint64(Node* node) {
769 UNIMPLEMENTED();
770 }
771
772
VisitTruncateInt64ToInt32(Node * node)773 void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) {
774 UNIMPLEMENTED();
775 }
776
777 #endif // V8_TARGET_ARCH_32_BIT && V8_TURBOFAN_BACKEND
778
779
780 // 32-bit targets and unsupported architectures need dummy implementations of
781 // selected 64-bit ops.
782 #if V8_TARGET_ARCH_32_BIT || !V8_TURBOFAN_BACKEND
783
VisitWord64Test(Node * node,FlagsContinuation * cont)784 void InstructionSelector::VisitWord64Test(Node* node, FlagsContinuation* cont) {
785 UNIMPLEMENTED();
786 }
787
788
VisitWord64Compare(Node * node,FlagsContinuation * cont)789 void InstructionSelector::VisitWord64Compare(Node* node,
790 FlagsContinuation* cont) {
791 UNIMPLEMENTED();
792 }
793
794 #endif // V8_TARGET_ARCH_32_BIT || !V8_TURBOFAN_BACKEND
795
796
VisitFinish(Node * node)797 void InstructionSelector::VisitFinish(Node* node) {
798 OperandGenerator g(this);
799 Node* value = node->InputAt(0);
800 Emit(kArchNop, g.DefineSameAsFirst(node), g.Use(value));
801 }
802
803
VisitParameter(Node * node)804 void InstructionSelector::VisitParameter(Node* node) {
805 OperandGenerator g(this);
806 int index = OpParameter<int>(node);
807 Emit(kArchNop,
808 g.DefineAsLocation(node, linkage()->GetParameterLocation(index),
809 linkage()->GetParameterType(index)));
810 }
811
812
VisitPhi(Node * node)813 void InstructionSelector::VisitPhi(Node* node) {
814 // TODO(bmeurer): Emit a PhiInstruction here.
815 for (InputIter i = node->inputs().begin(); i != node->inputs().end(); ++i) {
816 MarkAsUsed(*i);
817 }
818 }
819
820
VisitProjection(Node * node)821 void InstructionSelector::VisitProjection(Node* node) {
822 OperandGenerator g(this);
823 Node* value = node->InputAt(0);
824 switch (value->opcode()) {
825 case IrOpcode::kInt32AddWithOverflow:
826 case IrOpcode::kInt32SubWithOverflow:
827 if (OpParameter<size_t>(node) == 0) {
828 Emit(kArchNop, g.DefineSameAsFirst(node), g.Use(value));
829 } else {
830 DCHECK(OpParameter<size_t>(node) == 1u);
831 MarkAsUsed(value);
832 }
833 break;
834 default:
835 break;
836 }
837 }
838
839
VisitConstant(Node * node)840 void InstructionSelector::VisitConstant(Node* node) {
841 // We must emit a NOP here because every live range needs a defining
842 // instruction in the register allocator.
843 OperandGenerator g(this);
844 Emit(kArchNop, g.DefineAsConstant(node));
845 }
846
847
VisitGoto(BasicBlock * target)848 void InstructionSelector::VisitGoto(BasicBlock* target) {
849 if (IsNextInAssemblyOrder(target)) {
850 // fall through to the next block.
851 Emit(kArchNop, NULL)->MarkAsControl();
852 } else {
853 // jump to the next block.
854 OperandGenerator g(this);
855 Emit(kArchJmp, NULL, g.Label(target))->MarkAsControl();
856 }
857 }
858
859
VisitBranch(Node * branch,BasicBlock * tbranch,BasicBlock * fbranch)860 void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
861 BasicBlock* fbranch) {
862 OperandGenerator g(this);
863 Node* user = branch;
864 Node* value = branch->InputAt(0);
865
866 FlagsContinuation cont(kNotEqual, tbranch, fbranch);
867
868 // If we can fall through to the true block, invert the branch.
869 if (IsNextInAssemblyOrder(tbranch)) {
870 cont.Negate();
871 cont.SwapBlocks();
872 }
873
874 // Try to combine with comparisons against 0 by simply inverting the branch.
875 while (CanCover(user, value)) {
876 if (value->opcode() == IrOpcode::kWord32Equal) {
877 Int32BinopMatcher m(value);
878 if (m.right().Is(0)) {
879 user = value;
880 value = m.left().node();
881 cont.Negate();
882 } else {
883 break;
884 }
885 } else if (value->opcode() == IrOpcode::kWord64Equal) {
886 Int64BinopMatcher m(value);
887 if (m.right().Is(0)) {
888 user = value;
889 value = m.left().node();
890 cont.Negate();
891 } else {
892 break;
893 }
894 } else {
895 break;
896 }
897 }
898
899 // Try to combine the branch with a comparison.
900 if (CanCover(user, value)) {
901 switch (value->opcode()) {
902 case IrOpcode::kWord32Equal:
903 cont.OverwriteAndNegateIfEqual(kEqual);
904 return VisitWord32Compare(value, &cont);
905 case IrOpcode::kInt32LessThan:
906 cont.OverwriteAndNegateIfEqual(kSignedLessThan);
907 return VisitWord32Compare(value, &cont);
908 case IrOpcode::kInt32LessThanOrEqual:
909 cont.OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
910 return VisitWord32Compare(value, &cont);
911 case IrOpcode::kUint32LessThan:
912 cont.OverwriteAndNegateIfEqual(kUnsignedLessThan);
913 return VisitWord32Compare(value, &cont);
914 case IrOpcode::kUint32LessThanOrEqual:
915 cont.OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
916 return VisitWord32Compare(value, &cont);
917 case IrOpcode::kWord64Equal:
918 cont.OverwriteAndNegateIfEqual(kEqual);
919 return VisitWord64Compare(value, &cont);
920 case IrOpcode::kInt64LessThan:
921 cont.OverwriteAndNegateIfEqual(kSignedLessThan);
922 return VisitWord64Compare(value, &cont);
923 case IrOpcode::kInt64LessThanOrEqual:
924 cont.OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
925 return VisitWord64Compare(value, &cont);
926 case IrOpcode::kFloat64Equal:
927 cont.OverwriteAndNegateIfEqual(kUnorderedEqual);
928 return VisitFloat64Compare(value, &cont);
929 case IrOpcode::kFloat64LessThan:
930 cont.OverwriteAndNegateIfEqual(kUnorderedLessThan);
931 return VisitFloat64Compare(value, &cont);
932 case IrOpcode::kFloat64LessThanOrEqual:
933 cont.OverwriteAndNegateIfEqual(kUnorderedLessThanOrEqual);
934 return VisitFloat64Compare(value, &cont);
935 case IrOpcode::kProjection:
936 // Check if this is the overflow output projection of an
937 // <Operation>WithOverflow node.
938 if (OpParameter<size_t>(value) == 1u) {
939 // We cannot combine the <Operation>WithOverflow with this branch
940 // unless the 0th projection (the use of the actual value of the
941 // <Operation> is either NULL, which means there's no use of the
942 // actual value, or was already defined, which means it is scheduled
943 // *AFTER* this branch).
944 Node* node = value->InputAt(0);
945 Node* result = node->FindProjection(0);
946 if (result == NULL || IsDefined(result)) {
947 switch (node->opcode()) {
948 case IrOpcode::kInt32AddWithOverflow:
949 cont.OverwriteAndNegateIfEqual(kOverflow);
950 return VisitInt32AddWithOverflow(node, &cont);
951 case IrOpcode::kInt32SubWithOverflow:
952 cont.OverwriteAndNegateIfEqual(kOverflow);
953 return VisitInt32SubWithOverflow(node, &cont);
954 default:
955 break;
956 }
957 }
958 }
959 break;
960 default:
961 break;
962 }
963 }
964
965 // Branch could not be combined with a compare, emit compare against 0.
966 VisitWord32Test(value, &cont);
967 }
968
969
VisitReturn(Node * value)970 void InstructionSelector::VisitReturn(Node* value) {
971 OperandGenerator g(this);
972 if (value != NULL) {
973 Emit(kArchRet, NULL, g.UseLocation(value, linkage()->GetReturnLocation(),
974 linkage()->GetReturnType()));
975 } else {
976 Emit(kArchRet, NULL);
977 }
978 }
979
980
VisitThrow(Node * value)981 void InstructionSelector::VisitThrow(Node* value) {
982 UNIMPLEMENTED(); // TODO(titzer)
983 }
984
985
GetFrameStateDescriptor(Node * state)986 FrameStateDescriptor* InstructionSelector::GetFrameStateDescriptor(
987 Node* state) {
988 DCHECK(state->opcode() == IrOpcode::kFrameState);
989 DCHECK_EQ(5, state->InputCount());
990 FrameStateCallInfo state_info = OpParameter<FrameStateCallInfo>(state);
991 int parameters = OpParameter<int>(state->InputAt(0));
992 int locals = OpParameter<int>(state->InputAt(1));
993 int stack = OpParameter<int>(state->InputAt(2));
994
995 FrameStateDescriptor* outer_state = NULL;
996 Node* outer_node = state->InputAt(4);
997 if (outer_node->opcode() == IrOpcode::kFrameState) {
998 outer_state = GetFrameStateDescriptor(outer_node);
999 }
1000
1001 return new (instruction_zone())
1002 FrameStateDescriptor(state_info, parameters, locals, stack, outer_state);
1003 }
1004
1005
UseOrImmediate(OperandGenerator * g,Node * input)1006 static InstructionOperand* UseOrImmediate(OperandGenerator* g, Node* input) {
1007 switch (input->opcode()) {
1008 case IrOpcode::kInt32Constant:
1009 case IrOpcode::kNumberConstant:
1010 case IrOpcode::kFloat64Constant:
1011 case IrOpcode::kHeapConstant:
1012 return g->UseImmediate(input);
1013 default:
1014 return g->UseUnique(input);
1015 }
1016 }
1017
1018
AddFrameStateInputs(Node * state,InstructionOperandVector * inputs,FrameStateDescriptor * descriptor)1019 void InstructionSelector::AddFrameStateInputs(
1020 Node* state, InstructionOperandVector* inputs,
1021 FrameStateDescriptor* descriptor) {
1022 DCHECK_EQ(IrOpcode::kFrameState, state->op()->opcode());
1023
1024 if (descriptor->outer_state() != NULL) {
1025 AddFrameStateInputs(state->InputAt(4), inputs, descriptor->outer_state());
1026 }
1027
1028 Node* parameters = state->InputAt(0);
1029 Node* locals = state->InputAt(1);
1030 Node* stack = state->InputAt(2);
1031 Node* context = state->InputAt(3);
1032
1033 DCHECK_EQ(IrOpcode::kStateValues, parameters->op()->opcode());
1034 DCHECK_EQ(IrOpcode::kStateValues, locals->op()->opcode());
1035 DCHECK_EQ(IrOpcode::kStateValues, stack->op()->opcode());
1036
1037 DCHECK_EQ(descriptor->parameters_count(), parameters->InputCount());
1038 DCHECK_EQ(descriptor->locals_count(), locals->InputCount());
1039 DCHECK_EQ(descriptor->stack_count(), stack->InputCount());
1040
1041 OperandGenerator g(this);
1042 for (int i = 0; i < static_cast<int>(descriptor->parameters_count()); i++) {
1043 inputs->push_back(UseOrImmediate(&g, parameters->InputAt(i)));
1044 }
1045 if (descriptor->HasContext()) {
1046 inputs->push_back(UseOrImmediate(&g, context));
1047 }
1048 for (int i = 0; i < static_cast<int>(descriptor->locals_count()); i++) {
1049 inputs->push_back(UseOrImmediate(&g, locals->InputAt(i)));
1050 }
1051 for (int i = 0; i < static_cast<int>(descriptor->stack_count()); i++) {
1052 inputs->push_back(UseOrImmediate(&g, stack->InputAt(i)));
1053 }
1054 }
1055
1056
1057 #if !V8_TURBOFAN_BACKEND
1058
1059 #define DECLARE_UNIMPLEMENTED_SELECTOR(x) \
1060 void InstructionSelector::Visit##x(Node* node) { UNIMPLEMENTED(); }
MACHINE_OP_LIST(DECLARE_UNIMPLEMENTED_SELECTOR)1061 MACHINE_OP_LIST(DECLARE_UNIMPLEMENTED_SELECTOR)
1062 #undef DECLARE_UNIMPLEMENTED_SELECTOR
1063
1064
1065 void InstructionSelector::VisitInt32AddWithOverflow(Node* node,
1066 FlagsContinuation* cont) {
1067 UNIMPLEMENTED();
1068 }
1069
1070
VisitInt32SubWithOverflow(Node * node,FlagsContinuation * cont)1071 void InstructionSelector::VisitInt32SubWithOverflow(Node* node,
1072 FlagsContinuation* cont) {
1073 UNIMPLEMENTED();
1074 }
1075
1076
VisitWord32Test(Node * node,FlagsContinuation * cont)1077 void InstructionSelector::VisitWord32Test(Node* node, FlagsContinuation* cont) {
1078 UNIMPLEMENTED();
1079 }
1080
1081
VisitWord32Compare(Node * node,FlagsContinuation * cont)1082 void InstructionSelector::VisitWord32Compare(Node* node,
1083 FlagsContinuation* cont) {
1084 UNIMPLEMENTED();
1085 }
1086
1087
VisitFloat64Compare(Node * node,FlagsContinuation * cont)1088 void InstructionSelector::VisitFloat64Compare(Node* node,
1089 FlagsContinuation* cont) {
1090 UNIMPLEMENTED();
1091 }
1092
1093
VisitCall(Node * call,BasicBlock * continuation,BasicBlock * deoptimization)1094 void InstructionSelector::VisitCall(Node* call, BasicBlock* continuation,
1095 BasicBlock* deoptimization) {}
1096
1097 #endif // !V8_TURBOFAN_BACKEND
1098
1099 } // namespace compiler
1100 } // namespace internal
1101 } // namespace v8
1102