blob: 24ebc38393cd1e2e972a4996e891ed8ec9bfa64b [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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-impl.h"
6#include "src/compiler/node-matchers.h"
7#include "src/compiler/node-properties-inl.h"
8
9namespace v8 {
10namespace internal {
11namespace compiler {
12
13// Adds IA32-specific methods for generating operands.
14class IA32OperandGenerator FINAL : public OperandGenerator {
15 public:
16 explicit IA32OperandGenerator(InstructionSelector* selector)
17 : OperandGenerator(selector) {}
18
19 InstructionOperand* UseByteRegister(Node* node) {
20 // TODO(dcarney): relax constraint.
21 return UseFixed(node, edx);
22 }
23
24 bool CanBeImmediate(Node* node) {
25 switch (node->opcode()) {
26 case IrOpcode::kInt32Constant:
27 case IrOpcode::kNumberConstant:
28 case IrOpcode::kExternalConstant:
29 return true;
30 case IrOpcode::kHeapConstant: {
31 // Constants in new space cannot be used as immediates in V8 because
32 // the GC does not scan code objects when collecting the new generation.
33 Unique<HeapObject> value = OpParameter<Unique<HeapObject> >(node);
34 return !isolate()->heap()->InNewSpace(*value.handle());
35 }
36 default:
37 return false;
38 }
39 }
40};
41
42
43void InstructionSelector::VisitLoad(Node* node) {
44 MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node));
45 MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node));
46 IA32OperandGenerator g(this);
47 Node* base = node->InputAt(0);
48 Node* index = node->InputAt(1);
49
50 ArchOpcode opcode;
51 // TODO(titzer): signed/unsigned small loads
52 switch (rep) {
53 case kRepFloat32:
54 opcode = kIA32Movss;
55 break;
56 case kRepFloat64:
57 opcode = kIA32Movsd;
58 break;
59 case kRepBit: // Fall through.
60 case kRepWord8:
61 opcode = typ == kTypeInt32 ? kIA32Movsxbl : kIA32Movzxbl;
62 break;
63 case kRepWord16:
64 opcode = typ == kTypeInt32 ? kIA32Movsxwl : kIA32Movzxwl;
65 break;
66 case kRepTagged: // Fall through.
67 case kRepWord32:
68 opcode = kIA32Movl;
69 break;
70 default:
71 UNREACHABLE();
72 return;
73 }
74 if (g.CanBeImmediate(base)) {
75 if (Int32Matcher(index).Is(0)) { // load [#base + #0]
76 Emit(opcode | AddressingModeField::encode(kMode_MI),
77 g.DefineAsRegister(node), g.UseImmediate(base));
78 } else { // load [#base + %index]
79 Emit(opcode | AddressingModeField::encode(kMode_MRI),
80 g.DefineAsRegister(node), g.UseRegister(index),
81 g.UseImmediate(base));
82 }
83 } else if (g.CanBeImmediate(index)) { // load [%base + #index]
84 Emit(opcode | AddressingModeField::encode(kMode_MRI),
85 g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index));
86 } else { // load [%base + %index + K]
87 Emit(opcode | AddressingModeField::encode(kMode_MR1I),
88 g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(index));
89 }
90 // TODO(turbofan): addressing modes [r+r*{2,4,8}+K]
91}
92
93
94void InstructionSelector::VisitStore(Node* node) {
95 IA32OperandGenerator g(this);
96 Node* base = node->InputAt(0);
97 Node* index = node->InputAt(1);
98 Node* value = node->InputAt(2);
99
100 StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node);
101 MachineType rep = RepresentationOf(store_rep.machine_type());
102 if (store_rep.write_barrier_kind() == kFullWriteBarrier) {
103 DCHECK_EQ(kRepTagged, rep);
104 // TODO(dcarney): refactor RecordWrite function to take temp registers
105 // and pass them here instead of using fixed regs
106 // TODO(dcarney): handle immediate indices.
107 InstructionOperand* temps[] = {g.TempRegister(ecx), g.TempRegister(edx)};
108 Emit(kIA32StoreWriteBarrier, NULL, g.UseFixed(base, ebx),
109 g.UseFixed(index, ecx), g.UseFixed(value, edx), arraysize(temps),
110 temps);
111 return;
112 }
113 DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind());
114 InstructionOperand* val;
115 if (g.CanBeImmediate(value)) {
116 val = g.UseImmediate(value);
117 } else if (rep == kRepWord8 || rep == kRepBit) {
118 val = g.UseByteRegister(value);
119 } else {
120 val = g.UseRegister(value);
121 }
122 ArchOpcode opcode;
123 switch (rep) {
124 case kRepFloat32:
125 opcode = kIA32Movss;
126 break;
127 case kRepFloat64:
128 opcode = kIA32Movsd;
129 break;
130 case kRepBit: // Fall through.
131 case kRepWord8:
132 opcode = kIA32Movb;
133 break;
134 case kRepWord16:
135 opcode = kIA32Movw;
136 break;
137 case kRepTagged: // Fall through.
138 case kRepWord32:
139 opcode = kIA32Movl;
140 break;
141 default:
142 UNREACHABLE();
143 return;
144 }
145 if (g.CanBeImmediate(base)) {
146 if (Int32Matcher(index).Is(0)) { // store [#base], %|#value
147 Emit(opcode | AddressingModeField::encode(kMode_MI), NULL,
148 g.UseImmediate(base), val);
149 } else { // store [#base + %index], %|#value
150 Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL,
151 g.UseRegister(index), g.UseImmediate(base), val);
152 }
153 } else if (g.CanBeImmediate(index)) { // store [%base + #index], %|#value
154 Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL,
155 g.UseRegister(base), g.UseImmediate(index), val);
156 } else { // store [%base + %index], %|#value
157 Emit(opcode | AddressingModeField::encode(kMode_MR1I), NULL,
158 g.UseRegister(base), g.UseRegister(index), val);
159 }
160 // TODO(turbofan): addressing modes [r+r*{2,4,8}+K]
161}
162
163
164// Shared routine for multiple binary operations.
165static void VisitBinop(InstructionSelector* selector, Node* node,
166 InstructionCode opcode, FlagsContinuation* cont) {
167 IA32OperandGenerator g(selector);
168 Int32BinopMatcher m(node);
169 InstructionOperand* inputs[4];
170 size_t input_count = 0;
171 InstructionOperand* outputs[2];
172 size_t output_count = 0;
173
174 // TODO(turbofan): match complex addressing modes.
175 // TODO(turbofan): if commutative, pick the non-live-in operand as the left as
176 // this might be the last use and therefore its register can be reused.
177 if (g.CanBeImmediate(m.right().node())) {
178 inputs[input_count++] = g.Use(m.left().node());
179 inputs[input_count++] = g.UseImmediate(m.right().node());
180 } else {
181 inputs[input_count++] = g.UseRegister(m.left().node());
182 inputs[input_count++] = g.Use(m.right().node());
183 }
184
185 if (cont->IsBranch()) {
186 inputs[input_count++] = g.Label(cont->true_block());
187 inputs[input_count++] = g.Label(cont->false_block());
188 }
189
190 outputs[output_count++] = g.DefineSameAsFirst(node);
191 if (cont->IsSet()) {
192 // TODO(turbofan): Use byte register here.
193 outputs[output_count++] = g.DefineAsRegister(cont->result());
194 }
195
196 DCHECK_NE(0, input_count);
197 DCHECK_NE(0, output_count);
198 DCHECK_GE(arraysize(inputs), input_count);
199 DCHECK_GE(arraysize(outputs), output_count);
200
201 Instruction* instr = selector->Emit(cont->Encode(opcode), output_count,
202 outputs, input_count, inputs);
203 if (cont->IsBranch()) instr->MarkAsControl();
204}
205
206
207// Shared routine for multiple binary operations.
208static void VisitBinop(InstructionSelector* selector, Node* node,
209 InstructionCode opcode) {
210 FlagsContinuation cont;
211 VisitBinop(selector, node, opcode, &cont);
212}
213
214
215void InstructionSelector::VisitWord32And(Node* node) {
216 VisitBinop(this, node, kIA32And);
217}
218
219
220void InstructionSelector::VisitWord32Or(Node* node) {
221 VisitBinop(this, node, kIA32Or);
222}
223
224
225void InstructionSelector::VisitWord32Xor(Node* node) {
226 IA32OperandGenerator g(this);
227 Int32BinopMatcher m(node);
228 if (m.right().Is(-1)) {
229 Emit(kIA32Not, g.DefineSameAsFirst(node), g.Use(m.left().node()));
230 } else {
231 VisitBinop(this, node, kIA32Xor);
232 }
233}
234
235
236// Shared routine for multiple shift operations.
237static inline void VisitShift(InstructionSelector* selector, Node* node,
238 ArchOpcode opcode) {
239 IA32OperandGenerator g(selector);
240 Node* left = node->InputAt(0);
241 Node* right = node->InputAt(1);
242
243 // TODO(turbofan): assembler only supports some addressing modes for shifts.
244 if (g.CanBeImmediate(right)) {
245 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
246 g.UseImmediate(right));
247 } else {
248 Int32BinopMatcher m(node);
249 if (m.right().IsWord32And()) {
250 Int32BinopMatcher mright(right);
251 if (mright.right().Is(0x1F)) {
252 right = mright.left().node();
253 }
254 }
255 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
256 g.UseFixed(right, ecx));
257 }
258}
259
260
261void InstructionSelector::VisitWord32Shl(Node* node) {
262 VisitShift(this, node, kIA32Shl);
263}
264
265
266void InstructionSelector::VisitWord32Shr(Node* node) {
267 VisitShift(this, node, kIA32Shr);
268}
269
270
271void InstructionSelector::VisitWord32Sar(Node* node) {
272 VisitShift(this, node, kIA32Sar);
273}
274
275
276void InstructionSelector::VisitWord32Ror(Node* node) {
277 VisitShift(this, node, kIA32Ror);
278}
279
280
281void InstructionSelector::VisitInt32Add(Node* node) {
282 VisitBinop(this, node, kIA32Add);
283}
284
285
286void InstructionSelector::VisitInt32Sub(Node* node) {
287 IA32OperandGenerator g(this);
288 Int32BinopMatcher m(node);
289 if (m.left().Is(0)) {
290 Emit(kIA32Neg, g.DefineSameAsFirst(node), g.Use(m.right().node()));
291 } else {
292 VisitBinop(this, node, kIA32Sub);
293 }
294}
295
296
297void InstructionSelector::VisitInt32Mul(Node* node) {
298 IA32OperandGenerator g(this);
299 Node* left = node->InputAt(0);
300 Node* right = node->InputAt(1);
301 if (g.CanBeImmediate(right)) {
302 Emit(kIA32Imul, g.DefineAsRegister(node), g.Use(left),
303 g.UseImmediate(right));
304 } else if (g.CanBeImmediate(left)) {
305 Emit(kIA32Imul, g.DefineAsRegister(node), g.Use(right),
306 g.UseImmediate(left));
307 } else {
308 // TODO(turbofan): select better left operand.
309 Emit(kIA32Imul, g.DefineSameAsFirst(node), g.UseRegister(left),
310 g.Use(right));
311 }
312}
313
314
315static inline void VisitDiv(InstructionSelector* selector, Node* node,
316 ArchOpcode opcode) {
317 IA32OperandGenerator g(selector);
318 InstructionOperand* temps[] = {g.TempRegister(edx)};
319 size_t temp_count = arraysize(temps);
320 selector->Emit(opcode, g.DefineAsFixed(node, eax),
321 g.UseFixed(node->InputAt(0), eax),
322 g.UseUnique(node->InputAt(1)), temp_count, temps);
323}
324
325
326void InstructionSelector::VisitInt32Div(Node* node) {
327 VisitDiv(this, node, kIA32Idiv);
328}
329
330
331void InstructionSelector::VisitInt32UDiv(Node* node) {
332 VisitDiv(this, node, kIA32Udiv);
333}
334
335
336static inline void VisitMod(InstructionSelector* selector, Node* node,
337 ArchOpcode opcode) {
338 IA32OperandGenerator g(selector);
339 InstructionOperand* temps[] = {g.TempRegister(eax), g.TempRegister(edx)};
340 size_t temp_count = arraysize(temps);
341 selector->Emit(opcode, g.DefineAsFixed(node, edx),
342 g.UseFixed(node->InputAt(0), eax),
343 g.UseUnique(node->InputAt(1)), temp_count, temps);
344}
345
346
347void InstructionSelector::VisitInt32Mod(Node* node) {
348 VisitMod(this, node, kIA32Idiv);
349}
350
351
352void InstructionSelector::VisitInt32UMod(Node* node) {
353 VisitMod(this, node, kIA32Udiv);
354}
355
356
357void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
358 IA32OperandGenerator g(this);
359 Emit(kSSEInt32ToFloat64, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
360}
361
362
363void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
364 IA32OperandGenerator g(this);
365 // TODO(turbofan): IA32 SSE LoadUint32() should take an operand.
366 Emit(kSSEUint32ToFloat64, g.DefineAsRegister(node),
367 g.UseRegister(node->InputAt(0)));
368}
369
370
371void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
372 IA32OperandGenerator g(this);
373 Emit(kSSEFloat64ToInt32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
374}
375
376
377void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
378 IA32OperandGenerator g(this);
379 Emit(kSSEFloat64ToUint32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
380}
381
382
383void InstructionSelector::VisitFloat64Add(Node* node) {
384 IA32OperandGenerator g(this);
385 Emit(kSSEFloat64Add, g.DefineSameAsFirst(node),
386 g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
387}
388
389
390void InstructionSelector::VisitFloat64Sub(Node* node) {
391 IA32OperandGenerator g(this);
392 Emit(kSSEFloat64Sub, g.DefineSameAsFirst(node),
393 g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
394}
395
396
397void InstructionSelector::VisitFloat64Mul(Node* node) {
398 IA32OperandGenerator g(this);
399 Emit(kSSEFloat64Mul, g.DefineSameAsFirst(node),
400 g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
401}
402
403
404void InstructionSelector::VisitFloat64Div(Node* node) {
405 IA32OperandGenerator g(this);
406 Emit(kSSEFloat64Div, g.DefineSameAsFirst(node),
407 g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
408}
409
410
411void InstructionSelector::VisitFloat64Mod(Node* node) {
412 IA32OperandGenerator g(this);
413 InstructionOperand* temps[] = {g.TempRegister(eax)};
414 Emit(kSSEFloat64Mod, g.DefineSameAsFirst(node),
415 g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)), 1,
416 temps);
417}
418
419
420void InstructionSelector::VisitFloat64Sqrt(Node* node) {
421 IA32OperandGenerator g(this);
422 Emit(kSSEFloat64Sqrt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
423}
424
425
426void InstructionSelector::VisitInt32AddWithOverflow(Node* node,
427 FlagsContinuation* cont) {
428 VisitBinop(this, node, kIA32Add, cont);
429}
430
431
432void InstructionSelector::VisitInt32SubWithOverflow(Node* node,
433 FlagsContinuation* cont) {
434 VisitBinop(this, node, kIA32Sub, cont);
435}
436
437
438// Shared routine for multiple compare operations.
439static inline void VisitCompare(InstructionSelector* selector,
440 InstructionCode opcode,
441 InstructionOperand* left,
442 InstructionOperand* right,
443 FlagsContinuation* cont) {
444 IA32OperandGenerator g(selector);
445 if (cont->IsBranch()) {
446 selector->Emit(cont->Encode(opcode), NULL, left, right,
447 g.Label(cont->true_block()),
448 g.Label(cont->false_block()))->MarkAsControl();
449 } else {
450 DCHECK(cont->IsSet());
451 // TODO(titzer): Needs byte register.
452 selector->Emit(cont->Encode(opcode), g.DefineAsRegister(cont->result()),
453 left, right);
454 }
455}
456
457
458// Shared routine for multiple word compare operations.
459static inline void VisitWordCompare(InstructionSelector* selector, Node* node,
460 InstructionCode opcode,
461 FlagsContinuation* cont, bool commutative) {
462 IA32OperandGenerator g(selector);
463 Node* left = node->InputAt(0);
464 Node* right = node->InputAt(1);
465
466 // Match immediates on left or right side of comparison.
467 if (g.CanBeImmediate(right)) {
468 VisitCompare(selector, opcode, g.Use(left), g.UseImmediate(right), cont);
469 } else if (g.CanBeImmediate(left)) {
470 if (!commutative) cont->Commute();
471 VisitCompare(selector, opcode, g.Use(right), g.UseImmediate(left), cont);
472 } else {
473 VisitCompare(selector, opcode, g.UseRegister(left), g.Use(right), cont);
474 }
475}
476
477
478void InstructionSelector::VisitWord32Test(Node* node, FlagsContinuation* cont) {
479 switch (node->opcode()) {
480 case IrOpcode::kInt32Sub:
481 return VisitWordCompare(this, node, kIA32Cmp, cont, false);
482 case IrOpcode::kWord32And:
483 return VisitWordCompare(this, node, kIA32Test, cont, true);
484 default:
485 break;
486 }
487
488 IA32OperandGenerator g(this);
489 VisitCompare(this, kIA32Test, g.Use(node), g.TempImmediate(-1), cont);
490}
491
492
493void InstructionSelector::VisitWord32Compare(Node* node,
494 FlagsContinuation* cont) {
495 VisitWordCompare(this, node, kIA32Cmp, cont, false);
496}
497
498
499void InstructionSelector::VisitFloat64Compare(Node* node,
500 FlagsContinuation* cont) {
501 IA32OperandGenerator g(this);
502 Node* left = node->InputAt(0);
503 Node* right = node->InputAt(1);
504 VisitCompare(this, kSSEFloat64Cmp, g.UseRegister(left), g.Use(right), cont);
505}
506
507
508void InstructionSelector::VisitCall(Node* call, BasicBlock* continuation,
509 BasicBlock* deoptimization) {
510 IA32OperandGenerator g(this);
511 CallDescriptor* descriptor = OpParameter<CallDescriptor*>(call);
512
513 FrameStateDescriptor* frame_state_descriptor = NULL;
514
515 if (descriptor->NeedsFrameState()) {
516 frame_state_descriptor =
517 GetFrameStateDescriptor(call->InputAt(descriptor->InputCount()));
518 }
519
520 CallBuffer buffer(zone(), descriptor, frame_state_descriptor);
521
522 // Compute InstructionOperands for inputs and outputs.
523 InitializeCallBuffer(call, &buffer, true, true);
524
525 // Push any stack arguments.
526 for (NodeVectorRIter input = buffer.pushed_nodes.rbegin();
527 input != buffer.pushed_nodes.rend(); input++) {
528 // TODO(titzer): handle pushing double parameters.
529 Emit(kIA32Push, NULL,
530 g.CanBeImmediate(*input) ? g.UseImmediate(*input) : g.Use(*input));
531 }
532
533 // Select the appropriate opcode based on the call type.
534 InstructionCode opcode;
535 switch (descriptor->kind()) {
536 case CallDescriptor::kCallCodeObject: {
537 opcode = kArchCallCodeObject;
538 break;
539 }
540 case CallDescriptor::kCallJSFunction:
541 opcode = kArchCallJSFunction;
542 break;
543 default:
544 UNREACHABLE();
545 return;
546 }
547 opcode |= MiscField::encode(descriptor->flags());
548
549 // Emit the call instruction.
550 Instruction* call_instr =
551 Emit(opcode, buffer.outputs.size(), &buffer.outputs.front(),
552 buffer.instruction_args.size(), &buffer.instruction_args.front());
553
554 call_instr->MarkAsCall();
555 if (deoptimization != NULL) {
556 DCHECK(continuation != NULL);
557 call_instr->MarkAsControl();
558 }
559}
560
561} // namespace compiler
562} // namespace internal
563} // namespace v8