blob: 3ffdd30040ac1aaf77f0a79ddbb6cec161d1c5d9 [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 Murdochc5610432016-08-08 18:44:38 +010030 bool CanBeMemoryOperand(InstructionCode opcode, Node* node, Node* input,
31 int effect_level) {
Ben Murdochda12d292016-06-02 14:46:10 +010032 if (input->opcode() != IrOpcode::kLoad ||
33 !selector()->CanCover(node, input)) {
34 return false;
35 }
Ben Murdochc5610432016-08-08 18:44:38 +010036 if (effect_level != selector()->GetEffectLevel(input)) {
37 return false;
38 }
Ben Murdochda12d292016-06-02 14:46:10 +010039 MachineRepresentation rep =
40 LoadRepresentationOf(input->op()).representation();
41 switch (opcode) {
42 case kIA32Cmp:
43 case kIA32Test:
44 return rep == MachineRepresentation::kWord32 ||
45 rep == MachineRepresentation::kTagged;
46 case kIA32Cmp16:
47 case kIA32Test16:
48 return rep == MachineRepresentation::kWord16;
49 case kIA32Cmp8:
50 case kIA32Test8:
51 return rep == MachineRepresentation::kWord8;
52 default:
53 break;
54 }
55 return false;
56 }
57
Ben Murdochb8a8cc12014-11-26 15:28:44 +000058 bool CanBeImmediate(Node* node) {
59 switch (node->opcode()) {
60 case IrOpcode::kInt32Constant:
61 case IrOpcode::kNumberConstant:
62 case IrOpcode::kExternalConstant:
Ben Murdochc5610432016-08-08 18:44:38 +010063 case IrOpcode::kRelocatableInt32Constant:
64 case IrOpcode::kRelocatableInt64Constant:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000065 return true;
66 case IrOpcode::kHeapConstant: {
Ben Murdochc5610432016-08-08 18:44:38 +010067// TODO(bmeurer): We must not dereference handles concurrently. If we
68// really have to this here, then we need to find a way to put this
69// information on the HeapConstant node already.
70#if 0
Ben Murdochb8a8cc12014-11-26 15:28:44 +000071 // Constants in new space cannot be used as immediates in V8 because
72 // the GC does not scan code objects when collecting the new generation.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000073 Handle<HeapObject> value = OpParameter<Handle<HeapObject>>(node);
74 Isolate* isolate = value->GetIsolate();
75 return !isolate->heap()->InNewSpace(*value);
Ben Murdochc5610432016-08-08 18:44:38 +010076#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +000077 }
78 default:
79 return false;
80 }
81 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040082
83 AddressingMode GenerateMemoryOperandInputs(Node* index, int scale, Node* base,
84 Node* displacement_node,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000085 InstructionOperand inputs[],
Emily Bernierd0a1eb72015-03-24 16:35:39 -040086 size_t* input_count) {
87 AddressingMode mode = kMode_MRI;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000088 int32_t displacement = (displacement_node == nullptr)
Emily Bernierd0a1eb72015-03-24 16:35:39 -040089 ? 0
90 : OpParameter<int32_t>(displacement_node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000091 if (base != nullptr) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040092 if (base->opcode() == IrOpcode::kInt32Constant) {
93 displacement += OpParameter<int32_t>(base);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000094 base = nullptr;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040095 }
96 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000097 if (base != nullptr) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040098 inputs[(*input_count)++] = UseRegister(base);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000099 if (index != nullptr) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400100 DCHECK(scale >= 0 && scale <= 3);
101 inputs[(*input_count)++] = UseRegister(index);
102 if (displacement != 0) {
103 inputs[(*input_count)++] = TempImmediate(displacement);
104 static const AddressingMode kMRnI_modes[] = {kMode_MR1I, kMode_MR2I,
105 kMode_MR4I, kMode_MR8I};
106 mode = kMRnI_modes[scale];
107 } else {
108 static const AddressingMode kMRn_modes[] = {kMode_MR1, kMode_MR2,
109 kMode_MR4, kMode_MR8};
110 mode = kMRn_modes[scale];
111 }
112 } else {
113 if (displacement == 0) {
114 mode = kMode_MR;
115 } else {
116 inputs[(*input_count)++] = TempImmediate(displacement);
117 mode = kMode_MRI;
118 }
119 }
120 } else {
121 DCHECK(scale >= 0 && scale <= 3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000122 if (index != nullptr) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400123 inputs[(*input_count)++] = UseRegister(index);
124 if (displacement != 0) {
125 inputs[(*input_count)++] = TempImmediate(displacement);
126 static const AddressingMode kMnI_modes[] = {kMode_MRI, kMode_M2I,
127 kMode_M4I, kMode_M8I};
128 mode = kMnI_modes[scale];
129 } else {
130 static const AddressingMode kMn_modes[] = {kMode_MR, kMode_M2,
131 kMode_M4, kMode_M8};
132 mode = kMn_modes[scale];
133 }
134 } else {
135 inputs[(*input_count)++] = TempImmediate(displacement);
136 return kMode_MI;
137 }
138 }
139 return mode;
140 }
141
142 AddressingMode GetEffectiveAddressMemoryOperand(Node* node,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000143 InstructionOperand inputs[],
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400144 size_t* input_count) {
145 BaseWithIndexAndDisplacement32Matcher m(node, true);
146 DCHECK(m.matches());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000147 if ((m.displacement() == nullptr || CanBeImmediate(m.displacement()))) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400148 return GenerateMemoryOperandInputs(m.index(), m.scale(), m.base(),
149 m.displacement(), inputs, input_count);
150 } else {
151 inputs[(*input_count)++] = UseRegister(node->InputAt(0));
152 inputs[(*input_count)++] = UseRegister(node->InputAt(1));
153 return kMode_MR1;
154 }
155 }
156
157 bool CanBeBetterLeftOperand(Node* node) const {
158 return !selector()->IsLive(node);
159 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000160};
161
162
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000163namespace {
164
165void VisitRO(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
166 IA32OperandGenerator g(selector);
167 selector->Emit(opcode, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
168}
169
170
171void VisitRR(InstructionSelector* selector, Node* node,
172 InstructionCode opcode) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400173 IA32OperandGenerator g(selector);
174 selector->Emit(opcode, g.DefineAsRegister(node),
175 g.UseRegister(node->InputAt(0)));
176}
177
178
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000179void VisitRROFloat(InstructionSelector* selector, Node* node,
180 ArchOpcode avx_opcode, ArchOpcode sse_opcode) {
181 IA32OperandGenerator g(selector);
182 InstructionOperand operand0 = g.UseRegister(node->InputAt(0));
183 InstructionOperand operand1 = g.Use(node->InputAt(1));
184 if (selector->IsSupported(AVX)) {
185 selector->Emit(avx_opcode, g.DefineAsRegister(node), operand0, operand1);
186 } else {
187 selector->Emit(sse_opcode, g.DefineSameAsFirst(node), operand0, operand1);
188 }
189}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000190
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000191
192void VisitFloatUnop(InstructionSelector* selector, Node* node, Node* input,
193 ArchOpcode avx_opcode, ArchOpcode sse_opcode) {
194 IA32OperandGenerator g(selector);
195 if (selector->IsSupported(AVX)) {
196 selector->Emit(avx_opcode, g.DefineAsRegister(node), g.Use(input));
197 } else {
198 selector->Emit(sse_opcode, g.DefineSameAsFirst(node), g.UseRegister(input));
199 }
200}
201
202
203} // namespace
204
205
206void InstructionSelector::VisitLoad(Node* node) {
207 LoadRepresentation load_rep = LoadRepresentationOf(node->op());
208
209 ArchOpcode opcode = kArchNop;
210 switch (load_rep.representation()) {
211 case MachineRepresentation::kFloat32:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000212 opcode = kIA32Movss;
213 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000214 case MachineRepresentation::kFloat64:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000215 opcode = kIA32Movsd;
216 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000217 case MachineRepresentation::kBit: // Fall through.
218 case MachineRepresentation::kWord8:
219 opcode = load_rep.IsSigned() ? kIA32Movsxbl : kIA32Movzxbl;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000220 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000221 case MachineRepresentation::kWord16:
222 opcode = load_rep.IsSigned() ? kIA32Movsxwl : kIA32Movzxwl;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000223 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000224 case MachineRepresentation::kTagged: // Fall through.
225 case MachineRepresentation::kWord32:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000226 opcode = kIA32Movl;
227 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100228 case MachineRepresentation::kWord64: // Fall through.
229 case MachineRepresentation::kSimd128: // Fall through.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000230 case MachineRepresentation::kNone:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000231 UNREACHABLE();
232 return;
233 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400234
235 IA32OperandGenerator g(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000236 InstructionOperand outputs[1];
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400237 outputs[0] = g.DefineAsRegister(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000238 InstructionOperand inputs[3];
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400239 size_t input_count = 0;
240 AddressingMode mode =
241 g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count);
242 InstructionCode code = opcode | AddressingModeField::encode(mode);
243 Emit(code, 1, outputs, input_count, inputs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000244}
245
246
247void InstructionSelector::VisitStore(Node* node) {
248 IA32OperandGenerator g(this);
249 Node* base = node->InputAt(0);
250 Node* index = node->InputAt(1);
251 Node* value = node->InputAt(2);
252
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000253 StoreRepresentation store_rep = StoreRepresentationOf(node->op());
254 WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind();
255 MachineRepresentation rep = store_rep.representation();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400256
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000257 if (write_barrier_kind != kNoWriteBarrier) {
258 DCHECK_EQ(MachineRepresentation::kTagged, rep);
259 AddressingMode addressing_mode;
260 InstructionOperand inputs[3];
261 size_t input_count = 0;
262 inputs[input_count++] = g.UseUniqueRegister(base);
263 if (g.CanBeImmediate(index)) {
264 inputs[input_count++] = g.UseImmediate(index);
265 addressing_mode = kMode_MRI;
266 } else {
267 inputs[input_count++] = g.UseUniqueRegister(index);
268 addressing_mode = kMode_MR1;
269 }
Ben Murdochda12d292016-06-02 14:46:10 +0100270 inputs[input_count++] = g.UseUniqueRegister(value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000271 RecordWriteMode record_write_mode = RecordWriteMode::kValueIsAny;
272 switch (write_barrier_kind) {
273 case kNoWriteBarrier:
274 UNREACHABLE();
275 break;
276 case kMapWriteBarrier:
277 record_write_mode = RecordWriteMode::kValueIsMap;
278 break;
279 case kPointerWriteBarrier:
280 record_write_mode = RecordWriteMode::kValueIsPointer;
281 break;
282 case kFullWriteBarrier:
283 record_write_mode = RecordWriteMode::kValueIsAny;
284 break;
285 }
286 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
287 size_t const temp_count = arraysize(temps);
288 InstructionCode code = kArchStoreWithWriteBarrier;
289 code |= AddressingModeField::encode(addressing_mode);
290 code |= MiscField::encode(static_cast<int>(record_write_mode));
291 Emit(code, 0, nullptr, input_count, inputs, temp_count, temps);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400292 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000293 ArchOpcode opcode = kArchNop;
294 switch (rep) {
295 case MachineRepresentation::kFloat32:
296 opcode = kIA32Movss;
297 break;
298 case MachineRepresentation::kFloat64:
299 opcode = kIA32Movsd;
300 break;
301 case MachineRepresentation::kBit: // Fall through.
302 case MachineRepresentation::kWord8:
303 opcode = kIA32Movb;
304 break;
305 case MachineRepresentation::kWord16:
306 opcode = kIA32Movw;
307 break;
308 case MachineRepresentation::kTagged: // Fall through.
309 case MachineRepresentation::kWord32:
310 opcode = kIA32Movl;
311 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100312 case MachineRepresentation::kWord64: // Fall through.
313 case MachineRepresentation::kSimd128: // Fall through.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000314 case MachineRepresentation::kNone:
315 UNREACHABLE();
316 return;
317 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400318
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000319 InstructionOperand val;
320 if (g.CanBeImmediate(value)) {
321 val = g.UseImmediate(value);
322 } else if (rep == MachineRepresentation::kWord8 ||
323 rep == MachineRepresentation::kBit) {
324 val = g.UseByteRegister(value);
325 } else {
326 val = g.UseRegister(value);
327 }
328
329 InstructionOperand inputs[4];
330 size_t input_count = 0;
331 AddressingMode addressing_mode =
332 g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count);
333 InstructionCode code =
334 opcode | AddressingModeField::encode(addressing_mode);
335 inputs[input_count++] = val;
336 Emit(code, 0, static_cast<InstructionOperand*>(nullptr), input_count,
337 inputs);
338 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400339}
340
341
342void InstructionSelector::VisitCheckedLoad(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000343 CheckedLoadRepresentation load_rep = CheckedLoadRepresentationOf(node->op());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400344 IA32OperandGenerator g(this);
345 Node* const buffer = node->InputAt(0);
346 Node* const offset = node->InputAt(1);
347 Node* const length = node->InputAt(2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000348 ArchOpcode opcode = kArchNop;
349 switch (load_rep.representation()) {
350 case MachineRepresentation::kWord8:
351 opcode = load_rep.IsSigned() ? kCheckedLoadInt8 : kCheckedLoadUint8;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400352 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000353 case MachineRepresentation::kWord16:
354 opcode = load_rep.IsSigned() ? kCheckedLoadInt16 : kCheckedLoadUint16;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400355 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000356 case MachineRepresentation::kWord32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400357 opcode = kCheckedLoadWord32;
358 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000359 case MachineRepresentation::kFloat32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400360 opcode = kCheckedLoadFloat32;
361 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000362 case MachineRepresentation::kFloat64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400363 opcode = kCheckedLoadFloat64;
364 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100365 case MachineRepresentation::kBit: // Fall through.
366 case MachineRepresentation::kTagged: // Fall through.
367 case MachineRepresentation::kWord64: // Fall through.
368 case MachineRepresentation::kSimd128: // Fall through.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000369 case MachineRepresentation::kNone:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400370 UNREACHABLE();
371 return;
372 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000373 InstructionOperand offset_operand = g.UseRegister(offset);
374 InstructionOperand length_operand =
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400375 g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length);
376 if (g.CanBeImmediate(buffer)) {
377 Emit(opcode | AddressingModeField::encode(kMode_MRI),
378 g.DefineAsRegister(node), offset_operand, length_operand,
379 offset_operand, g.UseImmediate(buffer));
380 } else {
381 Emit(opcode | AddressingModeField::encode(kMode_MR1),
382 g.DefineAsRegister(node), offset_operand, length_operand,
383 g.UseRegister(buffer), offset_operand);
384 }
385}
386
387
388void InstructionSelector::VisitCheckedStore(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000389 MachineRepresentation rep = CheckedStoreRepresentationOf(node->op());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400390 IA32OperandGenerator g(this);
391 Node* const buffer = node->InputAt(0);
392 Node* const offset = node->InputAt(1);
393 Node* const length = node->InputAt(2);
394 Node* const value = node->InputAt(3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000395 ArchOpcode opcode = kArchNop;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400396 switch (rep) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000397 case MachineRepresentation::kWord8:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400398 opcode = kCheckedStoreWord8;
399 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000400 case MachineRepresentation::kWord16:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400401 opcode = kCheckedStoreWord16;
402 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000403 case MachineRepresentation::kWord32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400404 opcode = kCheckedStoreWord32;
405 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000406 case MachineRepresentation::kFloat32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400407 opcode = kCheckedStoreFloat32;
408 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000409 case MachineRepresentation::kFloat64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400410 opcode = kCheckedStoreFloat64;
411 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100412 case MachineRepresentation::kBit: // Fall through.
413 case MachineRepresentation::kTagged: // Fall through.
414 case MachineRepresentation::kWord64: // Fall through.
415 case MachineRepresentation::kSimd128: // Fall through.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000416 case MachineRepresentation::kNone:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400417 UNREACHABLE();
418 return;
419 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000420 InstructionOperand value_operand =
421 g.CanBeImmediate(value) ? g.UseImmediate(value)
422 : ((rep == MachineRepresentation::kWord8 ||
423 rep == MachineRepresentation::kBit)
424 ? g.UseByteRegister(value)
425 : g.UseRegister(value));
426 InstructionOperand offset_operand = g.UseRegister(offset);
427 InstructionOperand length_operand =
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400428 g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length);
429 if (g.CanBeImmediate(buffer)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000430 Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400431 offset_operand, length_operand, value_operand, offset_operand,
432 g.UseImmediate(buffer));
433 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000434 Emit(opcode | AddressingModeField::encode(kMode_MR1), g.NoOutput(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400435 offset_operand, length_operand, value_operand, g.UseRegister(buffer),
436 offset_operand);
437 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000438}
439
Ben Murdochda12d292016-06-02 14:46:10 +0100440namespace {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000441
442// Shared routine for multiple binary operations.
Ben Murdochda12d292016-06-02 14:46:10 +0100443void VisitBinop(InstructionSelector* selector, Node* node,
444 InstructionCode opcode, FlagsContinuation* cont) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000445 IA32OperandGenerator g(selector);
446 Int32BinopMatcher m(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400447 Node* left = m.left().node();
448 Node* right = m.right().node();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000449 InstructionOperand inputs[4];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000450 size_t input_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000451 InstructionOperand outputs[2];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000452 size_t output_count = 0;
453
454 // TODO(turbofan): match complex addressing modes.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400455 if (left == right) {
456 // If both inputs refer to the same operand, enforce allocating a register
457 // for both of them to ensure that we don't end up generating code like
458 // this:
459 //
460 // mov eax, [ebp-0x10]
461 // add eax, [ebp-0x10]
462 // jo label
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000463 InstructionOperand const input = g.UseRegister(left);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400464 inputs[input_count++] = input;
465 inputs[input_count++] = input;
466 } else if (g.CanBeImmediate(right)) {
467 inputs[input_count++] = g.UseRegister(left);
468 inputs[input_count++] = g.UseImmediate(right);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000469 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400470 if (node->op()->HasProperty(Operator::kCommutative) &&
471 g.CanBeBetterLeftOperand(right)) {
472 std::swap(left, right);
473 }
474 inputs[input_count++] = g.UseRegister(left);
475 inputs[input_count++] = g.Use(right);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000476 }
477
478 if (cont->IsBranch()) {
479 inputs[input_count++] = g.Label(cont->true_block());
480 inputs[input_count++] = g.Label(cont->false_block());
481 }
482
483 outputs[output_count++] = g.DefineSameAsFirst(node);
484 if (cont->IsSet()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000485 outputs[output_count++] = g.DefineAsByteRegister(cont->result());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000486 }
487
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000488 DCHECK_NE(0u, input_count);
489 DCHECK_NE(0u, output_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000490 DCHECK_GE(arraysize(inputs), input_count);
491 DCHECK_GE(arraysize(outputs), output_count);
492
Ben Murdochda12d292016-06-02 14:46:10 +0100493 opcode = cont->Encode(opcode);
494 if (cont->IsDeoptimize()) {
495 selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
496 cont->frame_state());
497 } else {
498 selector->Emit(opcode, output_count, outputs, input_count, inputs);
499 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000500}
501
502
503// Shared routine for multiple binary operations.
Ben Murdochda12d292016-06-02 14:46:10 +0100504void VisitBinop(InstructionSelector* selector, Node* node,
505 InstructionCode opcode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000506 FlagsContinuation cont;
507 VisitBinop(selector, node, opcode, &cont);
508}
509
Ben Murdochda12d292016-06-02 14:46:10 +0100510} // namespace
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000511
512void InstructionSelector::VisitWord32And(Node* node) {
513 VisitBinop(this, node, kIA32And);
514}
515
516
517void InstructionSelector::VisitWord32Or(Node* node) {
518 VisitBinop(this, node, kIA32Or);
519}
520
521
522void InstructionSelector::VisitWord32Xor(Node* node) {
523 IA32OperandGenerator g(this);
524 Int32BinopMatcher m(node);
525 if (m.right().Is(-1)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400526 Emit(kIA32Not, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000527 } else {
528 VisitBinop(this, node, kIA32Xor);
529 }
530}
531
532
533// Shared routine for multiple shift operations.
534static inline void VisitShift(InstructionSelector* selector, Node* node,
535 ArchOpcode opcode) {
536 IA32OperandGenerator g(selector);
537 Node* left = node->InputAt(0);
538 Node* right = node->InputAt(1);
539
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000540 if (g.CanBeImmediate(right)) {
541 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
542 g.UseImmediate(right));
543 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000544 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
545 g.UseFixed(right, ecx));
546 }
547}
548
549
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400550namespace {
551
552void VisitMulHigh(InstructionSelector* selector, Node* node,
553 ArchOpcode opcode) {
554 IA32OperandGenerator g(selector);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100555 InstructionOperand temps[] = {g.TempRegister(eax)};
556 selector->Emit(
557 opcode, g.DefineAsFixed(node, edx), g.UseFixed(node->InputAt(0), eax),
558 g.UseUniqueRegister(node->InputAt(1)), arraysize(temps), temps);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400559}
560
561
562void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
563 IA32OperandGenerator g(selector);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000564 InstructionOperand temps[] = {g.TempRegister(edx)};
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400565 selector->Emit(opcode, g.DefineAsFixed(node, eax),
566 g.UseFixed(node->InputAt(0), eax),
567 g.UseUnique(node->InputAt(1)), arraysize(temps), temps);
568}
569
570
571void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
572 IA32OperandGenerator g(selector);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100573 InstructionOperand temps[] = {g.TempRegister(eax)};
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400574 selector->Emit(opcode, g.DefineAsFixed(node, edx),
575 g.UseFixed(node->InputAt(0), eax),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100576 g.UseUnique(node->InputAt(1)), arraysize(temps), temps);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400577}
578
579void EmitLea(InstructionSelector* selector, Node* result, Node* index,
580 int scale, Node* base, Node* displacement) {
581 IA32OperandGenerator g(selector);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000582 InstructionOperand inputs[4];
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400583 size_t input_count = 0;
584 AddressingMode mode = g.GenerateMemoryOperandInputs(
585 index, scale, base, displacement, inputs, &input_count);
586
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000587 DCHECK_NE(0u, input_count);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400588 DCHECK_GE(arraysize(inputs), input_count);
589
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000590 InstructionOperand outputs[1];
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400591 outputs[0] = g.DefineAsRegister(result);
592
593 InstructionCode opcode = AddressingModeField::encode(mode) | kIA32Lea;
594
595 selector->Emit(opcode, 1, outputs, input_count, inputs);
596}
597
598} // namespace
599
600
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000601void InstructionSelector::VisitWord32Shl(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400602 Int32ScaleMatcher m(node, true);
603 if (m.matches()) {
604 Node* index = node->InputAt(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000605 Node* base = m.power_of_two_plus_one() ? index : nullptr;
606 EmitLea(this, node, index, m.scale(), base, nullptr);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400607 return;
608 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000609 VisitShift(this, node, kIA32Shl);
610}
611
612
613void InstructionSelector::VisitWord32Shr(Node* node) {
614 VisitShift(this, node, kIA32Shr);
615}
616
617
618void InstructionSelector::VisitWord32Sar(Node* node) {
619 VisitShift(this, node, kIA32Sar);
620}
621
Ben Murdochda12d292016-06-02 14:46:10 +0100622void InstructionSelector::VisitInt32PairAdd(Node* node) {
623 IA32OperandGenerator g(this);
624
625 // We use UseUniqueRegister here to avoid register sharing with the temp
626 // register.
627 InstructionOperand inputs[] = {
628 g.UseRegister(node->InputAt(0)), g.UseUniqueRegister(node->InputAt(1)),
629 g.UseRegister(node->InputAt(2)), g.UseUniqueRegister(node->InputAt(3))};
630
631 InstructionOperand outputs[] = {
632 g.DefineSameAsFirst(node),
633 g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
634
635 InstructionOperand temps[] = {g.TempRegister()};
636
637 Emit(kIA32AddPair, 2, outputs, 4, inputs, 1, temps);
638}
639
640void InstructionSelector::VisitInt32PairSub(Node* node) {
641 IA32OperandGenerator g(this);
642
643 // We use UseUniqueRegister here to avoid register sharing with the temp
644 // register.
645 InstructionOperand inputs[] = {
646 g.UseRegister(node->InputAt(0)), g.UseUniqueRegister(node->InputAt(1)),
647 g.UseRegister(node->InputAt(2)), g.UseUniqueRegister(node->InputAt(3))};
648
649 InstructionOperand outputs[] = {
650 g.DefineSameAsFirst(node),
651 g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
652
653 InstructionOperand temps[] = {g.TempRegister()};
654
655 Emit(kIA32SubPair, 2, outputs, 4, inputs, 1, temps);
656}
657
658void InstructionSelector::VisitInt32PairMul(Node* node) {
659 IA32OperandGenerator g(this);
660
661 // InputAt(3) explicitly shares ecx with OutputRegister(1) to save one
662 // register and one mov instruction.
663 InstructionOperand inputs[] = {
664 g.UseUnique(node->InputAt(0)), g.UseUnique(node->InputAt(1)),
665 g.UseUniqueRegister(node->InputAt(2)), g.UseFixed(node->InputAt(3), ecx)};
666
667 InstructionOperand outputs[] = {
668 g.DefineAsFixed(node, eax),
669 g.DefineAsFixed(NodeProperties::FindProjection(node, 1), ecx)};
670
671 InstructionOperand temps[] = {g.TempRegister(edx)};
672
673 Emit(kIA32MulPair, 2, outputs, 4, inputs, 1, temps);
674}
675
676void VisitWord32PairShift(InstructionSelector* selector, InstructionCode opcode,
677 Node* node) {
678 IA32OperandGenerator g(selector);
679
680 Node* shift = node->InputAt(2);
681 InstructionOperand shift_operand;
682 if (g.CanBeImmediate(shift)) {
683 shift_operand = g.UseImmediate(shift);
684 } else {
685 shift_operand = g.UseFixed(shift, ecx);
686 }
687 InstructionOperand inputs[] = {g.UseFixed(node->InputAt(0), eax),
688 g.UseFixed(node->InputAt(1), edx),
689 shift_operand};
690
691 InstructionOperand outputs[] = {
692 g.DefineAsFixed(node, eax),
693 g.DefineAsFixed(NodeProperties::FindProjection(node, 1), edx)};
694
695 selector->Emit(opcode, 2, outputs, 3, inputs);
696}
697
698void InstructionSelector::VisitWord32PairShl(Node* node) {
699 VisitWord32PairShift(this, kIA32ShlPair, node);
700}
701
702void InstructionSelector::VisitWord32PairShr(Node* node) {
703 VisitWord32PairShift(this, kIA32ShrPair, node);
704}
705
706void InstructionSelector::VisitWord32PairSar(Node* node) {
707 VisitWord32PairShift(this, kIA32SarPair, node);
708}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000709
710void InstructionSelector::VisitWord32Ror(Node* node) {
711 VisitShift(this, node, kIA32Ror);
712}
713
714
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000715void InstructionSelector::VisitWord32Clz(Node* node) {
716 IA32OperandGenerator g(this);
717 Emit(kIA32Lzcnt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
718}
719
720
721void InstructionSelector::VisitWord32Ctz(Node* node) {
722 IA32OperandGenerator g(this);
723 Emit(kIA32Tzcnt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
724}
725
726
Ben Murdoch097c5b22016-05-18 11:27:45 +0100727void InstructionSelector::VisitWord32ReverseBits(Node* node) { UNREACHABLE(); }
728
729
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000730void InstructionSelector::VisitWord32Popcnt(Node* node) {
731 IA32OperandGenerator g(this);
732 Emit(kIA32Popcnt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
733}
734
735
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000736void InstructionSelector::VisitInt32Add(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400737 IA32OperandGenerator g(this);
738
739 // Try to match the Add to a lea pattern
740 BaseWithIndexAndDisplacement32Matcher m(node);
741 if (m.matches() &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000742 (m.displacement() == nullptr || g.CanBeImmediate(m.displacement()))) {
743 InstructionOperand inputs[4];
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400744 size_t input_count = 0;
745 AddressingMode mode = g.GenerateMemoryOperandInputs(
746 m.index(), m.scale(), m.base(), m.displacement(), inputs, &input_count);
747
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000748 DCHECK_NE(0u, input_count);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400749 DCHECK_GE(arraysize(inputs), input_count);
750
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000751 InstructionOperand outputs[1];
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400752 outputs[0] = g.DefineAsRegister(node);
753
754 InstructionCode opcode = AddressingModeField::encode(mode) | kIA32Lea;
755 Emit(opcode, 1, outputs, input_count, inputs);
756 return;
757 }
758
759 // No lea pattern match, use add
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000760 VisitBinop(this, node, kIA32Add);
761}
762
763
764void InstructionSelector::VisitInt32Sub(Node* node) {
765 IA32OperandGenerator g(this);
766 Int32BinopMatcher m(node);
767 if (m.left().Is(0)) {
768 Emit(kIA32Neg, g.DefineSameAsFirst(node), g.Use(m.right().node()));
769 } else {
770 VisitBinop(this, node, kIA32Sub);
771 }
772}
773
774
775void InstructionSelector::VisitInt32Mul(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400776 Int32ScaleMatcher m(node, true);
777 if (m.matches()) {
778 Node* index = node->InputAt(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000779 Node* base = m.power_of_two_plus_one() ? index : nullptr;
780 EmitLea(this, node, index, m.scale(), base, nullptr);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400781 return;
782 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000783 IA32OperandGenerator g(this);
784 Node* left = node->InputAt(0);
785 Node* right = node->InputAt(1);
786 if (g.CanBeImmediate(right)) {
787 Emit(kIA32Imul, g.DefineAsRegister(node), g.Use(left),
788 g.UseImmediate(right));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000789 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400790 if (g.CanBeBetterLeftOperand(right)) {
791 std::swap(left, right);
792 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000793 Emit(kIA32Imul, g.DefineSameAsFirst(node), g.UseRegister(left),
794 g.Use(right));
795 }
796}
797
798
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400799void InstructionSelector::VisitInt32MulHigh(Node* node) {
800 VisitMulHigh(this, node, kIA32ImulHigh);
801}
802
803
804void InstructionSelector::VisitUint32MulHigh(Node* node) {
805 VisitMulHigh(this, node, kIA32UmulHigh);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000806}
807
808
809void InstructionSelector::VisitInt32Div(Node* node) {
810 VisitDiv(this, node, kIA32Idiv);
811}
812
813
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400814void InstructionSelector::VisitUint32Div(Node* node) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000815 VisitDiv(this, node, kIA32Udiv);
816}
817
818
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000819void InstructionSelector::VisitInt32Mod(Node* node) {
820 VisitMod(this, node, kIA32Idiv);
821}
822
823
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400824void InstructionSelector::VisitUint32Mod(Node* node) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000825 VisitMod(this, node, kIA32Udiv);
826}
827
828
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400829void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000830 VisitRO(this, node, kSSEFloat32ToFloat64);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400831}
832
833
Ben Murdoch097c5b22016-05-18 11:27:45 +0100834void InstructionSelector::VisitRoundInt32ToFloat32(Node* node) {
835 VisitRO(this, node, kSSEInt32ToFloat32);
836}
837
838
839void InstructionSelector::VisitRoundUint32ToFloat32(Node* node) {
840 IA32OperandGenerator g(this);
841 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
842 Emit(kSSEUint32ToFloat32, g.DefineAsRegister(node), g.Use(node->InputAt(0)),
843 arraysize(temps), temps);
844}
845
846
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000847void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000848 VisitRO(this, node, kSSEInt32ToFloat64);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000849}
850
851
852void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000853 VisitRO(this, node, kSSEUint32ToFloat64);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000854}
855
856
Ben Murdoch097c5b22016-05-18 11:27:45 +0100857void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) {
858 VisitRO(this, node, kSSEFloat32ToInt32);
859}
860
861
862void InstructionSelector::VisitTruncateFloat32ToUint32(Node* node) {
863 VisitRO(this, node, kSSEFloat32ToUint32);
864}
865
866
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000867void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000868 VisitRO(this, node, kSSEFloat64ToInt32);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000869}
870
871
872void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000873 VisitRO(this, node, kSSEFloat64ToUint32);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000874}
875
Ben Murdochda12d292016-06-02 14:46:10 +0100876void InstructionSelector::VisitTruncateFloat64ToUint32(Node* node) {
877 VisitRO(this, node, kSSEFloat64ToUint32);
878}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000879
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400880void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000881 VisitRO(this, node, kSSEFloat64ToFloat32);
882}
883
Ben Murdochc5610432016-08-08 18:44:38 +0100884void InstructionSelector::VisitTruncateFloat64ToWord32(Node* node) {
885 VisitRR(this, node, kArchTruncateDoubleToI);
886}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000887
Ben Murdochc5610432016-08-08 18:44:38 +0100888void InstructionSelector::VisitRoundFloat64ToInt32(Node* node) {
889 VisitRO(this, node, kSSEFloat64ToInt32);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000890}
891
892
893void InstructionSelector::VisitBitcastFloat32ToInt32(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400894 IA32OperandGenerator g(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000895 Emit(kIA32BitcastFI, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
896}
897
898
899void InstructionSelector::VisitBitcastInt32ToFloat32(Node* node) {
900 IA32OperandGenerator g(this);
901 Emit(kIA32BitcastIF, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
902}
903
904
905void InstructionSelector::VisitFloat32Add(Node* node) {
906 VisitRROFloat(this, node, kAVXFloat32Add, kSSEFloat32Add);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400907}
908
909
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000910void InstructionSelector::VisitFloat64Add(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000911 VisitRROFloat(this, node, kAVXFloat64Add, kSSEFloat64Add);
912}
913
914
915void InstructionSelector::VisitFloat32Sub(Node* node) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000916 IA32OperandGenerator g(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000917 Float32BinopMatcher m(node);
918 if (m.left().IsMinusZero()) {
919 VisitFloatUnop(this, node, m.right().node(), kAVXFloat32Neg,
920 kSSEFloat32Neg);
921 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400922 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000923 VisitRROFloat(this, node, kAVXFloat32Sub, kSSEFloat32Sub);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000924}
925
Ben Murdochc5610432016-08-08 18:44:38 +0100926void InstructionSelector::VisitFloat32SubPreserveNan(Node* node) {
927 VisitRROFloat(this, node, kAVXFloat32Sub, kSSEFloat32Sub);
928}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000929
930void InstructionSelector::VisitFloat64Sub(Node* node) {
931 IA32OperandGenerator g(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000932 Float64BinopMatcher m(node);
933 if (m.left().IsMinusZero()) {
934 if (m.right().IsFloat64RoundDown() &&
935 CanCover(m.node(), m.right().node())) {
936 if (m.right().InputAt(0)->opcode() == IrOpcode::kFloat64Sub &&
937 CanCover(m.right().node(), m.right().InputAt(0))) {
938 Float64BinopMatcher mright0(m.right().InputAt(0));
939 if (mright0.left().IsMinusZero()) {
940 Emit(kSSEFloat64Round | MiscField::encode(kRoundUp),
941 g.DefineAsRegister(node), g.UseRegister(mright0.right().node()));
942 return;
943 }
944 }
945 }
946 VisitFloatUnop(this, node, m.right().node(), kAVXFloat64Neg,
947 kSSEFloat64Neg);
948 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400949 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000950 VisitRROFloat(this, node, kAVXFloat64Sub, kSSEFloat64Sub);
951}
952
Ben Murdochc5610432016-08-08 18:44:38 +0100953void InstructionSelector::VisitFloat64SubPreserveNan(Node* node) {
954 VisitRROFloat(this, node, kAVXFloat64Sub, kSSEFloat64Sub);
955}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000956
957void InstructionSelector::VisitFloat32Mul(Node* node) {
958 VisitRROFloat(this, node, kAVXFloat32Mul, kSSEFloat32Mul);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000959}
960
961
962void InstructionSelector::VisitFloat64Mul(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000963 VisitRROFloat(this, node, kAVXFloat64Mul, kSSEFloat64Mul);
964}
965
966
967void InstructionSelector::VisitFloat32Div(Node* node) {
968 VisitRROFloat(this, node, kAVXFloat32Div, kSSEFloat32Div);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000969}
970
971
972void InstructionSelector::VisitFloat64Div(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000973 VisitRROFloat(this, node, kAVXFloat64Div, kSSEFloat64Div);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000974}
975
976
977void InstructionSelector::VisitFloat64Mod(Node* node) {
978 IA32OperandGenerator g(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000979 InstructionOperand temps[] = {g.TempRegister(eax)};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000980 Emit(kSSEFloat64Mod, g.DefineSameAsFirst(node),
981 g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)), 1,
982 temps);
983}
984
985
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000986void InstructionSelector::VisitFloat32Max(Node* node) {
987 VisitRROFloat(this, node, kAVXFloat32Max, kSSEFloat32Max);
988}
989
990
991void InstructionSelector::VisitFloat64Max(Node* node) {
992 VisitRROFloat(this, node, kAVXFloat64Max, kSSEFloat64Max);
993}
994
995
996void InstructionSelector::VisitFloat32Min(Node* node) {
997 VisitRROFloat(this, node, kAVXFloat32Min, kSSEFloat32Min);
998}
999
1000
1001void InstructionSelector::VisitFloat64Min(Node* node) {
1002 VisitRROFloat(this, node, kAVXFloat64Min, kSSEFloat64Min);
1003}
1004
1005
1006void InstructionSelector::VisitFloat32Abs(Node* node) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001007 IA32OperandGenerator g(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001008 VisitFloatUnop(this, node, node->InputAt(0), kAVXFloat32Abs, kSSEFloat32Abs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001009}
1010
1011
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001012void InstructionSelector::VisitFloat64Abs(Node* node) {
1013 IA32OperandGenerator g(this);
1014 VisitFloatUnop(this, node, node->InputAt(0), kAVXFloat64Abs, kSSEFloat64Abs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001015}
1016
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001017void InstructionSelector::VisitFloat32Sqrt(Node* node) {
1018 VisitRO(this, node, kSSEFloat32Sqrt);
1019}
1020
1021
1022void InstructionSelector::VisitFloat64Sqrt(Node* node) {
1023 VisitRO(this, node, kSSEFloat64Sqrt);
1024}
1025
1026
1027void InstructionSelector::VisitFloat32RoundDown(Node* node) {
1028 VisitRR(this, node, kSSEFloat32Round | MiscField::encode(kRoundDown));
1029}
1030
1031
1032void InstructionSelector::VisitFloat64RoundDown(Node* node) {
1033 VisitRR(this, node, kSSEFloat64Round | MiscField::encode(kRoundDown));
1034}
1035
1036
1037void InstructionSelector::VisitFloat32RoundUp(Node* node) {
1038 VisitRR(this, node, kSSEFloat32Round | MiscField::encode(kRoundUp));
1039}
1040
1041
1042void InstructionSelector::VisitFloat64RoundUp(Node* node) {
1043 VisitRR(this, node, kSSEFloat64Round | MiscField::encode(kRoundUp));
1044}
1045
1046
1047void InstructionSelector::VisitFloat32RoundTruncate(Node* node) {
1048 VisitRR(this, node, kSSEFloat32Round | MiscField::encode(kRoundToZero));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001049}
1050
1051
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001052void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001053 VisitRR(this, node, kSSEFloat64Round | MiscField::encode(kRoundToZero));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001054}
1055
1056
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001057void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
1058 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001059}
1060
1061
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001062void InstructionSelector::VisitFloat32RoundTiesEven(Node* node) {
1063 VisitRR(this, node, kSSEFloat32Round | MiscField::encode(kRoundToNearest));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001064}
1065
1066
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001067void InstructionSelector::VisitFloat64RoundTiesEven(Node* node) {
1068 VisitRR(this, node, kSSEFloat64Round | MiscField::encode(kRoundToNearest));
1069}
1070
Ben Murdoch61f157c2016-09-16 13:49:30 +01001071void InstructionSelector::VisitFloat32Neg(Node* node) { UNREACHABLE(); }
1072
1073void InstructionSelector::VisitFloat64Neg(Node* node) { UNREACHABLE(); }
1074
1075void InstructionSelector::VisitFloat64Ieee754Binop(Node* node,
1076 InstructionCode opcode) {
1077 IA32OperandGenerator g(this);
1078 Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)),
1079 g.UseRegister(node->InputAt(1)))
1080 ->MarkAsCall();
1081}
1082
1083void InstructionSelector::VisitFloat64Ieee754Unop(Node* node,
1084 InstructionCode opcode) {
1085 IA32OperandGenerator g(this);
1086 Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)))
1087 ->MarkAsCall();
1088}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001089
1090void InstructionSelector::EmitPrepareArguments(
1091 ZoneVector<PushParameter>* arguments, const CallDescriptor* descriptor,
1092 Node* node) {
1093 IA32OperandGenerator g(this);
1094
1095 // Prepare for C function call.
1096 if (descriptor->IsCFunctionCall()) {
1097 InstructionOperand temps[] = {g.TempRegister()};
1098 size_t const temp_count = arraysize(temps);
1099 Emit(kArchPrepareCallCFunction |
1100 MiscField::encode(static_cast<int>(descriptor->CParameterCount())),
1101 0, nullptr, 0, nullptr, temp_count, temps);
1102
1103 // Poke any stack arguments.
1104 for (size_t n = 0; n < arguments->size(); ++n) {
1105 PushParameter input = (*arguments)[n];
1106 if (input.node()) {
1107 int const slot = static_cast<int>(n);
1108 InstructionOperand value = g.CanBeImmediate(node)
1109 ? g.UseImmediate(input.node())
1110 : g.UseRegister(input.node());
1111 Emit(kIA32Poke | MiscField::encode(slot), g.NoOutput(), value);
1112 }
1113 }
1114 } else {
1115 // Push any stack arguments.
1116 for (PushParameter input : base::Reversed(*arguments)) {
1117 // Skip any alignment holes in pushed nodes.
1118 if (input.node() == nullptr) continue;
1119 InstructionOperand value =
1120 g.CanBeImmediate(input.node())
1121 ? g.UseImmediate(input.node())
1122 : IsSupported(ATOM) ||
Ben Murdoch61f157c2016-09-16 13:49:30 +01001123 sequence()->IsFP(GetVirtualRegister(input.node()))
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001124 ? g.UseRegister(input.node())
1125 : g.Use(input.node());
1126 if (input.type() == MachineType::Float32()) {
1127 Emit(kIA32PushFloat32, g.NoOutput(), value);
1128 } else if (input.type() == MachineType::Float64()) {
1129 Emit(kIA32PushFloat64, g.NoOutput(), value);
1130 } else {
1131 Emit(kIA32Push, g.NoOutput(), value);
1132 }
1133 }
1134 }
1135}
1136
1137
1138bool InstructionSelector::IsTailCallAddressImmediate() { return true; }
1139
Ben Murdochda12d292016-06-02 14:46:10 +01001140int InstructionSelector::GetTempsCountForTailCallFromJSFunction() { return 0; }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001141
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001142namespace {
1143
Ben Murdoch097c5b22016-05-18 11:27:45 +01001144void VisitCompareWithMemoryOperand(InstructionSelector* selector,
1145 InstructionCode opcode, Node* left,
1146 InstructionOperand right,
1147 FlagsContinuation* cont) {
1148 DCHECK(left->opcode() == IrOpcode::kLoad);
1149 IA32OperandGenerator g(selector);
1150 size_t input_count = 0;
1151 InstructionOperand inputs[6];
1152 AddressingMode addressing_mode =
1153 g.GetEffectiveAddressMemoryOperand(left, inputs, &input_count);
1154 opcode |= AddressingModeField::encode(addressing_mode);
1155 opcode = cont->Encode(opcode);
1156 inputs[input_count++] = right;
1157
1158 if (cont->IsBranch()) {
1159 inputs[input_count++] = g.Label(cont->true_block());
1160 inputs[input_count++] = g.Label(cont->false_block());
1161 selector->Emit(opcode, 0, nullptr, input_count, inputs);
Ben Murdochda12d292016-06-02 14:46:10 +01001162 } else if (cont->IsDeoptimize()) {
1163 selector->EmitDeoptimize(opcode, 0, nullptr, input_count, inputs,
1164 cont->frame_state());
Ben Murdoch097c5b22016-05-18 11:27:45 +01001165 } else {
1166 DCHECK(cont->IsSet());
1167 InstructionOperand output = g.DefineAsRegister(cont->result());
1168 selector->Emit(opcode, 1, &output, input_count, inputs);
1169 }
1170}
1171
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001172// Shared routine for multiple compare operations.
1173void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001174 InstructionOperand left, InstructionOperand right,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001175 FlagsContinuation* cont) {
1176 IA32OperandGenerator g(selector);
Ben Murdochda12d292016-06-02 14:46:10 +01001177 opcode = cont->Encode(opcode);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001178 if (cont->IsBranch()) {
Ben Murdochda12d292016-06-02 14:46:10 +01001179 selector->Emit(opcode, g.NoOutput(), left, right,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001180 g.Label(cont->true_block()), g.Label(cont->false_block()));
Ben Murdochda12d292016-06-02 14:46:10 +01001181 } else if (cont->IsDeoptimize()) {
1182 selector->EmitDeoptimize(opcode, g.NoOutput(), left, right,
1183 cont->frame_state());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001184 } else {
1185 DCHECK(cont->IsSet());
Ben Murdochda12d292016-06-02 14:46:10 +01001186 selector->Emit(opcode, g.DefineAsByteRegister(cont->result()), left, right);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001187 }
1188}
1189
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001190
1191// Shared routine for multiple compare operations.
1192void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
1193 Node* left, Node* right, FlagsContinuation* cont,
1194 bool commutative) {
1195 IA32OperandGenerator g(selector);
1196 if (commutative && g.CanBeBetterLeftOperand(right)) {
1197 std::swap(left, right);
1198 }
1199 VisitCompare(selector, opcode, g.UseRegister(left), g.Use(right), cont);
1200}
1201
Ben Murdochda12d292016-06-02 14:46:10 +01001202// Tries to match the size of the given opcode to that of the operands, if
1203// possible.
1204InstructionCode TryNarrowOpcodeSize(InstructionCode opcode, Node* left,
1205 Node* right) {
1206 if (opcode != kIA32Cmp && opcode != kIA32Test) {
1207 return opcode;
1208 }
1209 // Currently, if one of the two operands is not a Load, we don't know what its
1210 // machine representation is, so we bail out.
1211 // TODO(epertoso): we can probably get some size information out of immediates
1212 // and phi nodes.
1213 if (left->opcode() != IrOpcode::kLoad || right->opcode() != IrOpcode::kLoad) {
1214 return opcode;
1215 }
1216 // If the load representations don't match, both operands will be
1217 // zero/sign-extended to 32bit.
1218 LoadRepresentation left_representation = LoadRepresentationOf(left->op());
1219 if (left_representation != LoadRepresentationOf(right->op())) {
1220 return opcode;
1221 }
1222 switch (left_representation.representation()) {
1223 case MachineRepresentation::kBit:
1224 case MachineRepresentation::kWord8:
1225 return opcode == kIA32Cmp ? kIA32Cmp8 : kIA32Test8;
1226 case MachineRepresentation::kWord16:
1227 return opcode == kIA32Cmp ? kIA32Cmp16 : kIA32Test16;
1228 default:
1229 return opcode;
1230 }
1231}
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001232
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001233// Shared routine for multiple float32 compare operations (inputs commuted).
1234void VisitFloat32Compare(InstructionSelector* selector, Node* node,
1235 FlagsContinuation* cont) {
1236 Node* const left = node->InputAt(0);
1237 Node* const right = node->InputAt(1);
1238 VisitCompare(selector, kSSEFloat32Cmp, right, left, cont, false);
1239}
1240
1241
1242// Shared routine for multiple float64 compare operations (inputs commuted).
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001243void VisitFloat64Compare(InstructionSelector* selector, Node* node,
1244 FlagsContinuation* cont) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001245 Node* const left = node->InputAt(0);
1246 Node* const right = node->InputAt(1);
1247 VisitCompare(selector, kSSEFloat64Cmp, right, left, cont, false);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001248}
1249
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001250// Shared routine for multiple word compare operations.
1251void VisitWordCompare(InstructionSelector* selector, Node* node,
1252 InstructionCode opcode, FlagsContinuation* cont) {
1253 IA32OperandGenerator g(selector);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001254 Node* left = node->InputAt(0);
1255 Node* right = node->InputAt(1);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001256
Ben Murdochda12d292016-06-02 14:46:10 +01001257 InstructionCode narrowed_opcode = TryNarrowOpcodeSize(opcode, left, right);
1258
Ben Murdochc5610432016-08-08 18:44:38 +01001259 int effect_level = selector->GetEffectLevel(node);
1260 if (cont->IsBranch()) {
1261 effect_level = selector->GetEffectLevel(
1262 cont->true_block()->PredecessorAt(0)->control_input());
1263 }
1264
Ben Murdochda12d292016-06-02 14:46:10 +01001265 // If one of the two inputs is an immediate, make sure it's on the right, or
1266 // if one of the two inputs is a memory operand, make sure it's on the left.
1267 if ((!g.CanBeImmediate(right) && g.CanBeImmediate(left)) ||
Ben Murdochc5610432016-08-08 18:44:38 +01001268 (g.CanBeMemoryOperand(narrowed_opcode, node, right, effect_level) &&
1269 !g.CanBeMemoryOperand(narrowed_opcode, node, left, effect_level))) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001270 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001271 std::swap(left, right);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001272 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001273
Ben Murdoch097c5b22016-05-18 11:27:45 +01001274 // Match immediates on right side of comparison.
1275 if (g.CanBeImmediate(right)) {
Ben Murdochc5610432016-08-08 18:44:38 +01001276 if (g.CanBeMemoryOperand(opcode, node, left, effect_level)) {
Ben Murdochda12d292016-06-02 14:46:10 +01001277 // TODO(epertoso): we should use `narrowed_opcode' here once we match
1278 // immediates too.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001279 return VisitCompareWithMemoryOperand(selector, opcode, left,
1280 g.UseImmediate(right), cont);
1281 }
1282 return VisitCompare(selector, opcode, g.Use(left), g.UseImmediate(right),
1283 cont);
1284 }
1285
Ben Murdochda12d292016-06-02 14:46:10 +01001286 // Match memory operands on left side of comparison.
Ben Murdochc5610432016-08-08 18:44:38 +01001287 if (g.CanBeMemoryOperand(narrowed_opcode, node, left, effect_level)) {
Ben Murdochda12d292016-06-02 14:46:10 +01001288 bool needs_byte_register =
1289 narrowed_opcode == kIA32Test8 || narrowed_opcode == kIA32Cmp8;
1290 return VisitCompareWithMemoryOperand(
1291 selector, narrowed_opcode, left,
1292 needs_byte_register ? g.UseByteRegister(right) : g.UseRegister(right),
1293 cont);
1294 }
1295
Ben Murdoch097c5b22016-05-18 11:27:45 +01001296 if (g.CanBeBetterLeftOperand(right)) {
1297 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
1298 std::swap(left, right);
1299 }
1300
Ben Murdoch097c5b22016-05-18 11:27:45 +01001301 return VisitCompare(selector, opcode, left, right, cont,
1302 node->op()->HasProperty(Operator::kCommutative));
1303}
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001304
1305void VisitWordCompare(InstructionSelector* selector, Node* node,
1306 FlagsContinuation* cont) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001307 IA32OperandGenerator g(selector);
1308 Int32BinopMatcher m(node);
1309 if (m.left().IsLoad() && m.right().IsLoadStackPointer()) {
1310 LoadMatcher<ExternalReferenceMatcher> mleft(m.left().node());
1311 ExternalReference js_stack_limit =
1312 ExternalReference::address_of_stack_limit(selector->isolate());
1313 if (mleft.object().Is(js_stack_limit) && mleft.index().Is(0)) {
1314 // Compare(Load(js_stack_limit), LoadStackPointer)
1315 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
1316 InstructionCode opcode = cont->Encode(kIA32StackCheck);
1317 if (cont->IsBranch()) {
1318 selector->Emit(opcode, g.NoOutput(), g.Label(cont->true_block()),
1319 g.Label(cont->false_block()));
Ben Murdochda12d292016-06-02 14:46:10 +01001320 } else if (cont->IsDeoptimize()) {
1321 selector->EmitDeoptimize(opcode, 0, nullptr, 0, nullptr,
1322 cont->frame_state());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001323 } else {
1324 DCHECK(cont->IsSet());
1325 selector->Emit(opcode, g.DefineAsRegister(cont->result()));
1326 }
1327 return;
1328 }
1329 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001330 VisitWordCompare(selector, node, kIA32Cmp, cont);
1331}
1332
1333
1334// Shared routine for word comparison with zero.
1335void VisitWordCompareZero(InstructionSelector* selector, Node* user,
1336 Node* value, FlagsContinuation* cont) {
1337 // Try to combine the branch with a comparison.
1338 while (selector->CanCover(user, value)) {
1339 switch (value->opcode()) {
1340 case IrOpcode::kWord32Equal: {
1341 // Try to combine with comparisons against 0 by simply inverting the
1342 // continuation.
1343 Int32BinopMatcher m(value);
1344 if (m.right().Is(0)) {
1345 user = value;
1346 value = m.left().node();
1347 cont->Negate();
1348 continue;
1349 }
1350 cont->OverwriteAndNegateIfEqual(kEqual);
1351 return VisitWordCompare(selector, value, cont);
1352 }
1353 case IrOpcode::kInt32LessThan:
1354 cont->OverwriteAndNegateIfEqual(kSignedLessThan);
1355 return VisitWordCompare(selector, value, cont);
1356 case IrOpcode::kInt32LessThanOrEqual:
1357 cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
1358 return VisitWordCompare(selector, value, cont);
1359 case IrOpcode::kUint32LessThan:
1360 cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
1361 return VisitWordCompare(selector, value, cont);
1362 case IrOpcode::kUint32LessThanOrEqual:
1363 cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
1364 return VisitWordCompare(selector, value, cont);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001365 case IrOpcode::kFloat32Equal:
1366 cont->OverwriteAndNegateIfEqual(kUnorderedEqual);
1367 return VisitFloat32Compare(selector, value, cont);
1368 case IrOpcode::kFloat32LessThan:
1369 cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThan);
1370 return VisitFloat32Compare(selector, value, cont);
1371 case IrOpcode::kFloat32LessThanOrEqual:
1372 cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThanOrEqual);
1373 return VisitFloat32Compare(selector, value, cont);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001374 case IrOpcode::kFloat64Equal:
1375 cont->OverwriteAndNegateIfEqual(kUnorderedEqual);
1376 return VisitFloat64Compare(selector, value, cont);
1377 case IrOpcode::kFloat64LessThan:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001378 cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThan);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001379 return VisitFloat64Compare(selector, value, cont);
1380 case IrOpcode::kFloat64LessThanOrEqual:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001381 cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThanOrEqual);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001382 return VisitFloat64Compare(selector, value, cont);
1383 case IrOpcode::kProjection:
1384 // Check if this is the overflow output projection of an
1385 // <Operation>WithOverflow node.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001386 if (ProjectionIndexOf(value->op()) == 1u) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001387 // We cannot combine the <Operation>WithOverflow with this branch
1388 // unless the 0th projection (the use of the actual value of the
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001389 // <Operation> is either nullptr, which means there's no use of the
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001390 // actual value, or was already defined, which means it is scheduled
1391 // *AFTER* this branch).
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001392 Node* const node = value->InputAt(0);
1393 Node* const result = NodeProperties::FindProjection(node, 0);
1394 if (result == nullptr || selector->IsDefined(result)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001395 switch (node->opcode()) {
1396 case IrOpcode::kInt32AddWithOverflow:
1397 cont->OverwriteAndNegateIfEqual(kOverflow);
1398 return VisitBinop(selector, node, kIA32Add, cont);
1399 case IrOpcode::kInt32SubWithOverflow:
1400 cont->OverwriteAndNegateIfEqual(kOverflow);
1401 return VisitBinop(selector, node, kIA32Sub, cont);
1402 default:
1403 break;
1404 }
1405 }
1406 }
1407 break;
1408 case IrOpcode::kInt32Sub:
1409 return VisitWordCompare(selector, value, cont);
1410 case IrOpcode::kWord32And:
1411 return VisitWordCompare(selector, value, kIA32Test, cont);
1412 default:
1413 break;
1414 }
1415 break;
1416 }
1417
1418 // Continuation could not be combined with a compare, emit compare against 0.
1419 IA32OperandGenerator g(selector);
1420 VisitCompare(selector, kIA32Cmp, g.Use(value), g.TempImmediate(0), cont);
1421}
1422
1423} // namespace
1424
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001425void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
1426 BasicBlock* fbranch) {
1427 FlagsContinuation cont(kNotEqual, tbranch, fbranch);
1428 VisitWordCompareZero(this, branch, branch->InputAt(0), &cont);
1429}
1430
Ben Murdochda12d292016-06-02 14:46:10 +01001431void InstructionSelector::VisitDeoptimizeIf(Node* node) {
1432 FlagsContinuation cont =
1433 FlagsContinuation::ForDeoptimize(kNotEqual, node->InputAt(1));
1434 VisitWordCompareZero(this, node, node->InputAt(0), &cont);
1435}
1436
1437void InstructionSelector::VisitDeoptimizeUnless(Node* node) {
1438 FlagsContinuation cont =
1439 FlagsContinuation::ForDeoptimize(kEqual, node->InputAt(1));
1440 VisitWordCompareZero(this, node, node->InputAt(0), &cont);
1441}
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001442
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001443void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
1444 IA32OperandGenerator g(this);
1445 InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
1446
1447 // Emit either ArchTableSwitch or ArchLookupSwitch.
1448 size_t table_space_cost = 4 + sw.value_range;
1449 size_t table_time_cost = 3;
1450 size_t lookup_space_cost = 3 + 2 * sw.case_count;
1451 size_t lookup_time_cost = sw.case_count;
1452 if (sw.case_count > 4 &&
1453 table_space_cost + 3 * table_time_cost <=
1454 lookup_space_cost + 3 * lookup_time_cost &&
1455 sw.min_value > std::numeric_limits<int32_t>::min()) {
1456 InstructionOperand index_operand = value_operand;
1457 if (sw.min_value) {
1458 index_operand = g.TempRegister();
1459 Emit(kIA32Lea | AddressingModeField::encode(kMode_MRI), index_operand,
1460 value_operand, g.TempImmediate(-sw.min_value));
1461 }
1462 // Generate a table lookup.
1463 return EmitTableSwitch(sw, index_operand);
1464 }
1465
1466 // Generate a sequence of conditional jumps.
1467 return EmitLookupSwitch(sw, value_operand);
1468}
1469
1470
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001471void InstructionSelector::VisitWord32Equal(Node* const node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001472 FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001473 Int32BinopMatcher m(node);
1474 if (m.right().Is(0)) {
1475 return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
1476 }
1477 VisitWordCompare(this, node, &cont);
1478}
1479
1480
1481void InstructionSelector::VisitInt32LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001482 FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001483 VisitWordCompare(this, node, &cont);
1484}
1485
1486
1487void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001488 FlagsContinuation cont =
1489 FlagsContinuation::ForSet(kSignedLessThanOrEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001490 VisitWordCompare(this, node, &cont);
1491}
1492
1493
1494void InstructionSelector::VisitUint32LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001495 FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001496 VisitWordCompare(this, node, &cont);
1497}
1498
1499
1500void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001501 FlagsContinuation cont =
1502 FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001503 VisitWordCompare(this, node, &cont);
1504}
1505
1506
1507void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001508 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
Ben Murdochda12d292016-06-02 14:46:10 +01001509 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001510 return VisitBinop(this, node, kIA32Add, &cont);
1511 }
1512 FlagsContinuation cont;
1513 VisitBinop(this, node, kIA32Add, &cont);
1514}
1515
1516
1517void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001518 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
Ben Murdochda12d292016-06-02 14:46:10 +01001519 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001520 return VisitBinop(this, node, kIA32Sub, &cont);
1521 }
1522 FlagsContinuation cont;
1523 VisitBinop(this, node, kIA32Sub, &cont);
1524}
1525
1526
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001527void InstructionSelector::VisitFloat32Equal(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001528 FlagsContinuation cont = FlagsContinuation::ForSet(kUnorderedEqual, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001529 VisitFloat32Compare(this, node, &cont);
1530}
1531
1532
1533void InstructionSelector::VisitFloat32LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001534 FlagsContinuation cont =
1535 FlagsContinuation::ForSet(kUnsignedGreaterThan, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001536 VisitFloat32Compare(this, node, &cont);
1537}
1538
1539
1540void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001541 FlagsContinuation cont =
1542 FlagsContinuation::ForSet(kUnsignedGreaterThanOrEqual, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001543 VisitFloat32Compare(this, node, &cont);
1544}
1545
1546
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001547void InstructionSelector::VisitFloat64Equal(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001548 FlagsContinuation cont = FlagsContinuation::ForSet(kUnorderedEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001549 VisitFloat64Compare(this, node, &cont);
1550}
1551
1552
1553void InstructionSelector::VisitFloat64LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001554 FlagsContinuation cont =
1555 FlagsContinuation::ForSet(kUnsignedGreaterThan, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001556 VisitFloat64Compare(this, node, &cont);
1557}
1558
1559
1560void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001561 FlagsContinuation cont =
1562 FlagsContinuation::ForSet(kUnsignedGreaterThanOrEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001563 VisitFloat64Compare(this, node, &cont);
1564}
1565
1566
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001567void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) {
1568 IA32OperandGenerator g(this);
1569 Emit(kSSEFloat64ExtractLowWord32, g.DefineAsRegister(node),
1570 g.Use(node->InputAt(0)));
1571}
1572
1573
1574void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) {
1575 IA32OperandGenerator g(this);
1576 Emit(kSSEFloat64ExtractHighWord32, g.DefineAsRegister(node),
1577 g.Use(node->InputAt(0)));
1578}
1579
1580
1581void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) {
1582 IA32OperandGenerator g(this);
1583 Node* left = node->InputAt(0);
1584 Node* right = node->InputAt(1);
1585 Float64Matcher mleft(left);
1586 if (mleft.HasValue() && (bit_cast<uint64_t>(mleft.Value()) >> 32) == 0u) {
1587 Emit(kSSEFloat64LoadLowWord32, g.DefineAsRegister(node), g.Use(right));
1588 return;
1589 }
1590 Emit(kSSEFloat64InsertLowWord32, g.DefineSameAsFirst(node),
1591 g.UseRegister(left), g.Use(right));
1592}
1593
1594
1595void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
1596 IA32OperandGenerator g(this);
1597 Node* left = node->InputAt(0);
1598 Node* right = node->InputAt(1);
1599 Emit(kSSEFloat64InsertHighWord32, g.DefineSameAsFirst(node),
1600 g.UseRegister(left), g.Use(right));
1601}
1602
Ben Murdoch61f157c2016-09-16 13:49:30 +01001603void InstructionSelector::VisitFloat64SilenceNaN(Node* node) {
1604 IA32OperandGenerator g(this);
1605 Emit(kSSEFloat64SilenceNaN, g.DefineSameAsFirst(node),
1606 g.UseRegister(node->InputAt(0)));
1607}
1608
Ben Murdochc5610432016-08-08 18:44:38 +01001609void InstructionSelector::VisitAtomicLoad(Node* node) {
1610 LoadRepresentation load_rep = LoadRepresentationOf(node->op());
1611 DCHECK(load_rep.representation() == MachineRepresentation::kWord8 ||
1612 load_rep.representation() == MachineRepresentation::kWord16 ||
1613 load_rep.representation() == MachineRepresentation::kWord32);
1614 USE(load_rep);
1615 VisitLoad(node);
1616}
1617
1618void InstructionSelector::VisitAtomicStore(Node* node) {
1619 IA32OperandGenerator g(this);
1620 Node* base = node->InputAt(0);
1621 Node* index = node->InputAt(1);
1622 Node* value = node->InputAt(2);
1623
1624 MachineRepresentation rep = AtomicStoreRepresentationOf(node->op());
1625 ArchOpcode opcode = kArchNop;
1626 switch (rep) {
1627 case MachineRepresentation::kWord8:
1628 opcode = kIA32Xchgb;
1629 break;
1630 case MachineRepresentation::kWord16:
1631 opcode = kIA32Xchgw;
1632 break;
1633 case MachineRepresentation::kWord32:
1634 opcode = kIA32Xchgl;
1635 break;
1636 default:
1637 UNREACHABLE();
1638 break;
1639 }
1640 AddressingMode addressing_mode;
1641 InstructionOperand inputs[4];
1642 size_t input_count = 0;
1643 inputs[input_count++] = g.UseUniqueRegister(base);
1644 if (g.CanBeImmediate(index)) {
1645 inputs[input_count++] = g.UseImmediate(index);
1646 addressing_mode = kMode_MRI;
1647 } else {
1648 inputs[input_count++] = g.UseUniqueRegister(index);
1649 addressing_mode = kMode_MR1;
1650 }
1651 inputs[input_count++] = g.UseUniqueRegister(value);
1652 InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
1653 Emit(code, 0, nullptr, input_count, inputs);
1654}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001655
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001656// static
1657MachineOperatorBuilder::Flags
1658InstructionSelector::SupportedMachineOperatorFlags() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001659 MachineOperatorBuilder::Flags flags =
1660 MachineOperatorBuilder::kFloat32Max |
1661 MachineOperatorBuilder::kFloat32Min |
1662 MachineOperatorBuilder::kFloat64Max |
1663 MachineOperatorBuilder::kFloat64Min |
1664 MachineOperatorBuilder::kWord32ShiftIsSafe |
1665 MachineOperatorBuilder::kWord32Ctz;
1666 if (CpuFeatures::IsSupported(POPCNT)) {
1667 flags |= MachineOperatorBuilder::kWord32Popcnt;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001668 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001669 if (CpuFeatures::IsSupported(SSE4_1)) {
1670 flags |= MachineOperatorBuilder::kFloat32RoundDown |
1671 MachineOperatorBuilder::kFloat64RoundDown |
1672 MachineOperatorBuilder::kFloat32RoundUp |
1673 MachineOperatorBuilder::kFloat64RoundUp |
1674 MachineOperatorBuilder::kFloat32RoundTruncate |
1675 MachineOperatorBuilder::kFloat64RoundTruncate |
1676 MachineOperatorBuilder::kFloat32RoundTiesEven |
1677 MachineOperatorBuilder::kFloat64RoundTiesEven;
1678 }
1679 return flags;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001680}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001681
Ben Murdoch61f157c2016-09-16 13:49:30 +01001682// static
1683MachineOperatorBuilder::AlignmentRequirements
1684InstructionSelector::AlignmentRequirements() {
1685 return MachineOperatorBuilder::AlignmentRequirements::
1686 FullUnalignedAccessSupport();
1687}
1688
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001689} // namespace compiler
1690} // namespace internal
1691} // namespace v8