blob: 9002d7551d3538004ec42ab607059ef152be9666 [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
1017
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001018void InstructionSelector::VisitFloat32Sqrt(Node* node) {
1019 VisitRO(this, node, kSSEFloat32Sqrt);
1020}
1021
1022
1023void InstructionSelector::VisitFloat64Sqrt(Node* node) {
1024 VisitRO(this, node, kSSEFloat64Sqrt);
1025}
1026
1027
1028void InstructionSelector::VisitFloat32RoundDown(Node* node) {
1029 VisitRR(this, node, kSSEFloat32Round | MiscField::encode(kRoundDown));
1030}
1031
1032
1033void InstructionSelector::VisitFloat64RoundDown(Node* node) {
1034 VisitRR(this, node, kSSEFloat64Round | MiscField::encode(kRoundDown));
1035}
1036
1037
1038void InstructionSelector::VisitFloat32RoundUp(Node* node) {
1039 VisitRR(this, node, kSSEFloat32Round | MiscField::encode(kRoundUp));
1040}
1041
1042
1043void InstructionSelector::VisitFloat64RoundUp(Node* node) {
1044 VisitRR(this, node, kSSEFloat64Round | MiscField::encode(kRoundUp));
1045}
1046
1047
1048void InstructionSelector::VisitFloat32RoundTruncate(Node* node) {
1049 VisitRR(this, node, kSSEFloat32Round | MiscField::encode(kRoundToZero));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001050}
1051
1052
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001053void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001054 VisitRR(this, node, kSSEFloat64Round | MiscField::encode(kRoundToZero));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001055}
1056
1057
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001058void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
1059 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001060}
1061
1062
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001063void InstructionSelector::VisitFloat32RoundTiesEven(Node* node) {
1064 VisitRR(this, node, kSSEFloat32Round | MiscField::encode(kRoundToNearest));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001065}
1066
1067
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001068void InstructionSelector::VisitFloat64RoundTiesEven(Node* node) {
1069 VisitRR(this, node, kSSEFloat64Round | MiscField::encode(kRoundToNearest));
1070}
1071
1072
1073void InstructionSelector::EmitPrepareArguments(
1074 ZoneVector<PushParameter>* arguments, const CallDescriptor* descriptor,
1075 Node* node) {
1076 IA32OperandGenerator g(this);
1077
1078 // Prepare for C function call.
1079 if (descriptor->IsCFunctionCall()) {
1080 InstructionOperand temps[] = {g.TempRegister()};
1081 size_t const temp_count = arraysize(temps);
1082 Emit(kArchPrepareCallCFunction |
1083 MiscField::encode(static_cast<int>(descriptor->CParameterCount())),
1084 0, nullptr, 0, nullptr, temp_count, temps);
1085
1086 // Poke any stack arguments.
1087 for (size_t n = 0; n < arguments->size(); ++n) {
1088 PushParameter input = (*arguments)[n];
1089 if (input.node()) {
1090 int const slot = static_cast<int>(n);
1091 InstructionOperand value = g.CanBeImmediate(node)
1092 ? g.UseImmediate(input.node())
1093 : g.UseRegister(input.node());
1094 Emit(kIA32Poke | MiscField::encode(slot), g.NoOutput(), value);
1095 }
1096 }
1097 } else {
1098 // Push any stack arguments.
1099 for (PushParameter input : base::Reversed(*arguments)) {
1100 // Skip any alignment holes in pushed nodes.
1101 if (input.node() == nullptr) continue;
1102 InstructionOperand value =
1103 g.CanBeImmediate(input.node())
1104 ? g.UseImmediate(input.node())
1105 : IsSupported(ATOM) ||
1106 sequence()->IsFloat(GetVirtualRegister(input.node()))
1107 ? g.UseRegister(input.node())
1108 : g.Use(input.node());
1109 if (input.type() == MachineType::Float32()) {
1110 Emit(kIA32PushFloat32, g.NoOutput(), value);
1111 } else if (input.type() == MachineType::Float64()) {
1112 Emit(kIA32PushFloat64, g.NoOutput(), value);
1113 } else {
1114 Emit(kIA32Push, g.NoOutput(), value);
1115 }
1116 }
1117 }
1118}
1119
1120
1121bool InstructionSelector::IsTailCallAddressImmediate() { return true; }
1122
Ben Murdochda12d292016-06-02 14:46:10 +01001123int InstructionSelector::GetTempsCountForTailCallFromJSFunction() { return 0; }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001124
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001125namespace {
1126
Ben Murdoch097c5b22016-05-18 11:27:45 +01001127void VisitCompareWithMemoryOperand(InstructionSelector* selector,
1128 InstructionCode opcode, Node* left,
1129 InstructionOperand right,
1130 FlagsContinuation* cont) {
1131 DCHECK(left->opcode() == IrOpcode::kLoad);
1132 IA32OperandGenerator g(selector);
1133 size_t input_count = 0;
1134 InstructionOperand inputs[6];
1135 AddressingMode addressing_mode =
1136 g.GetEffectiveAddressMemoryOperand(left, inputs, &input_count);
1137 opcode |= AddressingModeField::encode(addressing_mode);
1138 opcode = cont->Encode(opcode);
1139 inputs[input_count++] = right;
1140
1141 if (cont->IsBranch()) {
1142 inputs[input_count++] = g.Label(cont->true_block());
1143 inputs[input_count++] = g.Label(cont->false_block());
1144 selector->Emit(opcode, 0, nullptr, input_count, inputs);
Ben Murdochda12d292016-06-02 14:46:10 +01001145 } else if (cont->IsDeoptimize()) {
1146 selector->EmitDeoptimize(opcode, 0, nullptr, input_count, inputs,
1147 cont->frame_state());
Ben Murdoch097c5b22016-05-18 11:27:45 +01001148 } else {
1149 DCHECK(cont->IsSet());
1150 InstructionOperand output = g.DefineAsRegister(cont->result());
1151 selector->Emit(opcode, 1, &output, input_count, inputs);
1152 }
1153}
1154
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001155// Shared routine for multiple compare operations.
1156void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001157 InstructionOperand left, InstructionOperand right,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001158 FlagsContinuation* cont) {
1159 IA32OperandGenerator g(selector);
Ben Murdochda12d292016-06-02 14:46:10 +01001160 opcode = cont->Encode(opcode);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001161 if (cont->IsBranch()) {
Ben Murdochda12d292016-06-02 14:46:10 +01001162 selector->Emit(opcode, g.NoOutput(), left, right,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001163 g.Label(cont->true_block()), g.Label(cont->false_block()));
Ben Murdochda12d292016-06-02 14:46:10 +01001164 } else if (cont->IsDeoptimize()) {
1165 selector->EmitDeoptimize(opcode, g.NoOutput(), left, right,
1166 cont->frame_state());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001167 } else {
1168 DCHECK(cont->IsSet());
Ben Murdochda12d292016-06-02 14:46:10 +01001169 selector->Emit(opcode, g.DefineAsByteRegister(cont->result()), left, right);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001170 }
1171}
1172
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001173
1174// Shared routine for multiple compare operations.
1175void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
1176 Node* left, Node* right, FlagsContinuation* cont,
1177 bool commutative) {
1178 IA32OperandGenerator g(selector);
1179 if (commutative && g.CanBeBetterLeftOperand(right)) {
1180 std::swap(left, right);
1181 }
1182 VisitCompare(selector, opcode, g.UseRegister(left), g.Use(right), cont);
1183}
1184
Ben Murdochda12d292016-06-02 14:46:10 +01001185// Tries to match the size of the given opcode to that of the operands, if
1186// possible.
1187InstructionCode TryNarrowOpcodeSize(InstructionCode opcode, Node* left,
1188 Node* right) {
1189 if (opcode != kIA32Cmp && opcode != kIA32Test) {
1190 return opcode;
1191 }
1192 // Currently, if one of the two operands is not a Load, we don't know what its
1193 // machine representation is, so we bail out.
1194 // TODO(epertoso): we can probably get some size information out of immediates
1195 // and phi nodes.
1196 if (left->opcode() != IrOpcode::kLoad || right->opcode() != IrOpcode::kLoad) {
1197 return opcode;
1198 }
1199 // If the load representations don't match, both operands will be
1200 // zero/sign-extended to 32bit.
1201 LoadRepresentation left_representation = LoadRepresentationOf(left->op());
1202 if (left_representation != LoadRepresentationOf(right->op())) {
1203 return opcode;
1204 }
1205 switch (left_representation.representation()) {
1206 case MachineRepresentation::kBit:
1207 case MachineRepresentation::kWord8:
1208 return opcode == kIA32Cmp ? kIA32Cmp8 : kIA32Test8;
1209 case MachineRepresentation::kWord16:
1210 return opcode == kIA32Cmp ? kIA32Cmp16 : kIA32Test16;
1211 default:
1212 return opcode;
1213 }
1214}
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001215
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001216// Shared routine for multiple float32 compare operations (inputs commuted).
1217void VisitFloat32Compare(InstructionSelector* selector, Node* node,
1218 FlagsContinuation* cont) {
1219 Node* const left = node->InputAt(0);
1220 Node* const right = node->InputAt(1);
1221 VisitCompare(selector, kSSEFloat32Cmp, right, left, cont, false);
1222}
1223
1224
1225// Shared routine for multiple float64 compare operations (inputs commuted).
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001226void VisitFloat64Compare(InstructionSelector* selector, Node* node,
1227 FlagsContinuation* cont) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001228 Node* const left = node->InputAt(0);
1229 Node* const right = node->InputAt(1);
1230 VisitCompare(selector, kSSEFloat64Cmp, right, left, cont, false);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001231}
1232
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001233// Shared routine for multiple word compare operations.
1234void VisitWordCompare(InstructionSelector* selector, Node* node,
1235 InstructionCode opcode, FlagsContinuation* cont) {
1236 IA32OperandGenerator g(selector);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001237 Node* left = node->InputAt(0);
1238 Node* right = node->InputAt(1);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001239
Ben Murdochda12d292016-06-02 14:46:10 +01001240 InstructionCode narrowed_opcode = TryNarrowOpcodeSize(opcode, left, right);
1241
Ben Murdochc5610432016-08-08 18:44:38 +01001242 int effect_level = selector->GetEffectLevel(node);
1243 if (cont->IsBranch()) {
1244 effect_level = selector->GetEffectLevel(
1245 cont->true_block()->PredecessorAt(0)->control_input());
1246 }
1247
Ben Murdochda12d292016-06-02 14:46:10 +01001248 // If one of the two inputs is an immediate, make sure it's on the right, or
1249 // if one of the two inputs is a memory operand, make sure it's on the left.
1250 if ((!g.CanBeImmediate(right) && g.CanBeImmediate(left)) ||
Ben Murdochc5610432016-08-08 18:44:38 +01001251 (g.CanBeMemoryOperand(narrowed_opcode, node, right, effect_level) &&
1252 !g.CanBeMemoryOperand(narrowed_opcode, node, left, effect_level))) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001253 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001254 std::swap(left, right);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001255 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001256
Ben Murdoch097c5b22016-05-18 11:27:45 +01001257 // Match immediates on right side of comparison.
1258 if (g.CanBeImmediate(right)) {
Ben Murdochc5610432016-08-08 18:44:38 +01001259 if (g.CanBeMemoryOperand(opcode, node, left, effect_level)) {
Ben Murdochda12d292016-06-02 14:46:10 +01001260 // TODO(epertoso): we should use `narrowed_opcode' here once we match
1261 // immediates too.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001262 return VisitCompareWithMemoryOperand(selector, opcode, left,
1263 g.UseImmediate(right), cont);
1264 }
1265 return VisitCompare(selector, opcode, g.Use(left), g.UseImmediate(right),
1266 cont);
1267 }
1268
Ben Murdochda12d292016-06-02 14:46:10 +01001269 // Match memory operands on left side of comparison.
Ben Murdochc5610432016-08-08 18:44:38 +01001270 if (g.CanBeMemoryOperand(narrowed_opcode, node, left, effect_level)) {
Ben Murdochda12d292016-06-02 14:46:10 +01001271 bool needs_byte_register =
1272 narrowed_opcode == kIA32Test8 || narrowed_opcode == kIA32Cmp8;
1273 return VisitCompareWithMemoryOperand(
1274 selector, narrowed_opcode, left,
1275 needs_byte_register ? g.UseByteRegister(right) : g.UseRegister(right),
1276 cont);
1277 }
1278
Ben Murdoch097c5b22016-05-18 11:27:45 +01001279 if (g.CanBeBetterLeftOperand(right)) {
1280 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
1281 std::swap(left, right);
1282 }
1283
Ben Murdoch097c5b22016-05-18 11:27:45 +01001284 return VisitCompare(selector, opcode, left, right, cont,
1285 node->op()->HasProperty(Operator::kCommutative));
1286}
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001287
1288void VisitWordCompare(InstructionSelector* selector, Node* node,
1289 FlagsContinuation* cont) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001290 IA32OperandGenerator g(selector);
1291 Int32BinopMatcher m(node);
1292 if (m.left().IsLoad() && m.right().IsLoadStackPointer()) {
1293 LoadMatcher<ExternalReferenceMatcher> mleft(m.left().node());
1294 ExternalReference js_stack_limit =
1295 ExternalReference::address_of_stack_limit(selector->isolate());
1296 if (mleft.object().Is(js_stack_limit) && mleft.index().Is(0)) {
1297 // Compare(Load(js_stack_limit), LoadStackPointer)
1298 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
1299 InstructionCode opcode = cont->Encode(kIA32StackCheck);
1300 if (cont->IsBranch()) {
1301 selector->Emit(opcode, g.NoOutput(), g.Label(cont->true_block()),
1302 g.Label(cont->false_block()));
Ben Murdochda12d292016-06-02 14:46:10 +01001303 } else if (cont->IsDeoptimize()) {
1304 selector->EmitDeoptimize(opcode, 0, nullptr, 0, nullptr,
1305 cont->frame_state());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001306 } else {
1307 DCHECK(cont->IsSet());
1308 selector->Emit(opcode, g.DefineAsRegister(cont->result()));
1309 }
1310 return;
1311 }
1312 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001313 VisitWordCompare(selector, node, kIA32Cmp, cont);
1314}
1315
1316
1317// Shared routine for word comparison with zero.
1318void VisitWordCompareZero(InstructionSelector* selector, Node* user,
1319 Node* value, FlagsContinuation* cont) {
1320 // Try to combine the branch with a comparison.
1321 while (selector->CanCover(user, value)) {
1322 switch (value->opcode()) {
1323 case IrOpcode::kWord32Equal: {
1324 // Try to combine with comparisons against 0 by simply inverting the
1325 // continuation.
1326 Int32BinopMatcher m(value);
1327 if (m.right().Is(0)) {
1328 user = value;
1329 value = m.left().node();
1330 cont->Negate();
1331 continue;
1332 }
1333 cont->OverwriteAndNegateIfEqual(kEqual);
1334 return VisitWordCompare(selector, value, cont);
1335 }
1336 case IrOpcode::kInt32LessThan:
1337 cont->OverwriteAndNegateIfEqual(kSignedLessThan);
1338 return VisitWordCompare(selector, value, cont);
1339 case IrOpcode::kInt32LessThanOrEqual:
1340 cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
1341 return VisitWordCompare(selector, value, cont);
1342 case IrOpcode::kUint32LessThan:
1343 cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
1344 return VisitWordCompare(selector, value, cont);
1345 case IrOpcode::kUint32LessThanOrEqual:
1346 cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
1347 return VisitWordCompare(selector, value, cont);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001348 case IrOpcode::kFloat32Equal:
1349 cont->OverwriteAndNegateIfEqual(kUnorderedEqual);
1350 return VisitFloat32Compare(selector, value, cont);
1351 case IrOpcode::kFloat32LessThan:
1352 cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThan);
1353 return VisitFloat32Compare(selector, value, cont);
1354 case IrOpcode::kFloat32LessThanOrEqual:
1355 cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThanOrEqual);
1356 return VisitFloat32Compare(selector, value, cont);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001357 case IrOpcode::kFloat64Equal:
1358 cont->OverwriteAndNegateIfEqual(kUnorderedEqual);
1359 return VisitFloat64Compare(selector, value, cont);
1360 case IrOpcode::kFloat64LessThan:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001361 cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThan);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001362 return VisitFloat64Compare(selector, value, cont);
1363 case IrOpcode::kFloat64LessThanOrEqual:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001364 cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThanOrEqual);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001365 return VisitFloat64Compare(selector, value, cont);
1366 case IrOpcode::kProjection:
1367 // Check if this is the overflow output projection of an
1368 // <Operation>WithOverflow node.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001369 if (ProjectionIndexOf(value->op()) == 1u) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001370 // We cannot combine the <Operation>WithOverflow with this branch
1371 // unless the 0th projection (the use of the actual value of the
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001372 // <Operation> is either nullptr, which means there's no use of the
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001373 // actual value, or was already defined, which means it is scheduled
1374 // *AFTER* this branch).
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001375 Node* const node = value->InputAt(0);
1376 Node* const result = NodeProperties::FindProjection(node, 0);
1377 if (result == nullptr || selector->IsDefined(result)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001378 switch (node->opcode()) {
1379 case IrOpcode::kInt32AddWithOverflow:
1380 cont->OverwriteAndNegateIfEqual(kOverflow);
1381 return VisitBinop(selector, node, kIA32Add, cont);
1382 case IrOpcode::kInt32SubWithOverflow:
1383 cont->OverwriteAndNegateIfEqual(kOverflow);
1384 return VisitBinop(selector, node, kIA32Sub, cont);
1385 default:
1386 break;
1387 }
1388 }
1389 }
1390 break;
1391 case IrOpcode::kInt32Sub:
1392 return VisitWordCompare(selector, value, cont);
1393 case IrOpcode::kWord32And:
1394 return VisitWordCompare(selector, value, kIA32Test, cont);
1395 default:
1396 break;
1397 }
1398 break;
1399 }
1400
1401 // Continuation could not be combined with a compare, emit compare against 0.
1402 IA32OperandGenerator g(selector);
1403 VisitCompare(selector, kIA32Cmp, g.Use(value), g.TempImmediate(0), cont);
1404}
1405
1406} // namespace
1407
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001408void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
1409 BasicBlock* fbranch) {
1410 FlagsContinuation cont(kNotEqual, tbranch, fbranch);
1411 VisitWordCompareZero(this, branch, branch->InputAt(0), &cont);
1412}
1413
Ben Murdochda12d292016-06-02 14:46:10 +01001414void InstructionSelector::VisitDeoptimizeIf(Node* node) {
1415 FlagsContinuation cont =
1416 FlagsContinuation::ForDeoptimize(kNotEqual, node->InputAt(1));
1417 VisitWordCompareZero(this, node, node->InputAt(0), &cont);
1418}
1419
1420void InstructionSelector::VisitDeoptimizeUnless(Node* node) {
1421 FlagsContinuation cont =
1422 FlagsContinuation::ForDeoptimize(kEqual, node->InputAt(1));
1423 VisitWordCompareZero(this, node, node->InputAt(0), &cont);
1424}
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001425
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001426void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
1427 IA32OperandGenerator g(this);
1428 InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
1429
1430 // Emit either ArchTableSwitch or ArchLookupSwitch.
1431 size_t table_space_cost = 4 + sw.value_range;
1432 size_t table_time_cost = 3;
1433 size_t lookup_space_cost = 3 + 2 * sw.case_count;
1434 size_t lookup_time_cost = sw.case_count;
1435 if (sw.case_count > 4 &&
1436 table_space_cost + 3 * table_time_cost <=
1437 lookup_space_cost + 3 * lookup_time_cost &&
1438 sw.min_value > std::numeric_limits<int32_t>::min()) {
1439 InstructionOperand index_operand = value_operand;
1440 if (sw.min_value) {
1441 index_operand = g.TempRegister();
1442 Emit(kIA32Lea | AddressingModeField::encode(kMode_MRI), index_operand,
1443 value_operand, g.TempImmediate(-sw.min_value));
1444 }
1445 // Generate a table lookup.
1446 return EmitTableSwitch(sw, index_operand);
1447 }
1448
1449 // Generate a sequence of conditional jumps.
1450 return EmitLookupSwitch(sw, value_operand);
1451}
1452
1453
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001454void InstructionSelector::VisitWord32Equal(Node* const node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001455 FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001456 Int32BinopMatcher m(node);
1457 if (m.right().Is(0)) {
1458 return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
1459 }
1460 VisitWordCompare(this, node, &cont);
1461}
1462
1463
1464void InstructionSelector::VisitInt32LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001465 FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001466 VisitWordCompare(this, node, &cont);
1467}
1468
1469
1470void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001471 FlagsContinuation cont =
1472 FlagsContinuation::ForSet(kSignedLessThanOrEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001473 VisitWordCompare(this, node, &cont);
1474}
1475
1476
1477void InstructionSelector::VisitUint32LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001478 FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001479 VisitWordCompare(this, node, &cont);
1480}
1481
1482
1483void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001484 FlagsContinuation cont =
1485 FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001486 VisitWordCompare(this, node, &cont);
1487}
1488
1489
1490void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001491 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
Ben Murdochda12d292016-06-02 14:46:10 +01001492 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001493 return VisitBinop(this, node, kIA32Add, &cont);
1494 }
1495 FlagsContinuation cont;
1496 VisitBinop(this, node, kIA32Add, &cont);
1497}
1498
1499
1500void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001501 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
Ben Murdochda12d292016-06-02 14:46:10 +01001502 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001503 return VisitBinop(this, node, kIA32Sub, &cont);
1504 }
1505 FlagsContinuation cont;
1506 VisitBinop(this, node, kIA32Sub, &cont);
1507}
1508
1509
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001510void InstructionSelector::VisitFloat32Equal(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001511 FlagsContinuation cont = FlagsContinuation::ForSet(kUnorderedEqual, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001512 VisitFloat32Compare(this, node, &cont);
1513}
1514
1515
1516void InstructionSelector::VisitFloat32LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001517 FlagsContinuation cont =
1518 FlagsContinuation::ForSet(kUnsignedGreaterThan, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001519 VisitFloat32Compare(this, node, &cont);
1520}
1521
1522
1523void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001524 FlagsContinuation cont =
1525 FlagsContinuation::ForSet(kUnsignedGreaterThanOrEqual, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001526 VisitFloat32Compare(this, node, &cont);
1527}
1528
1529
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001530void InstructionSelector::VisitFloat64Equal(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001531 FlagsContinuation cont = FlagsContinuation::ForSet(kUnorderedEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001532 VisitFloat64Compare(this, node, &cont);
1533}
1534
1535
1536void InstructionSelector::VisitFloat64LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001537 FlagsContinuation cont =
1538 FlagsContinuation::ForSet(kUnsignedGreaterThan, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001539 VisitFloat64Compare(this, node, &cont);
1540}
1541
1542
1543void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001544 FlagsContinuation cont =
1545 FlagsContinuation::ForSet(kUnsignedGreaterThanOrEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001546 VisitFloat64Compare(this, node, &cont);
1547}
1548
1549
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001550void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) {
1551 IA32OperandGenerator g(this);
1552 Emit(kSSEFloat64ExtractLowWord32, g.DefineAsRegister(node),
1553 g.Use(node->InputAt(0)));
1554}
1555
1556
1557void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) {
1558 IA32OperandGenerator g(this);
1559 Emit(kSSEFloat64ExtractHighWord32, g.DefineAsRegister(node),
1560 g.Use(node->InputAt(0)));
1561}
1562
1563
1564void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) {
1565 IA32OperandGenerator g(this);
1566 Node* left = node->InputAt(0);
1567 Node* right = node->InputAt(1);
1568 Float64Matcher mleft(left);
1569 if (mleft.HasValue() && (bit_cast<uint64_t>(mleft.Value()) >> 32) == 0u) {
1570 Emit(kSSEFloat64LoadLowWord32, g.DefineAsRegister(node), g.Use(right));
1571 return;
1572 }
1573 Emit(kSSEFloat64InsertLowWord32, g.DefineSameAsFirst(node),
1574 g.UseRegister(left), g.Use(right));
1575}
1576
1577
1578void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
1579 IA32OperandGenerator g(this);
1580 Node* left = node->InputAt(0);
1581 Node* right = node->InputAt(1);
1582 Emit(kSSEFloat64InsertHighWord32, g.DefineSameAsFirst(node),
1583 g.UseRegister(left), g.Use(right));
1584}
1585
Ben Murdochc5610432016-08-08 18:44:38 +01001586void InstructionSelector::VisitAtomicLoad(Node* node) {
1587 LoadRepresentation load_rep = LoadRepresentationOf(node->op());
1588 DCHECK(load_rep.representation() == MachineRepresentation::kWord8 ||
1589 load_rep.representation() == MachineRepresentation::kWord16 ||
1590 load_rep.representation() == MachineRepresentation::kWord32);
1591 USE(load_rep);
1592 VisitLoad(node);
1593}
1594
1595void InstructionSelector::VisitAtomicStore(Node* node) {
1596 IA32OperandGenerator g(this);
1597 Node* base = node->InputAt(0);
1598 Node* index = node->InputAt(1);
1599 Node* value = node->InputAt(2);
1600
1601 MachineRepresentation rep = AtomicStoreRepresentationOf(node->op());
1602 ArchOpcode opcode = kArchNop;
1603 switch (rep) {
1604 case MachineRepresentation::kWord8:
1605 opcode = kIA32Xchgb;
1606 break;
1607 case MachineRepresentation::kWord16:
1608 opcode = kIA32Xchgw;
1609 break;
1610 case MachineRepresentation::kWord32:
1611 opcode = kIA32Xchgl;
1612 break;
1613 default:
1614 UNREACHABLE();
1615 break;
1616 }
1617 AddressingMode addressing_mode;
1618 InstructionOperand inputs[4];
1619 size_t input_count = 0;
1620 inputs[input_count++] = g.UseUniqueRegister(base);
1621 if (g.CanBeImmediate(index)) {
1622 inputs[input_count++] = g.UseImmediate(index);
1623 addressing_mode = kMode_MRI;
1624 } else {
1625 inputs[input_count++] = g.UseUniqueRegister(index);
1626 addressing_mode = kMode_MR1;
1627 }
1628 inputs[input_count++] = g.UseUniqueRegister(value);
1629 InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
1630 Emit(code, 0, nullptr, input_count, inputs);
1631}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001632
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001633// static
1634MachineOperatorBuilder::Flags
1635InstructionSelector::SupportedMachineOperatorFlags() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001636 MachineOperatorBuilder::Flags flags =
1637 MachineOperatorBuilder::kFloat32Max |
1638 MachineOperatorBuilder::kFloat32Min |
1639 MachineOperatorBuilder::kFloat64Max |
1640 MachineOperatorBuilder::kFloat64Min |
1641 MachineOperatorBuilder::kWord32ShiftIsSafe |
1642 MachineOperatorBuilder::kWord32Ctz;
1643 if (CpuFeatures::IsSupported(POPCNT)) {
1644 flags |= MachineOperatorBuilder::kWord32Popcnt;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001645 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001646 if (CpuFeatures::IsSupported(SSE4_1)) {
1647 flags |= MachineOperatorBuilder::kFloat32RoundDown |
1648 MachineOperatorBuilder::kFloat64RoundDown |
1649 MachineOperatorBuilder::kFloat32RoundUp |
1650 MachineOperatorBuilder::kFloat64RoundUp |
1651 MachineOperatorBuilder::kFloat32RoundTruncate |
1652 MachineOperatorBuilder::kFloat64RoundTruncate |
1653 MachineOperatorBuilder::kFloat32RoundTiesEven |
1654 MachineOperatorBuilder::kFloat64RoundTiesEven;
1655 }
1656 return flags;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001657}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001658
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001659} // namespace compiler
1660} // namespace internal
1661} // namespace v8