blob: e4d085ee9c0b674b1379600fe7b2119318b70488 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// Copyright 2014 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/base/adapters.h"
6#include "src/compiler/instruction-selector-impl.h"
7#include "src/compiler/node-matchers.h"
8#include "src/compiler/node-properties.h"
9
10namespace v8 {
11namespace internal {
12namespace compiler {
13
14// Adds X87-specific methods for generating operands.
15class X87OperandGenerator final : public OperandGenerator {
16 public:
17 explicit X87OperandGenerator(InstructionSelector* selector)
18 : OperandGenerator(selector) {}
19
20 InstructionOperand UseByteRegister(Node* node) {
21 // TODO(titzer): encode byte register use constraints.
22 return UseFixed(node, edx);
23 }
24
25 InstructionOperand DefineAsByteRegister(Node* node) {
26 // TODO(titzer): encode byte register def constraints.
27 return DefineAsRegister(node);
28 }
29
Ben Murdochda12d292016-06-02 14:46:10 +010030 bool CanBeMemoryOperand(InstructionCode opcode, Node* node, Node* input) {
31 if (input->opcode() != IrOpcode::kLoad ||
32 !selector()->CanCover(node, input)) {
33 return false;
34 }
35 MachineRepresentation rep =
36 LoadRepresentationOf(input->op()).representation();
37 switch (opcode) {
38 case kX87Cmp:
39 case kX87Test:
40 return rep == MachineRepresentation::kWord32 ||
41 rep == MachineRepresentation::kTagged;
42 case kX87Cmp16:
43 case kX87Test16:
44 return rep == MachineRepresentation::kWord16;
45 case kX87Cmp8:
46 case kX87Test8:
47 return rep == MachineRepresentation::kWord8;
48 default:
49 break;
50 }
51 return false;
52 }
53
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000054 InstructionOperand CreateImmediate(int imm) {
55 return sequence()->AddImmediate(Constant(imm));
56 }
57
58 bool CanBeImmediate(Node* node) {
59 switch (node->opcode()) {
60 case IrOpcode::kInt32Constant:
61 case IrOpcode::kNumberConstant:
62 case IrOpcode::kExternalConstant:
63 return true;
64 case IrOpcode::kHeapConstant: {
65 // Constants in new space cannot be used as immediates in V8 because
66 // the GC does not scan code objects when collecting the new generation.
67 Handle<HeapObject> value = OpParameter<Handle<HeapObject>>(node);
68 Isolate* isolate = value->GetIsolate();
69 return !isolate->heap()->InNewSpace(*value);
70 }
71 default:
72 return false;
73 }
74 }
75
76 AddressingMode GenerateMemoryOperandInputs(Node* index, int scale, Node* base,
77 Node* displacement_node,
78 InstructionOperand inputs[],
79 size_t* input_count) {
80 AddressingMode mode = kMode_MRI;
81 int32_t displacement = (displacement_node == nullptr)
82 ? 0
83 : OpParameter<int32_t>(displacement_node);
84 if (base != nullptr) {
85 if (base->opcode() == IrOpcode::kInt32Constant) {
86 displacement += OpParameter<int32_t>(base);
87 base = nullptr;
88 }
89 }
90 if (base != nullptr) {
91 inputs[(*input_count)++] = UseRegister(base);
92 if (index != nullptr) {
93 DCHECK(scale >= 0 && scale <= 3);
94 inputs[(*input_count)++] = UseRegister(index);
95 if (displacement != 0) {
96 inputs[(*input_count)++] = TempImmediate(displacement);
97 static const AddressingMode kMRnI_modes[] = {kMode_MR1I, kMode_MR2I,
98 kMode_MR4I, kMode_MR8I};
99 mode = kMRnI_modes[scale];
100 } else {
101 static const AddressingMode kMRn_modes[] = {kMode_MR1, kMode_MR2,
102 kMode_MR4, kMode_MR8};
103 mode = kMRn_modes[scale];
104 }
105 } else {
106 if (displacement == 0) {
107 mode = kMode_MR;
108 } else {
109 inputs[(*input_count)++] = TempImmediate(displacement);
110 mode = kMode_MRI;
111 }
112 }
113 } else {
114 DCHECK(scale >= 0 && scale <= 3);
115 if (index != nullptr) {
116 inputs[(*input_count)++] = UseRegister(index);
117 if (displacement != 0) {
118 inputs[(*input_count)++] = TempImmediate(displacement);
119 static const AddressingMode kMnI_modes[] = {kMode_MRI, kMode_M2I,
120 kMode_M4I, kMode_M8I};
121 mode = kMnI_modes[scale];
122 } else {
123 static const AddressingMode kMn_modes[] = {kMode_MR, kMode_M2,
124 kMode_M4, kMode_M8};
125 mode = kMn_modes[scale];
126 }
127 } else {
128 inputs[(*input_count)++] = TempImmediate(displacement);
129 return kMode_MI;
130 }
131 }
132 return mode;
133 }
134
135 AddressingMode GetEffectiveAddressMemoryOperand(Node* node,
136 InstructionOperand inputs[],
137 size_t* input_count) {
138 BaseWithIndexAndDisplacement32Matcher m(node, true);
139 DCHECK(m.matches());
140 if ((m.displacement() == nullptr || CanBeImmediate(m.displacement()))) {
141 return GenerateMemoryOperandInputs(m.index(), m.scale(), m.base(),
142 m.displacement(), inputs, input_count);
143 } else {
144 inputs[(*input_count)++] = UseRegister(node->InputAt(0));
145 inputs[(*input_count)++] = UseRegister(node->InputAt(1));
146 return kMode_MR1;
147 }
148 }
149
150 bool CanBeBetterLeftOperand(Node* node) const {
151 return !selector()->IsLive(node);
152 }
153};
154
155
156void InstructionSelector::VisitLoad(Node* node) {
157 LoadRepresentation load_rep = LoadRepresentationOf(node->op());
158
159 ArchOpcode opcode = kArchNop;
160 switch (load_rep.representation()) {
161 case MachineRepresentation::kFloat32:
162 opcode = kX87Movss;
163 break;
164 case MachineRepresentation::kFloat64:
165 opcode = kX87Movsd;
166 break;
167 case MachineRepresentation::kBit: // Fall through.
168 case MachineRepresentation::kWord8:
169 opcode = load_rep.IsSigned() ? kX87Movsxbl : kX87Movzxbl;
170 break;
171 case MachineRepresentation::kWord16:
172 opcode = load_rep.IsSigned() ? kX87Movsxwl : kX87Movzxwl;
173 break;
174 case MachineRepresentation::kTagged: // Fall through.
175 case MachineRepresentation::kWord32:
176 opcode = kX87Movl;
177 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100178 case MachineRepresentation::kWord64: // Fall through.
179 case MachineRepresentation::kSimd128: // Fall through.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000180 case MachineRepresentation::kNone:
181 UNREACHABLE();
182 return;
183 }
184
185 X87OperandGenerator g(this);
186 InstructionOperand outputs[1];
187 outputs[0] = g.DefineAsRegister(node);
188 InstructionOperand inputs[3];
189 size_t input_count = 0;
190 AddressingMode mode =
191 g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count);
192 InstructionCode code = opcode | AddressingModeField::encode(mode);
193 Emit(code, 1, outputs, input_count, inputs);
194}
195
196
197void InstructionSelector::VisitStore(Node* node) {
198 X87OperandGenerator g(this);
199 Node* base = node->InputAt(0);
200 Node* index = node->InputAt(1);
201 Node* value = node->InputAt(2);
202
203 StoreRepresentation store_rep = StoreRepresentationOf(node->op());
204 WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind();
205 MachineRepresentation rep = store_rep.representation();
206
207 if (write_barrier_kind != kNoWriteBarrier) {
208 DCHECK_EQ(MachineRepresentation::kTagged, rep);
209 AddressingMode addressing_mode;
210 InstructionOperand inputs[3];
211 size_t input_count = 0;
212 inputs[input_count++] = g.UseUniqueRegister(base);
213 if (g.CanBeImmediate(index)) {
214 inputs[input_count++] = g.UseImmediate(index);
215 addressing_mode = kMode_MRI;
216 } else {
217 inputs[input_count++] = g.UseUniqueRegister(index);
218 addressing_mode = kMode_MR1;
219 }
Ben Murdochda12d292016-06-02 14:46:10 +0100220 inputs[input_count++] = g.UseUniqueRegister(value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000221 RecordWriteMode record_write_mode = RecordWriteMode::kValueIsAny;
222 switch (write_barrier_kind) {
223 case kNoWriteBarrier:
224 UNREACHABLE();
225 break;
226 case kMapWriteBarrier:
227 record_write_mode = RecordWriteMode::kValueIsMap;
228 break;
229 case kPointerWriteBarrier:
230 record_write_mode = RecordWriteMode::kValueIsPointer;
231 break;
232 case kFullWriteBarrier:
233 record_write_mode = RecordWriteMode::kValueIsAny;
234 break;
235 }
236 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
237 size_t const temp_count = arraysize(temps);
238 InstructionCode code = kArchStoreWithWriteBarrier;
239 code |= AddressingModeField::encode(addressing_mode);
240 code |= MiscField::encode(static_cast<int>(record_write_mode));
241 Emit(code, 0, nullptr, input_count, inputs, temp_count, temps);
242 } else {
243 ArchOpcode opcode = kArchNop;
244 switch (rep) {
245 case MachineRepresentation::kFloat32:
246 opcode = kX87Movss;
247 break;
248 case MachineRepresentation::kFloat64:
249 opcode = kX87Movsd;
250 break;
251 case MachineRepresentation::kBit: // Fall through.
252 case MachineRepresentation::kWord8:
253 opcode = kX87Movb;
254 break;
255 case MachineRepresentation::kWord16:
256 opcode = kX87Movw;
257 break;
258 case MachineRepresentation::kTagged: // Fall through.
259 case MachineRepresentation::kWord32:
260 opcode = kX87Movl;
261 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100262 case MachineRepresentation::kWord64: // Fall through.
263 case MachineRepresentation::kSimd128: // Fall through.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000264 case MachineRepresentation::kNone:
265 UNREACHABLE();
266 return;
267 }
268
269 InstructionOperand val;
270 if (g.CanBeImmediate(value)) {
271 val = g.UseImmediate(value);
272 } else if (rep == MachineRepresentation::kWord8 ||
273 rep == MachineRepresentation::kBit) {
274 val = g.UseByteRegister(value);
275 } else {
276 val = g.UseRegister(value);
277 }
278
279 InstructionOperand inputs[4];
280 size_t input_count = 0;
281 AddressingMode addressing_mode =
282 g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count);
283 InstructionCode code =
284 opcode | AddressingModeField::encode(addressing_mode);
285 inputs[input_count++] = val;
286 Emit(code, 0, static_cast<InstructionOperand*>(nullptr), input_count,
287 inputs);
288 }
289}
290
291
292void InstructionSelector::VisitCheckedLoad(Node* node) {
293 CheckedLoadRepresentation load_rep = CheckedLoadRepresentationOf(node->op());
294 X87OperandGenerator g(this);
295 Node* const buffer = node->InputAt(0);
296 Node* const offset = node->InputAt(1);
297 Node* const length = node->InputAt(2);
298 ArchOpcode opcode = kArchNop;
299 switch (load_rep.representation()) {
300 case MachineRepresentation::kWord8:
301 opcode = load_rep.IsSigned() ? kCheckedLoadInt8 : kCheckedLoadUint8;
302 break;
303 case MachineRepresentation::kWord16:
304 opcode = load_rep.IsSigned() ? kCheckedLoadInt16 : kCheckedLoadUint16;
305 break;
306 case MachineRepresentation::kWord32:
307 opcode = kCheckedLoadWord32;
308 break;
309 case MachineRepresentation::kFloat32:
310 opcode = kCheckedLoadFloat32;
311 break;
312 case MachineRepresentation::kFloat64:
313 opcode = kCheckedLoadFloat64;
314 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100315 case MachineRepresentation::kBit: // Fall through.
316 case MachineRepresentation::kTagged: // Fall through.
317 case MachineRepresentation::kWord64: // Fall through.
318 case MachineRepresentation::kSimd128: // Fall through.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000319 case MachineRepresentation::kNone:
320 UNREACHABLE();
321 return;
322 }
323 InstructionOperand offset_operand = g.UseRegister(offset);
324 InstructionOperand length_operand =
325 g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length);
326 if (g.CanBeImmediate(buffer)) {
327 Emit(opcode | AddressingModeField::encode(kMode_MRI),
328 g.DefineAsRegister(node), offset_operand, length_operand,
329 offset_operand, g.UseImmediate(buffer));
330 } else {
331 Emit(opcode | AddressingModeField::encode(kMode_MR1),
332 g.DefineAsRegister(node), offset_operand, length_operand,
333 g.UseRegister(buffer), offset_operand);
334 }
335}
336
337
338void InstructionSelector::VisitCheckedStore(Node* node) {
339 MachineRepresentation rep = CheckedStoreRepresentationOf(node->op());
340 X87OperandGenerator g(this);
341 Node* const buffer = node->InputAt(0);
342 Node* const offset = node->InputAt(1);
343 Node* const length = node->InputAt(2);
344 Node* const value = node->InputAt(3);
345 ArchOpcode opcode = kArchNop;
346 switch (rep) {
347 case MachineRepresentation::kWord8:
348 opcode = kCheckedStoreWord8;
349 break;
350 case MachineRepresentation::kWord16:
351 opcode = kCheckedStoreWord16;
352 break;
353 case MachineRepresentation::kWord32:
354 opcode = kCheckedStoreWord32;
355 break;
356 case MachineRepresentation::kFloat32:
357 opcode = kCheckedStoreFloat32;
358 break;
359 case MachineRepresentation::kFloat64:
360 opcode = kCheckedStoreFloat64;
361 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100362 case MachineRepresentation::kBit: // Fall through.
363 case MachineRepresentation::kTagged: // Fall through.
364 case MachineRepresentation::kWord64: // Fall through.
365 case MachineRepresentation::kSimd128: // Fall through.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000366 case MachineRepresentation::kNone:
367 UNREACHABLE();
368 return;
369 }
370 InstructionOperand value_operand =
371 g.CanBeImmediate(value) ? g.UseImmediate(value)
372 : ((rep == MachineRepresentation::kWord8 ||
373 rep == MachineRepresentation::kBit)
374 ? g.UseByteRegister(value)
375 : g.UseRegister(value));
376 InstructionOperand offset_operand = g.UseRegister(offset);
377 InstructionOperand length_operand =
378 g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length);
379 if (g.CanBeImmediate(buffer)) {
380 Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
381 offset_operand, length_operand, value_operand, offset_operand,
382 g.UseImmediate(buffer));
383 } else {
384 Emit(opcode | AddressingModeField::encode(kMode_MR1), g.NoOutput(),
385 offset_operand, length_operand, value_operand, g.UseRegister(buffer),
386 offset_operand);
387 }
388}
389
Ben Murdochda12d292016-06-02 14:46:10 +0100390namespace {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000391
392// Shared routine for multiple binary operations.
Ben Murdochda12d292016-06-02 14:46:10 +0100393void VisitBinop(InstructionSelector* selector, Node* node,
394 InstructionCode opcode, FlagsContinuation* cont) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000395 X87OperandGenerator g(selector);
396 Int32BinopMatcher m(node);
397 Node* left = m.left().node();
398 Node* right = m.right().node();
399 InstructionOperand inputs[4];
400 size_t input_count = 0;
401 InstructionOperand outputs[2];
402 size_t output_count = 0;
403
404 // TODO(turbofan): match complex addressing modes.
405 if (left == right) {
406 // If both inputs refer to the same operand, enforce allocating a register
407 // for both of them to ensure that we don't end up generating code like
408 // this:
409 //
410 // mov eax, [ebp-0x10]
411 // add eax, [ebp-0x10]
412 // jo label
413 InstructionOperand const input = g.UseRegister(left);
414 inputs[input_count++] = input;
415 inputs[input_count++] = input;
416 } else if (g.CanBeImmediate(right)) {
417 inputs[input_count++] = g.UseRegister(left);
418 inputs[input_count++] = g.UseImmediate(right);
419 } else {
420 if (node->op()->HasProperty(Operator::kCommutative) &&
421 g.CanBeBetterLeftOperand(right)) {
422 std::swap(left, right);
423 }
424 inputs[input_count++] = g.UseRegister(left);
425 inputs[input_count++] = g.Use(right);
426 }
427
428 if (cont->IsBranch()) {
429 inputs[input_count++] = g.Label(cont->true_block());
430 inputs[input_count++] = g.Label(cont->false_block());
431 }
432
433 outputs[output_count++] = g.DefineSameAsFirst(node);
434 if (cont->IsSet()) {
435 outputs[output_count++] = g.DefineAsRegister(cont->result());
436 }
437
438 DCHECK_NE(0u, input_count);
439 DCHECK_NE(0u, output_count);
440 DCHECK_GE(arraysize(inputs), input_count);
441 DCHECK_GE(arraysize(outputs), output_count);
442
Ben Murdochda12d292016-06-02 14:46:10 +0100443 opcode = cont->Encode(opcode);
444 if (cont->IsDeoptimize()) {
445 selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
446 cont->frame_state());
447 } else {
448 selector->Emit(opcode, output_count, outputs, input_count, inputs);
449 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000450}
451
452
453// Shared routine for multiple binary operations.
Ben Murdochda12d292016-06-02 14:46:10 +0100454void VisitBinop(InstructionSelector* selector, Node* node,
455 InstructionCode opcode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000456 FlagsContinuation cont;
457 VisitBinop(selector, node, opcode, &cont);
458}
459
Ben Murdochda12d292016-06-02 14:46:10 +0100460} // namespace
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000461
462void InstructionSelector::VisitWord32And(Node* node) {
463 VisitBinop(this, node, kX87And);
464}
465
466
467void InstructionSelector::VisitWord32Or(Node* node) {
468 VisitBinop(this, node, kX87Or);
469}
470
471
472void InstructionSelector::VisitWord32Xor(Node* node) {
473 X87OperandGenerator g(this);
474 Int32BinopMatcher m(node);
475 if (m.right().Is(-1)) {
476 Emit(kX87Not, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()));
477 } else {
478 VisitBinop(this, node, kX87Xor);
479 }
480}
481
482
483// Shared routine for multiple shift operations.
484static inline void VisitShift(InstructionSelector* selector, Node* node,
485 ArchOpcode opcode) {
486 X87OperandGenerator g(selector);
487 Node* left = node->InputAt(0);
488 Node* right = node->InputAt(1);
489
490 if (g.CanBeImmediate(right)) {
491 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
492 g.UseImmediate(right));
493 } else {
494 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
495 g.UseFixed(right, ecx));
496 }
497}
498
499
500namespace {
501
502void VisitMulHigh(InstructionSelector* selector, Node* node,
503 ArchOpcode opcode) {
504 X87OperandGenerator g(selector);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100505 InstructionOperand temps[] = {g.TempRegister(eax)};
506 selector->Emit(
507 opcode, g.DefineAsFixed(node, edx), g.UseFixed(node->InputAt(0), eax),
508 g.UseUniqueRegister(node->InputAt(1)), arraysize(temps), temps);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000509}
510
511
512void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
513 X87OperandGenerator g(selector);
514 InstructionOperand temps[] = {g.TempRegister(edx)};
515 selector->Emit(opcode, g.DefineAsFixed(node, eax),
516 g.UseFixed(node->InputAt(0), eax),
517 g.UseUnique(node->InputAt(1)), arraysize(temps), temps);
518}
519
520
521void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
522 X87OperandGenerator g(selector);
Ben Murdochda12d292016-06-02 14:46:10 +0100523 InstructionOperand temps[] = {g.TempRegister(eax)};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000524 selector->Emit(opcode, g.DefineAsFixed(node, edx),
525 g.UseFixed(node->InputAt(0), eax),
Ben Murdochda12d292016-06-02 14:46:10 +0100526 g.UseUnique(node->InputAt(1)), arraysize(temps), temps);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000527}
528
529void EmitLea(InstructionSelector* selector, Node* result, Node* index,
530 int scale, Node* base, Node* displacement) {
531 X87OperandGenerator g(selector);
532 InstructionOperand inputs[4];
533 size_t input_count = 0;
534 AddressingMode mode = g.GenerateMemoryOperandInputs(
535 index, scale, base, displacement, inputs, &input_count);
536
537 DCHECK_NE(0u, input_count);
538 DCHECK_GE(arraysize(inputs), input_count);
539
540 InstructionOperand outputs[1];
541 outputs[0] = g.DefineAsRegister(result);
542
543 InstructionCode opcode = AddressingModeField::encode(mode) | kX87Lea;
544
545 selector->Emit(opcode, 1, outputs, input_count, inputs);
546}
547
548} // namespace
549
550
551void InstructionSelector::VisitWord32Shl(Node* node) {
552 Int32ScaleMatcher m(node, true);
553 if (m.matches()) {
554 Node* index = node->InputAt(0);
555 Node* base = m.power_of_two_plus_one() ? index : nullptr;
556 EmitLea(this, node, index, m.scale(), base, nullptr);
557 return;
558 }
559 VisitShift(this, node, kX87Shl);
560}
561
562
563void InstructionSelector::VisitWord32Shr(Node* node) {
564 VisitShift(this, node, kX87Shr);
565}
566
567
568void InstructionSelector::VisitWord32Sar(Node* node) {
569 VisitShift(this, node, kX87Sar);
570}
571
Ben Murdochda12d292016-06-02 14:46:10 +0100572void InstructionSelector::VisitInt32PairAdd(Node* node) {
573 X87OperandGenerator g(this);
574
575 // We use UseUniqueRegister here to avoid register sharing with the temp
576 // register.
577 InstructionOperand inputs[] = {
578 g.UseRegister(node->InputAt(0)), g.UseUniqueRegister(node->InputAt(1)),
579 g.UseRegister(node->InputAt(2)), g.UseUniqueRegister(node->InputAt(3))};
580
581 InstructionOperand outputs[] = {
582 g.DefineSameAsFirst(node),
583 g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
584
585 InstructionOperand temps[] = {g.TempRegister()};
586
587 Emit(kX87AddPair, 2, outputs, 4, inputs, 1, temps);
588}
589
590void InstructionSelector::VisitInt32PairSub(Node* node) {
591 X87OperandGenerator g(this);
592
593 // We use UseUniqueRegister here to avoid register sharing with the temp
594 // register.
595 InstructionOperand inputs[] = {
596 g.UseRegister(node->InputAt(0)), g.UseUniqueRegister(node->InputAt(1)),
597 g.UseRegister(node->InputAt(2)), g.UseUniqueRegister(node->InputAt(3))};
598
599 InstructionOperand outputs[] = {
600 g.DefineSameAsFirst(node),
601 g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
602
603 InstructionOperand temps[] = {g.TempRegister()};
604
605 Emit(kX87SubPair, 2, outputs, 4, inputs, 1, temps);
606}
607
608void InstructionSelector::VisitInt32PairMul(Node* node) {
609 X87OperandGenerator g(this);
610
611 // InputAt(3) explicitly shares ecx with OutputRegister(1) to save one
612 // register and one mov instruction.
613 InstructionOperand inputs[] = {
614 g.UseUnique(node->InputAt(0)), g.UseUnique(node->InputAt(1)),
615 g.UseUniqueRegister(node->InputAt(2)), g.UseFixed(node->InputAt(3), ecx)};
616
617 InstructionOperand outputs[] = {
618 g.DefineAsFixed(node, eax),
619 g.DefineAsFixed(NodeProperties::FindProjection(node, 1), ecx)};
620
621 InstructionOperand temps[] = {g.TempRegister(edx)};
622
623 Emit(kX87MulPair, 2, outputs, 4, inputs, 1, temps);
624}
625
626void VisitWord32PairShift(InstructionSelector* selector, InstructionCode opcode,
627 Node* node) {
628 X87OperandGenerator g(selector);
629
630 Node* shift = node->InputAt(2);
631 InstructionOperand shift_operand;
632 if (g.CanBeImmediate(shift)) {
633 shift_operand = g.UseImmediate(shift);
634 } else {
635 shift_operand = g.UseFixed(shift, ecx);
636 }
637 InstructionOperand inputs[] = {g.UseFixed(node->InputAt(0), eax),
638 g.UseFixed(node->InputAt(1), edx),
639 shift_operand};
640
641 InstructionOperand outputs[] = {
642 g.DefineAsFixed(node, eax),
643 g.DefineAsFixed(NodeProperties::FindProjection(node, 1), edx)};
644
645 selector->Emit(opcode, 2, outputs, 3, inputs);
646}
647
648void InstructionSelector::VisitWord32PairShl(Node* node) {
649 VisitWord32PairShift(this, kX87ShlPair, node);
650}
651
652void InstructionSelector::VisitWord32PairShr(Node* node) {
653 VisitWord32PairShift(this, kX87ShrPair, node);
654}
655
656void InstructionSelector::VisitWord32PairSar(Node* node) {
657 VisitWord32PairShift(this, kX87SarPair, node);
658}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000659
660void InstructionSelector::VisitWord32Ror(Node* node) {
661 VisitShift(this, node, kX87Ror);
662}
663
664
665void InstructionSelector::VisitWord32Clz(Node* node) {
666 X87OperandGenerator g(this);
667 Emit(kX87Lzcnt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
668}
669
670
671void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); }
672
673
Ben Murdoch097c5b22016-05-18 11:27:45 +0100674void InstructionSelector::VisitWord32ReverseBits(Node* node) { UNREACHABLE(); }
675
676
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000677void InstructionSelector::VisitWord32Popcnt(Node* node) {
678 X87OperandGenerator g(this);
679 Emit(kX87Popcnt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
680}
681
682
683void InstructionSelector::VisitInt32Add(Node* node) {
684 X87OperandGenerator g(this);
685
686 // Try to match the Add to a lea pattern
687 BaseWithIndexAndDisplacement32Matcher m(node);
688 if (m.matches() &&
689 (m.displacement() == nullptr || g.CanBeImmediate(m.displacement()))) {
690 InstructionOperand inputs[4];
691 size_t input_count = 0;
692 AddressingMode mode = g.GenerateMemoryOperandInputs(
693 m.index(), m.scale(), m.base(), m.displacement(), inputs, &input_count);
694
695 DCHECK_NE(0u, input_count);
696 DCHECK_GE(arraysize(inputs), input_count);
697
698 InstructionOperand outputs[1];
699 outputs[0] = g.DefineAsRegister(node);
700
701 InstructionCode opcode = AddressingModeField::encode(mode) | kX87Lea;
702 Emit(opcode, 1, outputs, input_count, inputs);
703 return;
704 }
705
706 // No lea pattern match, use add
707 VisitBinop(this, node, kX87Add);
708}
709
710
711void InstructionSelector::VisitInt32Sub(Node* node) {
712 X87OperandGenerator g(this);
713 Int32BinopMatcher m(node);
714 if (m.left().Is(0)) {
715 Emit(kX87Neg, g.DefineSameAsFirst(node), g.Use(m.right().node()));
716 } else {
717 VisitBinop(this, node, kX87Sub);
718 }
719}
720
721
722void InstructionSelector::VisitInt32Mul(Node* node) {
723 Int32ScaleMatcher m(node, true);
724 if (m.matches()) {
725 Node* index = node->InputAt(0);
726 Node* base = m.power_of_two_plus_one() ? index : nullptr;
727 EmitLea(this, node, index, m.scale(), base, nullptr);
728 return;
729 }
730 X87OperandGenerator g(this);
731 Node* left = node->InputAt(0);
732 Node* right = node->InputAt(1);
733 if (g.CanBeImmediate(right)) {
734 Emit(kX87Imul, g.DefineAsRegister(node), g.Use(left),
735 g.UseImmediate(right));
736 } else {
737 if (g.CanBeBetterLeftOperand(right)) {
738 std::swap(left, right);
739 }
740 Emit(kX87Imul, g.DefineSameAsFirst(node), g.UseRegister(left),
741 g.Use(right));
742 }
743}
744
745
746void InstructionSelector::VisitInt32MulHigh(Node* node) {
747 VisitMulHigh(this, node, kX87ImulHigh);
748}
749
750
751void InstructionSelector::VisitUint32MulHigh(Node* node) {
752 VisitMulHigh(this, node, kX87UmulHigh);
753}
754
755
756void InstructionSelector::VisitInt32Div(Node* node) {
757 VisitDiv(this, node, kX87Idiv);
758}
759
760
761void InstructionSelector::VisitUint32Div(Node* node) {
762 VisitDiv(this, node, kX87Udiv);
763}
764
765
766void InstructionSelector::VisitInt32Mod(Node* node) {
767 VisitMod(this, node, kX87Idiv);
768}
769
770
771void InstructionSelector::VisitUint32Mod(Node* node) {
772 VisitMod(this, node, kX87Udiv);
773}
774
775
776void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
777 X87OperandGenerator g(this);
778 Emit(kX87Float32ToFloat64, g.DefineAsFixed(node, stX_0),
779 g.Use(node->InputAt(0)));
780}
781
782
Ben Murdoch097c5b22016-05-18 11:27:45 +0100783void InstructionSelector::VisitRoundInt32ToFloat32(Node* node) {
784 X87OperandGenerator g(this);
785 Emit(kX87Int32ToFloat32, g.DefineAsFixed(node, stX_0),
786 g.Use(node->InputAt(0)));
787}
788
789
790void InstructionSelector::VisitRoundUint32ToFloat32(Node* node) {
791 X87OperandGenerator g(this);
792 Emit(kX87Uint32ToFloat32, g.DefineAsFixed(node, stX_0),
793 g.Use(node->InputAt(0)));
794}
795
796
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000797void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
798 X87OperandGenerator g(this);
799 Emit(kX87Int32ToFloat64, g.DefineAsFixed(node, stX_0),
800 g.Use(node->InputAt(0)));
801}
802
803
804void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
805 X87OperandGenerator g(this);
806 Emit(kX87Uint32ToFloat64, g.DefineAsFixed(node, stX_0),
807 g.UseRegister(node->InputAt(0)));
808}
809
810
Ben Murdoch097c5b22016-05-18 11:27:45 +0100811void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) {
812 X87OperandGenerator g(this);
813 Emit(kX87Float32ToInt32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
814}
815
816
817void InstructionSelector::VisitTruncateFloat32ToUint32(Node* node) {
818 X87OperandGenerator g(this);
819 Emit(kX87Float32ToUint32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
820}
821
822
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000823void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
824 X87OperandGenerator g(this);
825 Emit(kX87Float64ToInt32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
826}
827
828
829void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
830 X87OperandGenerator g(this);
831 Emit(kX87Float64ToUint32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
832}
833
Ben Murdochda12d292016-06-02 14:46:10 +0100834void InstructionSelector::VisitTruncateFloat64ToUint32(Node* node) {
835 X87OperandGenerator g(this);
836 Emit(kX87Float64ToUint32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
837}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000838
839void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
840 X87OperandGenerator g(this);
841 Emit(kX87Float64ToFloat32, g.DefineAsFixed(node, stX_0),
842 g.Use(node->InputAt(0)));
843}
844
845
846void InstructionSelector::VisitTruncateFloat64ToInt32(Node* node) {
847 X87OperandGenerator g(this);
848
849 switch (TruncationModeOf(node->op())) {
850 case TruncationMode::kJavaScript:
851 Emit(kArchTruncateDoubleToI, g.DefineAsRegister(node),
852 g.Use(node->InputAt(0)));
853 return;
854 case TruncationMode::kRoundToZero:
855 Emit(kX87Float64ToInt32, g.DefineAsRegister(node),
856 g.Use(node->InputAt(0)));
857 return;
858 }
859 UNREACHABLE();
860}
861
862
863void InstructionSelector::VisitBitcastFloat32ToInt32(Node* node) {
864 X87OperandGenerator g(this);
865 Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(0)));
866 Emit(kX87BitcastFI, g.DefineAsRegister(node), 0, nullptr);
867}
868
869
870void InstructionSelector::VisitBitcastInt32ToFloat32(Node* node) {
871 X87OperandGenerator g(this);
872 Emit(kX87BitcastIF, g.DefineAsFixed(node, stX_0), g.Use(node->InputAt(0)));
873}
874
875
876void InstructionSelector::VisitFloat32Add(Node* node) {
877 X87OperandGenerator g(this);
878 Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(0)));
879 Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(1)));
880 Emit(kX87Float32Add, g.DefineAsFixed(node, stX_0), 0, nullptr);
881}
882
883
884void InstructionSelector::VisitFloat64Add(Node* node) {
885 X87OperandGenerator g(this);
886 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0)));
887 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(1)));
888 Emit(kX87Float64Add, g.DefineAsFixed(node, stX_0), 0, nullptr);
889}
890
891
892void InstructionSelector::VisitFloat32Sub(Node* node) {
893 X87OperandGenerator g(this);
894 Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(0)));
895 Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(1)));
896 Emit(kX87Float32Sub, g.DefineAsFixed(node, stX_0), 0, nullptr);
897}
898
899
900void InstructionSelector::VisitFloat64Sub(Node* node) {
901 X87OperandGenerator g(this);
902 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0)));
903 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(1)));
904 Emit(kX87Float64Sub, g.DefineAsFixed(node, stX_0), 0, nullptr);
905}
906
907
908void InstructionSelector::VisitFloat32Mul(Node* node) {
909 X87OperandGenerator g(this);
910 Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(0)));
911 Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(1)));
912 Emit(kX87Float32Mul, g.DefineAsFixed(node, stX_0), 0, nullptr);
913}
914
915
916void InstructionSelector::VisitFloat64Mul(Node* node) {
917 X87OperandGenerator g(this);
918 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0)));
919 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(1)));
920 Emit(kX87Float64Mul, g.DefineAsFixed(node, stX_0), 0, nullptr);
921}
922
923
924void InstructionSelector::VisitFloat32Div(Node* node) {
925 X87OperandGenerator g(this);
926 Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(0)));
927 Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(1)));
928 Emit(kX87Float32Div, g.DefineAsFixed(node, stX_0), 0, nullptr);
929}
930
931
932void InstructionSelector::VisitFloat64Div(Node* node) {
933 X87OperandGenerator g(this);
934 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0)));
935 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(1)));
936 Emit(kX87Float64Div, g.DefineAsFixed(node, stX_0), 0, nullptr);
937}
938
939
940void InstructionSelector::VisitFloat64Mod(Node* node) {
941 X87OperandGenerator g(this);
942 InstructionOperand temps[] = {g.TempRegister(eax)};
943 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0)));
944 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(1)));
945 Emit(kX87Float64Mod, g.DefineAsFixed(node, stX_0), 1, temps)->MarkAsCall();
946}
947
948
949void InstructionSelector::VisitFloat32Max(Node* node) {
950 X87OperandGenerator g(this);
951 Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(0)));
952 Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(1)));
953 Emit(kX87Float32Max, g.DefineAsFixed(node, stX_0), 0, nullptr);
954}
955
956
957void InstructionSelector::VisitFloat64Max(Node* node) {
958 X87OperandGenerator g(this);
959 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0)));
960 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(1)));
961 Emit(kX87Float64Max, g.DefineAsFixed(node, stX_0), 0, nullptr);
962}
963
964
965void InstructionSelector::VisitFloat32Min(Node* node) {
966 X87OperandGenerator g(this);
967 Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(0)));
968 Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(1)));
969 Emit(kX87Float32Min, g.DefineAsFixed(node, stX_0), 0, nullptr);
970}
971
972
973void InstructionSelector::VisitFloat64Min(Node* node) {
974 X87OperandGenerator g(this);
975 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0)));
976 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(1)));
977 Emit(kX87Float64Min, g.DefineAsFixed(node, stX_0), 0, nullptr);
978}
979
980
981void InstructionSelector::VisitFloat32Abs(Node* node) {
982 X87OperandGenerator g(this);
983 Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(0)));
984 Emit(kX87Float32Abs, g.DefineAsFixed(node, stX_0), 0, nullptr);
985}
986
987
988void InstructionSelector::VisitFloat64Abs(Node* node) {
989 X87OperandGenerator g(this);
990 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0)));
991 Emit(kX87Float64Abs, g.DefineAsFixed(node, stX_0), 0, nullptr);
992}
993
994
995void InstructionSelector::VisitFloat32Sqrt(Node* node) {
996 X87OperandGenerator g(this);
997 Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(0)));
998 Emit(kX87Float32Sqrt, g.DefineAsFixed(node, stX_0), 0, nullptr);
999}
1000
1001
1002void InstructionSelector::VisitFloat64Sqrt(Node* node) {
1003 X87OperandGenerator g(this);
1004 Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0)));
1005 Emit(kX87Float64Sqrt, g.DefineAsFixed(node, stX_0), 0, nullptr);
1006}
1007
1008
1009void InstructionSelector::VisitFloat32RoundDown(Node* node) {
1010 X87OperandGenerator g(this);
1011 Emit(kX87Float32Round | MiscField::encode(kRoundDown),
1012 g.UseFixed(node, stX_0), g.Use(node->InputAt(0)));
1013}
1014
1015
1016void InstructionSelector::VisitFloat64RoundDown(Node* node) {
1017 X87OperandGenerator g(this);
1018 Emit(kX87Float64Round | MiscField::encode(kRoundDown),
1019 g.UseFixed(node, stX_0), g.Use(node->InputAt(0)));
1020}
1021
1022
1023void InstructionSelector::VisitFloat32RoundUp(Node* node) {
1024 X87OperandGenerator g(this);
1025 Emit(kX87Float32Round | MiscField::encode(kRoundUp), g.UseFixed(node, stX_0),
1026 g.Use(node->InputAt(0)));
1027}
1028
1029
1030void InstructionSelector::VisitFloat64RoundUp(Node* node) {
1031 X87OperandGenerator g(this);
1032 Emit(kX87Float64Round | MiscField::encode(kRoundUp), g.UseFixed(node, stX_0),
1033 g.Use(node->InputAt(0)));
1034}
1035
1036
1037void InstructionSelector::VisitFloat32RoundTruncate(Node* node) {
1038 X87OperandGenerator g(this);
1039 Emit(kX87Float32Round | MiscField::encode(kRoundToZero),
1040 g.UseFixed(node, stX_0), g.Use(node->InputAt(0)));
1041}
1042
1043
1044void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
1045 X87OperandGenerator g(this);
1046 Emit(kX87Float64Round | MiscField::encode(kRoundToZero),
1047 g.UseFixed(node, stX_0), g.Use(node->InputAt(0)));
1048}
1049
1050
1051void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
1052 UNREACHABLE();
1053}
1054
1055
1056void InstructionSelector::VisitFloat32RoundTiesEven(Node* node) {
1057 X87OperandGenerator g(this);
1058 Emit(kX87Float32Round | MiscField::encode(kRoundToNearest),
1059 g.UseFixed(node, stX_0), g.Use(node->InputAt(0)));
1060}
1061
1062
1063void InstructionSelector::VisitFloat64RoundTiesEven(Node* node) {
1064 X87OperandGenerator g(this);
1065 Emit(kX87Float64Round | MiscField::encode(kRoundToNearest),
1066 g.UseFixed(node, stX_0), g.Use(node->InputAt(0)));
1067}
1068
1069
1070void InstructionSelector::EmitPrepareArguments(
1071 ZoneVector<PushParameter>* arguments, const CallDescriptor* descriptor,
1072 Node* node) {
1073 X87OperandGenerator g(this);
1074
1075 // Prepare for C function call.
1076 if (descriptor->IsCFunctionCall()) {
1077 InstructionOperand temps[] = {g.TempRegister()};
1078 size_t const temp_count = arraysize(temps);
1079 Emit(kArchPrepareCallCFunction |
1080 MiscField::encode(static_cast<int>(descriptor->CParameterCount())),
1081 0, nullptr, 0, nullptr, temp_count, temps);
1082
1083 // Poke any stack arguments.
1084 for (size_t n = 0; n < arguments->size(); ++n) {
1085 PushParameter input = (*arguments)[n];
1086 if (input.node()) {
1087 int const slot = static_cast<int>(n);
1088 InstructionOperand value = g.CanBeImmediate(input.node())
1089 ? g.UseImmediate(input.node())
1090 : g.UseRegister(input.node());
1091 Emit(kX87Poke | MiscField::encode(slot), g.NoOutput(), value);
1092 }
1093 }
1094 } else {
1095 // Push any stack arguments.
1096 for (PushParameter input : base::Reversed(*arguments)) {
1097 // TODO(titzer): handle pushing double parameters.
1098 if (input.node() == nullptr) continue;
1099 InstructionOperand value =
1100 g.CanBeImmediate(input.node())
1101 ? g.UseImmediate(input.node())
1102 : IsSupported(ATOM) ||
1103 sequence()->IsFloat(GetVirtualRegister(input.node()))
1104 ? g.UseRegister(input.node())
1105 : g.Use(input.node());
1106 Emit(kX87Push, g.NoOutput(), value);
1107 }
1108 }
1109}
1110
1111
1112bool InstructionSelector::IsTailCallAddressImmediate() { return true; }
1113
Ben Murdochda12d292016-06-02 14:46:10 +01001114int InstructionSelector::GetTempsCountForTailCallFromJSFunction() { return 0; }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001115
1116namespace {
1117
Ben Murdoch097c5b22016-05-18 11:27:45 +01001118void VisitCompareWithMemoryOperand(InstructionSelector* selector,
1119 InstructionCode opcode, Node* left,
1120 InstructionOperand right,
1121 FlagsContinuation* cont) {
1122 DCHECK(left->opcode() == IrOpcode::kLoad);
1123 X87OperandGenerator g(selector);
1124 size_t input_count = 0;
1125 InstructionOperand inputs[6];
1126 AddressingMode addressing_mode =
1127 g.GetEffectiveAddressMemoryOperand(left, inputs, &input_count);
1128 opcode |= AddressingModeField::encode(addressing_mode);
1129 opcode = cont->Encode(opcode);
1130 inputs[input_count++] = right;
1131
1132 if (cont->IsBranch()) {
1133 inputs[input_count++] = g.Label(cont->true_block());
1134 inputs[input_count++] = g.Label(cont->false_block());
1135 selector->Emit(opcode, 0, nullptr, input_count, inputs);
Ben Murdochda12d292016-06-02 14:46:10 +01001136 } else if (cont->IsDeoptimize()) {
1137 selector->EmitDeoptimize(opcode, 0, nullptr, input_count, inputs,
1138 cont->frame_state());
Ben Murdoch097c5b22016-05-18 11:27:45 +01001139 } else {
1140 DCHECK(cont->IsSet());
1141 InstructionOperand output = g.DefineAsRegister(cont->result());
1142 selector->Emit(opcode, 1, &output, input_count, inputs);
1143 }
1144}
1145
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001146// Shared routine for multiple compare operations.
1147void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
1148 InstructionOperand left, InstructionOperand right,
1149 FlagsContinuation* cont) {
1150 X87OperandGenerator g(selector);
Ben Murdochda12d292016-06-02 14:46:10 +01001151 opcode = cont->Encode(opcode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001152 if (cont->IsBranch()) {
Ben Murdochda12d292016-06-02 14:46:10 +01001153 selector->Emit(opcode, g.NoOutput(), left, right,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001154 g.Label(cont->true_block()), g.Label(cont->false_block()));
Ben Murdochda12d292016-06-02 14:46:10 +01001155 } else if (cont->IsDeoptimize()) {
1156 selector->EmitDeoptimize(opcode, g.NoOutput(), left, right,
1157 cont->frame_state());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001158 } else {
1159 DCHECK(cont->IsSet());
Ben Murdochda12d292016-06-02 14:46:10 +01001160 selector->Emit(opcode, g.DefineAsByteRegister(cont->result()), left, right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001161 }
1162}
1163
1164
1165// Shared routine for multiple compare operations.
1166void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
1167 Node* left, Node* right, FlagsContinuation* cont,
1168 bool commutative) {
1169 X87OperandGenerator g(selector);
1170 if (commutative && g.CanBeBetterLeftOperand(right)) {
1171 std::swap(left, right);
1172 }
1173 VisitCompare(selector, opcode, g.UseRegister(left), g.Use(right), cont);
1174}
1175
Ben Murdochda12d292016-06-02 14:46:10 +01001176// Tries to match the size of the given opcode to that of the operands, if
1177// possible.
1178InstructionCode TryNarrowOpcodeSize(InstructionCode opcode, Node* left,
1179 Node* right) {
1180 if (opcode != kX87Cmp && opcode != kX87Test) {
1181 return opcode;
1182 }
1183 // Currently, if one of the two operands is not a Load, we don't know what its
1184 // machine representation is, so we bail out.
1185 // TODO(epertoso): we can probably get some size information out of immediates
1186 // and phi nodes.
1187 if (left->opcode() != IrOpcode::kLoad || right->opcode() != IrOpcode::kLoad) {
1188 return opcode;
1189 }
1190 // If the load representations don't match, both operands will be
1191 // zero/sign-extended to 32bit.
1192 LoadRepresentation left_representation = LoadRepresentationOf(left->op());
1193 if (left_representation != LoadRepresentationOf(right->op())) {
1194 return opcode;
1195 }
1196 switch (left_representation.representation()) {
1197 case MachineRepresentation::kBit:
1198 case MachineRepresentation::kWord8:
1199 return opcode == kX87Cmp ? kX87Cmp8 : kX87Test8;
1200 case MachineRepresentation::kWord16:
1201 return opcode == kX87Cmp ? kX87Cmp16 : kX87Test16;
1202 default:
1203 return opcode;
1204 }
1205}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001206
1207// Shared routine for multiple float32 compare operations (inputs commuted).
1208void VisitFloat32Compare(InstructionSelector* selector, Node* node,
1209 FlagsContinuation* cont) {
1210 X87OperandGenerator g(selector);
1211 selector->Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(0)));
1212 selector->Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(1)));
1213 if (cont->IsBranch()) {
1214 selector->Emit(cont->Encode(kX87Float32Cmp), g.NoOutput(),
1215 g.Label(cont->true_block()), g.Label(cont->false_block()));
Ben Murdochda12d292016-06-02 14:46:10 +01001216 } else if (cont->IsDeoptimize()) {
1217 selector->EmitDeoptimize(cont->Encode(kX87Float32Cmp), g.NoOutput(),
1218 g.Use(node->InputAt(0)), g.Use(node->InputAt(1)),
1219 cont->frame_state());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001220 } else {
1221 DCHECK(cont->IsSet());
1222 selector->Emit(cont->Encode(kX87Float32Cmp),
1223 g.DefineAsByteRegister(cont->result()));
1224 }
1225}
1226
1227
1228// Shared routine for multiple float64 compare operations (inputs commuted).
1229void VisitFloat64Compare(InstructionSelector* selector, Node* node,
1230 FlagsContinuation* cont) {
1231 X87OperandGenerator g(selector);
1232 selector->Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0)));
1233 selector->Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(1)));
1234 if (cont->IsBranch()) {
1235 selector->Emit(cont->Encode(kX87Float64Cmp), g.NoOutput(),
1236 g.Label(cont->true_block()), g.Label(cont->false_block()));
Ben Murdochda12d292016-06-02 14:46:10 +01001237 } else if (cont->IsDeoptimize()) {
1238 selector->EmitDeoptimize(cont->Encode(kX87Float64Cmp), g.NoOutput(),
1239 g.Use(node->InputAt(0)), g.Use(node->InputAt(1)),
1240 cont->frame_state());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001241 } else {
1242 DCHECK(cont->IsSet());
1243 selector->Emit(cont->Encode(kX87Float64Cmp),
1244 g.DefineAsByteRegister(cont->result()));
1245 }
1246}
1247
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001248// Shared routine for multiple word compare operations.
1249void VisitWordCompare(InstructionSelector* selector, Node* node,
1250 InstructionCode opcode, FlagsContinuation* cont) {
1251 X87OperandGenerator g(selector);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001252 Node* left = node->InputAt(0);
1253 Node* right = node->InputAt(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001254
Ben Murdochda12d292016-06-02 14:46:10 +01001255 InstructionCode narrowed_opcode = TryNarrowOpcodeSize(opcode, left, right);
1256
1257 // If one of the two inputs is an immediate, make sure it's on the right, or
1258 // if one of the two inputs is a memory operand, make sure it's on the left.
1259 if ((!g.CanBeImmediate(right) && g.CanBeImmediate(left)) ||
1260 (g.CanBeMemoryOperand(narrowed_opcode, node, right) &&
1261 !g.CanBeMemoryOperand(narrowed_opcode, node, left))) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001262 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001263 std::swap(left, right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001264 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001265
Ben Murdoch097c5b22016-05-18 11:27:45 +01001266 // Match immediates on right side of comparison.
1267 if (g.CanBeImmediate(right)) {
Ben Murdochda12d292016-06-02 14:46:10 +01001268 if (g.CanBeMemoryOperand(opcode, node, left)) {
1269 // TODO(epertoso): we should use `narrowed_opcode' here once we match
1270 // immediates too.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001271 return VisitCompareWithMemoryOperand(selector, opcode, left,
1272 g.UseImmediate(right), cont);
1273 }
1274 return VisitCompare(selector, opcode, g.Use(left), g.UseImmediate(right),
1275 cont);
1276 }
1277
Ben Murdochda12d292016-06-02 14:46:10 +01001278 // Match memory operands on left side of comparison.
1279 if (g.CanBeMemoryOperand(narrowed_opcode, node, left)) {
1280 bool needs_byte_register =
1281 narrowed_opcode == kX87Test8 || narrowed_opcode == kX87Cmp8;
1282 return VisitCompareWithMemoryOperand(
1283 selector, narrowed_opcode, left,
1284 needs_byte_register ? g.UseByteRegister(right) : g.UseRegister(right),
1285 cont);
1286 }
1287
Ben Murdoch097c5b22016-05-18 11:27:45 +01001288 if (g.CanBeBetterLeftOperand(right)) {
1289 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
1290 std::swap(left, right);
1291 }
1292
Ben Murdoch097c5b22016-05-18 11:27:45 +01001293 return VisitCompare(selector, opcode, left, right, cont,
1294 node->op()->HasProperty(Operator::kCommutative));
1295}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001296
1297void VisitWordCompare(InstructionSelector* selector, Node* node,
1298 FlagsContinuation* cont) {
1299 X87OperandGenerator g(selector);
1300 Int32BinopMatcher m(node);
1301 if (m.left().IsLoad() && m.right().IsLoadStackPointer()) {
1302 LoadMatcher<ExternalReferenceMatcher> mleft(m.left().node());
1303 ExternalReference js_stack_limit =
1304 ExternalReference::address_of_stack_limit(selector->isolate());
1305 if (mleft.object().Is(js_stack_limit) && mleft.index().Is(0)) {
1306 // Compare(Load(js_stack_limit), LoadStackPointer)
1307 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
1308 InstructionCode opcode = cont->Encode(kX87StackCheck);
1309 if (cont->IsBranch()) {
1310 selector->Emit(opcode, g.NoOutput(), g.Label(cont->true_block()),
1311 g.Label(cont->false_block()));
Ben Murdochda12d292016-06-02 14:46:10 +01001312 } else if (cont->IsDeoptimize()) {
1313 selector->EmitDeoptimize(opcode, 0, nullptr, 0, nullptr,
1314 cont->frame_state());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001315 } else {
1316 DCHECK(cont->IsSet());
1317 selector->Emit(opcode, g.DefineAsRegister(cont->result()));
1318 }
1319 return;
1320 }
1321 }
1322 VisitWordCompare(selector, node, kX87Cmp, cont);
1323}
1324
1325
1326// Shared routine for word comparison with zero.
1327void VisitWordCompareZero(InstructionSelector* selector, Node* user,
1328 Node* value, FlagsContinuation* cont) {
1329 // Try to combine the branch with a comparison.
1330 while (selector->CanCover(user, value)) {
1331 switch (value->opcode()) {
1332 case IrOpcode::kWord32Equal: {
1333 // Try to combine with comparisons against 0 by simply inverting the
1334 // continuation.
1335 Int32BinopMatcher m(value);
1336 if (m.right().Is(0)) {
1337 user = value;
1338 value = m.left().node();
1339 cont->Negate();
1340 continue;
1341 }
1342 cont->OverwriteAndNegateIfEqual(kEqual);
1343 return VisitWordCompare(selector, value, cont);
1344 }
1345 case IrOpcode::kInt32LessThan:
1346 cont->OverwriteAndNegateIfEqual(kSignedLessThan);
1347 return VisitWordCompare(selector, value, cont);
1348 case IrOpcode::kInt32LessThanOrEqual:
1349 cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
1350 return VisitWordCompare(selector, value, cont);
1351 case IrOpcode::kUint32LessThan:
1352 cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
1353 return VisitWordCompare(selector, value, cont);
1354 case IrOpcode::kUint32LessThanOrEqual:
1355 cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
1356 return VisitWordCompare(selector, value, cont);
1357 case IrOpcode::kFloat32Equal:
1358 cont->OverwriteAndNegateIfEqual(kUnorderedEqual);
1359 return VisitFloat32Compare(selector, value, cont);
1360 case IrOpcode::kFloat32LessThan:
1361 cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThan);
1362 return VisitFloat32Compare(selector, value, cont);
1363 case IrOpcode::kFloat32LessThanOrEqual:
1364 cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThanOrEqual);
1365 return VisitFloat32Compare(selector, value, cont);
1366 case IrOpcode::kFloat64Equal:
1367 cont->OverwriteAndNegateIfEqual(kUnorderedEqual);
1368 return VisitFloat64Compare(selector, value, cont);
1369 case IrOpcode::kFloat64LessThan:
1370 cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThan);
1371 return VisitFloat64Compare(selector, value, cont);
1372 case IrOpcode::kFloat64LessThanOrEqual:
1373 cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThanOrEqual);
1374 return VisitFloat64Compare(selector, value, cont);
1375 case IrOpcode::kProjection:
1376 // Check if this is the overflow output projection of an
1377 // <Operation>WithOverflow node.
1378 if (ProjectionIndexOf(value->op()) == 1u) {
1379 // We cannot combine the <Operation>WithOverflow with this branch
1380 // unless the 0th projection (the use of the actual value of the
1381 // <Operation> is either nullptr, which means there's no use of the
1382 // actual value, or was already defined, which means it is scheduled
1383 // *AFTER* this branch).
1384 Node* const node = value->InputAt(0);
1385 Node* const result = NodeProperties::FindProjection(node, 0);
1386 if (result == nullptr || selector->IsDefined(result)) {
1387 switch (node->opcode()) {
1388 case IrOpcode::kInt32AddWithOverflow:
1389 cont->OverwriteAndNegateIfEqual(kOverflow);
1390 return VisitBinop(selector, node, kX87Add, cont);
1391 case IrOpcode::kInt32SubWithOverflow:
1392 cont->OverwriteAndNegateIfEqual(kOverflow);
1393 return VisitBinop(selector, node, kX87Sub, cont);
1394 default:
1395 break;
1396 }
1397 }
1398 }
1399 break;
1400 case IrOpcode::kInt32Sub:
1401 return VisitWordCompare(selector, value, cont);
1402 case IrOpcode::kWord32And:
1403 return VisitWordCompare(selector, value, kX87Test, cont);
1404 default:
1405 break;
1406 }
1407 break;
1408 }
1409
1410 // Continuation could not be combined with a compare, emit compare against 0.
1411 X87OperandGenerator g(selector);
1412 VisitCompare(selector, kX87Cmp, g.Use(value), g.TempImmediate(0), cont);
1413}
1414
1415} // namespace
1416
1417
1418void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
1419 BasicBlock* fbranch) {
1420 FlagsContinuation cont(kNotEqual, tbranch, fbranch);
1421 VisitWordCompareZero(this, branch, branch->InputAt(0), &cont);
1422}
1423
Ben Murdochda12d292016-06-02 14:46:10 +01001424void InstructionSelector::VisitDeoptimizeIf(Node* node) {
1425 FlagsContinuation cont =
1426 FlagsContinuation::ForDeoptimize(kNotEqual, node->InputAt(1));
1427 VisitWordCompareZero(this, node, node->InputAt(0), &cont);
1428}
1429
1430void InstructionSelector::VisitDeoptimizeUnless(Node* node) {
1431 FlagsContinuation cont =
1432 FlagsContinuation::ForDeoptimize(kEqual, node->InputAt(1));
1433 VisitWordCompareZero(this, node, node->InputAt(0), &cont);
1434}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001435
1436void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
1437 X87OperandGenerator g(this);
1438 InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
1439
1440 // Emit either ArchTableSwitch or ArchLookupSwitch.
1441 size_t table_space_cost = 4 + sw.value_range;
1442 size_t table_time_cost = 3;
1443 size_t lookup_space_cost = 3 + 2 * sw.case_count;
1444 size_t lookup_time_cost = sw.case_count;
1445 if (sw.case_count > 4 &&
1446 table_space_cost + 3 * table_time_cost <=
1447 lookup_space_cost + 3 * lookup_time_cost &&
1448 sw.min_value > std::numeric_limits<int32_t>::min()) {
1449 InstructionOperand index_operand = value_operand;
1450 if (sw.min_value) {
1451 index_operand = g.TempRegister();
1452 Emit(kX87Lea | AddressingModeField::encode(kMode_MRI), index_operand,
1453 value_operand, g.TempImmediate(-sw.min_value));
1454 }
1455 // Generate a table lookup.
1456 return EmitTableSwitch(sw, index_operand);
1457 }
1458
1459 // Generate a sequence of conditional jumps.
1460 return EmitLookupSwitch(sw, value_operand);
1461}
1462
1463
1464void InstructionSelector::VisitWord32Equal(Node* const node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001465 FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001466 Int32BinopMatcher m(node);
1467 if (m.right().Is(0)) {
1468 return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
1469 }
1470 VisitWordCompare(this, node, &cont);
1471}
1472
1473
1474void InstructionSelector::VisitInt32LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001475 FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001476 VisitWordCompare(this, node, &cont);
1477}
1478
1479
1480void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001481 FlagsContinuation cont =
1482 FlagsContinuation::ForSet(kSignedLessThanOrEqual, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001483 VisitWordCompare(this, node, &cont);
1484}
1485
1486
1487void InstructionSelector::VisitUint32LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001488 FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001489 VisitWordCompare(this, node, &cont);
1490}
1491
1492
1493void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001494 FlagsContinuation cont =
1495 FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001496 VisitWordCompare(this, node, &cont);
1497}
1498
1499
1500void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
1501 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
Ben Murdochda12d292016-06-02 14:46:10 +01001502 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001503 return VisitBinop(this, node, kX87Add, &cont);
1504 }
1505 FlagsContinuation cont;
1506 VisitBinop(this, node, kX87Add, &cont);
1507}
1508
1509
1510void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
1511 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
Ben Murdochda12d292016-06-02 14:46:10 +01001512 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001513 return VisitBinop(this, node, kX87Sub, &cont);
1514 }
1515 FlagsContinuation cont;
1516 VisitBinop(this, node, kX87Sub, &cont);
1517}
1518
1519
1520void InstructionSelector::VisitFloat32Equal(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001521 FlagsContinuation cont = FlagsContinuation::ForSet(kUnorderedEqual, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001522 VisitFloat32Compare(this, node, &cont);
1523}
1524
1525
1526void InstructionSelector::VisitFloat32LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001527 FlagsContinuation cont =
1528 FlagsContinuation::ForSet(kUnsignedGreaterThan, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001529 VisitFloat32Compare(this, node, &cont);
1530}
1531
1532
1533void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001534 FlagsContinuation cont =
1535 FlagsContinuation::ForSet(kUnsignedGreaterThanOrEqual, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001536 VisitFloat32Compare(this, node, &cont);
1537}
1538
1539
1540void InstructionSelector::VisitFloat64Equal(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001541 FlagsContinuation cont = FlagsContinuation::ForSet(kUnorderedEqual, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001542 VisitFloat64Compare(this, node, &cont);
1543}
1544
1545
1546void InstructionSelector::VisitFloat64LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001547 FlagsContinuation cont =
1548 FlagsContinuation::ForSet(kUnsignedGreaterThan, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001549 VisitFloat64Compare(this, node, &cont);
1550}
1551
1552
1553void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001554 FlagsContinuation cont =
1555 FlagsContinuation::ForSet(kUnsignedGreaterThanOrEqual, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001556 VisitFloat64Compare(this, node, &cont);
1557}
1558
1559
1560void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) {
1561 X87OperandGenerator g(this);
1562 Emit(kX87Float64ExtractLowWord32, g.DefineAsRegister(node),
1563 g.Use(node->InputAt(0)));
1564}
1565
1566
1567void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) {
1568 X87OperandGenerator g(this);
1569 Emit(kX87Float64ExtractHighWord32, g.DefineAsRegister(node),
1570 g.Use(node->InputAt(0)));
1571}
1572
1573
1574void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) {
1575 X87OperandGenerator g(this);
1576 Node* left = node->InputAt(0);
1577 Node* right = node->InputAt(1);
1578 Emit(kX87Float64InsertLowWord32, g.UseFixed(node, stX_0), g.UseRegister(left),
1579 g.UseRegister(right));
1580}
1581
1582
1583void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
1584 X87OperandGenerator g(this);
1585 Node* left = node->InputAt(0);
1586 Node* right = node->InputAt(1);
1587 Emit(kX87Float64InsertHighWord32, g.UseFixed(node, stX_0),
1588 g.UseRegister(left), g.UseRegister(right));
1589}
1590
1591
1592// static
1593MachineOperatorBuilder::Flags
1594InstructionSelector::SupportedMachineOperatorFlags() {
1595 MachineOperatorBuilder::Flags flags =
1596 MachineOperatorBuilder::kFloat32Max |
1597 MachineOperatorBuilder::kFloat32Min |
1598 MachineOperatorBuilder::kFloat64Max |
1599 MachineOperatorBuilder::kFloat64Min |
1600 MachineOperatorBuilder::kWord32ShiftIsSafe;
1601 if (CpuFeatures::IsSupported(POPCNT)) {
1602 flags |= MachineOperatorBuilder::kWord32Popcnt;
1603 }
1604
1605 flags |= MachineOperatorBuilder::kFloat32RoundDown |
1606 MachineOperatorBuilder::kFloat64RoundDown |
1607 MachineOperatorBuilder::kFloat32RoundUp |
1608 MachineOperatorBuilder::kFloat64RoundUp |
1609 MachineOperatorBuilder::kFloat32RoundTruncate |
1610 MachineOperatorBuilder::kFloat64RoundTruncate |
1611 MachineOperatorBuilder::kFloat32RoundTiesEven |
1612 MachineOperatorBuilder::kFloat64RoundTiesEven;
1613 return flags;
1614}
1615
1616} // namespace compiler
1617} // namespace internal
1618} // namespace v8