blob: 16063ab43b41c4b25e0618620a6f213b06985d42 [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 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040040
41 AddressingMode GenerateMemoryOperandInputs(Node* index, int scale, Node* base,
42 Node* displacement_node,
43 InstructionOperand* inputs[],
44 size_t* input_count) {
45 AddressingMode mode = kMode_MRI;
46 int32_t displacement = (displacement_node == NULL)
47 ? 0
48 : OpParameter<int32_t>(displacement_node);
49 if (base != NULL) {
50 if (base->opcode() == IrOpcode::kInt32Constant) {
51 displacement += OpParameter<int32_t>(base);
52 base = NULL;
53 }
54 }
55 if (base != NULL) {
56 inputs[(*input_count)++] = UseRegister(base);
57 if (index != NULL) {
58 DCHECK(scale >= 0 && scale <= 3);
59 inputs[(*input_count)++] = UseRegister(index);
60 if (displacement != 0) {
61 inputs[(*input_count)++] = TempImmediate(displacement);
62 static const AddressingMode kMRnI_modes[] = {kMode_MR1I, kMode_MR2I,
63 kMode_MR4I, kMode_MR8I};
64 mode = kMRnI_modes[scale];
65 } else {
66 static const AddressingMode kMRn_modes[] = {kMode_MR1, kMode_MR2,
67 kMode_MR4, kMode_MR8};
68 mode = kMRn_modes[scale];
69 }
70 } else {
71 if (displacement == 0) {
72 mode = kMode_MR;
73 } else {
74 inputs[(*input_count)++] = TempImmediate(displacement);
75 mode = kMode_MRI;
76 }
77 }
78 } else {
79 DCHECK(scale >= 0 && scale <= 3);
80 if (index != NULL) {
81 inputs[(*input_count)++] = UseRegister(index);
82 if (displacement != 0) {
83 inputs[(*input_count)++] = TempImmediate(displacement);
84 static const AddressingMode kMnI_modes[] = {kMode_MRI, kMode_M2I,
85 kMode_M4I, kMode_M8I};
86 mode = kMnI_modes[scale];
87 } else {
88 static const AddressingMode kMn_modes[] = {kMode_MR, kMode_M2,
89 kMode_M4, kMode_M8};
90 mode = kMn_modes[scale];
91 }
92 } else {
93 inputs[(*input_count)++] = TempImmediate(displacement);
94 return kMode_MI;
95 }
96 }
97 return mode;
98 }
99
100 AddressingMode GetEffectiveAddressMemoryOperand(Node* node,
101 InstructionOperand* inputs[],
102 size_t* input_count) {
103 BaseWithIndexAndDisplacement32Matcher m(node, true);
104 DCHECK(m.matches());
105 if ((m.displacement() == NULL || CanBeImmediate(m.displacement()))) {
106 return GenerateMemoryOperandInputs(m.index(), m.scale(), m.base(),
107 m.displacement(), inputs, input_count);
108 } else {
109 inputs[(*input_count)++] = UseRegister(node->InputAt(0));
110 inputs[(*input_count)++] = UseRegister(node->InputAt(1));
111 return kMode_MR1;
112 }
113 }
114
115 bool CanBeBetterLeftOperand(Node* node) const {
116 return !selector()->IsLive(node);
117 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000118};
119
120
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400121static void VisitRRFloat64(InstructionSelector* selector, ArchOpcode opcode,
122 Node* node) {
123 IA32OperandGenerator g(selector);
124 selector->Emit(opcode, g.DefineAsRegister(node),
125 g.UseRegister(node->InputAt(0)));
126}
127
128
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000129void InstructionSelector::VisitLoad(Node* node) {
130 MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node));
131 MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000132
133 ArchOpcode opcode;
134 // TODO(titzer): signed/unsigned small loads
135 switch (rep) {
136 case kRepFloat32:
137 opcode = kIA32Movss;
138 break;
139 case kRepFloat64:
140 opcode = kIA32Movsd;
141 break;
142 case kRepBit: // Fall through.
143 case kRepWord8:
144 opcode = typ == kTypeInt32 ? kIA32Movsxbl : kIA32Movzxbl;
145 break;
146 case kRepWord16:
147 opcode = typ == kTypeInt32 ? kIA32Movsxwl : kIA32Movzxwl;
148 break;
149 case kRepTagged: // Fall through.
150 case kRepWord32:
151 opcode = kIA32Movl;
152 break;
153 default:
154 UNREACHABLE();
155 return;
156 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400157
158 IA32OperandGenerator g(this);
159 InstructionOperand* outputs[1];
160 outputs[0] = g.DefineAsRegister(node);
161 InstructionOperand* inputs[3];
162 size_t input_count = 0;
163 AddressingMode mode =
164 g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count);
165 InstructionCode code = opcode | AddressingModeField::encode(mode);
166 Emit(code, 1, outputs, input_count, inputs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000167}
168
169
170void InstructionSelector::VisitStore(Node* node) {
171 IA32OperandGenerator g(this);
172 Node* base = node->InputAt(0);
173 Node* index = node->InputAt(1);
174 Node* value = node->InputAt(2);
175
176 StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node);
177 MachineType rep = RepresentationOf(store_rep.machine_type());
178 if (store_rep.write_barrier_kind() == kFullWriteBarrier) {
179 DCHECK_EQ(kRepTagged, rep);
180 // TODO(dcarney): refactor RecordWrite function to take temp registers
181 // and pass them here instead of using fixed regs
182 // TODO(dcarney): handle immediate indices.
183 InstructionOperand* temps[] = {g.TempRegister(ecx), g.TempRegister(edx)};
184 Emit(kIA32StoreWriteBarrier, NULL, g.UseFixed(base, ebx),
185 g.UseFixed(index, ecx), g.UseFixed(value, edx), arraysize(temps),
186 temps);
187 return;
188 }
189 DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400190
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000191 ArchOpcode opcode;
192 switch (rep) {
193 case kRepFloat32:
194 opcode = kIA32Movss;
195 break;
196 case kRepFloat64:
197 opcode = kIA32Movsd;
198 break;
199 case kRepBit: // Fall through.
200 case kRepWord8:
201 opcode = kIA32Movb;
202 break;
203 case kRepWord16:
204 opcode = kIA32Movw;
205 break;
206 case kRepTagged: // Fall through.
207 case kRepWord32:
208 opcode = kIA32Movl;
209 break;
210 default:
211 UNREACHABLE();
212 return;
213 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400214
215 InstructionOperand* val;
216 if (g.CanBeImmediate(value)) {
217 val = g.UseImmediate(value);
218 } else if (rep == kRepWord8 || rep == kRepBit) {
219 val = g.UseByteRegister(value);
220 } else {
221 val = g.UseRegister(value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000222 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400223
224 InstructionOperand* inputs[4];
225 size_t input_count = 0;
226 AddressingMode mode =
227 g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count);
228 InstructionCode code = opcode | AddressingModeField::encode(mode);
229 inputs[input_count++] = val;
230 Emit(code, 0, static_cast<InstructionOperand**>(NULL), input_count, inputs);
231}
232
233
234void InstructionSelector::VisitCheckedLoad(Node* node) {
235 MachineType rep = RepresentationOf(OpParameter<MachineType>(node));
236 MachineType typ = TypeOf(OpParameter<MachineType>(node));
237 IA32OperandGenerator g(this);
238 Node* const buffer = node->InputAt(0);
239 Node* const offset = node->InputAt(1);
240 Node* const length = node->InputAt(2);
241 ArchOpcode opcode;
242 switch (rep) {
243 case kRepWord8:
244 opcode = typ == kTypeInt32 ? kCheckedLoadInt8 : kCheckedLoadUint8;
245 break;
246 case kRepWord16:
247 opcode = typ == kTypeInt32 ? kCheckedLoadInt16 : kCheckedLoadUint16;
248 break;
249 case kRepWord32:
250 opcode = kCheckedLoadWord32;
251 break;
252 case kRepFloat32:
253 opcode = kCheckedLoadFloat32;
254 break;
255 case kRepFloat64:
256 opcode = kCheckedLoadFloat64;
257 break;
258 default:
259 UNREACHABLE();
260 return;
261 }
262 InstructionOperand* offset_operand = g.UseRegister(offset);
263 InstructionOperand* length_operand =
264 g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length);
265 if (g.CanBeImmediate(buffer)) {
266 Emit(opcode | AddressingModeField::encode(kMode_MRI),
267 g.DefineAsRegister(node), offset_operand, length_operand,
268 offset_operand, g.UseImmediate(buffer));
269 } else {
270 Emit(opcode | AddressingModeField::encode(kMode_MR1),
271 g.DefineAsRegister(node), offset_operand, length_operand,
272 g.UseRegister(buffer), offset_operand);
273 }
274}
275
276
277void InstructionSelector::VisitCheckedStore(Node* node) {
278 MachineType rep = RepresentationOf(OpParameter<MachineType>(node));
279 IA32OperandGenerator g(this);
280 Node* const buffer = node->InputAt(0);
281 Node* const offset = node->InputAt(1);
282 Node* const length = node->InputAt(2);
283 Node* const value = node->InputAt(3);
284 ArchOpcode opcode;
285 switch (rep) {
286 case kRepWord8:
287 opcode = kCheckedStoreWord8;
288 break;
289 case kRepWord16:
290 opcode = kCheckedStoreWord16;
291 break;
292 case kRepWord32:
293 opcode = kCheckedStoreWord32;
294 break;
295 case kRepFloat32:
296 opcode = kCheckedStoreFloat32;
297 break;
298 case kRepFloat64:
299 opcode = kCheckedStoreFloat64;
300 break;
301 default:
302 UNREACHABLE();
303 return;
304 }
305 InstructionOperand* value_operand =
306 g.CanBeImmediate(value)
307 ? g.UseImmediate(value)
308 : ((rep == kRepWord8 || rep == kRepBit) ? g.UseByteRegister(value)
309 : g.UseRegister(value));
310 InstructionOperand* offset_operand = g.UseRegister(offset);
311 InstructionOperand* length_operand =
312 g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length);
313 if (g.CanBeImmediate(buffer)) {
314 Emit(opcode | AddressingModeField::encode(kMode_MRI), nullptr,
315 offset_operand, length_operand, value_operand, offset_operand,
316 g.UseImmediate(buffer));
317 } else {
318 Emit(opcode | AddressingModeField::encode(kMode_MR1), nullptr,
319 offset_operand, length_operand, value_operand, g.UseRegister(buffer),
320 offset_operand);
321 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000322}
323
324
325// Shared routine for multiple binary operations.
326static void VisitBinop(InstructionSelector* selector, Node* node,
327 InstructionCode opcode, FlagsContinuation* cont) {
328 IA32OperandGenerator g(selector);
329 Int32BinopMatcher m(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400330 Node* left = m.left().node();
331 Node* right = m.right().node();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000332 InstructionOperand* inputs[4];
333 size_t input_count = 0;
334 InstructionOperand* outputs[2];
335 size_t output_count = 0;
336
337 // TODO(turbofan): match complex addressing modes.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400338 if (left == right) {
339 // If both inputs refer to the same operand, enforce allocating a register
340 // for both of them to ensure that we don't end up generating code like
341 // this:
342 //
343 // mov eax, [ebp-0x10]
344 // add eax, [ebp-0x10]
345 // jo label
346 InstructionOperand* const input = g.UseRegister(left);
347 inputs[input_count++] = input;
348 inputs[input_count++] = input;
349 } else if (g.CanBeImmediate(right)) {
350 inputs[input_count++] = g.UseRegister(left);
351 inputs[input_count++] = g.UseImmediate(right);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000352 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400353 if (node->op()->HasProperty(Operator::kCommutative) &&
354 g.CanBeBetterLeftOperand(right)) {
355 std::swap(left, right);
356 }
357 inputs[input_count++] = g.UseRegister(left);
358 inputs[input_count++] = g.Use(right);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000359 }
360
361 if (cont->IsBranch()) {
362 inputs[input_count++] = g.Label(cont->true_block());
363 inputs[input_count++] = g.Label(cont->false_block());
364 }
365
366 outputs[output_count++] = g.DefineSameAsFirst(node);
367 if (cont->IsSet()) {
368 // TODO(turbofan): Use byte register here.
369 outputs[output_count++] = g.DefineAsRegister(cont->result());
370 }
371
372 DCHECK_NE(0, input_count);
373 DCHECK_NE(0, output_count);
374 DCHECK_GE(arraysize(inputs), input_count);
375 DCHECK_GE(arraysize(outputs), output_count);
376
377 Instruction* instr = selector->Emit(cont->Encode(opcode), output_count,
378 outputs, input_count, inputs);
379 if (cont->IsBranch()) instr->MarkAsControl();
380}
381
382
383// Shared routine for multiple binary operations.
384static void VisitBinop(InstructionSelector* selector, Node* node,
385 InstructionCode opcode) {
386 FlagsContinuation cont;
387 VisitBinop(selector, node, opcode, &cont);
388}
389
390
391void InstructionSelector::VisitWord32And(Node* node) {
392 VisitBinop(this, node, kIA32And);
393}
394
395
396void InstructionSelector::VisitWord32Or(Node* node) {
397 VisitBinop(this, node, kIA32Or);
398}
399
400
401void InstructionSelector::VisitWord32Xor(Node* node) {
402 IA32OperandGenerator g(this);
403 Int32BinopMatcher m(node);
404 if (m.right().Is(-1)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400405 Emit(kIA32Not, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000406 } else {
407 VisitBinop(this, node, kIA32Xor);
408 }
409}
410
411
412// Shared routine for multiple shift operations.
413static inline void VisitShift(InstructionSelector* selector, Node* node,
414 ArchOpcode opcode) {
415 IA32OperandGenerator g(selector);
416 Node* left = node->InputAt(0);
417 Node* right = node->InputAt(1);
418
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000419 if (g.CanBeImmediate(right)) {
420 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
421 g.UseImmediate(right));
422 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000423 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
424 g.UseFixed(right, ecx));
425 }
426}
427
428
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400429namespace {
430
431void VisitMulHigh(InstructionSelector* selector, Node* node,
432 ArchOpcode opcode) {
433 IA32OperandGenerator g(selector);
434 selector->Emit(opcode, g.DefineAsFixed(node, edx),
435 g.UseFixed(node->InputAt(0), eax),
436 g.UseUniqueRegister(node->InputAt(1)));
437}
438
439
440void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
441 IA32OperandGenerator g(selector);
442 InstructionOperand* temps[] = {g.TempRegister(edx)};
443 selector->Emit(opcode, g.DefineAsFixed(node, eax),
444 g.UseFixed(node->InputAt(0), eax),
445 g.UseUnique(node->InputAt(1)), arraysize(temps), temps);
446}
447
448
449void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
450 IA32OperandGenerator g(selector);
451 selector->Emit(opcode, g.DefineAsFixed(node, edx),
452 g.UseFixed(node->InputAt(0), eax),
453 g.UseUnique(node->InputAt(1)));
454}
455
456void EmitLea(InstructionSelector* selector, Node* result, Node* index,
457 int scale, Node* base, Node* displacement) {
458 IA32OperandGenerator g(selector);
459 InstructionOperand* inputs[4];
460 size_t input_count = 0;
461 AddressingMode mode = g.GenerateMemoryOperandInputs(
462 index, scale, base, displacement, inputs, &input_count);
463
464 DCHECK_NE(0, static_cast<int>(input_count));
465 DCHECK_GE(arraysize(inputs), input_count);
466
467 InstructionOperand* outputs[1];
468 outputs[0] = g.DefineAsRegister(result);
469
470 InstructionCode opcode = AddressingModeField::encode(mode) | kIA32Lea;
471
472 selector->Emit(opcode, 1, outputs, input_count, inputs);
473}
474
475} // namespace
476
477
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000478void InstructionSelector::VisitWord32Shl(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400479 Int32ScaleMatcher m(node, true);
480 if (m.matches()) {
481 Node* index = node->InputAt(0);
482 Node* base = m.power_of_two_plus_one() ? index : NULL;
483 EmitLea(this, node, index, m.scale(), base, NULL);
484 return;
485 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000486 VisitShift(this, node, kIA32Shl);
487}
488
489
490void InstructionSelector::VisitWord32Shr(Node* node) {
491 VisitShift(this, node, kIA32Shr);
492}
493
494
495void InstructionSelector::VisitWord32Sar(Node* node) {
496 VisitShift(this, node, kIA32Sar);
497}
498
499
500void InstructionSelector::VisitWord32Ror(Node* node) {
501 VisitShift(this, node, kIA32Ror);
502}
503
504
505void InstructionSelector::VisitInt32Add(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400506 IA32OperandGenerator g(this);
507
508 // Try to match the Add to a lea pattern
509 BaseWithIndexAndDisplacement32Matcher m(node);
510 if (m.matches() &&
511 (m.displacement() == NULL || g.CanBeImmediate(m.displacement()))) {
512 InstructionOperand* inputs[4];
513 size_t input_count = 0;
514 AddressingMode mode = g.GenerateMemoryOperandInputs(
515 m.index(), m.scale(), m.base(), m.displacement(), inputs, &input_count);
516
517 DCHECK_NE(0, static_cast<int>(input_count));
518 DCHECK_GE(arraysize(inputs), input_count);
519
520 InstructionOperand* outputs[1];
521 outputs[0] = g.DefineAsRegister(node);
522
523 InstructionCode opcode = AddressingModeField::encode(mode) | kIA32Lea;
524 Emit(opcode, 1, outputs, input_count, inputs);
525 return;
526 }
527
528 // No lea pattern match, use add
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000529 VisitBinop(this, node, kIA32Add);
530}
531
532
533void InstructionSelector::VisitInt32Sub(Node* node) {
534 IA32OperandGenerator g(this);
535 Int32BinopMatcher m(node);
536 if (m.left().Is(0)) {
537 Emit(kIA32Neg, g.DefineSameAsFirst(node), g.Use(m.right().node()));
538 } else {
539 VisitBinop(this, node, kIA32Sub);
540 }
541}
542
543
544void InstructionSelector::VisitInt32Mul(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400545 Int32ScaleMatcher m(node, true);
546 if (m.matches()) {
547 Node* index = node->InputAt(0);
548 Node* base = m.power_of_two_plus_one() ? index : NULL;
549 EmitLea(this, node, index, m.scale(), base, NULL);
550 return;
551 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000552 IA32OperandGenerator g(this);
553 Node* left = node->InputAt(0);
554 Node* right = node->InputAt(1);
555 if (g.CanBeImmediate(right)) {
556 Emit(kIA32Imul, g.DefineAsRegister(node), g.Use(left),
557 g.UseImmediate(right));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000558 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400559 if (g.CanBeBetterLeftOperand(right)) {
560 std::swap(left, right);
561 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000562 Emit(kIA32Imul, g.DefineSameAsFirst(node), g.UseRegister(left),
563 g.Use(right));
564 }
565}
566
567
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400568void InstructionSelector::VisitInt32MulHigh(Node* node) {
569 VisitMulHigh(this, node, kIA32ImulHigh);
570}
571
572
573void InstructionSelector::VisitUint32MulHigh(Node* node) {
574 VisitMulHigh(this, node, kIA32UmulHigh);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000575}
576
577
578void InstructionSelector::VisitInt32Div(Node* node) {
579 VisitDiv(this, node, kIA32Idiv);
580}
581
582
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400583void InstructionSelector::VisitUint32Div(Node* node) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000584 VisitDiv(this, node, kIA32Udiv);
585}
586
587
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000588void InstructionSelector::VisitInt32Mod(Node* node) {
589 VisitMod(this, node, kIA32Idiv);
590}
591
592
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400593void InstructionSelector::VisitUint32Mod(Node* node) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000594 VisitMod(this, node, kIA32Udiv);
595}
596
597
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400598void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
599 IA32OperandGenerator g(this);
600 Emit(kSSECvtss2sd, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
601}
602
603
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000604void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
605 IA32OperandGenerator g(this);
606 Emit(kSSEInt32ToFloat64, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
607}
608
609
610void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
611 IA32OperandGenerator g(this);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400612 Emit(kSSEUint32ToFloat64, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000613}
614
615
616void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
617 IA32OperandGenerator g(this);
618 Emit(kSSEFloat64ToInt32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
619}
620
621
622void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
623 IA32OperandGenerator g(this);
624 Emit(kSSEFloat64ToUint32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
625}
626
627
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400628void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
629 IA32OperandGenerator g(this);
630 Emit(kSSECvtsd2ss, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
631}
632
633
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000634void InstructionSelector::VisitFloat64Add(Node* node) {
635 IA32OperandGenerator g(this);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400636 if (IsSupported(AVX)) {
637 Emit(kAVXFloat64Add, g.DefineAsRegister(node),
638 g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
639 } else {
640 Emit(kSSEFloat64Add, g.DefineSameAsFirst(node),
641 g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
642 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000643}
644
645
646void InstructionSelector::VisitFloat64Sub(Node* node) {
647 IA32OperandGenerator g(this);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400648 if (IsSupported(AVX)) {
649 Emit(kAVXFloat64Sub, g.DefineAsRegister(node),
650 g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
651 } else {
652 Emit(kSSEFloat64Sub, g.DefineSameAsFirst(node),
653 g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
654 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000655}
656
657
658void InstructionSelector::VisitFloat64Mul(Node* node) {
659 IA32OperandGenerator g(this);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400660 if (IsSupported(AVX)) {
661 Emit(kAVXFloat64Mul, g.DefineAsRegister(node),
662 g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
663 } else {
664 Emit(kSSEFloat64Mul, g.DefineSameAsFirst(node),
665 g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
666 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000667}
668
669
670void InstructionSelector::VisitFloat64Div(Node* node) {
671 IA32OperandGenerator g(this);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400672 if (IsSupported(AVX)) {
673 Emit(kAVXFloat64Div, g.DefineAsRegister(node),
674 g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
675 } else {
676 Emit(kSSEFloat64Div, g.DefineSameAsFirst(node),
677 g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
678 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000679}
680
681
682void InstructionSelector::VisitFloat64Mod(Node* node) {
683 IA32OperandGenerator g(this);
684 InstructionOperand* temps[] = {g.TempRegister(eax)};
685 Emit(kSSEFloat64Mod, g.DefineSameAsFirst(node),
686 g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)), 1,
687 temps);
688}
689
690
691void InstructionSelector::VisitFloat64Sqrt(Node* node) {
692 IA32OperandGenerator g(this);
693 Emit(kSSEFloat64Sqrt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
694}
695
696
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400697void InstructionSelector::VisitFloat64Floor(Node* node) {
698 DCHECK(CpuFeatures::IsSupported(SSE4_1));
699 VisitRRFloat64(this, kSSEFloat64Floor, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000700}
701
702
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400703void InstructionSelector::VisitFloat64Ceil(Node* node) {
704 DCHECK(CpuFeatures::IsSupported(SSE4_1));
705 VisitRRFloat64(this, kSSEFloat64Ceil, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000706}
707
708
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400709void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
710 DCHECK(CpuFeatures::IsSupported(SSE4_1));
711 VisitRRFloat64(this, kSSEFloat64RoundTruncate, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000712}
713
714
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400715void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
716 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000717}
718
719
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400720void InstructionSelector::VisitCall(Node* node) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000721 IA32OperandGenerator g(this);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400722 const CallDescriptor* descriptor = OpParameter<const CallDescriptor*>(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000723
724 FrameStateDescriptor* frame_state_descriptor = NULL;
725
726 if (descriptor->NeedsFrameState()) {
727 frame_state_descriptor =
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400728 GetFrameStateDescriptor(node->InputAt(descriptor->InputCount()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000729 }
730
731 CallBuffer buffer(zone(), descriptor, frame_state_descriptor);
732
733 // Compute InstructionOperands for inputs and outputs.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400734 InitializeCallBuffer(node, &buffer, true, true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000735
736 // Push any stack arguments.
737 for (NodeVectorRIter input = buffer.pushed_nodes.rbegin();
738 input != buffer.pushed_nodes.rend(); input++) {
739 // TODO(titzer): handle pushing double parameters.
740 Emit(kIA32Push, NULL,
741 g.CanBeImmediate(*input) ? g.UseImmediate(*input) : g.Use(*input));
742 }
743
744 // Select the appropriate opcode based on the call type.
745 InstructionCode opcode;
746 switch (descriptor->kind()) {
747 case CallDescriptor::kCallCodeObject: {
748 opcode = kArchCallCodeObject;
749 break;
750 }
751 case CallDescriptor::kCallJSFunction:
752 opcode = kArchCallJSFunction;
753 break;
754 default:
755 UNREACHABLE();
756 return;
757 }
758 opcode |= MiscField::encode(descriptor->flags());
759
760 // Emit the call instruction.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400761 InstructionOperand** first_output =
762 buffer.outputs.size() > 0 ? &buffer.outputs.front() : NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000763 Instruction* call_instr =
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400764 Emit(opcode, buffer.outputs.size(), first_output,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000765 buffer.instruction_args.size(), &buffer.instruction_args.front());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000766 call_instr->MarkAsCall();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400767}
768
769
770namespace {
771
772// Shared routine for multiple compare operations.
773void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
774 InstructionOperand* left, InstructionOperand* right,
775 FlagsContinuation* cont) {
776 IA32OperandGenerator g(selector);
777 if (cont->IsBranch()) {
778 selector->Emit(cont->Encode(opcode), NULL, left, right,
779 g.Label(cont->true_block()),
780 g.Label(cont->false_block()))->MarkAsControl();
781 } else {
782 DCHECK(cont->IsSet());
783 // TODO(titzer): Needs byte register.
784 selector->Emit(cont->Encode(opcode), g.DefineAsRegister(cont->result()),
785 left, right);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000786 }
787}
788
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400789
790// Shared routine for multiple compare operations.
791void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
792 Node* left, Node* right, FlagsContinuation* cont,
793 bool commutative) {
794 IA32OperandGenerator g(selector);
795 if (commutative && g.CanBeBetterLeftOperand(right)) {
796 std::swap(left, right);
797 }
798 VisitCompare(selector, opcode, g.UseRegister(left), g.Use(right), cont);
799}
800
801
802// Shared routine for multiple float compare operations.
803void VisitFloat64Compare(InstructionSelector* selector, Node* node,
804 FlagsContinuation* cont) {
805 VisitCompare(selector, kSSEFloat64Cmp, node->InputAt(0), node->InputAt(1),
806 cont, node->op()->HasProperty(Operator::kCommutative));
807}
808
809
810// Shared routine for multiple word compare operations.
811void VisitWordCompare(InstructionSelector* selector, Node* node,
812 InstructionCode opcode, FlagsContinuation* cont) {
813 IA32OperandGenerator g(selector);
814 Node* const left = node->InputAt(0);
815 Node* const right = node->InputAt(1);
816
817 // Match immediates on left or right side of comparison.
818 if (g.CanBeImmediate(right)) {
819 VisitCompare(selector, opcode, g.Use(left), g.UseImmediate(right), cont);
820 } else if (g.CanBeImmediate(left)) {
821 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
822 VisitCompare(selector, opcode, g.Use(right), g.UseImmediate(left), cont);
823 } else {
824 VisitCompare(selector, opcode, left, right, cont,
825 node->op()->HasProperty(Operator::kCommutative));
826 }
827}
828
829
830void VisitWordCompare(InstructionSelector* selector, Node* node,
831 FlagsContinuation* cont) {
832 VisitWordCompare(selector, node, kIA32Cmp, cont);
833}
834
835
836// Shared routine for word comparison with zero.
837void VisitWordCompareZero(InstructionSelector* selector, Node* user,
838 Node* value, FlagsContinuation* cont) {
839 // Try to combine the branch with a comparison.
840 while (selector->CanCover(user, value)) {
841 switch (value->opcode()) {
842 case IrOpcode::kWord32Equal: {
843 // Try to combine with comparisons against 0 by simply inverting the
844 // continuation.
845 Int32BinopMatcher m(value);
846 if (m.right().Is(0)) {
847 user = value;
848 value = m.left().node();
849 cont->Negate();
850 continue;
851 }
852 cont->OverwriteAndNegateIfEqual(kEqual);
853 return VisitWordCompare(selector, value, cont);
854 }
855 case IrOpcode::kInt32LessThan:
856 cont->OverwriteAndNegateIfEqual(kSignedLessThan);
857 return VisitWordCompare(selector, value, cont);
858 case IrOpcode::kInt32LessThanOrEqual:
859 cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
860 return VisitWordCompare(selector, value, cont);
861 case IrOpcode::kUint32LessThan:
862 cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
863 return VisitWordCompare(selector, value, cont);
864 case IrOpcode::kUint32LessThanOrEqual:
865 cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
866 return VisitWordCompare(selector, value, cont);
867 case IrOpcode::kFloat64Equal:
868 cont->OverwriteAndNegateIfEqual(kUnorderedEqual);
869 return VisitFloat64Compare(selector, value, cont);
870 case IrOpcode::kFloat64LessThan:
871 cont->OverwriteAndNegateIfEqual(kUnorderedLessThan);
872 return VisitFloat64Compare(selector, value, cont);
873 case IrOpcode::kFloat64LessThanOrEqual:
874 cont->OverwriteAndNegateIfEqual(kUnorderedLessThanOrEqual);
875 return VisitFloat64Compare(selector, value, cont);
876 case IrOpcode::kProjection:
877 // Check if this is the overflow output projection of an
878 // <Operation>WithOverflow node.
879 if (OpParameter<size_t>(value) == 1u) {
880 // We cannot combine the <Operation>WithOverflow with this branch
881 // unless the 0th projection (the use of the actual value of the
882 // <Operation> is either NULL, which means there's no use of the
883 // actual value, or was already defined, which means it is scheduled
884 // *AFTER* this branch).
885 Node* node = value->InputAt(0);
886 Node* result = node->FindProjection(0);
887 if (result == NULL || selector->IsDefined(result)) {
888 switch (node->opcode()) {
889 case IrOpcode::kInt32AddWithOverflow:
890 cont->OverwriteAndNegateIfEqual(kOverflow);
891 return VisitBinop(selector, node, kIA32Add, cont);
892 case IrOpcode::kInt32SubWithOverflow:
893 cont->OverwriteAndNegateIfEqual(kOverflow);
894 return VisitBinop(selector, node, kIA32Sub, cont);
895 default:
896 break;
897 }
898 }
899 }
900 break;
901 case IrOpcode::kInt32Sub:
902 return VisitWordCompare(selector, value, cont);
903 case IrOpcode::kWord32And:
904 return VisitWordCompare(selector, value, kIA32Test, cont);
905 default:
906 break;
907 }
908 break;
909 }
910
911 // Continuation could not be combined with a compare, emit compare against 0.
912 IA32OperandGenerator g(selector);
913 VisitCompare(selector, kIA32Cmp, g.Use(value), g.TempImmediate(0), cont);
914}
915
916} // namespace
917
918
919void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
920 BasicBlock* fbranch) {
921 FlagsContinuation cont(kNotEqual, tbranch, fbranch);
922 VisitWordCompareZero(this, branch, branch->InputAt(0), &cont);
923}
924
925
926void InstructionSelector::VisitWord32Equal(Node* const node) {
927 FlagsContinuation cont(kEqual, node);
928 Int32BinopMatcher m(node);
929 if (m.right().Is(0)) {
930 return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
931 }
932 VisitWordCompare(this, node, &cont);
933}
934
935
936void InstructionSelector::VisitInt32LessThan(Node* node) {
937 FlagsContinuation cont(kSignedLessThan, node);
938 VisitWordCompare(this, node, &cont);
939}
940
941
942void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
943 FlagsContinuation cont(kSignedLessThanOrEqual, node);
944 VisitWordCompare(this, node, &cont);
945}
946
947
948void InstructionSelector::VisitUint32LessThan(Node* node) {
949 FlagsContinuation cont(kUnsignedLessThan, node);
950 VisitWordCompare(this, node, &cont);
951}
952
953
954void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
955 FlagsContinuation cont(kUnsignedLessThanOrEqual, node);
956 VisitWordCompare(this, node, &cont);
957}
958
959
960void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
961 if (Node* ovf = node->FindProjection(1)) {
962 FlagsContinuation cont(kOverflow, ovf);
963 return VisitBinop(this, node, kIA32Add, &cont);
964 }
965 FlagsContinuation cont;
966 VisitBinop(this, node, kIA32Add, &cont);
967}
968
969
970void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
971 if (Node* ovf = node->FindProjection(1)) {
972 FlagsContinuation cont(kOverflow, ovf);
973 return VisitBinop(this, node, kIA32Sub, &cont);
974 }
975 FlagsContinuation cont;
976 VisitBinop(this, node, kIA32Sub, &cont);
977}
978
979
980void InstructionSelector::VisitFloat64Equal(Node* node) {
981 FlagsContinuation cont(kUnorderedEqual, node);
982 VisitFloat64Compare(this, node, &cont);
983}
984
985
986void InstructionSelector::VisitFloat64LessThan(Node* node) {
987 FlagsContinuation cont(kUnorderedLessThan, node);
988 VisitFloat64Compare(this, node, &cont);
989}
990
991
992void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
993 FlagsContinuation cont(kUnorderedLessThanOrEqual, node);
994 VisitFloat64Compare(this, node, &cont);
995}
996
997
998// static
999MachineOperatorBuilder::Flags
1000InstructionSelector::SupportedMachineOperatorFlags() {
1001 if (CpuFeatures::IsSupported(SSE4_1)) {
1002 return MachineOperatorBuilder::kFloat64Floor |
1003 MachineOperatorBuilder::kFloat64Ceil |
1004 MachineOperatorBuilder::kFloat64RoundTruncate |
1005 MachineOperatorBuilder::kWord32ShiftIsSafe;
1006 }
1007 return MachineOperatorBuilder::Flag::kNoFlags;
1008}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001009} // namespace compiler
1010} // namespace internal
1011} // namespace v8