blob: 5c4acce6735bd339dbb5a8c808c94b685ecbe09e [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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005#include "src/base/adapters.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006#include "src/compiler/instruction-selector-impl.h"
7#include "src/compiler/node-matchers.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008#include "src/compiler/node-properties.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009
10namespace v8 {
11namespace internal {
12namespace compiler {
13
14// Adds IA32-specific methods for generating operands.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015class IA32OperandGenerator final : public OperandGenerator {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016 public:
17 explicit IA32OperandGenerator(InstructionSelector* selector)
18 : OperandGenerator(selector) {}
19
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000020 InstructionOperand UseByteRegister(Node* node) {
21 // TODO(titzer): encode byte register use constraints.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000022 return UseFixed(node, edx);
23 }
24
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000025 InstructionOperand DefineAsByteRegister(Node* node) {
26 // TODO(titzer): encode byte register def constraints.
27 return DefineAsRegister(node);
28 }
29
Ben Murdochda12d292016-06-02 14:46:10 +010030 bool CanBeMemoryOperand(InstructionCode opcode, Node* node, Node* input) {
31 if (input->opcode() != IrOpcode::kLoad ||
32 !selector()->CanCover(node, input)) {
33 return false;
34 }
35 MachineRepresentation rep =
36 LoadRepresentationOf(input->op()).representation();
37 switch (opcode) {
38 case kIA32Cmp:
39 case kIA32Test:
40 return rep == MachineRepresentation::kWord32 ||
41 rep == MachineRepresentation::kTagged;
42 case kIA32Cmp16:
43 case kIA32Test16:
44 return rep == MachineRepresentation::kWord16;
45 case kIA32Cmp8:
46 case kIA32Test8:
47 return rep == MachineRepresentation::kWord8;
48 default:
49 break;
50 }
51 return false;
52 }
53
Ben Murdochb8a8cc12014-11-26 15:28:44 +000054 bool CanBeImmediate(Node* node) {
55 switch (node->opcode()) {
56 case IrOpcode::kInt32Constant:
57 case IrOpcode::kNumberConstant:
58 case IrOpcode::kExternalConstant:
59 return true;
60 case IrOpcode::kHeapConstant: {
61 // Constants in new space cannot be used as immediates in V8 because
62 // the GC does not scan code objects when collecting the new generation.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000063 Handle<HeapObject> value = OpParameter<Handle<HeapObject>>(node);
64 Isolate* isolate = value->GetIsolate();
65 return !isolate->heap()->InNewSpace(*value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000066 }
67 default:
68 return false;
69 }
70 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040071
72 AddressingMode GenerateMemoryOperandInputs(Node* index, int scale, Node* base,
73 Node* displacement_node,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000074 InstructionOperand inputs[],
Emily Bernierd0a1eb72015-03-24 16:35:39 -040075 size_t* input_count) {
76 AddressingMode mode = kMode_MRI;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000077 int32_t displacement = (displacement_node == nullptr)
Emily Bernierd0a1eb72015-03-24 16:35:39 -040078 ? 0
79 : OpParameter<int32_t>(displacement_node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000080 if (base != nullptr) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040081 if (base->opcode() == IrOpcode::kInt32Constant) {
82 displacement += OpParameter<int32_t>(base);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000083 base = nullptr;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040084 }
85 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000086 if (base != nullptr) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040087 inputs[(*input_count)++] = UseRegister(base);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000088 if (index != nullptr) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040089 DCHECK(scale >= 0 && scale <= 3);
90 inputs[(*input_count)++] = UseRegister(index);
91 if (displacement != 0) {
92 inputs[(*input_count)++] = TempImmediate(displacement);
93 static const AddressingMode kMRnI_modes[] = {kMode_MR1I, kMode_MR2I,
94 kMode_MR4I, kMode_MR8I};
95 mode = kMRnI_modes[scale];
96 } else {
97 static const AddressingMode kMRn_modes[] = {kMode_MR1, kMode_MR2,
98 kMode_MR4, kMode_MR8};
99 mode = kMRn_modes[scale];
100 }
101 } else {
102 if (displacement == 0) {
103 mode = kMode_MR;
104 } else {
105 inputs[(*input_count)++] = TempImmediate(displacement);
106 mode = kMode_MRI;
107 }
108 }
109 } else {
110 DCHECK(scale >= 0 && scale <= 3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000111 if (index != nullptr) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400112 inputs[(*input_count)++] = UseRegister(index);
113 if (displacement != 0) {
114 inputs[(*input_count)++] = TempImmediate(displacement);
115 static const AddressingMode kMnI_modes[] = {kMode_MRI, kMode_M2I,
116 kMode_M4I, kMode_M8I};
117 mode = kMnI_modes[scale];
118 } else {
119 static const AddressingMode kMn_modes[] = {kMode_MR, kMode_M2,
120 kMode_M4, kMode_M8};
121 mode = kMn_modes[scale];
122 }
123 } else {
124 inputs[(*input_count)++] = TempImmediate(displacement);
125 return kMode_MI;
126 }
127 }
128 return mode;
129 }
130
131 AddressingMode GetEffectiveAddressMemoryOperand(Node* node,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000132 InstructionOperand inputs[],
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400133 size_t* input_count) {
134 BaseWithIndexAndDisplacement32Matcher m(node, true);
135 DCHECK(m.matches());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000136 if ((m.displacement() == nullptr || CanBeImmediate(m.displacement()))) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400137 return GenerateMemoryOperandInputs(m.index(), m.scale(), m.base(),
138 m.displacement(), inputs, input_count);
139 } else {
140 inputs[(*input_count)++] = UseRegister(node->InputAt(0));
141 inputs[(*input_count)++] = UseRegister(node->InputAt(1));
142 return kMode_MR1;
143 }
144 }
145
146 bool CanBeBetterLeftOperand(Node* node) const {
147 return !selector()->IsLive(node);
148 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000149};
150
151
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000152namespace {
153
154void VisitRO(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
155 IA32OperandGenerator g(selector);
156 selector->Emit(opcode, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
157}
158
159
160void VisitRR(InstructionSelector* selector, Node* node,
161 InstructionCode opcode) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400162 IA32OperandGenerator g(selector);
163 selector->Emit(opcode, g.DefineAsRegister(node),
164 g.UseRegister(node->InputAt(0)));
165}
166
167
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000168void VisitRROFloat(InstructionSelector* selector, Node* node,
169 ArchOpcode avx_opcode, ArchOpcode sse_opcode) {
170 IA32OperandGenerator g(selector);
171 InstructionOperand operand0 = g.UseRegister(node->InputAt(0));
172 InstructionOperand operand1 = g.Use(node->InputAt(1));
173 if (selector->IsSupported(AVX)) {
174 selector->Emit(avx_opcode, g.DefineAsRegister(node), operand0, operand1);
175 } else {
176 selector->Emit(sse_opcode, g.DefineSameAsFirst(node), operand0, operand1);
177 }
178}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000179
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000180
181void VisitFloatUnop(InstructionSelector* selector, Node* node, Node* input,
182 ArchOpcode avx_opcode, ArchOpcode sse_opcode) {
183 IA32OperandGenerator g(selector);
184 if (selector->IsSupported(AVX)) {
185 selector->Emit(avx_opcode, g.DefineAsRegister(node), g.Use(input));
186 } else {
187 selector->Emit(sse_opcode, g.DefineSameAsFirst(node), g.UseRegister(input));
188 }
189}
190
191
192} // namespace
193
194
195void InstructionSelector::VisitLoad(Node* node) {
196 LoadRepresentation load_rep = LoadRepresentationOf(node->op());
197
198 ArchOpcode opcode = kArchNop;
199 switch (load_rep.representation()) {
200 case MachineRepresentation::kFloat32:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000201 opcode = kIA32Movss;
202 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000203 case MachineRepresentation::kFloat64:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000204 opcode = kIA32Movsd;
205 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000206 case MachineRepresentation::kBit: // Fall through.
207 case MachineRepresentation::kWord8:
208 opcode = load_rep.IsSigned() ? kIA32Movsxbl : kIA32Movzxbl;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000209 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000210 case MachineRepresentation::kWord16:
211 opcode = load_rep.IsSigned() ? kIA32Movsxwl : kIA32Movzxwl;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000212 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000213 case MachineRepresentation::kTagged: // Fall through.
214 case MachineRepresentation::kWord32:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000215 opcode = kIA32Movl;
216 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100217 case MachineRepresentation::kWord64: // Fall through.
218 case MachineRepresentation::kSimd128: // Fall through.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000219 case MachineRepresentation::kNone:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000220 UNREACHABLE();
221 return;
222 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400223
224 IA32OperandGenerator g(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000225 InstructionOperand outputs[1];
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400226 outputs[0] = g.DefineAsRegister(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000227 InstructionOperand inputs[3];
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400228 size_t input_count = 0;
229 AddressingMode mode =
230 g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count);
231 InstructionCode code = opcode | AddressingModeField::encode(mode);
232 Emit(code, 1, outputs, input_count, inputs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000233}
234
235
236void InstructionSelector::VisitStore(Node* node) {
237 IA32OperandGenerator g(this);
238 Node* base = node->InputAt(0);
239 Node* index = node->InputAt(1);
240 Node* value = node->InputAt(2);
241
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000242 StoreRepresentation store_rep = StoreRepresentationOf(node->op());
243 WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind();
244 MachineRepresentation rep = store_rep.representation();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400245
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000246 if (write_barrier_kind != kNoWriteBarrier) {
247 DCHECK_EQ(MachineRepresentation::kTagged, rep);
248 AddressingMode addressing_mode;
249 InstructionOperand inputs[3];
250 size_t input_count = 0;
251 inputs[input_count++] = g.UseUniqueRegister(base);
252 if (g.CanBeImmediate(index)) {
253 inputs[input_count++] = g.UseImmediate(index);
254 addressing_mode = kMode_MRI;
255 } else {
256 inputs[input_count++] = g.UseUniqueRegister(index);
257 addressing_mode = kMode_MR1;
258 }
Ben Murdochda12d292016-06-02 14:46:10 +0100259 inputs[input_count++] = g.UseUniqueRegister(value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000260 RecordWriteMode record_write_mode = RecordWriteMode::kValueIsAny;
261 switch (write_barrier_kind) {
262 case kNoWriteBarrier:
263 UNREACHABLE();
264 break;
265 case kMapWriteBarrier:
266 record_write_mode = RecordWriteMode::kValueIsMap;
267 break;
268 case kPointerWriteBarrier:
269 record_write_mode = RecordWriteMode::kValueIsPointer;
270 break;
271 case kFullWriteBarrier:
272 record_write_mode = RecordWriteMode::kValueIsAny;
273 break;
274 }
275 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
276 size_t const temp_count = arraysize(temps);
277 InstructionCode code = kArchStoreWithWriteBarrier;
278 code |= AddressingModeField::encode(addressing_mode);
279 code |= MiscField::encode(static_cast<int>(record_write_mode));
280 Emit(code, 0, nullptr, input_count, inputs, temp_count, temps);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400281 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000282 ArchOpcode opcode = kArchNop;
283 switch (rep) {
284 case MachineRepresentation::kFloat32:
285 opcode = kIA32Movss;
286 break;
287 case MachineRepresentation::kFloat64:
288 opcode = kIA32Movsd;
289 break;
290 case MachineRepresentation::kBit: // Fall through.
291 case MachineRepresentation::kWord8:
292 opcode = kIA32Movb;
293 break;
294 case MachineRepresentation::kWord16:
295 opcode = kIA32Movw;
296 break;
297 case MachineRepresentation::kTagged: // Fall through.
298 case MachineRepresentation::kWord32:
299 opcode = kIA32Movl;
300 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100301 case MachineRepresentation::kWord64: // Fall through.
302 case MachineRepresentation::kSimd128: // Fall through.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000303 case MachineRepresentation::kNone:
304 UNREACHABLE();
305 return;
306 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400307
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000308 InstructionOperand val;
309 if (g.CanBeImmediate(value)) {
310 val = g.UseImmediate(value);
311 } else if (rep == MachineRepresentation::kWord8 ||
312 rep == MachineRepresentation::kBit) {
313 val = g.UseByteRegister(value);
314 } else {
315 val = g.UseRegister(value);
316 }
317
318 InstructionOperand inputs[4];
319 size_t input_count = 0;
320 AddressingMode addressing_mode =
321 g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count);
322 InstructionCode code =
323 opcode | AddressingModeField::encode(addressing_mode);
324 inputs[input_count++] = val;
325 Emit(code, 0, static_cast<InstructionOperand*>(nullptr), input_count,
326 inputs);
327 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400328}
329
330
331void InstructionSelector::VisitCheckedLoad(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000332 CheckedLoadRepresentation load_rep = CheckedLoadRepresentationOf(node->op());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400333 IA32OperandGenerator g(this);
334 Node* const buffer = node->InputAt(0);
335 Node* const offset = node->InputAt(1);
336 Node* const length = node->InputAt(2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000337 ArchOpcode opcode = kArchNop;
338 switch (load_rep.representation()) {
339 case MachineRepresentation::kWord8:
340 opcode = load_rep.IsSigned() ? kCheckedLoadInt8 : kCheckedLoadUint8;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400341 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000342 case MachineRepresentation::kWord16:
343 opcode = load_rep.IsSigned() ? kCheckedLoadInt16 : kCheckedLoadUint16;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400344 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000345 case MachineRepresentation::kWord32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400346 opcode = kCheckedLoadWord32;
347 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000348 case MachineRepresentation::kFloat32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400349 opcode = kCheckedLoadFloat32;
350 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000351 case MachineRepresentation::kFloat64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400352 opcode = kCheckedLoadFloat64;
353 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100354 case MachineRepresentation::kBit: // Fall through.
355 case MachineRepresentation::kTagged: // Fall through.
356 case MachineRepresentation::kWord64: // Fall through.
357 case MachineRepresentation::kSimd128: // Fall through.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000358 case MachineRepresentation::kNone:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400359 UNREACHABLE();
360 return;
361 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000362 InstructionOperand offset_operand = g.UseRegister(offset);
363 InstructionOperand length_operand =
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400364 g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length);
365 if (g.CanBeImmediate(buffer)) {
366 Emit(opcode | AddressingModeField::encode(kMode_MRI),
367 g.DefineAsRegister(node), offset_operand, length_operand,
368 offset_operand, g.UseImmediate(buffer));
369 } else {
370 Emit(opcode | AddressingModeField::encode(kMode_MR1),
371 g.DefineAsRegister(node), offset_operand, length_operand,
372 g.UseRegister(buffer), offset_operand);
373 }
374}
375
376
377void InstructionSelector::VisitCheckedStore(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000378 MachineRepresentation rep = CheckedStoreRepresentationOf(node->op());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400379 IA32OperandGenerator g(this);
380 Node* const buffer = node->InputAt(0);
381 Node* const offset = node->InputAt(1);
382 Node* const length = node->InputAt(2);
383 Node* const value = node->InputAt(3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000384 ArchOpcode opcode = kArchNop;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400385 switch (rep) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000386 case MachineRepresentation::kWord8:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400387 opcode = kCheckedStoreWord8;
388 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000389 case MachineRepresentation::kWord16:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400390 opcode = kCheckedStoreWord16;
391 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000392 case MachineRepresentation::kWord32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400393 opcode = kCheckedStoreWord32;
394 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000395 case MachineRepresentation::kFloat32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400396 opcode = kCheckedStoreFloat32;
397 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000398 case MachineRepresentation::kFloat64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400399 opcode = kCheckedStoreFloat64;
400 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100401 case MachineRepresentation::kBit: // Fall through.
402 case MachineRepresentation::kTagged: // Fall through.
403 case MachineRepresentation::kWord64: // Fall through.
404 case MachineRepresentation::kSimd128: // Fall through.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000405 case MachineRepresentation::kNone:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400406 UNREACHABLE();
407 return;
408 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000409 InstructionOperand value_operand =
410 g.CanBeImmediate(value) ? g.UseImmediate(value)
411 : ((rep == MachineRepresentation::kWord8 ||
412 rep == MachineRepresentation::kBit)
413 ? g.UseByteRegister(value)
414 : g.UseRegister(value));
415 InstructionOperand offset_operand = g.UseRegister(offset);
416 InstructionOperand length_operand =
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400417 g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length);
418 if (g.CanBeImmediate(buffer)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000419 Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400420 offset_operand, length_operand, value_operand, offset_operand,
421 g.UseImmediate(buffer));
422 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000423 Emit(opcode | AddressingModeField::encode(kMode_MR1), g.NoOutput(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400424 offset_operand, length_operand, value_operand, g.UseRegister(buffer),
425 offset_operand);
426 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000427}
428
Ben Murdochda12d292016-06-02 14:46:10 +0100429namespace {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000430
431// Shared routine for multiple binary operations.
Ben Murdochda12d292016-06-02 14:46:10 +0100432void VisitBinop(InstructionSelector* selector, Node* node,
433 InstructionCode opcode, FlagsContinuation* cont) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000434 IA32OperandGenerator g(selector);
435 Int32BinopMatcher m(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400436 Node* left = m.left().node();
437 Node* right = m.right().node();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000438 InstructionOperand inputs[4];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000439 size_t input_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000440 InstructionOperand outputs[2];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000441 size_t output_count = 0;
442
443 // TODO(turbofan): match complex addressing modes.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400444 if (left == right) {
445 // If both inputs refer to the same operand, enforce allocating a register
446 // for both of them to ensure that we don't end up generating code like
447 // this:
448 //
449 // mov eax, [ebp-0x10]
450 // add eax, [ebp-0x10]
451 // jo label
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000452 InstructionOperand const input = g.UseRegister(left);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400453 inputs[input_count++] = input;
454 inputs[input_count++] = input;
455 } else if (g.CanBeImmediate(right)) {
456 inputs[input_count++] = g.UseRegister(left);
457 inputs[input_count++] = g.UseImmediate(right);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000458 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400459 if (node->op()->HasProperty(Operator::kCommutative) &&
460 g.CanBeBetterLeftOperand(right)) {
461 std::swap(left, right);
462 }
463 inputs[input_count++] = g.UseRegister(left);
464 inputs[input_count++] = g.Use(right);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000465 }
466
467 if (cont->IsBranch()) {
468 inputs[input_count++] = g.Label(cont->true_block());
469 inputs[input_count++] = g.Label(cont->false_block());
470 }
471
472 outputs[output_count++] = g.DefineSameAsFirst(node);
473 if (cont->IsSet()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000474 outputs[output_count++] = g.DefineAsByteRegister(cont->result());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000475 }
476
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000477 DCHECK_NE(0u, input_count);
478 DCHECK_NE(0u, output_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000479 DCHECK_GE(arraysize(inputs), input_count);
480 DCHECK_GE(arraysize(outputs), output_count);
481
Ben Murdochda12d292016-06-02 14:46:10 +0100482 opcode = cont->Encode(opcode);
483 if (cont->IsDeoptimize()) {
484 selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
485 cont->frame_state());
486 } else {
487 selector->Emit(opcode, output_count, outputs, input_count, inputs);
488 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000489}
490
491
492// Shared routine for multiple binary operations.
Ben Murdochda12d292016-06-02 14:46:10 +0100493void VisitBinop(InstructionSelector* selector, Node* node,
494 InstructionCode opcode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000495 FlagsContinuation cont;
496 VisitBinop(selector, node, opcode, &cont);
497}
498
Ben Murdochda12d292016-06-02 14:46:10 +0100499} // namespace
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000500
501void InstructionSelector::VisitWord32And(Node* node) {
502 VisitBinop(this, node, kIA32And);
503}
504
505
506void InstructionSelector::VisitWord32Or(Node* node) {
507 VisitBinop(this, node, kIA32Or);
508}
509
510
511void InstructionSelector::VisitWord32Xor(Node* node) {
512 IA32OperandGenerator g(this);
513 Int32BinopMatcher m(node);
514 if (m.right().Is(-1)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400515 Emit(kIA32Not, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000516 } else {
517 VisitBinop(this, node, kIA32Xor);
518 }
519}
520
521
522// Shared routine for multiple shift operations.
523static inline void VisitShift(InstructionSelector* selector, Node* node,
524 ArchOpcode opcode) {
525 IA32OperandGenerator g(selector);
526 Node* left = node->InputAt(0);
527 Node* right = node->InputAt(1);
528
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000529 if (g.CanBeImmediate(right)) {
530 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
531 g.UseImmediate(right));
532 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000533 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
534 g.UseFixed(right, ecx));
535 }
536}
537
538
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400539namespace {
540
541void VisitMulHigh(InstructionSelector* selector, Node* node,
542 ArchOpcode opcode) {
543 IA32OperandGenerator g(selector);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100544 InstructionOperand temps[] = {g.TempRegister(eax)};
545 selector->Emit(
546 opcode, g.DefineAsFixed(node, edx), g.UseFixed(node->InputAt(0), eax),
547 g.UseUniqueRegister(node->InputAt(1)), arraysize(temps), temps);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400548}
549
550
551void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
552 IA32OperandGenerator g(selector);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000553 InstructionOperand temps[] = {g.TempRegister(edx)};
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400554 selector->Emit(opcode, g.DefineAsFixed(node, eax),
555 g.UseFixed(node->InputAt(0), eax),
556 g.UseUnique(node->InputAt(1)), arraysize(temps), temps);
557}
558
559
560void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
561 IA32OperandGenerator g(selector);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100562 InstructionOperand temps[] = {g.TempRegister(eax)};
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400563 selector->Emit(opcode, g.DefineAsFixed(node, edx),
564 g.UseFixed(node->InputAt(0), eax),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100565 g.UseUnique(node->InputAt(1)), arraysize(temps), temps);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400566}
567
568void EmitLea(InstructionSelector* selector, Node* result, Node* index,
569 int scale, Node* base, Node* displacement) {
570 IA32OperandGenerator g(selector);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000571 InstructionOperand inputs[4];
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400572 size_t input_count = 0;
573 AddressingMode mode = g.GenerateMemoryOperandInputs(
574 index, scale, base, displacement, inputs, &input_count);
575
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000576 DCHECK_NE(0u, input_count);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400577 DCHECK_GE(arraysize(inputs), input_count);
578
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000579 InstructionOperand outputs[1];
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400580 outputs[0] = g.DefineAsRegister(result);
581
582 InstructionCode opcode = AddressingModeField::encode(mode) | kIA32Lea;
583
584 selector->Emit(opcode, 1, outputs, input_count, inputs);
585}
586
587} // namespace
588
589
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000590void InstructionSelector::VisitWord32Shl(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400591 Int32ScaleMatcher m(node, true);
592 if (m.matches()) {
593 Node* index = node->InputAt(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000594 Node* base = m.power_of_two_plus_one() ? index : nullptr;
595 EmitLea(this, node, index, m.scale(), base, nullptr);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400596 return;
597 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000598 VisitShift(this, node, kIA32Shl);
599}
600
601
602void InstructionSelector::VisitWord32Shr(Node* node) {
603 VisitShift(this, node, kIA32Shr);
604}
605
606
607void InstructionSelector::VisitWord32Sar(Node* node) {
608 VisitShift(this, node, kIA32Sar);
609}
610
Ben Murdochda12d292016-06-02 14:46:10 +0100611void InstructionSelector::VisitInt32PairAdd(Node* node) {
612 IA32OperandGenerator g(this);
613
614 // We use UseUniqueRegister here to avoid register sharing with the temp
615 // register.
616 InstructionOperand inputs[] = {
617 g.UseRegister(node->InputAt(0)), g.UseUniqueRegister(node->InputAt(1)),
618 g.UseRegister(node->InputAt(2)), g.UseUniqueRegister(node->InputAt(3))};
619
620 InstructionOperand outputs[] = {
621 g.DefineSameAsFirst(node),
622 g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
623
624 InstructionOperand temps[] = {g.TempRegister()};
625
626 Emit(kIA32AddPair, 2, outputs, 4, inputs, 1, temps);
627}
628
629void InstructionSelector::VisitInt32PairSub(Node* node) {
630 IA32OperandGenerator g(this);
631
632 // We use UseUniqueRegister here to avoid register sharing with the temp
633 // register.
634 InstructionOperand inputs[] = {
635 g.UseRegister(node->InputAt(0)), g.UseUniqueRegister(node->InputAt(1)),
636 g.UseRegister(node->InputAt(2)), g.UseUniqueRegister(node->InputAt(3))};
637
638 InstructionOperand outputs[] = {
639 g.DefineSameAsFirst(node),
640 g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
641
642 InstructionOperand temps[] = {g.TempRegister()};
643
644 Emit(kIA32SubPair, 2, outputs, 4, inputs, 1, temps);
645}
646
647void InstructionSelector::VisitInt32PairMul(Node* node) {
648 IA32OperandGenerator g(this);
649
650 // InputAt(3) explicitly shares ecx with OutputRegister(1) to save one
651 // register and one mov instruction.
652 InstructionOperand inputs[] = {
653 g.UseUnique(node->InputAt(0)), g.UseUnique(node->InputAt(1)),
654 g.UseUniqueRegister(node->InputAt(2)), g.UseFixed(node->InputAt(3), ecx)};
655
656 InstructionOperand outputs[] = {
657 g.DefineAsFixed(node, eax),
658 g.DefineAsFixed(NodeProperties::FindProjection(node, 1), ecx)};
659
660 InstructionOperand temps[] = {g.TempRegister(edx)};
661
662 Emit(kIA32MulPair, 2, outputs, 4, inputs, 1, temps);
663}
664
665void VisitWord32PairShift(InstructionSelector* selector, InstructionCode opcode,
666 Node* node) {
667 IA32OperandGenerator g(selector);
668
669 Node* shift = node->InputAt(2);
670 InstructionOperand shift_operand;
671 if (g.CanBeImmediate(shift)) {
672 shift_operand = g.UseImmediate(shift);
673 } else {
674 shift_operand = g.UseFixed(shift, ecx);
675 }
676 InstructionOperand inputs[] = {g.UseFixed(node->InputAt(0), eax),
677 g.UseFixed(node->InputAt(1), edx),
678 shift_operand};
679
680 InstructionOperand outputs[] = {
681 g.DefineAsFixed(node, eax),
682 g.DefineAsFixed(NodeProperties::FindProjection(node, 1), edx)};
683
684 selector->Emit(opcode, 2, outputs, 3, inputs);
685}
686
687void InstructionSelector::VisitWord32PairShl(Node* node) {
688 VisitWord32PairShift(this, kIA32ShlPair, node);
689}
690
691void InstructionSelector::VisitWord32PairShr(Node* node) {
692 VisitWord32PairShift(this, kIA32ShrPair, node);
693}
694
695void InstructionSelector::VisitWord32PairSar(Node* node) {
696 VisitWord32PairShift(this, kIA32SarPair, node);
697}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000698
699void InstructionSelector::VisitWord32Ror(Node* node) {
700 VisitShift(this, node, kIA32Ror);
701}
702
703
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000704void InstructionSelector::VisitWord32Clz(Node* node) {
705 IA32OperandGenerator g(this);
706 Emit(kIA32Lzcnt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
707}
708
709
710void InstructionSelector::VisitWord32Ctz(Node* node) {
711 IA32OperandGenerator g(this);
712 Emit(kIA32Tzcnt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
713}
714
715
Ben Murdoch097c5b22016-05-18 11:27:45 +0100716void InstructionSelector::VisitWord32ReverseBits(Node* node) { UNREACHABLE(); }
717
718
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000719void InstructionSelector::VisitWord32Popcnt(Node* node) {
720 IA32OperandGenerator g(this);
721 Emit(kIA32Popcnt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
722}
723
724
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000725void InstructionSelector::VisitInt32Add(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400726 IA32OperandGenerator g(this);
727
728 // Try to match the Add to a lea pattern
729 BaseWithIndexAndDisplacement32Matcher m(node);
730 if (m.matches() &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000731 (m.displacement() == nullptr || g.CanBeImmediate(m.displacement()))) {
732 InstructionOperand inputs[4];
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400733 size_t input_count = 0;
734 AddressingMode mode = g.GenerateMemoryOperandInputs(
735 m.index(), m.scale(), m.base(), m.displacement(), inputs, &input_count);
736
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000737 DCHECK_NE(0u, input_count);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400738 DCHECK_GE(arraysize(inputs), input_count);
739
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000740 InstructionOperand outputs[1];
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400741 outputs[0] = g.DefineAsRegister(node);
742
743 InstructionCode opcode = AddressingModeField::encode(mode) | kIA32Lea;
744 Emit(opcode, 1, outputs, input_count, inputs);
745 return;
746 }
747
748 // No lea pattern match, use add
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000749 VisitBinop(this, node, kIA32Add);
750}
751
752
753void InstructionSelector::VisitInt32Sub(Node* node) {
754 IA32OperandGenerator g(this);
755 Int32BinopMatcher m(node);
756 if (m.left().Is(0)) {
757 Emit(kIA32Neg, g.DefineSameAsFirst(node), g.Use(m.right().node()));
758 } else {
759 VisitBinop(this, node, kIA32Sub);
760 }
761}
762
763
764void InstructionSelector::VisitInt32Mul(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400765 Int32ScaleMatcher m(node, true);
766 if (m.matches()) {
767 Node* index = node->InputAt(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000768 Node* base = m.power_of_two_plus_one() ? index : nullptr;
769 EmitLea(this, node, index, m.scale(), base, nullptr);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400770 return;
771 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000772 IA32OperandGenerator g(this);
773 Node* left = node->InputAt(0);
774 Node* right = node->InputAt(1);
775 if (g.CanBeImmediate(right)) {
776 Emit(kIA32Imul, g.DefineAsRegister(node), g.Use(left),
777 g.UseImmediate(right));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000778 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400779 if (g.CanBeBetterLeftOperand(right)) {
780 std::swap(left, right);
781 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000782 Emit(kIA32Imul, g.DefineSameAsFirst(node), g.UseRegister(left),
783 g.Use(right));
784 }
785}
786
787
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400788void InstructionSelector::VisitInt32MulHigh(Node* node) {
789 VisitMulHigh(this, node, kIA32ImulHigh);
790}
791
792
793void InstructionSelector::VisitUint32MulHigh(Node* node) {
794 VisitMulHigh(this, node, kIA32UmulHigh);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000795}
796
797
798void InstructionSelector::VisitInt32Div(Node* node) {
799 VisitDiv(this, node, kIA32Idiv);
800}
801
802
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400803void InstructionSelector::VisitUint32Div(Node* node) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000804 VisitDiv(this, node, kIA32Udiv);
805}
806
807
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000808void InstructionSelector::VisitInt32Mod(Node* node) {
809 VisitMod(this, node, kIA32Idiv);
810}
811
812
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400813void InstructionSelector::VisitUint32Mod(Node* node) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000814 VisitMod(this, node, kIA32Udiv);
815}
816
817
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400818void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000819 VisitRO(this, node, kSSEFloat32ToFloat64);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400820}
821
822
Ben Murdoch097c5b22016-05-18 11:27:45 +0100823void InstructionSelector::VisitRoundInt32ToFloat32(Node* node) {
824 VisitRO(this, node, kSSEInt32ToFloat32);
825}
826
827
828void InstructionSelector::VisitRoundUint32ToFloat32(Node* node) {
829 IA32OperandGenerator g(this);
830 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
831 Emit(kSSEUint32ToFloat32, g.DefineAsRegister(node), g.Use(node->InputAt(0)),
832 arraysize(temps), temps);
833}
834
835
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000836void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000837 VisitRO(this, node, kSSEInt32ToFloat64);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000838}
839
840
841void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000842 VisitRO(this, node, kSSEUint32ToFloat64);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000843}
844
845
Ben Murdoch097c5b22016-05-18 11:27:45 +0100846void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) {
847 VisitRO(this, node, kSSEFloat32ToInt32);
848}
849
850
851void InstructionSelector::VisitTruncateFloat32ToUint32(Node* node) {
852 VisitRO(this, node, kSSEFloat32ToUint32);
853}
854
855
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000856void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000857 VisitRO(this, node, kSSEFloat64ToInt32);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000858}
859
860
861void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000862 VisitRO(this, node, kSSEFloat64ToUint32);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000863}
864
Ben Murdochda12d292016-06-02 14:46:10 +0100865void InstructionSelector::VisitTruncateFloat64ToUint32(Node* node) {
866 VisitRO(this, node, kSSEFloat64ToUint32);
867}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000868
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400869void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000870 VisitRO(this, node, kSSEFloat64ToFloat32);
871}
872
873
874void InstructionSelector::VisitTruncateFloat64ToInt32(Node* node) {
875 switch (TruncationModeOf(node->op())) {
876 case TruncationMode::kJavaScript:
877 return VisitRR(this, node, kArchTruncateDoubleToI);
878 case TruncationMode::kRoundToZero:
879 return VisitRO(this, node, kSSEFloat64ToInt32);
880 }
881 UNREACHABLE();
882}
883
884
885void InstructionSelector::VisitBitcastFloat32ToInt32(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400886 IA32OperandGenerator g(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000887 Emit(kIA32BitcastFI, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
888}
889
890
891void InstructionSelector::VisitBitcastInt32ToFloat32(Node* node) {
892 IA32OperandGenerator g(this);
893 Emit(kIA32BitcastIF, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
894}
895
896
897void InstructionSelector::VisitFloat32Add(Node* node) {
898 VisitRROFloat(this, node, kAVXFloat32Add, kSSEFloat32Add);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400899}
900
901
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000902void InstructionSelector::VisitFloat64Add(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000903 VisitRROFloat(this, node, kAVXFloat64Add, kSSEFloat64Add);
904}
905
906
907void InstructionSelector::VisitFloat32Sub(Node* node) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000908 IA32OperandGenerator g(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000909 Float32BinopMatcher m(node);
910 if (m.left().IsMinusZero()) {
911 VisitFloatUnop(this, node, m.right().node(), kAVXFloat32Neg,
912 kSSEFloat32Neg);
913 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400914 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000915 VisitRROFloat(this, node, kAVXFloat32Sub, kSSEFloat32Sub);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000916}
917
918
919void InstructionSelector::VisitFloat64Sub(Node* node) {
920 IA32OperandGenerator g(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000921 Float64BinopMatcher m(node);
922 if (m.left().IsMinusZero()) {
923 if (m.right().IsFloat64RoundDown() &&
924 CanCover(m.node(), m.right().node())) {
925 if (m.right().InputAt(0)->opcode() == IrOpcode::kFloat64Sub &&
926 CanCover(m.right().node(), m.right().InputAt(0))) {
927 Float64BinopMatcher mright0(m.right().InputAt(0));
928 if (mright0.left().IsMinusZero()) {
929 Emit(kSSEFloat64Round | MiscField::encode(kRoundUp),
930 g.DefineAsRegister(node), g.UseRegister(mright0.right().node()));
931 return;
932 }
933 }
934 }
935 VisitFloatUnop(this, node, m.right().node(), kAVXFloat64Neg,
936 kSSEFloat64Neg);
937 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400938 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000939 VisitRROFloat(this, node, kAVXFloat64Sub, kSSEFloat64Sub);
940}
941
942
943void InstructionSelector::VisitFloat32Mul(Node* node) {
944 VisitRROFloat(this, node, kAVXFloat32Mul, kSSEFloat32Mul);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000945}
946
947
948void InstructionSelector::VisitFloat64Mul(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000949 VisitRROFloat(this, node, kAVXFloat64Mul, kSSEFloat64Mul);
950}
951
952
953void InstructionSelector::VisitFloat32Div(Node* node) {
954 VisitRROFloat(this, node, kAVXFloat32Div, kSSEFloat32Div);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000955}
956
957
958void InstructionSelector::VisitFloat64Div(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000959 VisitRROFloat(this, node, kAVXFloat64Div, kSSEFloat64Div);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000960}
961
962
963void InstructionSelector::VisitFloat64Mod(Node* node) {
964 IA32OperandGenerator g(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000965 InstructionOperand temps[] = {g.TempRegister(eax)};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000966 Emit(kSSEFloat64Mod, g.DefineSameAsFirst(node),
967 g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)), 1,
968 temps);
969}
970
971
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000972void InstructionSelector::VisitFloat32Max(Node* node) {
973 VisitRROFloat(this, node, kAVXFloat32Max, kSSEFloat32Max);
974}
975
976
977void InstructionSelector::VisitFloat64Max(Node* node) {
978 VisitRROFloat(this, node, kAVXFloat64Max, kSSEFloat64Max);
979}
980
981
982void InstructionSelector::VisitFloat32Min(Node* node) {
983 VisitRROFloat(this, node, kAVXFloat32Min, kSSEFloat32Min);
984}
985
986
987void InstructionSelector::VisitFloat64Min(Node* node) {
988 VisitRROFloat(this, node, kAVXFloat64Min, kSSEFloat64Min);
989}
990
991
992void InstructionSelector::VisitFloat32Abs(Node* node) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000993 IA32OperandGenerator g(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000994 VisitFloatUnop(this, node, node->InputAt(0), kAVXFloat32Abs, kSSEFloat32Abs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000995}
996
997
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000998void InstructionSelector::VisitFloat64Abs(Node* node) {
999 IA32OperandGenerator g(this);
1000 VisitFloatUnop(this, node, node->InputAt(0), kAVXFloat64Abs, kSSEFloat64Abs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001001}
1002
1003
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001004void InstructionSelector::VisitFloat32Sqrt(Node* node) {
1005 VisitRO(this, node, kSSEFloat32Sqrt);
1006}
1007
1008
1009void InstructionSelector::VisitFloat64Sqrt(Node* node) {
1010 VisitRO(this, node, kSSEFloat64Sqrt);
1011}
1012
1013
1014void InstructionSelector::VisitFloat32RoundDown(Node* node) {
1015 VisitRR(this, node, kSSEFloat32Round | MiscField::encode(kRoundDown));
1016}
1017
1018
1019void InstructionSelector::VisitFloat64RoundDown(Node* node) {
1020 VisitRR(this, node, kSSEFloat64Round | MiscField::encode(kRoundDown));
1021}
1022
1023
1024void InstructionSelector::VisitFloat32RoundUp(Node* node) {
1025 VisitRR(this, node, kSSEFloat32Round | MiscField::encode(kRoundUp));
1026}
1027
1028
1029void InstructionSelector::VisitFloat64RoundUp(Node* node) {
1030 VisitRR(this, node, kSSEFloat64Round | MiscField::encode(kRoundUp));
1031}
1032
1033
1034void InstructionSelector::VisitFloat32RoundTruncate(Node* node) {
1035 VisitRR(this, node, kSSEFloat32Round | MiscField::encode(kRoundToZero));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001036}
1037
1038
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001039void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001040 VisitRR(this, node, kSSEFloat64Round | MiscField::encode(kRoundToZero));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001041}
1042
1043
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001044void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
1045 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001046}
1047
1048
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001049void InstructionSelector::VisitFloat32RoundTiesEven(Node* node) {
1050 VisitRR(this, node, kSSEFloat32Round | MiscField::encode(kRoundToNearest));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001051}
1052
1053
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001054void InstructionSelector::VisitFloat64RoundTiesEven(Node* node) {
1055 VisitRR(this, node, kSSEFloat64Round | MiscField::encode(kRoundToNearest));
1056}
1057
1058
1059void InstructionSelector::EmitPrepareArguments(
1060 ZoneVector<PushParameter>* arguments, const CallDescriptor* descriptor,
1061 Node* node) {
1062 IA32OperandGenerator g(this);
1063
1064 // Prepare for C function call.
1065 if (descriptor->IsCFunctionCall()) {
1066 InstructionOperand temps[] = {g.TempRegister()};
1067 size_t const temp_count = arraysize(temps);
1068 Emit(kArchPrepareCallCFunction |
1069 MiscField::encode(static_cast<int>(descriptor->CParameterCount())),
1070 0, nullptr, 0, nullptr, temp_count, temps);
1071
1072 // Poke any stack arguments.
1073 for (size_t n = 0; n < arguments->size(); ++n) {
1074 PushParameter input = (*arguments)[n];
1075 if (input.node()) {
1076 int const slot = static_cast<int>(n);
1077 InstructionOperand value = g.CanBeImmediate(node)
1078 ? g.UseImmediate(input.node())
1079 : g.UseRegister(input.node());
1080 Emit(kIA32Poke | MiscField::encode(slot), g.NoOutput(), value);
1081 }
1082 }
1083 } else {
1084 // Push any stack arguments.
1085 for (PushParameter input : base::Reversed(*arguments)) {
1086 // Skip any alignment holes in pushed nodes.
1087 if (input.node() == nullptr) continue;
1088 InstructionOperand value =
1089 g.CanBeImmediate(input.node())
1090 ? g.UseImmediate(input.node())
1091 : IsSupported(ATOM) ||
1092 sequence()->IsFloat(GetVirtualRegister(input.node()))
1093 ? g.UseRegister(input.node())
1094 : g.Use(input.node());
1095 if (input.type() == MachineType::Float32()) {
1096 Emit(kIA32PushFloat32, g.NoOutput(), value);
1097 } else if (input.type() == MachineType::Float64()) {
1098 Emit(kIA32PushFloat64, g.NoOutput(), value);
1099 } else {
1100 Emit(kIA32Push, g.NoOutput(), value);
1101 }
1102 }
1103 }
1104}
1105
1106
1107bool InstructionSelector::IsTailCallAddressImmediate() { return true; }
1108
Ben Murdochda12d292016-06-02 14:46:10 +01001109int InstructionSelector::GetTempsCountForTailCallFromJSFunction() { return 0; }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001110
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001111namespace {
1112
Ben Murdoch097c5b22016-05-18 11:27:45 +01001113void VisitCompareWithMemoryOperand(InstructionSelector* selector,
1114 InstructionCode opcode, Node* left,
1115 InstructionOperand right,
1116 FlagsContinuation* cont) {
1117 DCHECK(left->opcode() == IrOpcode::kLoad);
1118 IA32OperandGenerator g(selector);
1119 size_t input_count = 0;
1120 InstructionOperand inputs[6];
1121 AddressingMode addressing_mode =
1122 g.GetEffectiveAddressMemoryOperand(left, inputs, &input_count);
1123 opcode |= AddressingModeField::encode(addressing_mode);
1124 opcode = cont->Encode(opcode);
1125 inputs[input_count++] = right;
1126
1127 if (cont->IsBranch()) {
1128 inputs[input_count++] = g.Label(cont->true_block());
1129 inputs[input_count++] = g.Label(cont->false_block());
1130 selector->Emit(opcode, 0, nullptr, input_count, inputs);
Ben Murdochda12d292016-06-02 14:46:10 +01001131 } else if (cont->IsDeoptimize()) {
1132 selector->EmitDeoptimize(opcode, 0, nullptr, input_count, inputs,
1133 cont->frame_state());
Ben Murdoch097c5b22016-05-18 11:27:45 +01001134 } else {
1135 DCHECK(cont->IsSet());
1136 InstructionOperand output = g.DefineAsRegister(cont->result());
1137 selector->Emit(opcode, 1, &output, input_count, inputs);
1138 }
1139}
1140
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001141// Shared routine for multiple compare operations.
1142void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001143 InstructionOperand left, InstructionOperand right,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001144 FlagsContinuation* cont) {
1145 IA32OperandGenerator g(selector);
Ben Murdochda12d292016-06-02 14:46:10 +01001146 opcode = cont->Encode(opcode);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001147 if (cont->IsBranch()) {
Ben Murdochda12d292016-06-02 14:46:10 +01001148 selector->Emit(opcode, g.NoOutput(), left, right,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001149 g.Label(cont->true_block()), g.Label(cont->false_block()));
Ben Murdochda12d292016-06-02 14:46:10 +01001150 } else if (cont->IsDeoptimize()) {
1151 selector->EmitDeoptimize(opcode, g.NoOutput(), left, right,
1152 cont->frame_state());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001153 } else {
1154 DCHECK(cont->IsSet());
Ben Murdochda12d292016-06-02 14:46:10 +01001155 selector->Emit(opcode, g.DefineAsByteRegister(cont->result()), left, right);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001156 }
1157}
1158
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001159
1160// Shared routine for multiple compare operations.
1161void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
1162 Node* left, Node* right, FlagsContinuation* cont,
1163 bool commutative) {
1164 IA32OperandGenerator g(selector);
1165 if (commutative && g.CanBeBetterLeftOperand(right)) {
1166 std::swap(left, right);
1167 }
1168 VisitCompare(selector, opcode, g.UseRegister(left), g.Use(right), cont);
1169}
1170
Ben Murdochda12d292016-06-02 14:46:10 +01001171// Tries to match the size of the given opcode to that of the operands, if
1172// possible.
1173InstructionCode TryNarrowOpcodeSize(InstructionCode opcode, Node* left,
1174 Node* right) {
1175 if (opcode != kIA32Cmp && opcode != kIA32Test) {
1176 return opcode;
1177 }
1178 // Currently, if one of the two operands is not a Load, we don't know what its
1179 // machine representation is, so we bail out.
1180 // TODO(epertoso): we can probably get some size information out of immediates
1181 // and phi nodes.
1182 if (left->opcode() != IrOpcode::kLoad || right->opcode() != IrOpcode::kLoad) {
1183 return opcode;
1184 }
1185 // If the load representations don't match, both operands will be
1186 // zero/sign-extended to 32bit.
1187 LoadRepresentation left_representation = LoadRepresentationOf(left->op());
1188 if (left_representation != LoadRepresentationOf(right->op())) {
1189 return opcode;
1190 }
1191 switch (left_representation.representation()) {
1192 case MachineRepresentation::kBit:
1193 case MachineRepresentation::kWord8:
1194 return opcode == kIA32Cmp ? kIA32Cmp8 : kIA32Test8;
1195 case MachineRepresentation::kWord16:
1196 return opcode == kIA32Cmp ? kIA32Cmp16 : kIA32Test16;
1197 default:
1198 return opcode;
1199 }
1200}
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001201
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001202// Shared routine for multiple float32 compare operations (inputs commuted).
1203void VisitFloat32Compare(InstructionSelector* selector, Node* node,
1204 FlagsContinuation* cont) {
1205 Node* const left = node->InputAt(0);
1206 Node* const right = node->InputAt(1);
1207 VisitCompare(selector, kSSEFloat32Cmp, right, left, cont, false);
1208}
1209
1210
1211// Shared routine for multiple float64 compare operations (inputs commuted).
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001212void VisitFloat64Compare(InstructionSelector* selector, Node* node,
1213 FlagsContinuation* cont) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001214 Node* const left = node->InputAt(0);
1215 Node* const right = node->InputAt(1);
1216 VisitCompare(selector, kSSEFloat64Cmp, right, left, cont, false);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001217}
1218
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001219// Shared routine for multiple word compare operations.
1220void VisitWordCompare(InstructionSelector* selector, Node* node,
1221 InstructionCode opcode, FlagsContinuation* cont) {
1222 IA32OperandGenerator g(selector);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001223 Node* left = node->InputAt(0);
1224 Node* right = node->InputAt(1);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001225
Ben Murdochda12d292016-06-02 14:46:10 +01001226 InstructionCode narrowed_opcode = TryNarrowOpcodeSize(opcode, left, right);
1227
1228 // If one of the two inputs is an immediate, make sure it's on the right, or
1229 // if one of the two inputs is a memory operand, make sure it's on the left.
1230 if ((!g.CanBeImmediate(right) && g.CanBeImmediate(left)) ||
1231 (g.CanBeMemoryOperand(narrowed_opcode, node, right) &&
1232 !g.CanBeMemoryOperand(narrowed_opcode, node, left))) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001233 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001234 std::swap(left, right);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001235 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001236
Ben Murdoch097c5b22016-05-18 11:27:45 +01001237 // Match immediates on right side of comparison.
1238 if (g.CanBeImmediate(right)) {
Ben Murdochda12d292016-06-02 14:46:10 +01001239 if (g.CanBeMemoryOperand(opcode, node, left)) {
1240 // TODO(epertoso): we should use `narrowed_opcode' here once we match
1241 // immediates too.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001242 return VisitCompareWithMemoryOperand(selector, opcode, left,
1243 g.UseImmediate(right), cont);
1244 }
1245 return VisitCompare(selector, opcode, g.Use(left), g.UseImmediate(right),
1246 cont);
1247 }
1248
Ben Murdochda12d292016-06-02 14:46:10 +01001249 // Match memory operands on left side of comparison.
1250 if (g.CanBeMemoryOperand(narrowed_opcode, node, left)) {
1251 bool needs_byte_register =
1252 narrowed_opcode == kIA32Test8 || narrowed_opcode == kIA32Cmp8;
1253 return VisitCompareWithMemoryOperand(
1254 selector, narrowed_opcode, left,
1255 needs_byte_register ? g.UseByteRegister(right) : g.UseRegister(right),
1256 cont);
1257 }
1258
Ben Murdoch097c5b22016-05-18 11:27:45 +01001259 if (g.CanBeBetterLeftOperand(right)) {
1260 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
1261 std::swap(left, right);
1262 }
1263
Ben Murdoch097c5b22016-05-18 11:27:45 +01001264 return VisitCompare(selector, opcode, left, right, cont,
1265 node->op()->HasProperty(Operator::kCommutative));
1266}
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001267
1268void VisitWordCompare(InstructionSelector* selector, Node* node,
1269 FlagsContinuation* cont) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001270 IA32OperandGenerator g(selector);
1271 Int32BinopMatcher m(node);
1272 if (m.left().IsLoad() && m.right().IsLoadStackPointer()) {
1273 LoadMatcher<ExternalReferenceMatcher> mleft(m.left().node());
1274 ExternalReference js_stack_limit =
1275 ExternalReference::address_of_stack_limit(selector->isolate());
1276 if (mleft.object().Is(js_stack_limit) && mleft.index().Is(0)) {
1277 // Compare(Load(js_stack_limit), LoadStackPointer)
1278 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
1279 InstructionCode opcode = cont->Encode(kIA32StackCheck);
1280 if (cont->IsBranch()) {
1281 selector->Emit(opcode, g.NoOutput(), g.Label(cont->true_block()),
1282 g.Label(cont->false_block()));
Ben Murdochda12d292016-06-02 14:46:10 +01001283 } else if (cont->IsDeoptimize()) {
1284 selector->EmitDeoptimize(opcode, 0, nullptr, 0, nullptr,
1285 cont->frame_state());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001286 } else {
1287 DCHECK(cont->IsSet());
1288 selector->Emit(opcode, g.DefineAsRegister(cont->result()));
1289 }
1290 return;
1291 }
1292 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001293 VisitWordCompare(selector, node, kIA32Cmp, cont);
1294}
1295
1296
1297// Shared routine for word comparison with zero.
1298void VisitWordCompareZero(InstructionSelector* selector, Node* user,
1299 Node* value, FlagsContinuation* cont) {
1300 // Try to combine the branch with a comparison.
1301 while (selector->CanCover(user, value)) {
1302 switch (value->opcode()) {
1303 case IrOpcode::kWord32Equal: {
1304 // Try to combine with comparisons against 0 by simply inverting the
1305 // continuation.
1306 Int32BinopMatcher m(value);
1307 if (m.right().Is(0)) {
1308 user = value;
1309 value = m.left().node();
1310 cont->Negate();
1311 continue;
1312 }
1313 cont->OverwriteAndNegateIfEqual(kEqual);
1314 return VisitWordCompare(selector, value, cont);
1315 }
1316 case IrOpcode::kInt32LessThan:
1317 cont->OverwriteAndNegateIfEqual(kSignedLessThan);
1318 return VisitWordCompare(selector, value, cont);
1319 case IrOpcode::kInt32LessThanOrEqual:
1320 cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
1321 return VisitWordCompare(selector, value, cont);
1322 case IrOpcode::kUint32LessThan:
1323 cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
1324 return VisitWordCompare(selector, value, cont);
1325 case IrOpcode::kUint32LessThanOrEqual:
1326 cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
1327 return VisitWordCompare(selector, value, cont);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001328 case IrOpcode::kFloat32Equal:
1329 cont->OverwriteAndNegateIfEqual(kUnorderedEqual);
1330 return VisitFloat32Compare(selector, value, cont);
1331 case IrOpcode::kFloat32LessThan:
1332 cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThan);
1333 return VisitFloat32Compare(selector, value, cont);
1334 case IrOpcode::kFloat32LessThanOrEqual:
1335 cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThanOrEqual);
1336 return VisitFloat32Compare(selector, value, cont);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001337 case IrOpcode::kFloat64Equal:
1338 cont->OverwriteAndNegateIfEqual(kUnorderedEqual);
1339 return VisitFloat64Compare(selector, value, cont);
1340 case IrOpcode::kFloat64LessThan:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001341 cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThan);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001342 return VisitFloat64Compare(selector, value, cont);
1343 case IrOpcode::kFloat64LessThanOrEqual:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001344 cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThanOrEqual);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001345 return VisitFloat64Compare(selector, value, cont);
1346 case IrOpcode::kProjection:
1347 // Check if this is the overflow output projection of an
1348 // <Operation>WithOverflow node.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001349 if (ProjectionIndexOf(value->op()) == 1u) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001350 // We cannot combine the <Operation>WithOverflow with this branch
1351 // unless the 0th projection (the use of the actual value of the
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001352 // <Operation> is either nullptr, which means there's no use of the
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001353 // actual value, or was already defined, which means it is scheduled
1354 // *AFTER* this branch).
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001355 Node* const node = value->InputAt(0);
1356 Node* const result = NodeProperties::FindProjection(node, 0);
1357 if (result == nullptr || selector->IsDefined(result)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001358 switch (node->opcode()) {
1359 case IrOpcode::kInt32AddWithOverflow:
1360 cont->OverwriteAndNegateIfEqual(kOverflow);
1361 return VisitBinop(selector, node, kIA32Add, cont);
1362 case IrOpcode::kInt32SubWithOverflow:
1363 cont->OverwriteAndNegateIfEqual(kOverflow);
1364 return VisitBinop(selector, node, kIA32Sub, cont);
1365 default:
1366 break;
1367 }
1368 }
1369 }
1370 break;
1371 case IrOpcode::kInt32Sub:
1372 return VisitWordCompare(selector, value, cont);
1373 case IrOpcode::kWord32And:
1374 return VisitWordCompare(selector, value, kIA32Test, cont);
1375 default:
1376 break;
1377 }
1378 break;
1379 }
1380
1381 // Continuation could not be combined with a compare, emit compare against 0.
1382 IA32OperandGenerator g(selector);
1383 VisitCompare(selector, kIA32Cmp, g.Use(value), g.TempImmediate(0), cont);
1384}
1385
1386} // namespace
1387
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001388void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
1389 BasicBlock* fbranch) {
1390 FlagsContinuation cont(kNotEqual, tbranch, fbranch);
1391 VisitWordCompareZero(this, branch, branch->InputAt(0), &cont);
1392}
1393
Ben Murdochda12d292016-06-02 14:46:10 +01001394void InstructionSelector::VisitDeoptimizeIf(Node* node) {
1395 FlagsContinuation cont =
1396 FlagsContinuation::ForDeoptimize(kNotEqual, node->InputAt(1));
1397 VisitWordCompareZero(this, node, node->InputAt(0), &cont);
1398}
1399
1400void InstructionSelector::VisitDeoptimizeUnless(Node* node) {
1401 FlagsContinuation cont =
1402 FlagsContinuation::ForDeoptimize(kEqual, node->InputAt(1));
1403 VisitWordCompareZero(this, node, node->InputAt(0), &cont);
1404}
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001405
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001406void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
1407 IA32OperandGenerator g(this);
1408 InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
1409
1410 // Emit either ArchTableSwitch or ArchLookupSwitch.
1411 size_t table_space_cost = 4 + sw.value_range;
1412 size_t table_time_cost = 3;
1413 size_t lookup_space_cost = 3 + 2 * sw.case_count;
1414 size_t lookup_time_cost = sw.case_count;
1415 if (sw.case_count > 4 &&
1416 table_space_cost + 3 * table_time_cost <=
1417 lookup_space_cost + 3 * lookup_time_cost &&
1418 sw.min_value > std::numeric_limits<int32_t>::min()) {
1419 InstructionOperand index_operand = value_operand;
1420 if (sw.min_value) {
1421 index_operand = g.TempRegister();
1422 Emit(kIA32Lea | AddressingModeField::encode(kMode_MRI), index_operand,
1423 value_operand, g.TempImmediate(-sw.min_value));
1424 }
1425 // Generate a table lookup.
1426 return EmitTableSwitch(sw, index_operand);
1427 }
1428
1429 // Generate a sequence of conditional jumps.
1430 return EmitLookupSwitch(sw, value_operand);
1431}
1432
1433
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001434void InstructionSelector::VisitWord32Equal(Node* const node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001435 FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001436 Int32BinopMatcher m(node);
1437 if (m.right().Is(0)) {
1438 return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
1439 }
1440 VisitWordCompare(this, node, &cont);
1441}
1442
1443
1444void InstructionSelector::VisitInt32LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001445 FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001446 VisitWordCompare(this, node, &cont);
1447}
1448
1449
1450void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001451 FlagsContinuation cont =
1452 FlagsContinuation::ForSet(kSignedLessThanOrEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001453 VisitWordCompare(this, node, &cont);
1454}
1455
1456
1457void InstructionSelector::VisitUint32LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001458 FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001459 VisitWordCompare(this, node, &cont);
1460}
1461
1462
1463void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001464 FlagsContinuation cont =
1465 FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001466 VisitWordCompare(this, node, &cont);
1467}
1468
1469
1470void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001471 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
Ben Murdochda12d292016-06-02 14:46:10 +01001472 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001473 return VisitBinop(this, node, kIA32Add, &cont);
1474 }
1475 FlagsContinuation cont;
1476 VisitBinop(this, node, kIA32Add, &cont);
1477}
1478
1479
1480void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001481 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
Ben Murdochda12d292016-06-02 14:46:10 +01001482 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001483 return VisitBinop(this, node, kIA32Sub, &cont);
1484 }
1485 FlagsContinuation cont;
1486 VisitBinop(this, node, kIA32Sub, &cont);
1487}
1488
1489
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001490void InstructionSelector::VisitFloat32Equal(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001491 FlagsContinuation cont = FlagsContinuation::ForSet(kUnorderedEqual, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001492 VisitFloat32Compare(this, node, &cont);
1493}
1494
1495
1496void InstructionSelector::VisitFloat32LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001497 FlagsContinuation cont =
1498 FlagsContinuation::ForSet(kUnsignedGreaterThan, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001499 VisitFloat32Compare(this, node, &cont);
1500}
1501
1502
1503void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001504 FlagsContinuation cont =
1505 FlagsContinuation::ForSet(kUnsignedGreaterThanOrEqual, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001506 VisitFloat32Compare(this, node, &cont);
1507}
1508
1509
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001510void InstructionSelector::VisitFloat64Equal(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001511 FlagsContinuation cont = FlagsContinuation::ForSet(kUnorderedEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001512 VisitFloat64Compare(this, node, &cont);
1513}
1514
1515
1516void InstructionSelector::VisitFloat64LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001517 FlagsContinuation cont =
1518 FlagsContinuation::ForSet(kUnsignedGreaterThan, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001519 VisitFloat64Compare(this, node, &cont);
1520}
1521
1522
1523void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001524 FlagsContinuation cont =
1525 FlagsContinuation::ForSet(kUnsignedGreaterThanOrEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001526 VisitFloat64Compare(this, node, &cont);
1527}
1528
1529
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001530void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) {
1531 IA32OperandGenerator g(this);
1532 Emit(kSSEFloat64ExtractLowWord32, g.DefineAsRegister(node),
1533 g.Use(node->InputAt(0)));
1534}
1535
1536
1537void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) {
1538 IA32OperandGenerator g(this);
1539 Emit(kSSEFloat64ExtractHighWord32, g.DefineAsRegister(node),
1540 g.Use(node->InputAt(0)));
1541}
1542
1543
1544void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) {
1545 IA32OperandGenerator g(this);
1546 Node* left = node->InputAt(0);
1547 Node* right = node->InputAt(1);
1548 Float64Matcher mleft(left);
1549 if (mleft.HasValue() && (bit_cast<uint64_t>(mleft.Value()) >> 32) == 0u) {
1550 Emit(kSSEFloat64LoadLowWord32, g.DefineAsRegister(node), g.Use(right));
1551 return;
1552 }
1553 Emit(kSSEFloat64InsertLowWord32, g.DefineSameAsFirst(node),
1554 g.UseRegister(left), g.Use(right));
1555}
1556
1557
1558void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
1559 IA32OperandGenerator g(this);
1560 Node* left = node->InputAt(0);
1561 Node* right = node->InputAt(1);
1562 Emit(kSSEFloat64InsertHighWord32, g.DefineSameAsFirst(node),
1563 g.UseRegister(left), g.Use(right));
1564}
1565
1566
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001567// static
1568MachineOperatorBuilder::Flags
1569InstructionSelector::SupportedMachineOperatorFlags() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001570 MachineOperatorBuilder::Flags flags =
1571 MachineOperatorBuilder::kFloat32Max |
1572 MachineOperatorBuilder::kFloat32Min |
1573 MachineOperatorBuilder::kFloat64Max |
1574 MachineOperatorBuilder::kFloat64Min |
1575 MachineOperatorBuilder::kWord32ShiftIsSafe |
1576 MachineOperatorBuilder::kWord32Ctz;
1577 if (CpuFeatures::IsSupported(POPCNT)) {
1578 flags |= MachineOperatorBuilder::kWord32Popcnt;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001579 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001580 if (CpuFeatures::IsSupported(SSE4_1)) {
1581 flags |= MachineOperatorBuilder::kFloat32RoundDown |
1582 MachineOperatorBuilder::kFloat64RoundDown |
1583 MachineOperatorBuilder::kFloat32RoundUp |
1584 MachineOperatorBuilder::kFloat64RoundUp |
1585 MachineOperatorBuilder::kFloat32RoundTruncate |
1586 MachineOperatorBuilder::kFloat64RoundTruncate |
1587 MachineOperatorBuilder::kFloat32RoundTiesEven |
1588 MachineOperatorBuilder::kFloat64RoundTiesEven;
1589 }
1590 return flags;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001591}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001592
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001593} // namespace compiler
1594} // namespace internal
1595} // namespace v8