• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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/bits.h"
6 #include "src/base/enum-set.h"
7 #include "src/base/iterator.h"
8 #include "src/base/platform/wrappers.h"
9 #include "src/codegen/machine-type.h"
10 #include "src/compiler/backend/instruction-selector-impl.h"
11 #include "src/compiler/node-matchers.h"
12 #include "src/compiler/node-properties.h"
13 
14 namespace v8 {
15 namespace internal {
16 namespace compiler {
17 
18 // Adds Arm-specific methods for generating InstructionOperands.
19 class ArmOperandGenerator : public OperandGenerator {
20  public:
ArmOperandGenerator(InstructionSelector * selector)21   explicit ArmOperandGenerator(InstructionSelector* selector)
22       : OperandGenerator(selector) {}
23 
CanBeImmediate(int32_t value) const24   bool CanBeImmediate(int32_t value) const {
25     return Assembler::ImmediateFitsAddrMode1Instruction(value);
26   }
27 
CanBeImmediate(uint32_t value) const28   bool CanBeImmediate(uint32_t value) const {
29     return CanBeImmediate(bit_cast<int32_t>(value));
30   }
31 
CanBeImmediate(Node * node,InstructionCode opcode)32   bool CanBeImmediate(Node* node, InstructionCode opcode) {
33     Int32Matcher m(node);
34     if (!m.HasResolvedValue()) return false;
35     int32_t value = m.ResolvedValue();
36     switch (ArchOpcodeField::decode(opcode)) {
37       case kArmAnd:
38       case kArmMov:
39       case kArmMvn:
40       case kArmBic:
41         return CanBeImmediate(value) || CanBeImmediate(~value);
42 
43       case kArmAdd:
44       case kArmSub:
45       case kArmCmp:
46       case kArmCmn:
47         return CanBeImmediate(value) || CanBeImmediate(-value);
48 
49       case kArmTst:
50       case kArmTeq:
51       case kArmOrr:
52       case kArmEor:
53       case kArmRsb:
54         return CanBeImmediate(value);
55 
56       case kArmVldrF32:
57       case kArmVstrF32:
58       case kArmVldrF64:
59       case kArmVstrF64:
60         return value >= -1020 && value <= 1020 && (value % 4) == 0;
61 
62       case kArmLdrb:
63       case kArmLdrsb:
64       case kArmStrb:
65       case kArmLdr:
66       case kArmStr:
67         return value >= -4095 && value <= 4095;
68 
69       case kArmLdrh:
70       case kArmLdrsh:
71       case kArmStrh:
72         return value >= -255 && value <= 255;
73 
74       default:
75         break;
76     }
77     return false;
78   }
79 };
80 
81 namespace {
82 
VisitRR(InstructionSelector * selector,InstructionCode opcode,Node * node)83 void VisitRR(InstructionSelector* selector, InstructionCode opcode,
84              Node* node) {
85   ArmOperandGenerator g(selector);
86   selector->Emit(opcode, g.DefineAsRegister(node),
87                  g.UseRegister(node->InputAt(0)));
88 }
89 
VisitRRR(InstructionSelector * selector,InstructionCode opcode,Node * node)90 void VisitRRR(InstructionSelector* selector, InstructionCode opcode,
91               Node* node) {
92   ArmOperandGenerator g(selector);
93   selector->Emit(opcode, g.DefineAsRegister(node),
94                  g.UseRegister(node->InputAt(0)),
95                  g.UseRegister(node->InputAt(1)));
96 }
97 
VisitSimdShiftRRR(InstructionSelector * selector,ArchOpcode opcode,Node * node,int width)98 void VisitSimdShiftRRR(InstructionSelector* selector, ArchOpcode opcode,
99                        Node* node, int width) {
100   ArmOperandGenerator g(selector);
101   Int32Matcher m(node->InputAt(1));
102   if (m.HasResolvedValue()) {
103     if (m.IsMultipleOf(width)) {
104       selector->EmitIdentity(node);
105     } else {
106       selector->Emit(opcode, g.DefineAsRegister(node),
107                      g.UseRegister(node->InputAt(0)),
108                      g.UseImmediate(node->InputAt(1)));
109     }
110   } else {
111     VisitRRR(selector, opcode, node);
112   }
113 }
114 
115 #if V8_ENABLE_WEBASSEMBLY
VisitRRRShuffle(InstructionSelector * selector,ArchOpcode opcode,Node * node)116 void VisitRRRShuffle(InstructionSelector* selector, ArchOpcode opcode,
117                      Node* node) {
118   ArmOperandGenerator g(selector);
119   // Swap inputs to save an instruction in the CodeGenerator for High ops.
120   if (opcode == kArmS32x4ZipRight || opcode == kArmS32x4UnzipRight ||
121       opcode == kArmS32x4TransposeRight || opcode == kArmS16x8ZipRight ||
122       opcode == kArmS16x8UnzipRight || opcode == kArmS16x8TransposeRight ||
123       opcode == kArmS8x16ZipRight || opcode == kArmS8x16UnzipRight ||
124       opcode == kArmS8x16TransposeRight) {
125     Node* in0 = node->InputAt(0);
126     Node* in1 = node->InputAt(1);
127     node->ReplaceInput(0, in1);
128     node->ReplaceInput(1, in0);
129   }
130   // Use DefineSameAsFirst for binary ops that clobber their inputs, e.g. the
131   // NEON vzip, vuzp, and vtrn instructions.
132   selector->Emit(opcode, g.DefineSameAsFirst(node),
133                  g.UseRegister(node->InputAt(0)),
134                  g.UseRegister(node->InputAt(1)));
135 }
136 #endif  // V8_ENABLE_WEBASSEMBLY
137 
VisitRRI(InstructionSelector * selector,ArchOpcode opcode,Node * node)138 void VisitRRI(InstructionSelector* selector, ArchOpcode opcode, Node* node) {
139   ArmOperandGenerator g(selector);
140   int32_t imm = OpParameter<int32_t>(node->op());
141   selector->Emit(opcode, g.DefineAsRegister(node),
142                  g.UseRegister(node->InputAt(0)), g.UseImmediate(imm));
143 }
144 
VisitRRIR(InstructionSelector * selector,ArchOpcode opcode,Node * node)145 void VisitRRIR(InstructionSelector* selector, ArchOpcode opcode, Node* node) {
146   ArmOperandGenerator g(selector);
147   int32_t imm = OpParameter<int32_t>(node->op());
148   selector->Emit(opcode, g.DefineAsRegister(node),
149                  g.UseRegister(node->InputAt(0)), g.UseImmediate(imm),
150                  g.UseUniqueRegister(node->InputAt(1)));
151 }
152 
153 template <IrOpcode::Value kOpcode, int kImmMin, int kImmMax,
154           AddressingMode kImmMode, AddressingMode kRegMode>
TryMatchShift(InstructionSelector * selector,InstructionCode * opcode_return,Node * node,InstructionOperand * value_return,InstructionOperand * shift_return)155 bool TryMatchShift(InstructionSelector* selector,
156                    InstructionCode* opcode_return, Node* node,
157                    InstructionOperand* value_return,
158                    InstructionOperand* shift_return) {
159   ArmOperandGenerator g(selector);
160   if (node->opcode() == kOpcode) {
161     Int32BinopMatcher m(node);
162     *value_return = g.UseRegister(m.left().node());
163     if (m.right().IsInRange(kImmMin, kImmMax)) {
164       *opcode_return |= AddressingModeField::encode(kImmMode);
165       *shift_return = g.UseImmediate(m.right().node());
166     } else {
167       *opcode_return |= AddressingModeField::encode(kRegMode);
168       *shift_return = g.UseRegister(m.right().node());
169     }
170     return true;
171   }
172   return false;
173 }
174 
175 template <IrOpcode::Value kOpcode, int kImmMin, int kImmMax,
176           AddressingMode kImmMode>
TryMatchShiftImmediate(InstructionSelector * selector,InstructionCode * opcode_return,Node * node,InstructionOperand * value_return,InstructionOperand * shift_return)177 bool TryMatchShiftImmediate(InstructionSelector* selector,
178                             InstructionCode* opcode_return, Node* node,
179                             InstructionOperand* value_return,
180                             InstructionOperand* shift_return) {
181   ArmOperandGenerator g(selector);
182   if (node->opcode() == kOpcode) {
183     Int32BinopMatcher m(node);
184     if (m.right().IsInRange(kImmMin, kImmMax)) {
185       *opcode_return |= AddressingModeField::encode(kImmMode);
186       *value_return = g.UseRegister(m.left().node());
187       *shift_return = g.UseImmediate(m.right().node());
188       return true;
189     }
190   }
191   return false;
192 }
193 
TryMatchROR(InstructionSelector * selector,InstructionCode * opcode_return,Node * node,InstructionOperand * value_return,InstructionOperand * shift_return)194 bool TryMatchROR(InstructionSelector* selector, InstructionCode* opcode_return,
195                  Node* node, InstructionOperand* value_return,
196                  InstructionOperand* shift_return) {
197   return TryMatchShift<IrOpcode::kWord32Ror, 1, 31, kMode_Operand2_R_ROR_I,
198                        kMode_Operand2_R_ROR_R>(selector, opcode_return, node,
199                                                value_return, shift_return);
200 }
201 
TryMatchASR(InstructionSelector * selector,InstructionCode * opcode_return,Node * node,InstructionOperand * value_return,InstructionOperand * shift_return)202 bool TryMatchASR(InstructionSelector* selector, InstructionCode* opcode_return,
203                  Node* node, InstructionOperand* value_return,
204                  InstructionOperand* shift_return) {
205   return TryMatchShift<IrOpcode::kWord32Sar, 1, 32, kMode_Operand2_R_ASR_I,
206                        kMode_Operand2_R_ASR_R>(selector, opcode_return, node,
207                                                value_return, shift_return);
208 }
209 
TryMatchLSL(InstructionSelector * selector,InstructionCode * opcode_return,Node * node,InstructionOperand * value_return,InstructionOperand * shift_return)210 bool TryMatchLSL(InstructionSelector* selector, InstructionCode* opcode_return,
211                  Node* node, InstructionOperand* value_return,
212                  InstructionOperand* shift_return) {
213   return TryMatchShift<IrOpcode::kWord32Shl, 0, 31, kMode_Operand2_R_LSL_I,
214                        kMode_Operand2_R_LSL_R>(selector, opcode_return, node,
215                                                value_return, shift_return);
216 }
217 
TryMatchLSLImmediate(InstructionSelector * selector,InstructionCode * opcode_return,Node * node,InstructionOperand * value_return,InstructionOperand * shift_return)218 bool TryMatchLSLImmediate(InstructionSelector* selector,
219                           InstructionCode* opcode_return, Node* node,
220                           InstructionOperand* value_return,
221                           InstructionOperand* shift_return) {
222   return TryMatchShiftImmediate<IrOpcode::kWord32Shl, 0, 31,
223                                 kMode_Operand2_R_LSL_I>(
224       selector, opcode_return, node, value_return, shift_return);
225 }
226 
TryMatchLSR(InstructionSelector * selector,InstructionCode * opcode_return,Node * node,InstructionOperand * value_return,InstructionOperand * shift_return)227 bool TryMatchLSR(InstructionSelector* selector, InstructionCode* opcode_return,
228                  Node* node, InstructionOperand* value_return,
229                  InstructionOperand* shift_return) {
230   return TryMatchShift<IrOpcode::kWord32Shr, 1, 32, kMode_Operand2_R_LSR_I,
231                        kMode_Operand2_R_LSR_R>(selector, opcode_return, node,
232                                                value_return, shift_return);
233 }
234 
TryMatchShift(InstructionSelector * selector,InstructionCode * opcode_return,Node * node,InstructionOperand * value_return,InstructionOperand * shift_return)235 bool TryMatchShift(InstructionSelector* selector,
236                    InstructionCode* opcode_return, Node* node,
237                    InstructionOperand* value_return,
238                    InstructionOperand* shift_return) {
239   return (
240       TryMatchASR(selector, opcode_return, node, value_return, shift_return) ||
241       TryMatchLSL(selector, opcode_return, node, value_return, shift_return) ||
242       TryMatchLSR(selector, opcode_return, node, value_return, shift_return) ||
243       TryMatchROR(selector, opcode_return, node, value_return, shift_return));
244 }
245 
TryMatchImmediateOrShift(InstructionSelector * selector,InstructionCode * opcode_return,Node * node,size_t * input_count_return,InstructionOperand * inputs)246 bool TryMatchImmediateOrShift(InstructionSelector* selector,
247                               InstructionCode* opcode_return, Node* node,
248                               size_t* input_count_return,
249                               InstructionOperand* inputs) {
250   ArmOperandGenerator g(selector);
251   if (g.CanBeImmediate(node, *opcode_return)) {
252     *opcode_return |= AddressingModeField::encode(kMode_Operand2_I);
253     inputs[0] = g.UseImmediate(node);
254     *input_count_return = 1;
255     return true;
256   }
257   if (TryMatchShift(selector, opcode_return, node, &inputs[0], &inputs[1])) {
258     *input_count_return = 2;
259     return true;
260   }
261   return false;
262 }
263 
VisitBinop(InstructionSelector * selector,Node * node,InstructionCode opcode,InstructionCode reverse_opcode,FlagsContinuation * cont)264 void VisitBinop(InstructionSelector* selector, Node* node,
265                 InstructionCode opcode, InstructionCode reverse_opcode,
266                 FlagsContinuation* cont) {
267   ArmOperandGenerator g(selector);
268   Int32BinopMatcher m(node);
269   InstructionOperand inputs[3];
270   size_t input_count = 0;
271   InstructionOperand outputs[1];
272   size_t output_count = 0;
273 
274   if (m.left().node() == m.right().node()) {
275     // If both inputs refer to the same operand, enforce allocating a register
276     // for both of them to ensure that we don't end up generating code like
277     // this:
278     //
279     //   mov r0, r1, asr #16
280     //   adds r0, r0, r1, asr #16
281     //   bvs label
282     InstructionOperand const input = g.UseRegister(m.left().node());
283     opcode |= AddressingModeField::encode(kMode_Operand2_R);
284     inputs[input_count++] = input;
285     inputs[input_count++] = input;
286   } else if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(),
287                                       &input_count, &inputs[1])) {
288     inputs[0] = g.UseRegister(m.left().node());
289     input_count++;
290   } else if (TryMatchImmediateOrShift(selector, &reverse_opcode,
291                                       m.left().node(), &input_count,
292                                       &inputs[1])) {
293     inputs[0] = g.UseRegister(m.right().node());
294     opcode = reverse_opcode;
295     input_count++;
296   } else {
297     opcode |= AddressingModeField::encode(kMode_Operand2_R);
298     inputs[input_count++] = g.UseRegister(m.left().node());
299     inputs[input_count++] = g.UseRegister(m.right().node());
300   }
301 
302   outputs[output_count++] = g.DefineAsRegister(node);
303 
304   DCHECK_NE(0u, input_count);
305   DCHECK_EQ(1u, output_count);
306   DCHECK_GE(arraysize(inputs), input_count);
307   DCHECK_GE(arraysize(outputs), output_count);
308   DCHECK_NE(kMode_None, AddressingModeField::decode(opcode));
309 
310   selector->EmitWithContinuation(opcode, output_count, outputs, input_count,
311                                  inputs, cont);
312 }
313 
VisitBinop(InstructionSelector * selector,Node * node,InstructionCode opcode,InstructionCode reverse_opcode)314 void VisitBinop(InstructionSelector* selector, Node* node,
315                 InstructionCode opcode, InstructionCode reverse_opcode) {
316   FlagsContinuation cont;
317   VisitBinop(selector, node, opcode, reverse_opcode, &cont);
318 }
319 
EmitDiv(InstructionSelector * selector,ArchOpcode div_opcode,ArchOpcode f64i32_opcode,ArchOpcode i32f64_opcode,InstructionOperand result_operand,InstructionOperand left_operand,InstructionOperand right_operand)320 void EmitDiv(InstructionSelector* selector, ArchOpcode div_opcode,
321              ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode,
322              InstructionOperand result_operand, InstructionOperand left_operand,
323              InstructionOperand right_operand) {
324   ArmOperandGenerator g(selector);
325   if (selector->IsSupported(SUDIV)) {
326     selector->Emit(div_opcode, result_operand, left_operand, right_operand);
327     return;
328   }
329   InstructionOperand left_double_operand = g.TempDoubleRegister();
330   InstructionOperand right_double_operand = g.TempDoubleRegister();
331   InstructionOperand result_double_operand = g.TempDoubleRegister();
332   selector->Emit(f64i32_opcode, left_double_operand, left_operand);
333   selector->Emit(f64i32_opcode, right_double_operand, right_operand);
334   selector->Emit(kArmVdivF64, result_double_operand, left_double_operand,
335                  right_double_operand);
336   selector->Emit(i32f64_opcode, result_operand, result_double_operand);
337 }
338 
VisitDiv(InstructionSelector * selector,Node * node,ArchOpcode div_opcode,ArchOpcode f64i32_opcode,ArchOpcode i32f64_opcode)339 void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode div_opcode,
340               ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode) {
341   ArmOperandGenerator g(selector);
342   Int32BinopMatcher m(node);
343   EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode,
344           g.DefineAsRegister(node), g.UseRegister(m.left().node()),
345           g.UseRegister(m.right().node()));
346 }
347 
VisitMod(InstructionSelector * selector,Node * node,ArchOpcode div_opcode,ArchOpcode f64i32_opcode,ArchOpcode i32f64_opcode)348 void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode div_opcode,
349               ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode) {
350   ArmOperandGenerator g(selector);
351   Int32BinopMatcher m(node);
352   InstructionOperand div_operand = g.TempRegister();
353   InstructionOperand result_operand = g.DefineAsRegister(node);
354   InstructionOperand left_operand = g.UseRegister(m.left().node());
355   InstructionOperand right_operand = g.UseRegister(m.right().node());
356   EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode, div_operand,
357           left_operand, right_operand);
358   if (selector->IsSupported(ARMv7)) {
359     selector->Emit(kArmMls, result_operand, div_operand, right_operand,
360                    left_operand);
361   } else {
362     InstructionOperand mul_operand = g.TempRegister();
363     selector->Emit(kArmMul, mul_operand, div_operand, right_operand);
364     selector->Emit(kArmSub | AddressingModeField::encode(kMode_Operand2_R),
365                    result_operand, left_operand, mul_operand);
366   }
367 }
368 
369 // Adds the base and offset into a register, then change the addressing
370 // mode of opcode_return to use this register. Certain instructions, e.g.
371 // vld1 and vst1, when given two registers, will post-increment the offset, i.e.
372 // perform the operation at base, then add offset to base. What we intend is to
373 // access at (base+offset).
EmitAddBeforeS128LoadStore(InstructionSelector * selector,InstructionCode * opcode_return,size_t * input_count_return,InstructionOperand * inputs)374 void EmitAddBeforeS128LoadStore(InstructionSelector* selector,
375                                 InstructionCode* opcode_return,
376                                 size_t* input_count_return,
377                                 InstructionOperand* inputs) {
378   ArmOperandGenerator g(selector);
379   InstructionOperand addr = g.TempRegister();
380   InstructionCode op = kArmAdd;
381   op |= AddressingModeField::encode(kMode_Operand2_R);
382   selector->Emit(op, 1, &addr, 2, inputs);
383   *opcode_return |= AddressingModeField::encode(kMode_Operand2_R);
384   *input_count_return -= 1;
385   inputs[0] = addr;
386 }
387 
EmitLoad(InstructionSelector * selector,InstructionCode opcode,InstructionOperand * output,Node * base,Node * index)388 void EmitLoad(InstructionSelector* selector, InstructionCode opcode,
389               InstructionOperand* output, Node* base, Node* index) {
390   ArmOperandGenerator g(selector);
391   InstructionOperand inputs[3];
392   size_t input_count = 2;
393 
394   ExternalReferenceMatcher m(base);
395   if (m.HasResolvedValue() &&
396       selector->CanAddressRelativeToRootsRegister(m.ResolvedValue())) {
397     Int32Matcher int_matcher(index);
398     if (int_matcher.HasResolvedValue()) {
399       ptrdiff_t const delta =
400           int_matcher.ResolvedValue() +
401           TurboAssemblerBase::RootRegisterOffsetForExternalReference(
402               selector->isolate(), m.ResolvedValue());
403       input_count = 1;
404       inputs[0] = g.UseImmediate(static_cast<int32_t>(delta));
405       opcode |= AddressingModeField::encode(kMode_Root);
406       selector->Emit(opcode, 1, output, input_count, inputs);
407       return;
408     }
409   }
410 
411   inputs[0] = g.UseRegister(base);
412   if (g.CanBeImmediate(index, opcode)) {
413     inputs[1] = g.UseImmediate(index);
414     opcode |= AddressingModeField::encode(kMode_Offset_RI);
415   } else if ((opcode == kArmLdr) &&
416              TryMatchLSLImmediate(selector, &opcode, index, &inputs[1],
417                                   &inputs[2])) {
418     input_count = 3;
419   } else {
420     inputs[1] = g.UseRegister(index);
421     if (opcode == kArmVld1S128) {
422       EmitAddBeforeS128LoadStore(selector, &opcode, &input_count, &inputs[0]);
423     } else {
424       opcode |= AddressingModeField::encode(kMode_Offset_RR);
425     }
426   }
427   selector->Emit(opcode, 1, output, input_count, inputs);
428 }
429 
EmitStore(InstructionSelector * selector,InstructionCode opcode,size_t input_count,InstructionOperand * inputs,Node * index)430 void EmitStore(InstructionSelector* selector, InstructionCode opcode,
431                size_t input_count, InstructionOperand* inputs, Node* index) {
432   ArmOperandGenerator g(selector);
433   ArchOpcode arch_opcode = ArchOpcodeField::decode(opcode);
434 
435   if (g.CanBeImmediate(index, opcode)) {
436     inputs[input_count++] = g.UseImmediate(index);
437     opcode |= AddressingModeField::encode(kMode_Offset_RI);
438   } else if ((arch_opcode == kArmStr || arch_opcode == kAtomicStoreWord32) &&
439              TryMatchLSLImmediate(selector, &opcode, index, &inputs[2],
440                                   &inputs[3])) {
441     input_count = 4;
442   } else {
443     inputs[input_count++] = g.UseRegister(index);
444     if (arch_opcode == kArmVst1S128) {
445       // Inputs are value, base, index, only care about base and index.
446       EmitAddBeforeS128LoadStore(selector, &opcode, &input_count, &inputs[1]);
447     } else {
448       opcode |= AddressingModeField::encode(kMode_Offset_RR);
449     }
450   }
451   selector->Emit(opcode, 0, nullptr, input_count, inputs);
452 }
453 
VisitPairAtomicBinOp(InstructionSelector * selector,Node * node,ArchOpcode opcode)454 void VisitPairAtomicBinOp(InstructionSelector* selector, Node* node,
455                           ArchOpcode opcode) {
456   ArmOperandGenerator g(selector);
457   Node* base = node->InputAt(0);
458   Node* index = node->InputAt(1);
459   Node* value = node->InputAt(2);
460   Node* value_high = node->InputAt(3);
461   AddressingMode addressing_mode = kMode_Offset_RR;
462   InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
463   InstructionOperand inputs[] = {
464       g.UseUniqueRegister(value), g.UseUniqueRegister(value_high),
465       g.UseUniqueRegister(base), g.UseUniqueRegister(index)};
466   InstructionOperand outputs[2];
467   size_t output_count = 0;
468   InstructionOperand temps[6];
469   size_t temp_count = 0;
470   temps[temp_count++] = g.TempRegister();
471   temps[temp_count++] = g.TempRegister(r6);
472   temps[temp_count++] = g.TempRegister(r7);
473   temps[temp_count++] = g.TempRegister();
474   Node* projection0 = NodeProperties::FindProjection(node, 0);
475   Node* projection1 = NodeProperties::FindProjection(node, 1);
476   if (projection0) {
477     outputs[output_count++] = g.DefineAsFixed(projection0, r2);
478   } else {
479     temps[temp_count++] = g.TempRegister(r2);
480   }
481   if (projection1) {
482     outputs[output_count++] = g.DefineAsFixed(projection1, r3);
483   } else {
484     temps[temp_count++] = g.TempRegister(r3);
485   }
486   selector->Emit(code, output_count, outputs, arraysize(inputs), inputs,
487                  temp_count, temps);
488 }
489 
490 }  // namespace
491 
VisitStackSlot(Node * node)492 void InstructionSelector::VisitStackSlot(Node* node) {
493   StackSlotRepresentation rep = StackSlotRepresentationOf(node->op());
494   int slot = frame_->AllocateSpillSlot(rep.size(), rep.alignment());
495   OperandGenerator g(this);
496 
497   Emit(kArchStackSlot, g.DefineAsRegister(node),
498        sequence()->AddImmediate(Constant(slot)), 0, nullptr);
499 }
500 
VisitAbortCSADcheck(Node * node)501 void InstructionSelector::VisitAbortCSADcheck(Node* node) {
502   ArmOperandGenerator g(this);
503   Emit(kArchAbortCSADcheck, g.NoOutput(), g.UseFixed(node->InputAt(0), r1));
504 }
505 
VisitStoreLane(Node * node)506 void InstructionSelector::VisitStoreLane(Node* node) {
507   StoreLaneParameters params = StoreLaneParametersOf(node->op());
508   LoadStoreLaneParams f(params.rep, params.laneidx);
509   InstructionCode opcode =
510       f.low_op ? kArmS128StoreLaneLow : kArmS128StoreLaneHigh;
511   opcode |= MiscField::encode(f.sz);
512 
513   ArmOperandGenerator g(this);
514   InstructionOperand inputs[4];
515   size_t input_count = 4;
516   inputs[0] = g.UseRegister(node->InputAt(2));
517   inputs[1] = g.UseImmediate(f.laneidx);
518   inputs[2] = g.UseRegister(node->InputAt(0));
519   inputs[3] = g.UseRegister(node->InputAt(1));
520   EmitAddBeforeS128LoadStore(this, &opcode, &input_count, &inputs[2]);
521   Emit(opcode, 0, nullptr, input_count, inputs);
522 }
523 
VisitLoadLane(Node * node)524 void InstructionSelector::VisitLoadLane(Node* node) {
525   LoadLaneParameters params = LoadLaneParametersOf(node->op());
526   LoadStoreLaneParams f(params.rep.representation(), params.laneidx);
527   InstructionCode opcode =
528       f.low_op ? kArmS128LoadLaneLow : kArmS128LoadLaneHigh;
529   opcode |= MiscField::encode(f.sz);
530 
531   ArmOperandGenerator g(this);
532   InstructionOperand output = g.DefineSameAsFirst(node);
533   InstructionOperand inputs[4];
534   size_t input_count = 4;
535   inputs[0] = g.UseRegister(node->InputAt(2));
536   inputs[1] = g.UseImmediate(f.laneidx);
537   inputs[2] = g.UseRegister(node->InputAt(0));
538   inputs[3] = g.UseRegister(node->InputAt(1));
539   EmitAddBeforeS128LoadStore(this, &opcode, &input_count, &inputs[2]);
540   Emit(opcode, 1, &output, input_count, inputs);
541 }
542 
VisitLoadTransform(Node * node)543 void InstructionSelector::VisitLoadTransform(Node* node) {
544   LoadTransformParameters params = LoadTransformParametersOf(node->op());
545   InstructionCode opcode = kArchNop;
546   switch (params.transformation) {
547     case LoadTransformation::kS128Load8Splat:
548       opcode = kArmS128Load8Splat;
549       break;
550     case LoadTransformation::kS128Load16Splat:
551       opcode = kArmS128Load16Splat;
552       break;
553     case LoadTransformation::kS128Load32Splat:
554       opcode = kArmS128Load32Splat;
555       break;
556     case LoadTransformation::kS128Load64Splat:
557       opcode = kArmS128Load64Splat;
558       break;
559     case LoadTransformation::kS128Load8x8S:
560       opcode = kArmS128Load8x8S;
561       break;
562     case LoadTransformation::kS128Load8x8U:
563       opcode = kArmS128Load8x8U;
564       break;
565     case LoadTransformation::kS128Load16x4S:
566       opcode = kArmS128Load16x4S;
567       break;
568     case LoadTransformation::kS128Load16x4U:
569       opcode = kArmS128Load16x4U;
570       break;
571     case LoadTransformation::kS128Load32x2S:
572       opcode = kArmS128Load32x2S;
573       break;
574     case LoadTransformation::kS128Load32x2U:
575       opcode = kArmS128Load32x2U;
576       break;
577     case LoadTransformation::kS128Load32Zero:
578       opcode = kArmS128Load32Zero;
579       break;
580     case LoadTransformation::kS128Load64Zero:
581       opcode = kArmS128Load64Zero;
582       break;
583     default:
584       UNIMPLEMENTED();
585   }
586 
587   ArmOperandGenerator g(this);
588   InstructionOperand output = g.DefineAsRegister(node);
589   InstructionOperand inputs[2];
590   size_t input_count = 2;
591   inputs[0] = g.UseRegister(node->InputAt(0));
592   inputs[1] = g.UseRegister(node->InputAt(1));
593   EmitAddBeforeS128LoadStore(this, &opcode, &input_count, &inputs[0]);
594   Emit(opcode, 1, &output, input_count, inputs);
595 }
596 
VisitLoad(Node * node)597 void InstructionSelector::VisitLoad(Node* node) {
598   LoadRepresentation load_rep = LoadRepresentationOf(node->op());
599   ArmOperandGenerator g(this);
600   Node* base = node->InputAt(0);
601   Node* index = node->InputAt(1);
602 
603   InstructionCode opcode = kArchNop;
604   switch (load_rep.representation()) {
605     case MachineRepresentation::kFloat32:
606       opcode = kArmVldrF32;
607       break;
608     case MachineRepresentation::kFloat64:
609       opcode = kArmVldrF64;
610       break;
611     case MachineRepresentation::kBit:  // Fall through.
612     case MachineRepresentation::kWord8:
613       opcode = load_rep.IsUnsigned() ? kArmLdrb : kArmLdrsb;
614       break;
615     case MachineRepresentation::kWord16:
616       opcode = load_rep.IsUnsigned() ? kArmLdrh : kArmLdrsh;
617       break;
618     case MachineRepresentation::kTaggedSigned:   // Fall through.
619     case MachineRepresentation::kTaggedPointer:  // Fall through.
620     case MachineRepresentation::kTagged:         // Fall through.
621     case MachineRepresentation::kWord32:
622       opcode = kArmLdr;
623       break;
624     case MachineRepresentation::kSimd128:
625       opcode = kArmVld1S128;
626       break;
627     case MachineRepresentation::kCompressedPointer:  // Fall through.
628     case MachineRepresentation::kCompressed:         // Fall through.
629     case MachineRepresentation::kSandboxedPointer:   // Fall through.
630     case MachineRepresentation::kWord64:             // Fall through.
631     case MachineRepresentation::kMapWord:            // Fall through.
632     case MachineRepresentation::kNone:
633       UNREACHABLE();
634   }
635 
636   InstructionOperand output = g.DefineAsRegister(node);
637   EmitLoad(this, opcode, &output, base, index);
638 }
639 
VisitProtectedLoad(Node * node)640 void InstructionSelector::VisitProtectedLoad(Node* node) {
641   // TODO(eholk)
642   UNIMPLEMENTED();
643 }
644 
645 namespace {
646 
GetStoreOpcode(MachineRepresentation rep)647 ArchOpcode GetStoreOpcode(MachineRepresentation rep) {
648   switch (rep) {
649     case MachineRepresentation::kFloat32:
650       return kArmVstrF32;
651     case MachineRepresentation::kFloat64:
652       return kArmVstrF64;
653     case MachineRepresentation::kBit:  // Fall through.
654     case MachineRepresentation::kWord8:
655       return kArmStrb;
656     case MachineRepresentation::kWord16:
657       return kArmStrh;
658     case MachineRepresentation::kTaggedSigned:   // Fall through.
659     case MachineRepresentation::kTaggedPointer:  // Fall through.
660     case MachineRepresentation::kTagged:         // Fall through.
661     case MachineRepresentation::kWord32:
662       return kArmStr;
663     case MachineRepresentation::kSimd128:
664       return kArmVst1S128;
665     case MachineRepresentation::kCompressedPointer:  // Fall through.
666     case MachineRepresentation::kCompressed:         // Fall through.
667     case MachineRepresentation::kSandboxedPointer:   // Fall through.
668     case MachineRepresentation::kWord64:             // Fall through.
669     case MachineRepresentation::kMapWord:            // Fall through.
670     case MachineRepresentation::kNone:
671       UNREACHABLE();
672   }
673 }
674 
GetAtomicStoreOpcode(MachineRepresentation rep)675 ArchOpcode GetAtomicStoreOpcode(MachineRepresentation rep) {
676   switch (rep) {
677     case MachineRepresentation::kWord8:
678       return kAtomicStoreWord8;
679     case MachineRepresentation::kWord16:
680       return kAtomicStoreWord16;
681     case MachineRepresentation::kTaggedSigned:   // Fall through.
682     case MachineRepresentation::kTaggedPointer:  // Fall through.
683     case MachineRepresentation::kTagged:         // Fall through.
684     case MachineRepresentation::kWord32:
685       return kAtomicStoreWord32;
686     default:
687       UNREACHABLE();
688   }
689 }
690 
VisitStoreCommon(InstructionSelector * selector,Node * node,StoreRepresentation store_rep,base::Optional<AtomicMemoryOrder> atomic_order)691 void VisitStoreCommon(InstructionSelector* selector, Node* node,
692                       StoreRepresentation store_rep,
693                       base::Optional<AtomicMemoryOrder> atomic_order) {
694   ArmOperandGenerator g(selector);
695   Node* base = node->InputAt(0);
696   Node* index = node->InputAt(1);
697   Node* value = node->InputAt(2);
698 
699   WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind();
700   MachineRepresentation rep = store_rep.representation();
701 
702   if (FLAG_enable_unconditional_write_barriers && CanBeTaggedPointer(rep)) {
703     write_barrier_kind = kFullWriteBarrier;
704   }
705 
706   if (write_barrier_kind != kNoWriteBarrier && !FLAG_disable_write_barriers) {
707     DCHECK(CanBeTaggedPointer(rep));
708     AddressingMode addressing_mode;
709     InstructionOperand inputs[3];
710     size_t input_count = 0;
711     inputs[input_count++] = g.UseUniqueRegister(base);
712     // OutOfLineRecordWrite uses the index in an 'add' instruction as well as
713     // for the store itself, so we must check compatibility with both.
714     if (g.CanBeImmediate(index, kArmAdd) && g.CanBeImmediate(index, kArmStr)) {
715       inputs[input_count++] = g.UseImmediate(index);
716       addressing_mode = kMode_Offset_RI;
717     } else {
718       inputs[input_count++] = g.UseUniqueRegister(index);
719       addressing_mode = kMode_Offset_RR;
720     }
721     inputs[input_count++] = g.UseUniqueRegister(value);
722     RecordWriteMode record_write_mode =
723         WriteBarrierKindToRecordWriteMode(write_barrier_kind);
724     InstructionCode code;
725     if (!atomic_order) {
726       code = kArchStoreWithWriteBarrier;
727       code |= MiscField::encode(static_cast<int>(record_write_mode));
728     } else {
729       code = kArchAtomicStoreWithWriteBarrier;
730       code |= AtomicMemoryOrderField::encode(*atomic_order);
731       code |= AtomicStoreRecordWriteModeField::encode(record_write_mode);
732     }
733     code |= AddressingModeField::encode(addressing_mode);
734     selector->Emit(code, 0, nullptr, input_count, inputs);
735   } else {
736     InstructionCode opcode = kArchNop;
737     if (!atomic_order) {
738       opcode = GetStoreOpcode(rep);
739     } else {
740       // Release stores emit DMB ISH; STR while sequentially consistent stores
741       // emit DMB ISH; STR; DMB ISH.
742       // https://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html
743       opcode = GetAtomicStoreOpcode(rep);
744       opcode |= AtomicMemoryOrderField::encode(*atomic_order);
745     }
746 
747     ExternalReferenceMatcher m(base);
748     if (m.HasResolvedValue() &&
749         selector->CanAddressRelativeToRootsRegister(m.ResolvedValue())) {
750       Int32Matcher int_matcher(index);
751       if (int_matcher.HasResolvedValue()) {
752         ptrdiff_t const delta =
753             int_matcher.ResolvedValue() +
754             TurboAssemblerBase::RootRegisterOffsetForExternalReference(
755                 selector->isolate(), m.ResolvedValue());
756         int input_count = 2;
757         InstructionOperand inputs[2];
758         inputs[0] = g.UseRegister(value);
759         inputs[1] = g.UseImmediate(static_cast<int32_t>(delta));
760         opcode |= AddressingModeField::encode(kMode_Root);
761         selector->Emit(opcode, 0, nullptr, input_count, inputs);
762         return;
763       }
764     }
765 
766     InstructionOperand inputs[4];
767     size_t input_count = 0;
768     inputs[input_count++] = g.UseRegister(value);
769     inputs[input_count++] = g.UseRegister(base);
770     EmitStore(selector, opcode, input_count, inputs, index);
771   }
772 }
773 
774 }  // namespace
775 
VisitStore(Node * node)776 void InstructionSelector::VisitStore(Node* node) {
777   VisitStoreCommon(this, node, StoreRepresentationOf(node->op()),
778                    base::nullopt);
779 }
780 
VisitProtectedStore(Node * node)781 void InstructionSelector::VisitProtectedStore(Node* node) {
782   // TODO(eholk)
783   UNIMPLEMENTED();
784 }
785 
VisitUnalignedLoad(Node * node)786 void InstructionSelector::VisitUnalignedLoad(Node* node) {
787   MachineRepresentation load_rep =
788       LoadRepresentationOf(node->op()).representation();
789   ArmOperandGenerator g(this);
790   Node* base = node->InputAt(0);
791   Node* index = node->InputAt(1);
792 
793   InstructionCode opcode = kArmLdr;
794   // Only floating point loads need to be specially handled; integer loads
795   // support unaligned access. We support unaligned FP loads by loading to
796   // integer registers first, then moving to the destination FP register. If
797   // NEON is supported, we use the vld1.8 instruction.
798   switch (load_rep) {
799     case MachineRepresentation::kFloat32: {
800       InstructionOperand temp = g.TempRegister();
801       EmitLoad(this, opcode, &temp, base, index);
802       Emit(kArmVmovF32U32, g.DefineAsRegister(node), temp);
803       return;
804     }
805     case MachineRepresentation::kFloat64: {
806       // Compute the address of the least-significant byte of the FP value.
807       // We assume that the base node is unlikely to be an encodable immediate
808       // or the result of a shift operation, so only consider the addressing
809       // mode that should be used for the index node.
810       InstructionCode add_opcode = kArmAdd;
811       InstructionOperand inputs[3];
812       inputs[0] = g.UseRegister(base);
813 
814       size_t input_count;
815       if (TryMatchImmediateOrShift(this, &add_opcode, index, &input_count,
816                                    &inputs[1])) {
817         // input_count has been set by TryMatchImmediateOrShift(), so
818         // increment it to account for the base register in inputs[0].
819         input_count++;
820       } else {
821         add_opcode |= AddressingModeField::encode(kMode_Operand2_R);
822         inputs[1] = g.UseRegister(index);
823         input_count = 2;  // Base register and index.
824       }
825 
826       InstructionOperand addr = g.TempRegister();
827       Emit(add_opcode, 1, &addr, input_count, inputs);
828 
829       if (CpuFeatures::IsSupported(NEON)) {
830         // With NEON we can load directly from the calculated address.
831         InstructionCode op = kArmVld1F64;
832         op |= AddressingModeField::encode(kMode_Operand2_R);
833         Emit(op, g.DefineAsRegister(node), addr);
834       } else {
835         // Load both halves and move to an FP register.
836         InstructionOperand fp_lo = g.TempRegister();
837         InstructionOperand fp_hi = g.TempRegister();
838         opcode |= AddressingModeField::encode(kMode_Offset_RI);
839         Emit(opcode, fp_lo, addr, g.TempImmediate(0));
840         Emit(opcode, fp_hi, addr, g.TempImmediate(4));
841         Emit(kArmVmovF64U32U32, g.DefineAsRegister(node), fp_lo, fp_hi);
842       }
843       return;
844     }
845     default:
846       // All other cases should support unaligned accesses.
847       UNREACHABLE();
848   }
849 }
850 
VisitUnalignedStore(Node * node)851 void InstructionSelector::VisitUnalignedStore(Node* node) {
852   ArmOperandGenerator g(this);
853   Node* base = node->InputAt(0);
854   Node* index = node->InputAt(1);
855   Node* value = node->InputAt(2);
856 
857   InstructionOperand inputs[4];
858   size_t input_count = 0;
859 
860   UnalignedStoreRepresentation store_rep =
861       UnalignedStoreRepresentationOf(node->op());
862 
863   // Only floating point stores need to be specially handled; integer stores
864   // support unaligned access. We support unaligned FP stores by moving the
865   // value to integer registers first, then storing to the destination address.
866   // If NEON is supported, we use the vst1.8 instruction.
867   switch (store_rep) {
868     case MachineRepresentation::kFloat32: {
869       inputs[input_count++] = g.TempRegister();
870       Emit(kArmVmovU32F32, inputs[0], g.UseRegister(value));
871       inputs[input_count++] = g.UseRegister(base);
872       EmitStore(this, kArmStr, input_count, inputs, index);
873       return;
874     }
875     case MachineRepresentation::kFloat64: {
876       if (CpuFeatures::IsSupported(NEON)) {
877         InstructionOperand address = g.TempRegister();
878         {
879           // First we have to calculate the actual address.
880           InstructionCode add_opcode = kArmAdd;
881           InstructionOperand inputs[3];
882           inputs[0] = g.UseRegister(base);
883 
884           size_t input_count;
885           if (TryMatchImmediateOrShift(this, &add_opcode, index, &input_count,
886                                        &inputs[1])) {
887             // input_count has been set by TryMatchImmediateOrShift(), so
888             // increment it to account for the base register in inputs[0].
889             input_count++;
890           } else {
891             add_opcode |= AddressingModeField::encode(kMode_Operand2_R);
892             inputs[1] = g.UseRegister(index);
893             input_count = 2;  // Base register and index.
894           }
895 
896           Emit(add_opcode, 1, &address, input_count, inputs);
897         }
898 
899         inputs[input_count++] = g.UseRegister(value);
900         inputs[input_count++] = address;
901         InstructionCode op = kArmVst1F64;
902         op |= AddressingModeField::encode(kMode_Operand2_R);
903         Emit(op, 0, nullptr, input_count, inputs);
904       } else {
905         // Store a 64-bit floating point value using two 32-bit integer stores.
906         // Computing the store address here would require three live temporary
907         // registers (fp<63:32>, fp<31:0>, address), so compute base + 4 after
908         // storing the least-significant half of the value.
909 
910         // First, move the 64-bit FP value into two temporary integer registers.
911         InstructionOperand fp[] = {g.TempRegister(), g.TempRegister()};
912         inputs[input_count++] = g.UseRegister(value);
913         Emit(kArmVmovU32U32F64, arraysize(fp), fp, input_count, inputs);
914 
915         // Store the least-significant half.
916         inputs[0] = fp[0];  // Low 32-bits of FP value.
917         inputs[input_count++] =
918             g.UseRegister(base);  // First store base address.
919         EmitStore(this, kArmStr, input_count, inputs, index);
920 
921         // Store the most-significant half.
922         InstructionOperand base4 = g.TempRegister();
923         Emit(kArmAdd | AddressingModeField::encode(kMode_Operand2_I), base4,
924              g.UseRegister(base), g.TempImmediate(4));  // Compute base + 4.
925         inputs[0] = fp[1];  // High 32-bits of FP value.
926         inputs[1] = base4;  // Second store base + 4 address.
927         EmitStore(this, kArmStr, input_count, inputs, index);
928       }
929       return;
930     }
931     default:
932       // All other cases should support unaligned accesses.
933       UNREACHABLE();
934   }
935 }
936 
937 namespace {
938 
EmitBic(InstructionSelector * selector,Node * node,Node * left,Node * right)939 void EmitBic(InstructionSelector* selector, Node* node, Node* left,
940              Node* right) {
941   ArmOperandGenerator g(selector);
942   InstructionCode opcode = kArmBic;
943   InstructionOperand value_operand;
944   InstructionOperand shift_operand;
945   if (TryMatchShift(selector, &opcode, right, &value_operand, &shift_operand)) {
946     selector->Emit(opcode, g.DefineAsRegister(node), g.UseRegister(left),
947                    value_operand, shift_operand);
948     return;
949   }
950   selector->Emit(opcode | AddressingModeField::encode(kMode_Operand2_R),
951                  g.DefineAsRegister(node), g.UseRegister(left),
952                  g.UseRegister(right));
953 }
954 
EmitUbfx(InstructionSelector * selector,Node * node,Node * left,uint32_t lsb,uint32_t width)955 void EmitUbfx(InstructionSelector* selector, Node* node, Node* left,
956               uint32_t lsb, uint32_t width) {
957   DCHECK_LE(lsb, 31u);
958   DCHECK_LE(1u, width);
959   DCHECK_LE(width, 32u - lsb);
960   ArmOperandGenerator g(selector);
961   selector->Emit(kArmUbfx, g.DefineAsRegister(node), g.UseRegister(left),
962                  g.TempImmediate(lsb), g.TempImmediate(width));
963 }
964 
965 }  // namespace
966 
VisitWord32And(Node * node)967 void InstructionSelector::VisitWord32And(Node* node) {
968   ArmOperandGenerator g(this);
969   Int32BinopMatcher m(node);
970   if (m.left().IsWord32Xor() && CanCover(node, m.left().node())) {
971     Int32BinopMatcher mleft(m.left().node());
972     if (mleft.right().Is(-1)) {
973       EmitBic(this, node, m.right().node(), mleft.left().node());
974       return;
975     }
976   }
977   if (m.right().IsWord32Xor() && CanCover(node, m.right().node())) {
978     Int32BinopMatcher mright(m.right().node());
979     if (mright.right().Is(-1)) {
980       EmitBic(this, node, m.left().node(), mright.left().node());
981       return;
982     }
983   }
984   if (m.right().HasResolvedValue()) {
985     uint32_t const value = m.right().ResolvedValue();
986     uint32_t width = base::bits::CountPopulation(value);
987     uint32_t leading_zeros = base::bits::CountLeadingZeros32(value);
988 
989     // Try to merge SHR operations on the left hand input into this AND.
990     if (m.left().IsWord32Shr()) {
991       Int32BinopMatcher mshr(m.left().node());
992       if (mshr.right().HasResolvedValue()) {
993         uint32_t const shift = mshr.right().ResolvedValue();
994 
995         if (((shift == 8) || (shift == 16) || (shift == 24)) &&
996             (value == 0xFF)) {
997           // Merge SHR into AND by emitting a UXTB instruction with a
998           // bytewise rotation.
999           Emit(kArmUxtb, g.DefineAsRegister(m.node()),
1000                g.UseRegister(mshr.left().node()),
1001                g.TempImmediate(mshr.right().ResolvedValue()));
1002           return;
1003         } else if (((shift == 8) || (shift == 16)) && (value == 0xFFFF)) {
1004           // Merge SHR into AND by emitting a UXTH instruction with a
1005           // bytewise rotation.
1006           Emit(kArmUxth, g.DefineAsRegister(m.node()),
1007                g.UseRegister(mshr.left().node()),
1008                g.TempImmediate(mshr.right().ResolvedValue()));
1009           return;
1010         } else if (IsSupported(ARMv7) && (width != 0) &&
1011                    ((leading_zeros + width) == 32)) {
1012           // Merge Shr into And by emitting a UBFX instruction.
1013           DCHECK_EQ(0u, base::bits::CountTrailingZeros32(value));
1014           if ((1 <= shift) && (shift <= 31)) {
1015             // UBFX cannot extract bits past the register size, however since
1016             // shifting the original value would have introduced some zeros we
1017             // can still use UBFX with a smaller mask and the remaining bits
1018             // will be zeros.
1019             EmitUbfx(this, node, mshr.left().node(), shift,
1020                      std::min(width, 32 - shift));
1021             return;
1022           }
1023         }
1024       }
1025     } else if (value == 0xFFFF) {
1026       // Emit UXTH for this AND. We don't bother testing for UXTB, as it's no
1027       // better than AND 0xFF for this operation.
1028       Emit(kArmUxth, g.DefineAsRegister(m.node()),
1029            g.UseRegister(m.left().node()), g.TempImmediate(0));
1030       return;
1031     }
1032     if (g.CanBeImmediate(~value)) {
1033       // Emit BIC for this AND by inverting the immediate value first.
1034       Emit(kArmBic | AddressingModeField::encode(kMode_Operand2_I),
1035            g.DefineAsRegister(node), g.UseRegister(m.left().node()),
1036            g.TempImmediate(~value));
1037       return;
1038     }
1039     if (!g.CanBeImmediate(value) && IsSupported(ARMv7)) {
1040       // If value has 9 to 23 contiguous set bits, and has the lsb set, we can
1041       // replace this AND with UBFX. Other contiguous bit patterns have already
1042       // been handled by BIC or will be handled by AND.
1043       if ((width != 0) && ((leading_zeros + width) == 32) &&
1044           (9 <= leading_zeros) && (leading_zeros <= 23)) {
1045         DCHECK_EQ(0u, base::bits::CountTrailingZeros32(value));
1046         EmitUbfx(this, node, m.left().node(), 0, width);
1047         return;
1048       }
1049 
1050       width = 32 - width;
1051       leading_zeros = base::bits::CountLeadingZeros32(~value);
1052       uint32_t lsb = base::bits::CountTrailingZeros32(~value);
1053       if ((leading_zeros + width + lsb) == 32) {
1054         // This AND can be replaced with BFC.
1055         Emit(kArmBfc, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
1056              g.TempImmediate(lsb), g.TempImmediate(width));
1057         return;
1058       }
1059     }
1060   }
1061   VisitBinop(this, node, kArmAnd, kArmAnd);
1062 }
1063 
VisitWord32Or(Node * node)1064 void InstructionSelector::VisitWord32Or(Node* node) {
1065   VisitBinop(this, node, kArmOrr, kArmOrr);
1066 }
1067 
VisitWord32Xor(Node * node)1068 void InstructionSelector::VisitWord32Xor(Node* node) {
1069   ArmOperandGenerator g(this);
1070   Int32BinopMatcher m(node);
1071   if (m.right().Is(-1)) {
1072     InstructionCode opcode = kArmMvn;
1073     InstructionOperand value_operand;
1074     InstructionOperand shift_operand;
1075     if (TryMatchShift(this, &opcode, m.left().node(), &value_operand,
1076                       &shift_operand)) {
1077       Emit(opcode, g.DefineAsRegister(node), value_operand, shift_operand);
1078       return;
1079     }
1080     Emit(opcode | AddressingModeField::encode(kMode_Operand2_R),
1081          g.DefineAsRegister(node), g.UseRegister(m.left().node()));
1082     return;
1083   }
1084   VisitBinop(this, node, kArmEor, kArmEor);
1085 }
1086 
VisitStackPointerGreaterThan(Node * node,FlagsContinuation * cont)1087 void InstructionSelector::VisitStackPointerGreaterThan(
1088     Node* node, FlagsContinuation* cont) {
1089   StackCheckKind kind = StackCheckKindOf(node->op());
1090   InstructionCode opcode =
1091       kArchStackPointerGreaterThan | MiscField::encode(static_cast<int>(kind));
1092 
1093   ArmOperandGenerator g(this);
1094 
1095   // No outputs.
1096   InstructionOperand* const outputs = nullptr;
1097   const int output_count = 0;
1098 
1099   // Applying an offset to this stack check requires a temp register. Offsets
1100   // are only applied to the first stack check. If applying an offset, we must
1101   // ensure the input and temp registers do not alias, thus kUniqueRegister.
1102   InstructionOperand temps[] = {g.TempRegister()};
1103   const int temp_count = (kind == StackCheckKind::kJSFunctionEntry) ? 1 : 0;
1104   const auto register_mode = (kind == StackCheckKind::kJSFunctionEntry)
1105                                  ? OperandGenerator::kUniqueRegister
1106                                  : OperandGenerator::kRegister;
1107 
1108   Node* const value = node->InputAt(0);
1109   InstructionOperand inputs[] = {g.UseRegisterWithMode(value, register_mode)};
1110   static constexpr int input_count = arraysize(inputs);
1111 
1112   EmitWithContinuation(opcode, output_count, outputs, input_count, inputs,
1113                        temp_count, temps, cont);
1114 }
1115 
1116 namespace {
1117 
1118 template <typename TryMatchShift>
VisitShift(InstructionSelector * selector,Node * node,TryMatchShift try_match_shift,FlagsContinuation * cont)1119 void VisitShift(InstructionSelector* selector, Node* node,
1120                 TryMatchShift try_match_shift, FlagsContinuation* cont) {
1121   ArmOperandGenerator g(selector);
1122   InstructionCode opcode = kArmMov;
1123   InstructionOperand inputs[2];
1124   size_t input_count = 2;
1125   InstructionOperand outputs[1];
1126   size_t output_count = 0;
1127 
1128   CHECK(try_match_shift(selector, &opcode, node, &inputs[0], &inputs[1]));
1129 
1130   outputs[output_count++] = g.DefineAsRegister(node);
1131 
1132   DCHECK_NE(0u, input_count);
1133   DCHECK_NE(0u, output_count);
1134   DCHECK_GE(arraysize(inputs), input_count);
1135   DCHECK_GE(arraysize(outputs), output_count);
1136   DCHECK_NE(kMode_None, AddressingModeField::decode(opcode));
1137 
1138   selector->EmitWithContinuation(opcode, output_count, outputs, input_count,
1139                                  inputs, cont);
1140 }
1141 
1142 template <typename TryMatchShift>
VisitShift(InstructionSelector * selector,Node * node,TryMatchShift try_match_shift)1143 void VisitShift(InstructionSelector* selector, Node* node,
1144                 TryMatchShift try_match_shift) {
1145   FlagsContinuation cont;
1146   VisitShift(selector, node, try_match_shift, &cont);
1147 }
1148 
1149 }  // namespace
1150 
VisitWord32Shl(Node * node)1151 void InstructionSelector::VisitWord32Shl(Node* node) {
1152   VisitShift(this, node, TryMatchLSL);
1153 }
1154 
VisitWord32Shr(Node * node)1155 void InstructionSelector::VisitWord32Shr(Node* node) {
1156   ArmOperandGenerator g(this);
1157   Int32BinopMatcher m(node);
1158   if (IsSupported(ARMv7) && m.left().IsWord32And() &&
1159       m.right().IsInRange(0, 31)) {
1160     uint32_t lsb = m.right().ResolvedValue();
1161     Int32BinopMatcher mleft(m.left().node());
1162     if (mleft.right().HasResolvedValue()) {
1163       uint32_t value =
1164           static_cast<uint32_t>(mleft.right().ResolvedValue() >> lsb) << lsb;
1165       uint32_t width = base::bits::CountPopulation(value);
1166       uint32_t msb = base::bits::CountLeadingZeros32(value);
1167       if ((width != 0) && (msb + width + lsb == 32)) {
1168         DCHECK_EQ(lsb, base::bits::CountTrailingZeros32(value));
1169         return EmitUbfx(this, node, mleft.left().node(), lsb, width);
1170       }
1171     }
1172   }
1173   VisitShift(this, node, TryMatchLSR);
1174 }
1175 
VisitWord32Sar(Node * node)1176 void InstructionSelector::VisitWord32Sar(Node* node) {
1177   ArmOperandGenerator g(this);
1178   Int32BinopMatcher m(node);
1179   if (CanCover(m.node(), m.left().node()) && m.left().IsWord32Shl()) {
1180     Int32BinopMatcher mleft(m.left().node());
1181     if (m.right().HasResolvedValue() && mleft.right().HasResolvedValue()) {
1182       uint32_t sar = m.right().ResolvedValue();
1183       uint32_t shl = mleft.right().ResolvedValue();
1184       if ((sar == shl) && (sar == 16)) {
1185         Emit(kArmSxth, g.DefineAsRegister(node),
1186              g.UseRegister(mleft.left().node()), g.TempImmediate(0));
1187         return;
1188       } else if ((sar == shl) && (sar == 24)) {
1189         Emit(kArmSxtb, g.DefineAsRegister(node),
1190              g.UseRegister(mleft.left().node()), g.TempImmediate(0));
1191         return;
1192       } else if (IsSupported(ARMv7) && (sar >= shl)) {
1193         Emit(kArmSbfx, g.DefineAsRegister(node),
1194              g.UseRegister(mleft.left().node()), g.TempImmediate(sar - shl),
1195              g.TempImmediate(32 - sar));
1196         return;
1197       }
1198     }
1199   }
1200   VisitShift(this, node, TryMatchASR);
1201 }
1202 
VisitInt32PairAdd(Node * node)1203 void InstructionSelector::VisitInt32PairAdd(Node* node) {
1204   ArmOperandGenerator g(this);
1205 
1206   Node* projection1 = NodeProperties::FindProjection(node, 1);
1207   if (projection1) {
1208     // We use UseUniqueRegister here to avoid register sharing with the output
1209     // registers.
1210     InstructionOperand inputs[] = {
1211         g.UseRegister(node->InputAt(0)), g.UseUniqueRegister(node->InputAt(1)),
1212         g.UseRegister(node->InputAt(2)), g.UseUniqueRegister(node->InputAt(3))};
1213 
1214     InstructionOperand outputs[] = {
1215         g.DefineAsRegister(node),
1216         g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
1217 
1218     Emit(kArmAddPair, 2, outputs, 4, inputs);
1219   } else {
1220     // The high word of the result is not used, so we emit the standard 32 bit
1221     // instruction.
1222     Emit(kArmAdd | AddressingModeField::encode(kMode_Operand2_R),
1223          g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)),
1224          g.UseRegister(node->InputAt(2)));
1225   }
1226 }
1227 
VisitInt32PairSub(Node * node)1228 void InstructionSelector::VisitInt32PairSub(Node* node) {
1229   ArmOperandGenerator g(this);
1230 
1231   Node* projection1 = NodeProperties::FindProjection(node, 1);
1232   if (projection1) {
1233     // We use UseUniqueRegister here to avoid register sharing with the output
1234     // register.
1235     InstructionOperand inputs[] = {
1236         g.UseRegister(node->InputAt(0)), g.UseUniqueRegister(node->InputAt(1)),
1237         g.UseRegister(node->InputAt(2)), g.UseUniqueRegister(node->InputAt(3))};
1238 
1239     InstructionOperand outputs[] = {
1240         g.DefineAsRegister(node),
1241         g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
1242 
1243     Emit(kArmSubPair, 2, outputs, 4, inputs);
1244   } else {
1245     // The high word of the result is not used, so we emit the standard 32 bit
1246     // instruction.
1247     Emit(kArmSub | AddressingModeField::encode(kMode_Operand2_R),
1248          g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)),
1249          g.UseRegister(node->InputAt(2)));
1250   }
1251 }
1252 
VisitInt32PairMul(Node * node)1253 void InstructionSelector::VisitInt32PairMul(Node* node) {
1254   ArmOperandGenerator g(this);
1255   Node* projection1 = NodeProperties::FindProjection(node, 1);
1256   if (projection1) {
1257     InstructionOperand inputs[] = {g.UseUniqueRegister(node->InputAt(0)),
1258                                    g.UseUniqueRegister(node->InputAt(1)),
1259                                    g.UseUniqueRegister(node->InputAt(2)),
1260                                    g.UseUniqueRegister(node->InputAt(3))};
1261 
1262     InstructionOperand outputs[] = {
1263         g.DefineAsRegister(node),
1264         g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
1265 
1266     Emit(kArmMulPair, 2, outputs, 4, inputs);
1267   } else {
1268     // The high word of the result is not used, so we emit the standard 32 bit
1269     // instruction.
1270     Emit(kArmMul | AddressingModeField::encode(kMode_Operand2_R),
1271          g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)),
1272          g.UseRegister(node->InputAt(2)));
1273   }
1274 }
1275 
1276 namespace {
1277 // Shared routine for multiple shift operations.
VisitWord32PairShift(InstructionSelector * selector,InstructionCode opcode,Node * node)1278 void VisitWord32PairShift(InstructionSelector* selector, InstructionCode opcode,
1279                           Node* node) {
1280   ArmOperandGenerator g(selector);
1281   // We use g.UseUniqueRegister here to guarantee that there is
1282   // no register aliasing of input registers with output registers.
1283   Int32Matcher m(node->InputAt(2));
1284   InstructionOperand shift_operand;
1285   if (m.HasResolvedValue()) {
1286     shift_operand = g.UseImmediate(m.node());
1287   } else {
1288     shift_operand = g.UseUniqueRegister(m.node());
1289   }
1290 
1291   InstructionOperand inputs[] = {g.UseUniqueRegister(node->InputAt(0)),
1292                                  g.UseUniqueRegister(node->InputAt(1)),
1293                                  shift_operand};
1294 
1295   Node* projection1 = NodeProperties::FindProjection(node, 1);
1296 
1297   InstructionOperand outputs[2];
1298   InstructionOperand temps[1];
1299   int32_t output_count = 0;
1300   int32_t temp_count = 0;
1301 
1302   outputs[output_count++] = g.DefineAsRegister(node);
1303   if (projection1) {
1304     outputs[output_count++] = g.DefineAsRegister(projection1);
1305   } else {
1306     temps[temp_count++] = g.TempRegister();
1307   }
1308 
1309   selector->Emit(opcode, output_count, outputs, 3, inputs, temp_count, temps);
1310 }
1311 }  // namespace
VisitWord32PairShl(Node * node)1312 void InstructionSelector::VisitWord32PairShl(Node* node) {
1313   VisitWord32PairShift(this, kArmLslPair, node);
1314 }
1315 
VisitWord32PairShr(Node * node)1316 void InstructionSelector::VisitWord32PairShr(Node* node) {
1317   VisitWord32PairShift(this, kArmLsrPair, node);
1318 }
1319 
VisitWord32PairSar(Node * node)1320 void InstructionSelector::VisitWord32PairSar(Node* node) {
1321   VisitWord32PairShift(this, kArmAsrPair, node);
1322 }
1323 
VisitWord32Rol(Node * node)1324 void InstructionSelector::VisitWord32Rol(Node* node) { UNREACHABLE(); }
1325 
VisitWord32Ror(Node * node)1326 void InstructionSelector::VisitWord32Ror(Node* node) {
1327   VisitShift(this, node, TryMatchROR);
1328 }
1329 
VisitWord32Ctz(Node * node)1330 void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); }
1331 
VisitWord32ReverseBits(Node * node)1332 void InstructionSelector::VisitWord32ReverseBits(Node* node) {
1333   DCHECK(IsSupported(ARMv7));
1334   VisitRR(this, kArmRbit, node);
1335 }
1336 
VisitWord64ReverseBytes(Node * node)1337 void InstructionSelector::VisitWord64ReverseBytes(Node* node) { UNREACHABLE(); }
1338 
VisitWord32ReverseBytes(Node * node)1339 void InstructionSelector::VisitWord32ReverseBytes(Node* node) {
1340   VisitRR(this, kArmRev, node);
1341 }
1342 
VisitSimd128ReverseBytes(Node * node)1343 void InstructionSelector::VisitSimd128ReverseBytes(Node* node) {
1344   UNREACHABLE();
1345 }
1346 
VisitWord32Popcnt(Node * node)1347 void InstructionSelector::VisitWord32Popcnt(Node* node) { UNREACHABLE(); }
1348 
VisitInt32Add(Node * node)1349 void InstructionSelector::VisitInt32Add(Node* node) {
1350   ArmOperandGenerator g(this);
1351   Int32BinopMatcher m(node);
1352   if (CanCover(node, m.left().node())) {
1353     switch (m.left().opcode()) {
1354       case IrOpcode::kInt32Mul: {
1355         Int32BinopMatcher mleft(m.left().node());
1356         Emit(kArmMla, g.DefineAsRegister(node),
1357              g.UseRegister(mleft.left().node()),
1358              g.UseRegister(mleft.right().node()),
1359              g.UseRegister(m.right().node()));
1360         return;
1361       }
1362       case IrOpcode::kInt32MulHigh: {
1363         Int32BinopMatcher mleft(m.left().node());
1364         Emit(kArmSmmla, g.DefineAsRegister(node),
1365              g.UseRegister(mleft.left().node()),
1366              g.UseRegister(mleft.right().node()),
1367              g.UseRegister(m.right().node()));
1368         return;
1369       }
1370       case IrOpcode::kWord32And: {
1371         Int32BinopMatcher mleft(m.left().node());
1372         if (mleft.right().Is(0xFF)) {
1373           Emit(kArmUxtab, g.DefineAsRegister(node),
1374                g.UseRegister(m.right().node()),
1375                g.UseRegister(mleft.left().node()), g.TempImmediate(0));
1376           return;
1377         } else if (mleft.right().Is(0xFFFF)) {
1378           Emit(kArmUxtah, g.DefineAsRegister(node),
1379                g.UseRegister(m.right().node()),
1380                g.UseRegister(mleft.left().node()), g.TempImmediate(0));
1381           return;
1382         }
1383         break;
1384       }
1385       case IrOpcode::kWord32Sar: {
1386         Int32BinopMatcher mleft(m.left().node());
1387         if (CanCover(mleft.node(), mleft.left().node()) &&
1388             mleft.left().IsWord32Shl()) {
1389           Int32BinopMatcher mleftleft(mleft.left().node());
1390           if (mleft.right().Is(24) && mleftleft.right().Is(24)) {
1391             Emit(kArmSxtab, g.DefineAsRegister(node),
1392                  g.UseRegister(m.right().node()),
1393                  g.UseRegister(mleftleft.left().node()), g.TempImmediate(0));
1394             return;
1395           } else if (mleft.right().Is(16) && mleftleft.right().Is(16)) {
1396             Emit(kArmSxtah, g.DefineAsRegister(node),
1397                  g.UseRegister(m.right().node()),
1398                  g.UseRegister(mleftleft.left().node()), g.TempImmediate(0));
1399             return;
1400           }
1401         }
1402         break;
1403       }
1404       default:
1405         break;
1406     }
1407   }
1408   if (CanCover(node, m.right().node())) {
1409     switch (m.right().opcode()) {
1410       case IrOpcode::kInt32Mul: {
1411         Int32BinopMatcher mright(m.right().node());
1412         Emit(kArmMla, g.DefineAsRegister(node),
1413              g.UseRegister(mright.left().node()),
1414              g.UseRegister(mright.right().node()),
1415              g.UseRegister(m.left().node()));
1416         return;
1417       }
1418       case IrOpcode::kInt32MulHigh: {
1419         Int32BinopMatcher mright(m.right().node());
1420         Emit(kArmSmmla, g.DefineAsRegister(node),
1421              g.UseRegister(mright.left().node()),
1422              g.UseRegister(mright.right().node()),
1423              g.UseRegister(m.left().node()));
1424         return;
1425       }
1426       case IrOpcode::kWord32And: {
1427         Int32BinopMatcher mright(m.right().node());
1428         if (mright.right().Is(0xFF)) {
1429           Emit(kArmUxtab, g.DefineAsRegister(node),
1430                g.UseRegister(m.left().node()),
1431                g.UseRegister(mright.left().node()), g.TempImmediate(0));
1432           return;
1433         } else if (mright.right().Is(0xFFFF)) {
1434           Emit(kArmUxtah, g.DefineAsRegister(node),
1435                g.UseRegister(m.left().node()),
1436                g.UseRegister(mright.left().node()), g.TempImmediate(0));
1437           return;
1438         }
1439         break;
1440       }
1441       case IrOpcode::kWord32Sar: {
1442         Int32BinopMatcher mright(m.right().node());
1443         if (CanCover(mright.node(), mright.left().node()) &&
1444             mright.left().IsWord32Shl()) {
1445           Int32BinopMatcher mrightleft(mright.left().node());
1446           if (mright.right().Is(24) && mrightleft.right().Is(24)) {
1447             Emit(kArmSxtab, g.DefineAsRegister(node),
1448                  g.UseRegister(m.left().node()),
1449                  g.UseRegister(mrightleft.left().node()), g.TempImmediate(0));
1450             return;
1451           } else if (mright.right().Is(16) && mrightleft.right().Is(16)) {
1452             Emit(kArmSxtah, g.DefineAsRegister(node),
1453                  g.UseRegister(m.left().node()),
1454                  g.UseRegister(mrightleft.left().node()), g.TempImmediate(0));
1455             return;
1456           }
1457         }
1458         break;
1459       }
1460       default:
1461         break;
1462     }
1463   }
1464   VisitBinop(this, node, kArmAdd, kArmAdd);
1465 }
1466 
VisitInt32Sub(Node * node)1467 void InstructionSelector::VisitInt32Sub(Node* node) {
1468   ArmOperandGenerator g(this);
1469   Int32BinopMatcher m(node);
1470   if (IsSupported(ARMv7) && m.right().IsInt32Mul() &&
1471       CanCover(node, m.right().node())) {
1472     Int32BinopMatcher mright(m.right().node());
1473     Emit(kArmMls, g.DefineAsRegister(node), g.UseRegister(mright.left().node()),
1474          g.UseRegister(mright.right().node()), g.UseRegister(m.left().node()));
1475     return;
1476   }
1477   VisitBinop(this, node, kArmSub, kArmRsb);
1478 }
1479 
1480 namespace {
1481 
EmitInt32MulWithOverflow(InstructionSelector * selector,Node * node,FlagsContinuation * cont)1482 void EmitInt32MulWithOverflow(InstructionSelector* selector, Node* node,
1483                               FlagsContinuation* cont) {
1484   ArmOperandGenerator g(selector);
1485   Int32BinopMatcher m(node);
1486   InstructionOperand result_operand = g.DefineAsRegister(node);
1487   InstructionOperand temp_operand = g.TempRegister();
1488   InstructionOperand outputs[] = {result_operand, temp_operand};
1489   InstructionOperand inputs[] = {g.UseRegister(m.left().node()),
1490                                  g.UseRegister(m.right().node())};
1491   selector->Emit(kArmSmull, 2, outputs, 2, inputs);
1492 
1493   // result operand needs shift operator.
1494   InstructionOperand shift_31 = g.UseImmediate(31);
1495   InstructionCode opcode =
1496       kArmCmp | AddressingModeField::encode(kMode_Operand2_R_ASR_I);
1497   selector->EmitWithContinuation(opcode, temp_operand, result_operand, shift_31,
1498                                  cont);
1499 }
1500 
1501 }  // namespace
1502 
VisitInt32Mul(Node * node)1503 void InstructionSelector::VisitInt32Mul(Node* node) {
1504   ArmOperandGenerator g(this);
1505   Int32BinopMatcher m(node);
1506   if (m.right().HasResolvedValue() && m.right().ResolvedValue() > 0) {
1507     int32_t value = m.right().ResolvedValue();
1508     if (base::bits::IsPowerOfTwo(value - 1)) {
1509       Emit(kArmAdd | AddressingModeField::encode(kMode_Operand2_R_LSL_I),
1510            g.DefineAsRegister(node), g.UseRegister(m.left().node()),
1511            g.UseRegister(m.left().node()),
1512            g.TempImmediate(base::bits::WhichPowerOfTwo(value - 1)));
1513       return;
1514     }
1515     if (value < kMaxInt && base::bits::IsPowerOfTwo(value + 1)) {
1516       Emit(kArmRsb | AddressingModeField::encode(kMode_Operand2_R_LSL_I),
1517            g.DefineAsRegister(node), g.UseRegister(m.left().node()),
1518            g.UseRegister(m.left().node()),
1519            g.TempImmediate(base::bits::WhichPowerOfTwo(value + 1)));
1520       return;
1521     }
1522   }
1523   VisitRRR(this, kArmMul, node);
1524 }
1525 
VisitUint32MulHigh(Node * node)1526 void InstructionSelector::VisitUint32MulHigh(Node* node) {
1527   ArmOperandGenerator g(this);
1528   InstructionOperand outputs[] = {g.TempRegister(), g.DefineAsRegister(node)};
1529   InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0)),
1530                                  g.UseRegister(node->InputAt(1))};
1531   Emit(kArmUmull, arraysize(outputs), outputs, arraysize(inputs), inputs);
1532 }
1533 
VisitInt32Div(Node * node)1534 void InstructionSelector::VisitInt32Div(Node* node) {
1535   VisitDiv(this, node, kArmSdiv, kArmVcvtF64S32, kArmVcvtS32F64);
1536 }
1537 
VisitUint32Div(Node * node)1538 void InstructionSelector::VisitUint32Div(Node* node) {
1539   VisitDiv(this, node, kArmUdiv, kArmVcvtF64U32, kArmVcvtU32F64);
1540 }
1541 
VisitInt32Mod(Node * node)1542 void InstructionSelector::VisitInt32Mod(Node* node) {
1543   VisitMod(this, node, kArmSdiv, kArmVcvtF64S32, kArmVcvtS32F64);
1544 }
1545 
VisitUint32Mod(Node * node)1546 void InstructionSelector::VisitUint32Mod(Node* node) {
1547   VisitMod(this, node, kArmUdiv, kArmVcvtF64U32, kArmVcvtU32F64);
1548 }
1549 
1550 #define RR_OP_LIST(V)                                \
1551   V(Word32Clz, kArmClz)                              \
1552   V(ChangeFloat32ToFloat64, kArmVcvtF64F32)          \
1553   V(RoundInt32ToFloat32, kArmVcvtF32S32)             \
1554   V(RoundUint32ToFloat32, kArmVcvtF32U32)            \
1555   V(ChangeInt32ToFloat64, kArmVcvtF64S32)            \
1556   V(ChangeUint32ToFloat64, kArmVcvtF64U32)           \
1557   V(ChangeFloat64ToInt32, kArmVcvtS32F64)            \
1558   V(ChangeFloat64ToUint32, kArmVcvtU32F64)           \
1559   V(TruncateFloat64ToUint32, kArmVcvtU32F64)         \
1560   V(TruncateFloat64ToFloat32, kArmVcvtF32F64)        \
1561   V(TruncateFloat64ToWord32, kArchTruncateDoubleToI) \
1562   V(RoundFloat64ToInt32, kArmVcvtS32F64)             \
1563   V(BitcastFloat32ToInt32, kArmVmovU32F32)           \
1564   V(BitcastInt32ToFloat32, kArmVmovF32U32)           \
1565   V(Float64ExtractLowWord32, kArmVmovLowU32F64)      \
1566   V(Float64ExtractHighWord32, kArmVmovHighU32F64)    \
1567   V(Float64SilenceNaN, kArmFloat64SilenceNaN)        \
1568   V(Float32Abs, kArmVabsF32)                         \
1569   V(Float64Abs, kArmVabsF64)                         \
1570   V(Float32Neg, kArmVnegF32)                         \
1571   V(Float64Neg, kArmVnegF64)                         \
1572   V(Float32Sqrt, kArmVsqrtF32)                       \
1573   V(Float64Sqrt, kArmVsqrtF64)
1574 
1575 #define RR_OP_LIST_V8(V)                  \
1576   V(Float32RoundDown, kArmVrintmF32)      \
1577   V(Float64RoundDown, kArmVrintmF64)      \
1578   V(Float32RoundUp, kArmVrintpF32)        \
1579   V(Float64RoundUp, kArmVrintpF64)        \
1580   V(Float32RoundTruncate, kArmVrintzF32)  \
1581   V(Float64RoundTruncate, kArmVrintzF64)  \
1582   V(Float64RoundTiesAway, kArmVrintaF64)  \
1583   V(Float32RoundTiesEven, kArmVrintnF32)  \
1584   V(Float64RoundTiesEven, kArmVrintnF64)  \
1585   V(F64x2Ceil, kArmF64x2Ceil)             \
1586   V(F64x2Floor, kArmF64x2Floor)           \
1587   V(F64x2Trunc, kArmF64x2Trunc)           \
1588   V(F64x2NearestInt, kArmF64x2NearestInt) \
1589   V(F32x4Ceil, kArmVrintpF32)             \
1590   V(F32x4Floor, kArmVrintmF32)            \
1591   V(F32x4Trunc, kArmVrintzF32)            \
1592   V(F32x4NearestInt, kArmVrintnF32)
1593 
1594 #define RRR_OP_LIST(V)          \
1595   V(Int32MulHigh, kArmSmmul)    \
1596   V(Float32Mul, kArmVmulF32)    \
1597   V(Float64Mul, kArmVmulF64)    \
1598   V(Float32Div, kArmVdivF32)    \
1599   V(Float64Div, kArmVdivF64)    \
1600   V(Float32Max, kArmFloat32Max) \
1601   V(Float64Max, kArmFloat64Max) \
1602   V(Float32Min, kArmFloat32Min) \
1603   V(Float64Min, kArmFloat64Min)
1604 
1605 #define RR_VISITOR(Name, opcode)                      \
1606   void InstructionSelector::Visit##Name(Node* node) { \
1607     VisitRR(this, opcode, node);                      \
1608   }
1609 RR_OP_LIST(RR_VISITOR)
1610 #undef RR_VISITOR
1611 #undef RR_OP_LIST
1612 
1613 #define RR_VISITOR_V8(Name, opcode)                   \
1614   void InstructionSelector::Visit##Name(Node* node) { \
1615     DCHECK(CpuFeatures::IsSupported(ARMv8));          \
1616     VisitRR(this, opcode, node);                      \
1617   }
RR_OP_LIST_V8(RR_VISITOR_V8)1618 RR_OP_LIST_V8(RR_VISITOR_V8)
1619 #undef RR_VISITOR_V8
1620 #undef RR_OP_LIST_V8
1621 
1622 #define RRR_VISITOR(Name, opcode)                     \
1623   void InstructionSelector::Visit##Name(Node* node) { \
1624     VisitRRR(this, opcode, node);                     \
1625   }
1626 RRR_OP_LIST(RRR_VISITOR)
1627 #undef RRR_VISITOR
1628 #undef RRR_OP_LIST
1629 
1630 void InstructionSelector::VisitFloat32Add(Node* node) {
1631   ArmOperandGenerator g(this);
1632   Float32BinopMatcher m(node);
1633   if (m.left().IsFloat32Mul() && CanCover(node, m.left().node())) {
1634     Float32BinopMatcher mleft(m.left().node());
1635     Emit(kArmVmlaF32, g.DefineSameAsFirst(node),
1636          g.UseRegister(m.right().node()), g.UseRegister(mleft.left().node()),
1637          g.UseRegister(mleft.right().node()));
1638     return;
1639   }
1640   if (m.right().IsFloat32Mul() && CanCover(node, m.right().node())) {
1641     Float32BinopMatcher mright(m.right().node());
1642     Emit(kArmVmlaF32, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
1643          g.UseRegister(mright.left().node()),
1644          g.UseRegister(mright.right().node()));
1645     return;
1646   }
1647   VisitRRR(this, kArmVaddF32, node);
1648 }
1649 
VisitFloat64Add(Node * node)1650 void InstructionSelector::VisitFloat64Add(Node* node) {
1651   ArmOperandGenerator g(this);
1652   Float64BinopMatcher m(node);
1653   if (m.left().IsFloat64Mul() && CanCover(node, m.left().node())) {
1654     Float64BinopMatcher mleft(m.left().node());
1655     Emit(kArmVmlaF64, g.DefineSameAsFirst(node),
1656          g.UseRegister(m.right().node()), g.UseRegister(mleft.left().node()),
1657          g.UseRegister(mleft.right().node()));
1658     return;
1659   }
1660   if (m.right().IsFloat64Mul() && CanCover(node, m.right().node())) {
1661     Float64BinopMatcher mright(m.right().node());
1662     Emit(kArmVmlaF64, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
1663          g.UseRegister(mright.left().node()),
1664          g.UseRegister(mright.right().node()));
1665     return;
1666   }
1667   VisitRRR(this, kArmVaddF64, node);
1668 }
1669 
VisitFloat32Sub(Node * node)1670 void InstructionSelector::VisitFloat32Sub(Node* node) {
1671   ArmOperandGenerator g(this);
1672   Float32BinopMatcher m(node);
1673   if (m.right().IsFloat32Mul() && CanCover(node, m.right().node())) {
1674     Float32BinopMatcher mright(m.right().node());
1675     Emit(kArmVmlsF32, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
1676          g.UseRegister(mright.left().node()),
1677          g.UseRegister(mright.right().node()));
1678     return;
1679   }
1680   VisitRRR(this, kArmVsubF32, node);
1681 }
1682 
VisitFloat64Sub(Node * node)1683 void InstructionSelector::VisitFloat64Sub(Node* node) {
1684   ArmOperandGenerator g(this);
1685   Float64BinopMatcher m(node);
1686   if (m.right().IsFloat64Mul() && CanCover(node, m.right().node())) {
1687     Float64BinopMatcher mright(m.right().node());
1688     Emit(kArmVmlsF64, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
1689          g.UseRegister(mright.left().node()),
1690          g.UseRegister(mright.right().node()));
1691     return;
1692   }
1693   VisitRRR(this, kArmVsubF64, node);
1694 }
1695 
VisitFloat64Mod(Node * node)1696 void InstructionSelector::VisitFloat64Mod(Node* node) {
1697   ArmOperandGenerator g(this);
1698   Emit(kArmVmodF64, g.DefineAsFixed(node, d0), g.UseFixed(node->InputAt(0), d0),
1699        g.UseFixed(node->InputAt(1), d1))
1700       ->MarkAsCall();
1701 }
1702 
VisitFloat64Ieee754Binop(Node * node,InstructionCode opcode)1703 void InstructionSelector::VisitFloat64Ieee754Binop(Node* node,
1704                                                    InstructionCode opcode) {
1705   ArmOperandGenerator g(this);
1706   Emit(opcode, g.DefineAsFixed(node, d0), g.UseFixed(node->InputAt(0), d0),
1707        g.UseFixed(node->InputAt(1), d1))
1708       ->MarkAsCall();
1709 }
1710 
VisitFloat64Ieee754Unop(Node * node,InstructionCode opcode)1711 void InstructionSelector::VisitFloat64Ieee754Unop(Node* node,
1712                                                   InstructionCode opcode) {
1713   ArmOperandGenerator g(this);
1714   Emit(opcode, g.DefineAsFixed(node, d0), g.UseFixed(node->InputAt(0), d0))
1715       ->MarkAsCall();
1716 }
1717 
EmitPrepareArguments(ZoneVector<PushParameter> * arguments,const CallDescriptor * call_descriptor,Node * node)1718 void InstructionSelector::EmitPrepareArguments(
1719     ZoneVector<PushParameter>* arguments, const CallDescriptor* call_descriptor,
1720     Node* node) {
1721   ArmOperandGenerator g(this);
1722 
1723   // Prepare for C function call.
1724   if (call_descriptor->IsCFunctionCall()) {
1725     Emit(kArchPrepareCallCFunction | MiscField::encode(static_cast<int>(
1726                                          call_descriptor->ParameterCount())),
1727          0, nullptr, 0, nullptr);
1728 
1729     // Poke any stack arguments.
1730     for (size_t n = 0; n < arguments->size(); ++n) {
1731       PushParameter input = (*arguments)[n];
1732       if (input.node) {
1733         int slot = static_cast<int>(n);
1734         Emit(kArmPoke | MiscField::encode(slot), g.NoOutput(),
1735              g.UseRegister(input.node));
1736       }
1737     }
1738   } else {
1739     // Push any stack arguments.
1740     int stack_decrement = 0;
1741     for (PushParameter input : base::Reversed(*arguments)) {
1742       stack_decrement += kSystemPointerSize;
1743       // Skip any alignment holes in pushed nodes.
1744       if (input.node == nullptr) continue;
1745       InstructionOperand decrement = g.UseImmediate(stack_decrement);
1746       stack_decrement = 0;
1747       Emit(kArmPush, g.NoOutput(), decrement, g.UseRegister(input.node));
1748     }
1749   }
1750 }
1751 
EmitPrepareResults(ZoneVector<PushParameter> * results,const CallDescriptor * call_descriptor,Node * node)1752 void InstructionSelector::EmitPrepareResults(
1753     ZoneVector<PushParameter>* results, const CallDescriptor* call_descriptor,
1754     Node* node) {
1755   ArmOperandGenerator g(this);
1756 
1757   for (PushParameter output : *results) {
1758     if (!output.location.IsCallerFrameSlot()) continue;
1759     // Skip any alignment holes in nodes.
1760     if (output.node != nullptr) {
1761       DCHECK(!call_descriptor->IsCFunctionCall());
1762       if (output.location.GetType() == MachineType::Float32()) {
1763         MarkAsFloat32(output.node);
1764       } else if (output.location.GetType() == MachineType::Float64()) {
1765         MarkAsFloat64(output.node);
1766       } else if (output.location.GetType() == MachineType::Simd128()) {
1767         MarkAsSimd128(output.node);
1768       }
1769       int offset = call_descriptor->GetOffsetToReturns();
1770       int reverse_slot = -output.location.GetLocation() - offset;
1771       Emit(kArmPeek, g.DefineAsRegister(output.node),
1772            g.UseImmediate(reverse_slot));
1773     }
1774   }
1775 }
1776 
IsTailCallAddressImmediate()1777 bool InstructionSelector::IsTailCallAddressImmediate() { return false; }
1778 
1779 namespace {
1780 
1781 // Shared routine for multiple compare operations.
VisitCompare(InstructionSelector * selector,InstructionCode opcode,InstructionOperand left,InstructionOperand right,FlagsContinuation * cont)1782 void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
1783                   InstructionOperand left, InstructionOperand right,
1784                   FlagsContinuation* cont) {
1785   selector->EmitWithContinuation(opcode, left, right, cont);
1786 }
1787 
1788 // Shared routine for multiple float32 compare operations.
VisitFloat32Compare(InstructionSelector * selector,Node * node,FlagsContinuation * cont)1789 void VisitFloat32Compare(InstructionSelector* selector, Node* node,
1790                          FlagsContinuation* cont) {
1791   ArmOperandGenerator g(selector);
1792   Float32BinopMatcher m(node);
1793   if (m.right().Is(0.0f)) {
1794     VisitCompare(selector, kArmVcmpF32, g.UseRegister(m.left().node()),
1795                  g.UseImmediate(m.right().node()), cont);
1796   } else if (m.left().Is(0.0f)) {
1797     cont->Commute();
1798     VisitCompare(selector, kArmVcmpF32, g.UseRegister(m.right().node()),
1799                  g.UseImmediate(m.left().node()), cont);
1800   } else {
1801     VisitCompare(selector, kArmVcmpF32, g.UseRegister(m.left().node()),
1802                  g.UseRegister(m.right().node()), cont);
1803   }
1804 }
1805 
1806 // Shared routine for multiple float64 compare operations.
VisitFloat64Compare(InstructionSelector * selector,Node * node,FlagsContinuation * cont)1807 void VisitFloat64Compare(InstructionSelector* selector, Node* node,
1808                          FlagsContinuation* cont) {
1809   ArmOperandGenerator g(selector);
1810   Float64BinopMatcher m(node);
1811   if (m.right().Is(0.0)) {
1812     VisitCompare(selector, kArmVcmpF64, g.UseRegister(m.left().node()),
1813                  g.UseImmediate(m.right().node()), cont);
1814   } else if (m.left().Is(0.0)) {
1815     cont->Commute();
1816     VisitCompare(selector, kArmVcmpF64, g.UseRegister(m.right().node()),
1817                  g.UseImmediate(m.left().node()), cont);
1818   } else {
1819     VisitCompare(selector, kArmVcmpF64, g.UseRegister(m.left().node()),
1820                  g.UseRegister(m.right().node()), cont);
1821   }
1822 }
1823 
1824 // Check whether we can convert:
1825 // ((a <op> b) cmp 0), b.<cond>
1826 // to:
1827 // (a <ops> b), b.<cond'>
1828 // where <ops> is the flag setting version of <op>.
1829 // We only generate conditions <cond'> that are a combination of the N
1830 // and Z flags. This avoids the need to make this function dependent on
1831 // the flag-setting operation.
CanUseFlagSettingBinop(FlagsCondition cond)1832 bool CanUseFlagSettingBinop(FlagsCondition cond) {
1833   switch (cond) {
1834     case kEqual:
1835     case kNotEqual:
1836     case kSignedLessThan:
1837     case kSignedGreaterThanOrEqual:
1838     case kUnsignedLessThanOrEqual:  // x <= 0 -> x == 0
1839     case kUnsignedGreaterThan:      // x > 0 -> x != 0
1840       return true;
1841     default:
1842       return false;
1843   }
1844 }
1845 
1846 // Map <cond> to <cond'> so that the following transformation is possible:
1847 // ((a <op> b) cmp 0), b.<cond>
1848 // to:
1849 // (a <ops> b), b.<cond'>
1850 // where <ops> is the flag setting version of <op>.
MapForFlagSettingBinop(FlagsCondition cond)1851 FlagsCondition MapForFlagSettingBinop(FlagsCondition cond) {
1852   DCHECK(CanUseFlagSettingBinop(cond));
1853   switch (cond) {
1854     case kEqual:
1855     case kNotEqual:
1856       return cond;
1857     case kSignedLessThan:
1858       return kNegative;
1859     case kSignedGreaterThanOrEqual:
1860       return kPositiveOrZero;
1861     case kUnsignedLessThanOrEqual:  // x <= 0 -> x == 0
1862       return kEqual;
1863     case kUnsignedGreaterThan:  // x > 0 -> x != 0
1864       return kNotEqual;
1865     default:
1866       UNREACHABLE();
1867   }
1868 }
1869 
1870 // Check if we can perform the transformation:
1871 // ((a <op> b) cmp 0), b.<cond>
1872 // to:
1873 // (a <ops> b), b.<cond'>
1874 // where <ops> is the flag setting version of <op>, and if so,
1875 // updates {node}, {opcode} and {cont} accordingly.
MaybeReplaceCmpZeroWithFlagSettingBinop(InstructionSelector * selector,Node ** node,Node * binop,InstructionCode * opcode,FlagsCondition cond,FlagsContinuation * cont)1876 void MaybeReplaceCmpZeroWithFlagSettingBinop(InstructionSelector* selector,
1877                                              Node** node, Node* binop,
1878                                              InstructionCode* opcode,
1879                                              FlagsCondition cond,
1880                                              FlagsContinuation* cont) {
1881   InstructionCode binop_opcode;
1882   InstructionCode no_output_opcode;
1883   switch (binop->opcode()) {
1884     case IrOpcode::kInt32Add:
1885       binop_opcode = kArmAdd;
1886       no_output_opcode = kArmCmn;
1887       break;
1888     case IrOpcode::kWord32And:
1889       binop_opcode = kArmAnd;
1890       no_output_opcode = kArmTst;
1891       break;
1892     case IrOpcode::kWord32Or:
1893       binop_opcode = kArmOrr;
1894       no_output_opcode = kArmOrr;
1895       break;
1896     case IrOpcode::kWord32Xor:
1897       binop_opcode = kArmEor;
1898       no_output_opcode = kArmTeq;
1899       break;
1900     default:
1901       UNREACHABLE();
1902   }
1903   if (selector->CanCover(*node, binop)) {
1904     // The comparison is the only user of {node}.
1905     cont->Overwrite(MapForFlagSettingBinop(cond));
1906     *opcode = no_output_opcode;
1907     *node = binop;
1908   } else if (selector->IsOnlyUserOfNodeInSameBlock(*node, binop)) {
1909     // We can also handle the case where the {node} and the comparison are in
1910     // the same basic block, and the comparison is the only user of {node} in
1911     // this basic block ({node} has users in other basic blocks).
1912     cont->Overwrite(MapForFlagSettingBinop(cond));
1913     *opcode = binop_opcode;
1914     *node = binop;
1915   }
1916 }
1917 
1918 // Shared routine for multiple word compare operations.
VisitWordCompare(InstructionSelector * selector,Node * node,InstructionCode opcode,FlagsContinuation * cont)1919 void VisitWordCompare(InstructionSelector* selector, Node* node,
1920                       InstructionCode opcode, FlagsContinuation* cont) {
1921   ArmOperandGenerator g(selector);
1922   Int32BinopMatcher m(node);
1923   InstructionOperand inputs[3];
1924   size_t input_count = 0;
1925   InstructionOperand outputs[2];
1926   size_t output_count = 0;
1927   bool has_result = (opcode != kArmCmp) && (opcode != kArmCmn) &&
1928                     (opcode != kArmTst) && (opcode != kArmTeq);
1929 
1930   if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(),
1931                                &input_count, &inputs[1])) {
1932     inputs[0] = g.UseRegister(m.left().node());
1933     input_count++;
1934   } else if (TryMatchImmediateOrShift(selector, &opcode, m.left().node(),
1935                                       &input_count, &inputs[1])) {
1936     if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
1937     inputs[0] = g.UseRegister(m.right().node());
1938     input_count++;
1939   } else {
1940     opcode |= AddressingModeField::encode(kMode_Operand2_R);
1941     inputs[input_count++] = g.UseRegister(m.left().node());
1942     inputs[input_count++] = g.UseRegister(m.right().node());
1943   }
1944 
1945   if (has_result) {
1946     if (cont->IsDeoptimize()) {
1947       // If we can deoptimize as a result of the binop, we need to make sure
1948       // that the deopt inputs are not overwritten by the binop result. One way
1949       // to achieve that is to declare the output register as same-as-first.
1950       outputs[output_count++] = g.DefineSameAsFirst(node);
1951     } else {
1952       outputs[output_count++] = g.DefineAsRegister(node);
1953     }
1954   }
1955 
1956   DCHECK_NE(0u, input_count);
1957   DCHECK_GE(arraysize(inputs), input_count);
1958   DCHECK_GE(arraysize(outputs), output_count);
1959 
1960   selector->EmitWithContinuation(opcode, output_count, outputs, input_count,
1961                                  inputs, cont);
1962 }
1963 
VisitWordCompare(InstructionSelector * selector,Node * node,FlagsContinuation * cont)1964 void VisitWordCompare(InstructionSelector* selector, Node* node,
1965                       FlagsContinuation* cont) {
1966   InstructionCode opcode = kArmCmp;
1967   Int32BinopMatcher m(node);
1968 
1969   FlagsCondition cond = cont->condition();
1970   if (m.right().Is(0) && (m.left().IsInt32Add() || m.left().IsWord32Or() ||
1971                           m.left().IsWord32And() || m.left().IsWord32Xor())) {
1972     // Emit flag setting instructions for comparisons against zero.
1973     if (CanUseFlagSettingBinop(cond)) {
1974       Node* binop = m.left().node();
1975       MaybeReplaceCmpZeroWithFlagSettingBinop(selector, &node, binop, &opcode,
1976                                               cond, cont);
1977     }
1978   } else if (m.left().Is(0) &&
1979              (m.right().IsInt32Add() || m.right().IsWord32Or() ||
1980               m.right().IsWord32And() || m.right().IsWord32Xor())) {
1981     // Same as above, but we need to commute the condition before we
1982     // continue with the rest of the checks.
1983     cond = CommuteFlagsCondition(cond);
1984     if (CanUseFlagSettingBinop(cond)) {
1985       Node* binop = m.right().node();
1986       MaybeReplaceCmpZeroWithFlagSettingBinop(selector, &node, binop, &opcode,
1987                                               cond, cont);
1988     }
1989   }
1990 
1991   VisitWordCompare(selector, node, opcode, cont);
1992 }
1993 
1994 }  // namespace
1995 
1996 // Shared routine for word comparisons against zero.
VisitWordCompareZero(Node * user,Node * value,FlagsContinuation * cont)1997 void InstructionSelector::VisitWordCompareZero(Node* user, Node* value,
1998                                                FlagsContinuation* cont) {
1999   // Try to combine with comparisons against 0 by simply inverting the branch.
2000   while (value->opcode() == IrOpcode::kWord32Equal && CanCover(user, value)) {
2001     Int32BinopMatcher m(value);
2002     if (!m.right().Is(0)) break;
2003 
2004     user = value;
2005     value = m.left().node();
2006     cont->Negate();
2007   }
2008 
2009   if (CanCover(user, value)) {
2010     switch (value->opcode()) {
2011       case IrOpcode::kWord32Equal:
2012         cont->OverwriteAndNegateIfEqual(kEqual);
2013         return VisitWordCompare(this, value, cont);
2014       case IrOpcode::kInt32LessThan:
2015         cont->OverwriteAndNegateIfEqual(kSignedLessThan);
2016         return VisitWordCompare(this, value, cont);
2017       case IrOpcode::kInt32LessThanOrEqual:
2018         cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
2019         return VisitWordCompare(this, value, cont);
2020       case IrOpcode::kUint32LessThan:
2021         cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
2022         return VisitWordCompare(this, value, cont);
2023       case IrOpcode::kUint32LessThanOrEqual:
2024         cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
2025         return VisitWordCompare(this, value, cont);
2026       case IrOpcode::kFloat32Equal:
2027         cont->OverwriteAndNegateIfEqual(kEqual);
2028         return VisitFloat32Compare(this, value, cont);
2029       case IrOpcode::kFloat32LessThan:
2030         cont->OverwriteAndNegateIfEqual(kFloatLessThan);
2031         return VisitFloat32Compare(this, value, cont);
2032       case IrOpcode::kFloat32LessThanOrEqual:
2033         cont->OverwriteAndNegateIfEqual(kFloatLessThanOrEqual);
2034         return VisitFloat32Compare(this, value, cont);
2035       case IrOpcode::kFloat64Equal:
2036         cont->OverwriteAndNegateIfEqual(kEqual);
2037         return VisitFloat64Compare(this, value, cont);
2038       case IrOpcode::kFloat64LessThan:
2039         cont->OverwriteAndNegateIfEqual(kFloatLessThan);
2040         return VisitFloat64Compare(this, value, cont);
2041       case IrOpcode::kFloat64LessThanOrEqual:
2042         cont->OverwriteAndNegateIfEqual(kFloatLessThanOrEqual);
2043         return VisitFloat64Compare(this, value, cont);
2044       case IrOpcode::kProjection:
2045         // Check if this is the overflow output projection of an
2046         // <Operation>WithOverflow node.
2047         if (ProjectionIndexOf(value->op()) == 1u) {
2048           // We cannot combine the <Operation>WithOverflow with this branch
2049           // unless the 0th projection (the use of the actual value of the
2050           // <Operation> is either nullptr, which means there's no use of the
2051           // actual value, or was already defined, which means it is scheduled
2052           // *AFTER* this branch).
2053           Node* const node = value->InputAt(0);
2054           Node* const result = NodeProperties::FindProjection(node, 0);
2055           if (!result || IsDefined(result)) {
2056             switch (node->opcode()) {
2057               case IrOpcode::kInt32AddWithOverflow:
2058                 cont->OverwriteAndNegateIfEqual(kOverflow);
2059                 return VisitBinop(this, node, kArmAdd, kArmAdd, cont);
2060               case IrOpcode::kInt32SubWithOverflow:
2061                 cont->OverwriteAndNegateIfEqual(kOverflow);
2062                 return VisitBinop(this, node, kArmSub, kArmRsb, cont);
2063               case IrOpcode::kInt32MulWithOverflow:
2064                 // ARM doesn't set the overflow flag for multiplication, so we
2065                 // need to test on kNotEqual. Here is the code sequence used:
2066                 //   smull resultlow, resulthigh, left, right
2067                 //   cmp resulthigh, Operand(resultlow, ASR, 31)
2068                 cont->OverwriteAndNegateIfEqual(kNotEqual);
2069                 return EmitInt32MulWithOverflow(this, node, cont);
2070               default:
2071                 break;
2072             }
2073           }
2074         }
2075         break;
2076       case IrOpcode::kInt32Add:
2077         return VisitWordCompare(this, value, kArmCmn, cont);
2078       case IrOpcode::kInt32Sub:
2079         return VisitWordCompare(this, value, kArmCmp, cont);
2080       case IrOpcode::kWord32And:
2081         return VisitWordCompare(this, value, kArmTst, cont);
2082       case IrOpcode::kWord32Or:
2083         return VisitBinop(this, value, kArmOrr, kArmOrr, cont);
2084       case IrOpcode::kWord32Xor:
2085         return VisitWordCompare(this, value, kArmTeq, cont);
2086       case IrOpcode::kWord32Sar:
2087         return VisitShift(this, value, TryMatchASR, cont);
2088       case IrOpcode::kWord32Shl:
2089         return VisitShift(this, value, TryMatchLSL, cont);
2090       case IrOpcode::kWord32Shr:
2091         return VisitShift(this, value, TryMatchLSR, cont);
2092       case IrOpcode::kWord32Ror:
2093         return VisitShift(this, value, TryMatchROR, cont);
2094       case IrOpcode::kStackPointerGreaterThan:
2095         cont->OverwriteAndNegateIfEqual(kStackPointerGreaterThanCondition);
2096         return VisitStackPointerGreaterThan(value, cont);
2097       default:
2098         break;
2099     }
2100   }
2101 
2102   if (user->opcode() == IrOpcode::kWord32Equal) {
2103     return VisitWordCompare(this, user, cont);
2104   }
2105 
2106   // Continuation could not be combined with a compare, emit compare against 0.
2107   ArmOperandGenerator g(this);
2108   InstructionCode const opcode =
2109       kArmTst | AddressingModeField::encode(kMode_Operand2_R);
2110   InstructionOperand const value_operand = g.UseRegister(value);
2111   EmitWithContinuation(opcode, value_operand, value_operand, cont);
2112 }
2113 
VisitSwitch(Node * node,const SwitchInfo & sw)2114 void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
2115   ArmOperandGenerator g(this);
2116   InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
2117 
2118   // Emit either ArchTableSwitch or ArchBinarySearchSwitch.
2119   if (enable_switch_jump_table_ == kEnableSwitchJumpTable) {
2120     static const size_t kMaxTableSwitchValueRange = 2 << 16;
2121     size_t table_space_cost = 4 + sw.value_range();
2122     size_t table_time_cost = 3;
2123     size_t lookup_space_cost = 3 + 2 * sw.case_count();
2124     size_t lookup_time_cost = sw.case_count();
2125     if (sw.case_count() > 0 &&
2126         table_space_cost + 3 * table_time_cost <=
2127             lookup_space_cost + 3 * lookup_time_cost &&
2128         sw.min_value() > std::numeric_limits<int32_t>::min() &&
2129         sw.value_range() <= kMaxTableSwitchValueRange) {
2130       InstructionOperand index_operand = value_operand;
2131       if (sw.min_value()) {
2132         index_operand = g.TempRegister();
2133         Emit(kArmSub | AddressingModeField::encode(kMode_Operand2_I),
2134              index_operand, value_operand, g.TempImmediate(sw.min_value()));
2135       }
2136       // Generate a table lookup.
2137       return EmitTableSwitch(sw, index_operand);
2138     }
2139   }
2140 
2141   // Generate a tree of conditional jumps.
2142   return EmitBinarySearchSwitch(sw, value_operand);
2143 }
2144 
VisitWord32Equal(Node * const node)2145 void InstructionSelector::VisitWord32Equal(Node* const node) {
2146   FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
2147   Int32BinopMatcher m(node);
2148   if (m.right().Is(0)) {
2149     return VisitWordCompareZero(m.node(), m.left().node(), &cont);
2150   }
2151   VisitWordCompare(this, node, &cont);
2152 }
2153 
VisitInt32LessThan(Node * node)2154 void InstructionSelector::VisitInt32LessThan(Node* node) {
2155   FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node);
2156   VisitWordCompare(this, node, &cont);
2157 }
2158 
VisitInt32LessThanOrEqual(Node * node)2159 void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
2160   FlagsContinuation cont =
2161       FlagsContinuation::ForSet(kSignedLessThanOrEqual, node);
2162   VisitWordCompare(this, node, &cont);
2163 }
2164 
VisitUint32LessThan(Node * node)2165 void InstructionSelector::VisitUint32LessThan(Node* node) {
2166   FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
2167   VisitWordCompare(this, node, &cont);
2168 }
2169 
VisitUint32LessThanOrEqual(Node * node)2170 void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
2171   FlagsContinuation cont =
2172       FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
2173   VisitWordCompare(this, node, &cont);
2174 }
2175 
VisitInt32AddWithOverflow(Node * node)2176 void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
2177   if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
2178     FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
2179     return VisitBinop(this, node, kArmAdd, kArmAdd, &cont);
2180   }
2181   FlagsContinuation cont;
2182   VisitBinop(this, node, kArmAdd, kArmAdd, &cont);
2183 }
2184 
VisitInt32SubWithOverflow(Node * node)2185 void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
2186   if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
2187     FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
2188     return VisitBinop(this, node, kArmSub, kArmRsb, &cont);
2189   }
2190   FlagsContinuation cont;
2191   VisitBinop(this, node, kArmSub, kArmRsb, &cont);
2192 }
2193 
VisitInt32MulWithOverflow(Node * node)2194 void InstructionSelector::VisitInt32MulWithOverflow(Node* node) {
2195   if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
2196     // ARM doesn't set the overflow flag for multiplication, so we need to test
2197     // on kNotEqual. Here is the code sequence used:
2198     //   smull resultlow, resulthigh, left, right
2199     //   cmp resulthigh, Operand(resultlow, ASR, 31)
2200     FlagsContinuation cont = FlagsContinuation::ForSet(kNotEqual, ovf);
2201     return EmitInt32MulWithOverflow(this, node, &cont);
2202   }
2203   FlagsContinuation cont;
2204   EmitInt32MulWithOverflow(this, node, &cont);
2205 }
2206 
VisitFloat32Equal(Node * node)2207 void InstructionSelector::VisitFloat32Equal(Node* node) {
2208   FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
2209   VisitFloat32Compare(this, node, &cont);
2210 }
2211 
VisitFloat32LessThan(Node * node)2212 void InstructionSelector::VisitFloat32LessThan(Node* node) {
2213   FlagsContinuation cont = FlagsContinuation::ForSet(kFloatLessThan, node);
2214   VisitFloat32Compare(this, node, &cont);
2215 }
2216 
VisitFloat32LessThanOrEqual(Node * node)2217 void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) {
2218   FlagsContinuation cont =
2219       FlagsContinuation::ForSet(kFloatLessThanOrEqual, node);
2220   VisitFloat32Compare(this, node, &cont);
2221 }
2222 
VisitFloat64Equal(Node * node)2223 void InstructionSelector::VisitFloat64Equal(Node* node) {
2224   FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
2225   VisitFloat64Compare(this, node, &cont);
2226 }
2227 
VisitFloat64LessThan(Node * node)2228 void InstructionSelector::VisitFloat64LessThan(Node* node) {
2229   FlagsContinuation cont = FlagsContinuation::ForSet(kFloatLessThan, node);
2230   VisitFloat64Compare(this, node, &cont);
2231 }
2232 
VisitFloat64LessThanOrEqual(Node * node)2233 void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
2234   FlagsContinuation cont =
2235       FlagsContinuation::ForSet(kFloatLessThanOrEqual, node);
2236   VisitFloat64Compare(this, node, &cont);
2237 }
2238 
VisitFloat64InsertLowWord32(Node * node)2239 void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) {
2240   ArmOperandGenerator g(this);
2241   Node* left = node->InputAt(0);
2242   Node* right = node->InputAt(1);
2243   if (left->opcode() == IrOpcode::kFloat64InsertHighWord32 &&
2244       CanCover(node, left)) {
2245     left = left->InputAt(1);
2246     Emit(kArmVmovF64U32U32, g.DefineAsRegister(node), g.UseRegister(right),
2247          g.UseRegister(left));
2248     return;
2249   }
2250   Emit(kArmVmovLowF64U32, g.DefineSameAsFirst(node), g.UseRegister(left),
2251        g.UseRegister(right));
2252 }
2253 
VisitFloat64InsertHighWord32(Node * node)2254 void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
2255   ArmOperandGenerator g(this);
2256   Node* left = node->InputAt(0);
2257   Node* right = node->InputAt(1);
2258   if (left->opcode() == IrOpcode::kFloat64InsertLowWord32 &&
2259       CanCover(node, left)) {
2260     left = left->InputAt(1);
2261     Emit(kArmVmovF64U32U32, g.DefineAsRegister(node), g.UseRegister(left),
2262          g.UseRegister(right));
2263     return;
2264   }
2265   Emit(kArmVmovHighF64U32, g.DefineSameAsFirst(node), g.UseRegister(left),
2266        g.UseRegister(right));
2267 }
2268 
VisitMemoryBarrier(Node * node)2269 void InstructionSelector::VisitMemoryBarrier(Node* node) {
2270   ArmOperandGenerator g(this);
2271   Emit(kArmDmbIsh, g.NoOutput());
2272 }
2273 
VisitWord32AtomicLoad(Node * node)2274 void InstructionSelector::VisitWord32AtomicLoad(Node* node) {
2275   // The memory order is ignored as both acquire and sequentially consistent
2276   // loads can emit LDR; DMB ISH.
2277   // https://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html
2278   AtomicLoadParameters atomic_load_params = AtomicLoadParametersOf(node->op());
2279   LoadRepresentation load_rep = atomic_load_params.representation();
2280   ArmOperandGenerator g(this);
2281   Node* base = node->InputAt(0);
2282   Node* index = node->InputAt(1);
2283   ArchOpcode opcode;
2284   switch (load_rep.representation()) {
2285     case MachineRepresentation::kWord8:
2286       opcode = load_rep.IsSigned() ? kAtomicLoadInt8 : kAtomicLoadUint8;
2287       break;
2288     case MachineRepresentation::kWord16:
2289       opcode = load_rep.IsSigned() ? kAtomicLoadInt16 : kAtomicLoadUint16;
2290       break;
2291     case MachineRepresentation::kTaggedSigned:   // Fall through.
2292     case MachineRepresentation::kTaggedPointer:  // Fall through.
2293     case MachineRepresentation::kTagged:         // Fall through.
2294     case MachineRepresentation::kWord32:
2295       opcode = kAtomicLoadWord32;
2296       break;
2297     default:
2298       UNREACHABLE();
2299   }
2300   Emit(opcode | AddressingModeField::encode(kMode_Offset_RR),
2301        g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(index));
2302 }
2303 
VisitWord32AtomicStore(Node * node)2304 void InstructionSelector::VisitWord32AtomicStore(Node* node) {
2305   AtomicStoreParameters store_params = AtomicStoreParametersOf(node->op());
2306   VisitStoreCommon(this, node, store_params.store_representation(),
2307                    store_params.order());
2308 }
2309 
VisitWord32AtomicExchange(Node * node)2310 void InstructionSelector::VisitWord32AtomicExchange(Node* node) {
2311   ArmOperandGenerator g(this);
2312   Node* base = node->InputAt(0);
2313   Node* index = node->InputAt(1);
2314   Node* value = node->InputAt(2);
2315   ArchOpcode opcode;
2316   MachineType type = AtomicOpType(node->op());
2317   if (type == MachineType::Int8()) {
2318     opcode = kAtomicExchangeInt8;
2319   } else if (type == MachineType::Uint8()) {
2320     opcode = kAtomicExchangeUint8;
2321   } else if (type == MachineType::Int16()) {
2322     opcode = kAtomicExchangeInt16;
2323   } else if (type == MachineType::Uint16()) {
2324     opcode = kAtomicExchangeUint16;
2325   } else if (type == MachineType::Int32() || type == MachineType::Uint32()) {
2326     opcode = kAtomicExchangeWord32;
2327   } else {
2328     UNREACHABLE();
2329   }
2330 
2331   AddressingMode addressing_mode = kMode_Offset_RR;
2332   InstructionOperand inputs[3];
2333   size_t input_count = 0;
2334   inputs[input_count++] = g.UseRegister(base);
2335   inputs[input_count++] = g.UseRegister(index);
2336   inputs[input_count++] = g.UseUniqueRegister(value);
2337   InstructionOperand outputs[1];
2338   outputs[0] = g.DefineAsRegister(node);
2339   InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
2340   InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
2341   Emit(code, 1, outputs, input_count, inputs, arraysize(temps), temps);
2342 }
2343 
VisitWord32AtomicCompareExchange(Node * node)2344 void InstructionSelector::VisitWord32AtomicCompareExchange(Node* node) {
2345   ArmOperandGenerator g(this);
2346   Node* base = node->InputAt(0);
2347   Node* index = node->InputAt(1);
2348   Node* old_value = node->InputAt(2);
2349   Node* new_value = node->InputAt(3);
2350   ArchOpcode opcode;
2351   MachineType type = AtomicOpType(node->op());
2352   if (type == MachineType::Int8()) {
2353     opcode = kAtomicCompareExchangeInt8;
2354   } else if (type == MachineType::Uint8()) {
2355     opcode = kAtomicCompareExchangeUint8;
2356   } else if (type == MachineType::Int16()) {
2357     opcode = kAtomicCompareExchangeInt16;
2358   } else if (type == MachineType::Uint16()) {
2359     opcode = kAtomicCompareExchangeUint16;
2360   } else if (type == MachineType::Int32() || type == MachineType::Uint32()) {
2361     opcode = kAtomicCompareExchangeWord32;
2362   } else {
2363     UNREACHABLE();
2364   }
2365 
2366   AddressingMode addressing_mode = kMode_Offset_RR;
2367   InstructionOperand inputs[4];
2368   size_t input_count = 0;
2369   inputs[input_count++] = g.UseRegister(base);
2370   inputs[input_count++] = g.UseRegister(index);
2371   inputs[input_count++] = g.UseUniqueRegister(old_value);
2372   inputs[input_count++] = g.UseUniqueRegister(new_value);
2373   InstructionOperand outputs[1];
2374   outputs[0] = g.DefineAsRegister(node);
2375   InstructionOperand temps[] = {g.TempRegister(), g.TempRegister(),
2376                                 g.TempRegister()};
2377   InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
2378   Emit(code, 1, outputs, input_count, inputs, arraysize(temps), temps);
2379 }
2380 
VisitWord32AtomicBinaryOperation(Node * node,ArchOpcode int8_op,ArchOpcode uint8_op,ArchOpcode int16_op,ArchOpcode uint16_op,ArchOpcode word32_op)2381 void InstructionSelector::VisitWord32AtomicBinaryOperation(
2382     Node* node, ArchOpcode int8_op, ArchOpcode uint8_op, ArchOpcode int16_op,
2383     ArchOpcode uint16_op, ArchOpcode word32_op) {
2384   ArmOperandGenerator g(this);
2385   Node* base = node->InputAt(0);
2386   Node* index = node->InputAt(1);
2387   Node* value = node->InputAt(2);
2388   ArchOpcode opcode;
2389   MachineType type = AtomicOpType(node->op());
2390   if (type == MachineType::Int8()) {
2391     opcode = int8_op;
2392   } else if (type == MachineType::Uint8()) {
2393     opcode = uint8_op;
2394   } else if (type == MachineType::Int16()) {
2395     opcode = int16_op;
2396   } else if (type == MachineType::Uint16()) {
2397     opcode = uint16_op;
2398   } else if (type == MachineType::Int32() || type == MachineType::Uint32()) {
2399     opcode = word32_op;
2400   } else {
2401     UNREACHABLE();
2402   }
2403 
2404   AddressingMode addressing_mode = kMode_Offset_RR;
2405   InstructionOperand inputs[3];
2406   size_t input_count = 0;
2407   inputs[input_count++] = g.UseRegister(base);
2408   inputs[input_count++] = g.UseRegister(index);
2409   inputs[input_count++] = g.UseUniqueRegister(value);
2410   InstructionOperand outputs[1];
2411   outputs[0] = g.DefineAsRegister(node);
2412   InstructionOperand temps[] = {g.TempRegister(), g.TempRegister(),
2413                                 g.TempRegister()};
2414   InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
2415   Emit(code, 1, outputs, input_count, inputs, arraysize(temps), temps);
2416 }
2417 
2418 #define VISIT_ATOMIC_BINOP(op)                                           \
2419   void InstructionSelector::VisitWord32Atomic##op(Node* node) {          \
2420     VisitWord32AtomicBinaryOperation(                                    \
2421         node, kAtomic##op##Int8, kAtomic##op##Uint8, kAtomic##op##Int16, \
2422         kAtomic##op##Uint16, kAtomic##op##Word32);                       \
2423   }
2424 VISIT_ATOMIC_BINOP(Add)
VISIT_ATOMIC_BINOP(Sub)2425 VISIT_ATOMIC_BINOP(Sub)
2426 VISIT_ATOMIC_BINOP(And)
2427 VISIT_ATOMIC_BINOP(Or)
2428 VISIT_ATOMIC_BINOP(Xor)
2429 #undef VISIT_ATOMIC_BINOP
2430 
2431 void InstructionSelector::VisitWord32AtomicPairLoad(Node* node) {
2432   ArmOperandGenerator g(this);
2433   Node* base = node->InputAt(0);
2434   Node* index = node->InputAt(1);
2435   InstructionOperand inputs[3];
2436   size_t input_count = 0;
2437   inputs[input_count++] = g.UseUniqueRegister(base);
2438   inputs[input_count++] = g.UseUniqueRegister(index);
2439   InstructionOperand temps[1];
2440   size_t temp_count = 0;
2441   InstructionOperand outputs[2];
2442   size_t output_count = 0;
2443 
2444   Node* projection0 = NodeProperties::FindProjection(node, 0);
2445   Node* projection1 = NodeProperties::FindProjection(node, 1);
2446   if (projection0 && projection1) {
2447     outputs[output_count++] = g.DefineAsFixed(projection0, r0);
2448     outputs[output_count++] = g.DefineAsFixed(projection1, r1);
2449     temps[temp_count++] = g.TempRegister();
2450   } else if (projection0) {
2451     inputs[input_count++] = g.UseImmediate(0);
2452     outputs[output_count++] = g.DefineAsRegister(projection0);
2453   } else if (projection1) {
2454     inputs[input_count++] = g.UseImmediate(4);
2455     temps[temp_count++] = g.TempRegister();
2456     outputs[output_count++] = g.DefineAsRegister(projection1);
2457   } else {
2458     // There is no use of the loaded value, we don't need to generate code.
2459     return;
2460   }
2461   Emit(kArmWord32AtomicPairLoad, output_count, outputs, input_count, inputs,
2462        temp_count, temps);
2463 }
2464 
VisitWord32AtomicPairStore(Node * node)2465 void InstructionSelector::VisitWord32AtomicPairStore(Node* node) {
2466   ArmOperandGenerator g(this);
2467   Node* base = node->InputAt(0);
2468   Node* index = node->InputAt(1);
2469   Node* value_low = node->InputAt(2);
2470   Node* value_high = node->InputAt(3);
2471   AddressingMode addressing_mode = kMode_Offset_RR;
2472   InstructionOperand inputs[] = {
2473       g.UseUniqueRegister(base), g.UseUniqueRegister(index),
2474       g.UseFixed(value_low, r2), g.UseFixed(value_high, r3)};
2475   InstructionOperand temps[] = {g.TempRegister(), g.TempRegister(r0),
2476                                 g.TempRegister(r1)};
2477   InstructionCode code =
2478       kArmWord32AtomicPairStore | AddressingModeField::encode(addressing_mode);
2479   Emit(code, 0, nullptr, arraysize(inputs), inputs, arraysize(temps), temps);
2480 }
2481 
VisitWord32AtomicPairAdd(Node * node)2482 void InstructionSelector::VisitWord32AtomicPairAdd(Node* node) {
2483   VisitPairAtomicBinOp(this, node, kArmWord32AtomicPairAdd);
2484 }
2485 
VisitWord32AtomicPairSub(Node * node)2486 void InstructionSelector::VisitWord32AtomicPairSub(Node* node) {
2487   VisitPairAtomicBinOp(this, node, kArmWord32AtomicPairSub);
2488 }
2489 
VisitWord32AtomicPairAnd(Node * node)2490 void InstructionSelector::VisitWord32AtomicPairAnd(Node* node) {
2491   VisitPairAtomicBinOp(this, node, kArmWord32AtomicPairAnd);
2492 }
2493 
VisitWord32AtomicPairOr(Node * node)2494 void InstructionSelector::VisitWord32AtomicPairOr(Node* node) {
2495   VisitPairAtomicBinOp(this, node, kArmWord32AtomicPairOr);
2496 }
2497 
VisitWord32AtomicPairXor(Node * node)2498 void InstructionSelector::VisitWord32AtomicPairXor(Node* node) {
2499   VisitPairAtomicBinOp(this, node, kArmWord32AtomicPairXor);
2500 }
2501 
VisitWord32AtomicPairExchange(Node * node)2502 void InstructionSelector::VisitWord32AtomicPairExchange(Node* node) {
2503   ArmOperandGenerator g(this);
2504   Node* base = node->InputAt(0);
2505   Node* index = node->InputAt(1);
2506   Node* value = node->InputAt(2);
2507   Node* value_high = node->InputAt(3);
2508   AddressingMode addressing_mode = kMode_Offset_RR;
2509   InstructionOperand inputs[] = {
2510       g.UseFixed(value, r0), g.UseFixed(value_high, r1),
2511       g.UseUniqueRegister(base), g.UseUniqueRegister(index)};
2512   InstructionCode code = kArmWord32AtomicPairExchange |
2513                          AddressingModeField::encode(addressing_mode);
2514   Node* projection0 = NodeProperties::FindProjection(node, 0);
2515   Node* projection1 = NodeProperties::FindProjection(node, 1);
2516   InstructionOperand outputs[2];
2517   size_t output_count = 0;
2518   InstructionOperand temps[4];
2519   size_t temp_count = 0;
2520   temps[temp_count++] = g.TempRegister();
2521   temps[temp_count++] = g.TempRegister();
2522   if (projection0) {
2523     outputs[output_count++] = g.DefineAsFixed(projection0, r6);
2524   } else {
2525     temps[temp_count++] = g.TempRegister(r6);
2526   }
2527   if (projection1) {
2528     outputs[output_count++] = g.DefineAsFixed(projection1, r7);
2529   } else {
2530     temps[temp_count++] = g.TempRegister(r7);
2531   }
2532   Emit(code, output_count, outputs, arraysize(inputs), inputs, temp_count,
2533        temps);
2534 }
2535 
VisitWord32AtomicPairCompareExchange(Node * node)2536 void InstructionSelector::VisitWord32AtomicPairCompareExchange(Node* node) {
2537   ArmOperandGenerator g(this);
2538   AddressingMode addressing_mode = kMode_Offset_RR;
2539   InstructionOperand inputs[] = {g.UseFixed(node->InputAt(2), r4),
2540                                  g.UseFixed(node->InputAt(3), r5),
2541                                  g.UseFixed(node->InputAt(4), r8),
2542                                  g.UseFixed(node->InputAt(5), r9),
2543                                  g.UseUniqueRegister(node->InputAt(0)),
2544                                  g.UseUniqueRegister(node->InputAt(1))};
2545   InstructionCode code = kArmWord32AtomicPairCompareExchange |
2546                          AddressingModeField::encode(addressing_mode);
2547   Node* projection0 = NodeProperties::FindProjection(node, 0);
2548   Node* projection1 = NodeProperties::FindProjection(node, 1);
2549   InstructionOperand outputs[2];
2550   size_t output_count = 0;
2551   InstructionOperand temps[4];
2552   size_t temp_count = 0;
2553   temps[temp_count++] = g.TempRegister();
2554   temps[temp_count++] = g.TempRegister();
2555   if (projection0) {
2556     outputs[output_count++] = g.DefineAsFixed(projection0, r2);
2557   } else {
2558     temps[temp_count++] = g.TempRegister(r2);
2559   }
2560   if (projection1) {
2561     outputs[output_count++] = g.DefineAsFixed(projection1, r3);
2562   } else {
2563     temps[temp_count++] = g.TempRegister(r3);
2564   }
2565   Emit(code, output_count, outputs, arraysize(inputs), inputs, temp_count,
2566        temps);
2567 }
2568 
2569 #define SIMD_TYPE_LIST(V) \
2570   V(F32x4)                \
2571   V(I32x4)                \
2572   V(I16x8)                \
2573   V(I8x16)
2574 
2575 #define SIMD_UNOP_LIST(V)                               \
2576   V(F64x2Abs, kArmF64x2Abs)                             \
2577   V(F64x2Neg, kArmF64x2Neg)                             \
2578   V(F64x2Sqrt, kArmF64x2Sqrt)                           \
2579   V(F32x4SConvertI32x4, kArmF32x4SConvertI32x4)         \
2580   V(F32x4UConvertI32x4, kArmF32x4UConvertI32x4)         \
2581   V(F32x4Abs, kArmF32x4Abs)                             \
2582   V(F32x4Neg, kArmF32x4Neg)                             \
2583   V(F32x4RecipApprox, kArmF32x4RecipApprox)             \
2584   V(F32x4RecipSqrtApprox, kArmF32x4RecipSqrtApprox)     \
2585   V(I64x2Abs, kArmI64x2Abs)                             \
2586   V(I64x2SConvertI32x4Low, kArmI64x2SConvertI32x4Low)   \
2587   V(I64x2SConvertI32x4High, kArmI64x2SConvertI32x4High) \
2588   V(I64x2UConvertI32x4Low, kArmI64x2UConvertI32x4Low)   \
2589   V(I64x2UConvertI32x4High, kArmI64x2UConvertI32x4High) \
2590   V(I32x4SConvertF32x4, kArmI32x4SConvertF32x4)         \
2591   V(I32x4RelaxedTruncF32x4S, kArmI32x4SConvertF32x4)    \
2592   V(I32x4SConvertI16x8Low, kArmI32x4SConvertI16x8Low)   \
2593   V(I32x4SConvertI16x8High, kArmI32x4SConvertI16x8High) \
2594   V(I32x4Neg, kArmI32x4Neg)                             \
2595   V(I32x4UConvertF32x4, kArmI32x4UConvertF32x4)         \
2596   V(I32x4RelaxedTruncF32x4U, kArmI32x4UConvertF32x4)    \
2597   V(I32x4UConvertI16x8Low, kArmI32x4UConvertI16x8Low)   \
2598   V(I32x4UConvertI16x8High, kArmI32x4UConvertI16x8High) \
2599   V(I32x4Abs, kArmI32x4Abs)                             \
2600   V(I16x8SConvertI8x16Low, kArmI16x8SConvertI8x16Low)   \
2601   V(I16x8SConvertI8x16High, kArmI16x8SConvertI8x16High) \
2602   V(I16x8Neg, kArmI16x8Neg)                             \
2603   V(I16x8UConvertI8x16Low, kArmI16x8UConvertI8x16Low)   \
2604   V(I16x8UConvertI8x16High, kArmI16x8UConvertI8x16High) \
2605   V(I16x8Abs, kArmI16x8Abs)                             \
2606   V(I8x16Neg, kArmI8x16Neg)                             \
2607   V(I8x16Abs, kArmI8x16Abs)                             \
2608   V(I8x16Popcnt, kArmVcnt)                              \
2609   V(S128Not, kArmS128Not)                               \
2610   V(I64x2AllTrue, kArmI64x2AllTrue)                     \
2611   V(I32x4AllTrue, kArmI32x4AllTrue)                     \
2612   V(I16x8AllTrue, kArmI16x8AllTrue)                     \
2613   V(V128AnyTrue, kArmV128AnyTrue)                       \
2614   V(I8x16AllTrue, kArmI8x16AllTrue)
2615 
2616 #define SIMD_SHIFT_OP_LIST(V) \
2617   V(I64x2Shl, 64)             \
2618   V(I64x2ShrS, 64)            \
2619   V(I64x2ShrU, 64)            \
2620   V(I32x4Shl, 32)             \
2621   V(I32x4ShrS, 32)            \
2622   V(I32x4ShrU, 32)            \
2623   V(I16x8Shl, 16)             \
2624   V(I16x8ShrS, 16)            \
2625   V(I16x8ShrU, 16)            \
2626   V(I8x16Shl, 8)              \
2627   V(I8x16ShrS, 8)             \
2628   V(I8x16ShrU, 8)
2629 
2630 #define SIMD_BINOP_LIST(V)                            \
2631   V(F64x2Add, kArmF64x2Add)                           \
2632   V(F64x2Sub, kArmF64x2Sub)                           \
2633   V(F64x2Mul, kArmF64x2Mul)                           \
2634   V(F64x2Div, kArmF64x2Div)                           \
2635   V(F64x2Min, kArmF64x2Min)                           \
2636   V(F64x2Max, kArmF64x2Max)                           \
2637   V(F64x2Eq, kArmF64x2Eq)                             \
2638   V(F64x2Ne, kArmF64x2Ne)                             \
2639   V(F64x2Lt, kArmF64x2Lt)                             \
2640   V(F64x2Le, kArmF64x2Le)                             \
2641   V(F32x4Add, kArmF32x4Add)                           \
2642   V(F32x4Sub, kArmF32x4Sub)                           \
2643   V(F32x4Mul, kArmF32x4Mul)                           \
2644   V(F32x4Min, kArmF32x4Min)                           \
2645   V(F32x4RelaxedMin, kArmF32x4Min)                    \
2646   V(F32x4Max, kArmF32x4Max)                           \
2647   V(F32x4RelaxedMax, kArmF32x4Max)                    \
2648   V(F32x4Eq, kArmF32x4Eq)                             \
2649   V(F32x4Ne, kArmF32x4Ne)                             \
2650   V(F32x4Lt, kArmF32x4Lt)                             \
2651   V(F32x4Le, kArmF32x4Le)                             \
2652   V(I64x2Add, kArmI64x2Add)                           \
2653   V(I64x2Sub, kArmI64x2Sub)                           \
2654   V(I32x4Sub, kArmI32x4Sub)                           \
2655   V(I32x4Mul, kArmI32x4Mul)                           \
2656   V(I32x4MinS, kArmI32x4MinS)                         \
2657   V(I32x4MaxS, kArmI32x4MaxS)                         \
2658   V(I32x4Eq, kArmI32x4Eq)                             \
2659   V(I64x2Eq, kArmI64x2Eq)                             \
2660   V(I64x2Ne, kArmI64x2Ne)                             \
2661   V(I64x2GtS, kArmI64x2GtS)                           \
2662   V(I64x2GeS, kArmI64x2GeS)                           \
2663   V(I32x4Ne, kArmI32x4Ne)                             \
2664   V(I32x4GtS, kArmI32x4GtS)                           \
2665   V(I32x4GeS, kArmI32x4GeS)                           \
2666   V(I32x4MinU, kArmI32x4MinU)                         \
2667   V(I32x4MaxU, kArmI32x4MaxU)                         \
2668   V(I32x4GtU, kArmI32x4GtU)                           \
2669   V(I32x4GeU, kArmI32x4GeU)                           \
2670   V(I16x8SConvertI32x4, kArmI16x8SConvertI32x4)       \
2671   V(I16x8AddSatS, kArmI16x8AddSatS)                   \
2672   V(I16x8Sub, kArmI16x8Sub)                           \
2673   V(I16x8SubSatS, kArmI16x8SubSatS)                   \
2674   V(I16x8Mul, kArmI16x8Mul)                           \
2675   V(I16x8MinS, kArmI16x8MinS)                         \
2676   V(I16x8MaxS, kArmI16x8MaxS)                         \
2677   V(I16x8Eq, kArmI16x8Eq)                             \
2678   V(I16x8Ne, kArmI16x8Ne)                             \
2679   V(I16x8GtS, kArmI16x8GtS)                           \
2680   V(I16x8GeS, kArmI16x8GeS)                           \
2681   V(I16x8UConvertI32x4, kArmI16x8UConvertI32x4)       \
2682   V(I16x8AddSatU, kArmI16x8AddSatU)                   \
2683   V(I16x8SubSatU, kArmI16x8SubSatU)                   \
2684   V(I16x8MinU, kArmI16x8MinU)                         \
2685   V(I16x8MaxU, kArmI16x8MaxU)                         \
2686   V(I16x8GtU, kArmI16x8GtU)                           \
2687   V(I16x8GeU, kArmI16x8GeU)                           \
2688   V(I16x8RoundingAverageU, kArmI16x8RoundingAverageU) \
2689   V(I16x8Q15MulRSatS, kArmI16x8Q15MulRSatS)           \
2690   V(I8x16SConvertI16x8, kArmI8x16SConvertI16x8)       \
2691   V(I8x16Add, kArmI8x16Add)                           \
2692   V(I8x16AddSatS, kArmI8x16AddSatS)                   \
2693   V(I8x16Sub, kArmI8x16Sub)                           \
2694   V(I8x16SubSatS, kArmI8x16SubSatS)                   \
2695   V(I8x16MinS, kArmI8x16MinS)                         \
2696   V(I8x16MaxS, kArmI8x16MaxS)                         \
2697   V(I8x16Eq, kArmI8x16Eq)                             \
2698   V(I8x16Ne, kArmI8x16Ne)                             \
2699   V(I8x16GtS, kArmI8x16GtS)                           \
2700   V(I8x16GeS, kArmI8x16GeS)                           \
2701   V(I8x16UConvertI16x8, kArmI8x16UConvertI16x8)       \
2702   V(I8x16AddSatU, kArmI8x16AddSatU)                   \
2703   V(I8x16SubSatU, kArmI8x16SubSatU)                   \
2704   V(I8x16MinU, kArmI8x16MinU)                         \
2705   V(I8x16MaxU, kArmI8x16MaxU)                         \
2706   V(I8x16GtU, kArmI8x16GtU)                           \
2707   V(I8x16GeU, kArmI8x16GeU)                           \
2708   V(I8x16RoundingAverageU, kArmI8x16RoundingAverageU) \
2709   V(S128And, kArmS128And)                             \
2710   V(S128Or, kArmS128Or)                               \
2711   V(S128Xor, kArmS128Xor)                             \
2712   V(S128AndNot, kArmS128AndNot)
2713 
VisitI32x4DotI16x8S(Node * node)2714 void InstructionSelector::VisitI32x4DotI16x8S(Node* node) {
2715   ArmOperandGenerator g(this);
2716   InstructionOperand temps[] = {g.TempSimd128Register()};
2717   Emit(kArmI32x4DotI16x8S, g.DefineAsRegister(node),
2718        g.UseUniqueRegister(node->InputAt(0)),
2719        g.UseUniqueRegister(node->InputAt(1)), arraysize(temps), temps);
2720 }
2721 
VisitS128Const(Node * node)2722 void InstructionSelector::VisitS128Const(Node* node) {
2723   ArmOperandGenerator g(this);
2724   uint32_t val[kSimd128Size / sizeof(uint32_t)];
2725   memcpy(val, S128ImmediateParameterOf(node->op()).data(), kSimd128Size);
2726   // If all bytes are zeros, avoid emitting code for generic constants.
2727   bool all_zeros = !(val[0] || val[1] || val[2] || val[3]);
2728   bool all_ones = val[0] == UINT32_MAX && val[1] == UINT32_MAX &&
2729                   val[2] == UINT32_MAX && val[3] == UINT32_MAX;
2730   InstructionOperand dst = g.DefineAsRegister(node);
2731   if (all_zeros) {
2732     Emit(kArmS128Zero, dst);
2733   } else if (all_ones) {
2734     Emit(kArmS128AllOnes, dst);
2735   } else {
2736     Emit(kArmS128Const, dst, g.UseImmediate(val[0]), g.UseImmediate(val[1]),
2737          g.UseImmediate(val[2]), g.UseImmediate(val[3]));
2738   }
2739 }
2740 
VisitS128Zero(Node * node)2741 void InstructionSelector::VisitS128Zero(Node* node) {
2742   ArmOperandGenerator g(this);
2743   Emit(kArmS128Zero, g.DefineAsRegister(node));
2744 }
2745 
2746 #define SIMD_VISIT_SPLAT(Type)                               \
2747   void InstructionSelector::Visit##Type##Splat(Node* node) { \
2748     VisitRR(this, kArm##Type##Splat, node);                  \
2749   }
2750 SIMD_TYPE_LIST(SIMD_VISIT_SPLAT)
SIMD_VISIT_SPLAT(F64x2)2751 SIMD_VISIT_SPLAT(F64x2)
2752 #undef SIMD_VISIT_SPLAT
2753 
2754 #define SIMD_VISIT_EXTRACT_LANE(Type, Sign)                              \
2755   void InstructionSelector::Visit##Type##ExtractLane##Sign(Node* node) { \
2756     VisitRRI(this, kArm##Type##ExtractLane##Sign, node);                 \
2757   }
2758 SIMD_VISIT_EXTRACT_LANE(F64x2, )
2759 SIMD_VISIT_EXTRACT_LANE(F32x4, )
2760 SIMD_VISIT_EXTRACT_LANE(I32x4, )
2761 SIMD_VISIT_EXTRACT_LANE(I16x8, U)
2762 SIMD_VISIT_EXTRACT_LANE(I16x8, S)
2763 SIMD_VISIT_EXTRACT_LANE(I8x16, U)
2764 SIMD_VISIT_EXTRACT_LANE(I8x16, S)
2765 #undef SIMD_VISIT_EXTRACT_LANE
2766 
2767 #define SIMD_VISIT_REPLACE_LANE(Type)                              \
2768   void InstructionSelector::Visit##Type##ReplaceLane(Node* node) { \
2769     VisitRRIR(this, kArm##Type##ReplaceLane, node);                \
2770   }
2771 SIMD_TYPE_LIST(SIMD_VISIT_REPLACE_LANE)
2772 SIMD_VISIT_REPLACE_LANE(F64x2)
2773 #undef SIMD_VISIT_REPLACE_LANE
2774 #undef SIMD_TYPE_LIST
2775 
2776 #define SIMD_VISIT_UNOP(Name, instruction)            \
2777   void InstructionSelector::Visit##Name(Node* node) { \
2778     VisitRR(this, instruction, node);                 \
2779   }
2780 SIMD_UNOP_LIST(SIMD_VISIT_UNOP)
2781 #undef SIMD_VISIT_UNOP
2782 #undef SIMD_UNOP_LIST
2783 
2784 #define SIMD_VISIT_SHIFT_OP(Name, width)              \
2785   void InstructionSelector::Visit##Name(Node* node) { \
2786     VisitSimdShiftRRR(this, kArm##Name, node, width); \
2787   }
2788 SIMD_SHIFT_OP_LIST(SIMD_VISIT_SHIFT_OP)
2789 #undef SIMD_VISIT_SHIFT_OP
2790 #undef SIMD_SHIFT_OP_LIST
2791 
2792 #define SIMD_VISIT_BINOP(Name, instruction)           \
2793   void InstructionSelector::Visit##Name(Node* node) { \
2794     VisitRRR(this, instruction, node);                \
2795   }
2796 SIMD_BINOP_LIST(SIMD_VISIT_BINOP)
2797 #undef SIMD_VISIT_BINOP
2798 #undef SIMD_BINOP_LIST
2799 
2800 #define VISIT_SIMD_ADD(Type, PairwiseType, NeonWidth)             \
2801   void InstructionSelector::Visit##Type##Add(Node* node) {        \
2802     ArmOperandGenerator g(this);                                  \
2803     Node* left = node->InputAt(0);                                \
2804     Node* right = node->InputAt(1);                               \
2805     if (left->opcode() ==                                         \
2806             IrOpcode::k##Type##ExtAddPairwise##PairwiseType##S && \
2807         CanCover(node, left)) {                                   \
2808       Emit(kArmVpadal | MiscField::encode(NeonS##NeonWidth),      \
2809            g.DefineSameAsFirst(node), g.UseRegister(right),       \
2810            g.UseRegister(left->InputAt(0)));                      \
2811       return;                                                     \
2812     }                                                             \
2813     if (left->opcode() ==                                         \
2814             IrOpcode::k##Type##ExtAddPairwise##PairwiseType##U && \
2815         CanCover(node, left)) {                                   \
2816       Emit(kArmVpadal | MiscField::encode(NeonU##NeonWidth),      \
2817            g.DefineSameAsFirst(node), g.UseRegister(right),       \
2818            g.UseRegister(left->InputAt(0)));                      \
2819       return;                                                     \
2820     }                                                             \
2821     if (right->opcode() ==                                        \
2822             IrOpcode::k##Type##ExtAddPairwise##PairwiseType##S && \
2823         CanCover(node, right)) {                                  \
2824       Emit(kArmVpadal | MiscField::encode(NeonS##NeonWidth),      \
2825            g.DefineSameAsFirst(node), g.UseRegister(left),        \
2826            g.UseRegister(right->InputAt(0)));                     \
2827       return;                                                     \
2828     }                                                             \
2829     if (right->opcode() ==                                        \
2830             IrOpcode::k##Type##ExtAddPairwise##PairwiseType##U && \
2831         CanCover(node, right)) {                                  \
2832       Emit(kArmVpadal | MiscField::encode(NeonU##NeonWidth),      \
2833            g.DefineSameAsFirst(node), g.UseRegister(left),        \
2834            g.UseRegister(right->InputAt(0)));                     \
2835       return;                                                     \
2836     }                                                             \
2837     VisitRRR(this, kArm##Type##Add, node);                        \
2838   }
2839 
2840 VISIT_SIMD_ADD(I16x8, I8x16, 8)
2841 VISIT_SIMD_ADD(I32x4, I16x8, 16)
2842 #undef VISIT_SIMD_ADD
2843 
2844 void InstructionSelector::VisitI64x2SplatI32Pair(Node* node) {
2845   ArmOperandGenerator g(this);
2846   InstructionOperand operand0 = g.UseRegister(node->InputAt(0));
2847   InstructionOperand operand1 = g.UseRegister(node->InputAt(1));
2848   Emit(kArmI64x2SplatI32Pair, g.DefineAsRegister(node), operand0, operand1);
2849 }
2850 
VisitI64x2ReplaceLaneI32Pair(Node * node)2851 void InstructionSelector::VisitI64x2ReplaceLaneI32Pair(Node* node) {
2852   ArmOperandGenerator g(this);
2853   InstructionOperand operand = g.UseRegister(node->InputAt(0));
2854   InstructionOperand lane = g.UseImmediate(OpParameter<int32_t>(node->op()));
2855   InstructionOperand low = g.UseRegister(node->InputAt(1));
2856   InstructionOperand high = g.UseRegister(node->InputAt(2));
2857   Emit(kArmI64x2ReplaceLaneI32Pair, g.DefineSameAsFirst(node), operand, lane,
2858        low, high);
2859 }
2860 
VisitI64x2Neg(Node * node)2861 void InstructionSelector::VisitI64x2Neg(Node* node) {
2862   ArmOperandGenerator g(this);
2863   Emit(kArmI64x2Neg, g.DefineAsRegister(node),
2864        g.UseUniqueRegister(node->InputAt(0)));
2865 }
2866 
VisitI64x2Mul(Node * node)2867 void InstructionSelector::VisitI64x2Mul(Node* node) {
2868   ArmOperandGenerator g(this);
2869   InstructionOperand temps[] = {g.TempSimd128Register()};
2870   Emit(kArmI64x2Mul, g.DefineAsRegister(node),
2871        g.UseUniqueRegister(node->InputAt(0)),
2872        g.UseUniqueRegister(node->InputAt(1)), arraysize(temps), temps);
2873 }
2874 
VisitF32x4Sqrt(Node * node)2875 void InstructionSelector::VisitF32x4Sqrt(Node* node) {
2876   ArmOperandGenerator g(this);
2877   // Use fixed registers in the lower 8 Q-registers so we can directly access
2878   // mapped registers S0-S31.
2879   Emit(kArmF32x4Sqrt, g.DefineAsFixed(node, q0),
2880        g.UseFixed(node->InputAt(0), q0));
2881 }
2882 
VisitF32x4Div(Node * node)2883 void InstructionSelector::VisitF32x4Div(Node* node) {
2884   ArmOperandGenerator g(this);
2885   // Use fixed registers in the lower 8 Q-registers so we can directly access
2886   // mapped registers S0-S31.
2887   Emit(kArmF32x4Div, g.DefineAsFixed(node, q0),
2888        g.UseFixed(node->InputAt(0), q0), g.UseFixed(node->InputAt(1), q1));
2889 }
2890 
VisitS128Select(Node * node)2891 void InstructionSelector::VisitS128Select(Node* node) {
2892   ArmOperandGenerator g(this);
2893   Emit(kArmS128Select, g.DefineSameAsFirst(node),
2894        g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)),
2895        g.UseRegister(node->InputAt(2)));
2896 }
2897 
VisitI8x16RelaxedLaneSelect(Node * node)2898 void InstructionSelector::VisitI8x16RelaxedLaneSelect(Node* node) {
2899   VisitS128Select(node);
2900 }
2901 
VisitI16x8RelaxedLaneSelect(Node * node)2902 void InstructionSelector::VisitI16x8RelaxedLaneSelect(Node* node) {
2903   VisitS128Select(node);
2904 }
2905 
VisitI32x4RelaxedLaneSelect(Node * node)2906 void InstructionSelector::VisitI32x4RelaxedLaneSelect(Node* node) {
2907   VisitS128Select(node);
2908 }
2909 
VisitI64x2RelaxedLaneSelect(Node * node)2910 void InstructionSelector::VisitI64x2RelaxedLaneSelect(Node* node) {
2911   VisitS128Select(node);
2912 }
2913 
2914 #if V8_ENABLE_WEBASSEMBLY
2915 namespace {
2916 
2917 struct ShuffleEntry {
2918   uint8_t shuffle[kSimd128Size];
2919   ArchOpcode opcode;
2920 };
2921 
2922 static const ShuffleEntry arch_shuffles[] = {
2923     {{0, 1, 2, 3, 16, 17, 18, 19, 4, 5, 6, 7, 20, 21, 22, 23},
2924      kArmS32x4ZipLeft},
2925     {{8, 9, 10, 11, 24, 25, 26, 27, 12, 13, 14, 15, 28, 29, 30, 31},
2926      kArmS32x4ZipRight},
2927     {{0, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19, 24, 25, 26, 27},
2928      kArmS32x4UnzipLeft},
2929     {{4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23, 28, 29, 30, 31},
2930      kArmS32x4UnzipRight},
2931     {{0, 1, 2, 3, 16, 17, 18, 19, 8, 9, 10, 11, 24, 25, 26, 27},
2932      kArmS32x4TransposeLeft},
2933     {{4, 5, 6, 7, 20, 21, 22, 23, 12, 13, 14, 15, 28, 29, 30, 31},
2934      kArmS32x4TransposeRight},
2935     {{4, 5, 6, 7, 0, 1, 2, 3, 12, 13, 14, 15, 8, 9, 10, 11}, kArmS32x2Reverse},
2936 
2937     {{0, 1, 16, 17, 2, 3, 18, 19, 4, 5, 20, 21, 6, 7, 22, 23},
2938      kArmS16x8ZipLeft},
2939     {{8, 9, 24, 25, 10, 11, 26, 27, 12, 13, 28, 29, 14, 15, 30, 31},
2940      kArmS16x8ZipRight},
2941     {{0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21, 24, 25, 28, 29},
2942      kArmS16x8UnzipLeft},
2943     {{2, 3, 6, 7, 10, 11, 14, 15, 18, 19, 22, 23, 26, 27, 30, 31},
2944      kArmS16x8UnzipRight},
2945     {{0, 1, 16, 17, 4, 5, 20, 21, 8, 9, 24, 25, 12, 13, 28, 29},
2946      kArmS16x8TransposeLeft},
2947     {{2, 3, 18, 19, 6, 7, 22, 23, 10, 11, 26, 27, 14, 15, 30, 31},
2948      kArmS16x8TransposeRight},
2949     {{6, 7, 4, 5, 2, 3, 0, 1, 14, 15, 12, 13, 10, 11, 8, 9}, kArmS16x4Reverse},
2950     {{2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13}, kArmS16x2Reverse},
2951 
2952     {{0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23},
2953      kArmS8x16ZipLeft},
2954     {{8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30, 15, 31},
2955      kArmS8x16ZipRight},
2956     {{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30},
2957      kArmS8x16UnzipLeft},
2958     {{1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31},
2959      kArmS8x16UnzipRight},
2960     {{0, 16, 2, 18, 4, 20, 6, 22, 8, 24, 10, 26, 12, 28, 14, 30},
2961      kArmS8x16TransposeLeft},
2962     {{1, 17, 3, 19, 5, 21, 7, 23, 9, 25, 11, 27, 13, 29, 15, 31},
2963      kArmS8x16TransposeRight},
2964     {{7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8}, kArmS8x8Reverse},
2965     {{3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12}, kArmS8x4Reverse},
2966     {{1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14}, kArmS8x2Reverse}};
2967 
TryMatchArchShuffle(const uint8_t * shuffle,const ShuffleEntry * table,size_t num_entries,bool is_swizzle,ArchOpcode * opcode)2968 bool TryMatchArchShuffle(const uint8_t* shuffle, const ShuffleEntry* table,
2969                          size_t num_entries, bool is_swizzle,
2970                          ArchOpcode* opcode) {
2971   uint8_t mask = is_swizzle ? kSimd128Size - 1 : 2 * kSimd128Size - 1;
2972   for (size_t i = 0; i < num_entries; ++i) {
2973     const ShuffleEntry& entry = table[i];
2974     int j = 0;
2975     for (; j < kSimd128Size; ++j) {
2976       if ((entry.shuffle[j] & mask) != (shuffle[j] & mask)) {
2977         break;
2978       }
2979     }
2980     if (j == kSimd128Size) {
2981       *opcode = entry.opcode;
2982       return true;
2983     }
2984   }
2985   return false;
2986 }
2987 
ArrangeShuffleTable(ArmOperandGenerator * g,Node * input0,Node * input1,InstructionOperand * src0,InstructionOperand * src1)2988 void ArrangeShuffleTable(ArmOperandGenerator* g, Node* input0, Node* input1,
2989                          InstructionOperand* src0, InstructionOperand* src1) {
2990   if (input0 == input1) {
2991     // Unary, any q-register can be the table.
2992     *src0 = *src1 = g->UseRegister(input0);
2993   } else {
2994     // Binary, table registers must be consecutive.
2995     *src0 = g->UseFixed(input0, q0);
2996     *src1 = g->UseFixed(input1, q1);
2997   }
2998 }
2999 
3000 }  // namespace
3001 
VisitI8x16Shuffle(Node * node)3002 void InstructionSelector::VisitI8x16Shuffle(Node* node) {
3003   uint8_t shuffle[kSimd128Size];
3004   bool is_swizzle;
3005   CanonicalizeShuffle(node, shuffle, &is_swizzle);
3006   Node* input0 = node->InputAt(0);
3007   Node* input1 = node->InputAt(1);
3008   uint8_t shuffle32x4[4];
3009   ArmOperandGenerator g(this);
3010   int index = 0;
3011   if (wasm::SimdShuffle::TryMatch32x4Shuffle(shuffle, shuffle32x4)) {
3012     if (wasm::SimdShuffle::TryMatchSplat<4>(shuffle, &index)) {
3013       DCHECK_GT(4, index);
3014       Emit(kArmS128Dup, g.DefineAsRegister(node), g.UseRegister(input0),
3015            g.UseImmediate(Neon32), g.UseImmediate(index % 4));
3016     } else if (wasm::SimdShuffle::TryMatchIdentity(shuffle)) {
3017       EmitIdentity(node);
3018     } else {
3019       // 32x4 shuffles are implemented as s-register moves. To simplify these,
3020       // make sure the destination is distinct from both sources.
3021       InstructionOperand src0 = g.UseUniqueRegister(input0);
3022       InstructionOperand src1 = is_swizzle ? src0 : g.UseUniqueRegister(input1);
3023       Emit(kArmS32x4Shuffle, g.DefineAsRegister(node), src0, src1,
3024            g.UseImmediate(wasm::SimdShuffle::Pack4Lanes(shuffle32x4)));
3025     }
3026     return;
3027   }
3028   if (wasm::SimdShuffle::TryMatchSplat<8>(shuffle, &index)) {
3029     DCHECK_GT(8, index);
3030     Emit(kArmS128Dup, g.DefineAsRegister(node), g.UseRegister(input0),
3031          g.UseImmediate(Neon16), g.UseImmediate(index % 8));
3032     return;
3033   }
3034   if (wasm::SimdShuffle::TryMatchSplat<16>(shuffle, &index)) {
3035     DCHECK_GT(16, index);
3036     Emit(kArmS128Dup, g.DefineAsRegister(node), g.UseRegister(input0),
3037          g.UseImmediate(Neon8), g.UseImmediate(index % 16));
3038     return;
3039   }
3040   ArchOpcode opcode;
3041   if (TryMatchArchShuffle(shuffle, arch_shuffles, arraysize(arch_shuffles),
3042                           is_swizzle, &opcode)) {
3043     VisitRRRShuffle(this, opcode, node);
3044     return;
3045   }
3046   uint8_t offset;
3047   if (wasm::SimdShuffle::TryMatchConcat(shuffle, &offset)) {
3048     Emit(kArmS8x16Concat, g.DefineAsRegister(node), g.UseRegister(input0),
3049          g.UseRegister(input1), g.UseImmediate(offset));
3050     return;
3051   }
3052   // Code generator uses vtbl, arrange sources to form a valid lookup table.
3053   InstructionOperand src0, src1;
3054   ArrangeShuffleTable(&g, input0, input1, &src0, &src1);
3055   Emit(kArmI8x16Shuffle, g.DefineAsRegister(node), src0, src1,
3056        g.UseImmediate(wasm::SimdShuffle::Pack4Lanes(shuffle)),
3057        g.UseImmediate(wasm::SimdShuffle::Pack4Lanes(shuffle + 4)),
3058        g.UseImmediate(wasm::SimdShuffle::Pack4Lanes(shuffle + 8)),
3059        g.UseImmediate(wasm::SimdShuffle::Pack4Lanes(shuffle + 12)));
3060 }
3061 #else
VisitI8x16Shuffle(Node * node)3062 void InstructionSelector::VisitI8x16Shuffle(Node* node) { UNREACHABLE(); }
3063 #endif  // V8_ENABLE_WEBASSEMBLY
3064 
VisitI8x16Swizzle(Node * node)3065 void InstructionSelector::VisitI8x16Swizzle(Node* node) {
3066   ArmOperandGenerator g(this);
3067   // We don't want input 0 (the table) to be the same as output, since we will
3068   // modify output twice (low and high), and need to keep the table the same.
3069   Emit(kArmI8x16Swizzle, g.DefineAsRegister(node),
3070        g.UseUniqueRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
3071 }
3072 
VisitSignExtendWord8ToInt32(Node * node)3073 void InstructionSelector::VisitSignExtendWord8ToInt32(Node* node) {
3074   ArmOperandGenerator g(this);
3075   Emit(kArmSxtb, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
3076        g.TempImmediate(0));
3077 }
3078 
VisitSignExtendWord16ToInt32(Node * node)3079 void InstructionSelector::VisitSignExtendWord16ToInt32(Node* node) {
3080   ArmOperandGenerator g(this);
3081   Emit(kArmSxth, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
3082        g.TempImmediate(0));
3083 }
3084 
VisitInt32AbsWithOverflow(Node * node)3085 void InstructionSelector::VisitInt32AbsWithOverflow(Node* node) {
3086   UNREACHABLE();
3087 }
3088 
VisitInt64AbsWithOverflow(Node * node)3089 void InstructionSelector::VisitInt64AbsWithOverflow(Node* node) {
3090   UNREACHABLE();
3091 }
3092 
3093 namespace {
3094 template <ArchOpcode opcode>
VisitBitMask(InstructionSelector * selector,Node * node)3095 void VisitBitMask(InstructionSelector* selector, Node* node) {
3096   ArmOperandGenerator g(selector);
3097   InstructionOperand temps[] = {g.TempSimd128Register()};
3098   selector->Emit(opcode, g.DefineAsRegister(node),
3099                  g.UseRegister(node->InputAt(0)), arraysize(temps), temps);
3100 }
3101 }  // namespace
3102 
VisitI8x16BitMask(Node * node)3103 void InstructionSelector::VisitI8x16BitMask(Node* node) {
3104   VisitBitMask<kArmI8x16BitMask>(this, node);
3105 }
3106 
VisitI16x8BitMask(Node * node)3107 void InstructionSelector::VisitI16x8BitMask(Node* node) {
3108   VisitBitMask<kArmI16x8BitMask>(this, node);
3109 }
3110 
VisitI32x4BitMask(Node * node)3111 void InstructionSelector::VisitI32x4BitMask(Node* node) {
3112   VisitBitMask<kArmI32x4BitMask>(this, node);
3113 }
3114 
VisitI64x2BitMask(Node * node)3115 void InstructionSelector::VisitI64x2BitMask(Node* node) {
3116   VisitBitMask<kArmI64x2BitMask>(this, node);
3117 }
3118 
3119 namespace {
VisitF32x4PminOrPmax(InstructionSelector * selector,ArchOpcode opcode,Node * node)3120 void VisitF32x4PminOrPmax(InstructionSelector* selector, ArchOpcode opcode,
3121                           Node* node) {
3122   ArmOperandGenerator g(selector);
3123   // Need all unique registers because we first compare the two inputs, then we
3124   // need the inputs to remain unchanged for the bitselect later.
3125   selector->Emit(opcode, g.DefineAsRegister(node),
3126                  g.UseUniqueRegister(node->InputAt(0)),
3127                  g.UseUniqueRegister(node->InputAt(1)));
3128 }
3129 
VisitF64x2PminOrPMax(InstructionSelector * selector,ArchOpcode opcode,Node * node)3130 void VisitF64x2PminOrPMax(InstructionSelector* selector, ArchOpcode opcode,
3131                           Node* node) {
3132   ArmOperandGenerator g(selector);
3133   selector->Emit(opcode, g.DefineSameAsFirst(node),
3134                  g.UseRegister(node->InputAt(0)),
3135                  g.UseRegister(node->InputAt(1)));
3136 }
3137 }  // namespace
3138 
VisitF32x4Pmin(Node * node)3139 void InstructionSelector::VisitF32x4Pmin(Node* node) {
3140   VisitF32x4PminOrPmax(this, kArmF32x4Pmin, node);
3141 }
3142 
VisitF32x4Pmax(Node * node)3143 void InstructionSelector::VisitF32x4Pmax(Node* node) {
3144   VisitF32x4PminOrPmax(this, kArmF32x4Pmax, node);
3145 }
3146 
VisitF64x2Pmin(Node * node)3147 void InstructionSelector::VisitF64x2Pmin(Node* node) {
3148   VisitF64x2PminOrPMax(this, kArmF64x2Pmin, node);
3149 }
3150 
VisitF64x2Pmax(Node * node)3151 void InstructionSelector::VisitF64x2Pmax(Node* node) {
3152   VisitF64x2PminOrPMax(this, kArmF64x2Pmax, node);
3153 }
3154 
VisitF64x2RelaxedMin(Node * node)3155 void InstructionSelector::VisitF64x2RelaxedMin(Node* node) {
3156   VisitF64x2Pmin(node);
3157 }
3158 
VisitF64x2RelaxedMax(Node * node)3159 void InstructionSelector::VisitF64x2RelaxedMax(Node* node) {
3160   VisitF64x2Pmax(node);
3161 }
3162 
3163 #define EXT_MUL_LIST(V)                            \
3164   V(I16x8ExtMulLowI8x16S, kArmVmullLow, NeonS8)    \
3165   V(I16x8ExtMulHighI8x16S, kArmVmullHigh, NeonS8)  \
3166   V(I16x8ExtMulLowI8x16U, kArmVmullLow, NeonU8)    \
3167   V(I16x8ExtMulHighI8x16U, kArmVmullHigh, NeonU8)  \
3168   V(I32x4ExtMulLowI16x8S, kArmVmullLow, NeonS16)   \
3169   V(I32x4ExtMulHighI16x8S, kArmVmullHigh, NeonS16) \
3170   V(I32x4ExtMulLowI16x8U, kArmVmullLow, NeonU16)   \
3171   V(I32x4ExtMulHighI16x8U, kArmVmullHigh, NeonU16) \
3172   V(I64x2ExtMulLowI32x4S, kArmVmullLow, NeonS32)   \
3173   V(I64x2ExtMulHighI32x4S, kArmVmullHigh, NeonS32) \
3174   V(I64x2ExtMulLowI32x4U, kArmVmullLow, NeonU32)   \
3175   V(I64x2ExtMulHighI32x4U, kArmVmullHigh, NeonU32)
3176 
3177 #define VISIT_EXT_MUL(OPCODE, VMULL, NEONSIZE)                 \
3178   void InstructionSelector::Visit##OPCODE(Node* node) {        \
3179     VisitRRR(this, VMULL | MiscField::encode(NEONSIZE), node); \
3180   }
3181 
3182 EXT_MUL_LIST(VISIT_EXT_MUL)
3183 
3184 #undef VISIT_EXT_MUL
3185 #undef EXT_MUL_LIST
3186 
3187 #define VISIT_EXTADD_PAIRWISE(OPCODE, NEONSIZE)                    \
3188   void InstructionSelector::Visit##OPCODE(Node* node) {            \
3189     VisitRR(this, kArmVpaddl | MiscField::encode(NEONSIZE), node); \
3190   }
VISIT_EXTADD_PAIRWISE(I16x8ExtAddPairwiseI8x16S,NeonS8)3191 VISIT_EXTADD_PAIRWISE(I16x8ExtAddPairwiseI8x16S, NeonS8)
3192 VISIT_EXTADD_PAIRWISE(I16x8ExtAddPairwiseI8x16U, NeonU8)
3193 VISIT_EXTADD_PAIRWISE(I32x4ExtAddPairwiseI16x8S, NeonS16)
3194 VISIT_EXTADD_PAIRWISE(I32x4ExtAddPairwiseI16x8U, NeonU16)
3195 #undef VISIT_EXTADD_PAIRWISE
3196 
3197 void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) {
3198   ArmOperandGenerator g(this);
3199 
3200   InstructionCode opcode = kArmVcvtS32F32;
3201   TruncateKind kind = OpParameter<TruncateKind>(node->op());
3202   if (kind == TruncateKind::kSetOverflowToMin) {
3203     opcode |= MiscField::encode(true);
3204   }
3205 
3206   Emit(opcode, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
3207 }
3208 
VisitTruncateFloat32ToUint32(Node * node)3209 void InstructionSelector::VisitTruncateFloat32ToUint32(Node* node) {
3210   ArmOperandGenerator g(this);
3211 
3212   InstructionCode opcode = kArmVcvtU32F32;
3213   TruncateKind kind = OpParameter<TruncateKind>(node->op());
3214   if (kind == TruncateKind::kSetOverflowToMin) {
3215     opcode |= MiscField::encode(true);
3216   }
3217 
3218   Emit(opcode, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
3219 }
3220 
3221 // TODO(v8:9780)
3222 // These double precision conversion instructions need a low Q register (q0-q7)
3223 // because the codegen accesses the S registers they overlap with.
VisitF64x2ConvertLowI32x4S(Node * node)3224 void InstructionSelector::VisitF64x2ConvertLowI32x4S(Node* node) {
3225   ArmOperandGenerator g(this);
3226   Emit(kArmF64x2ConvertLowI32x4S, g.DefineAsRegister(node),
3227        g.UseFixed(node->InputAt(0), q0));
3228 }
3229 
VisitF64x2ConvertLowI32x4U(Node * node)3230 void InstructionSelector::VisitF64x2ConvertLowI32x4U(Node* node) {
3231   ArmOperandGenerator g(this);
3232   Emit(kArmF64x2ConvertLowI32x4U, g.DefineAsRegister(node),
3233        g.UseFixed(node->InputAt(0), q0));
3234 }
3235 
VisitI32x4TruncSatF64x2SZero(Node * node)3236 void InstructionSelector::VisitI32x4TruncSatF64x2SZero(Node* node) {
3237   ArmOperandGenerator g(this);
3238   Emit(kArmI32x4TruncSatF64x2SZero, g.DefineAsFixed(node, q0),
3239        g.UseUniqueRegister(node->InputAt(0)));
3240 }
3241 
VisitI32x4TruncSatF64x2UZero(Node * node)3242 void InstructionSelector::VisitI32x4TruncSatF64x2UZero(Node* node) {
3243   ArmOperandGenerator g(this);
3244   Emit(kArmI32x4TruncSatF64x2UZero, g.DefineAsFixed(node, q0),
3245        g.UseUniqueRegister(node->InputAt(0)));
3246 }
3247 
VisitF32x4DemoteF64x2Zero(Node * node)3248 void InstructionSelector::VisitF32x4DemoteF64x2Zero(Node* node) {
3249   ArmOperandGenerator g(this);
3250   Emit(kArmF32x4DemoteF64x2Zero, g.DefineAsFixed(node, q0),
3251        g.UseUniqueRegister(node->InputAt(0)));
3252 }
3253 
VisitF64x2PromoteLowF32x4(Node * node)3254 void InstructionSelector::VisitF64x2PromoteLowF32x4(Node* node) {
3255   ArmOperandGenerator g(this);
3256   Emit(kArmF64x2PromoteLowF32x4, g.DefineAsRegister(node),
3257        g.UseFixed(node->InputAt(0), q0));
3258 }
3259 
VisitI32x4RelaxedTruncF64x2SZero(Node * node)3260 void InstructionSelector::VisitI32x4RelaxedTruncF64x2SZero(Node* node) {
3261   VisitI32x4TruncSatF64x2SZero(node);
3262 }
3263 
VisitI32x4RelaxedTruncF64x2UZero(Node * node)3264 void InstructionSelector::VisitI32x4RelaxedTruncF64x2UZero(Node* node) {
3265   VisitI32x4TruncSatF64x2UZero(node);
3266 }
3267 
AddOutputToSelectContinuation(OperandGenerator * g,int first_input_index,Node * node)3268 void InstructionSelector::AddOutputToSelectContinuation(OperandGenerator* g,
3269                                                         int first_input_index,
3270                                                         Node* node) {
3271   UNREACHABLE();
3272 }
3273 
3274 // static
3275 MachineOperatorBuilder::Flags
SupportedMachineOperatorFlags()3276 InstructionSelector::SupportedMachineOperatorFlags() {
3277   MachineOperatorBuilder::Flags flags = MachineOperatorBuilder::kNoFlags;
3278   if (CpuFeatures::IsSupported(SUDIV)) {
3279     // The sdiv and udiv instructions correctly return 0 if the divisor is 0,
3280     // but the fall-back implementation does not.
3281     flags |= MachineOperatorBuilder::kInt32DivIsSafe |
3282              MachineOperatorBuilder::kUint32DivIsSafe;
3283   }
3284   if (CpuFeatures::IsSupported(ARMv7)) {
3285     flags |= MachineOperatorBuilder::kWord32ReverseBits;
3286   }
3287   if (CpuFeatures::IsSupported(ARMv8)) {
3288     flags |= MachineOperatorBuilder::kFloat32RoundDown |
3289              MachineOperatorBuilder::kFloat64RoundDown |
3290              MachineOperatorBuilder::kFloat32RoundUp |
3291              MachineOperatorBuilder::kFloat64RoundUp |
3292              MachineOperatorBuilder::kFloat32RoundTruncate |
3293              MachineOperatorBuilder::kFloat64RoundTruncate |
3294              MachineOperatorBuilder::kFloat64RoundTiesAway |
3295              MachineOperatorBuilder::kFloat32RoundTiesEven |
3296              MachineOperatorBuilder::kFloat64RoundTiesEven;
3297   }
3298   flags |= MachineOperatorBuilder::kSatConversionIsSafe;
3299   return flags;
3300 }
3301 
3302 // static
3303 MachineOperatorBuilder::AlignmentRequirements
AlignmentRequirements()3304 InstructionSelector::AlignmentRequirements() {
3305   base::EnumSet<MachineRepresentation> req_aligned;
3306   req_aligned.Add(MachineRepresentation::kFloat32);
3307   req_aligned.Add(MachineRepresentation::kFloat64);
3308   return MachineOperatorBuilder::AlignmentRequirements::
3309       SomeUnalignedAccessUnsupported(req_aligned, req_aligned);
3310 }
3311 
3312 }  // namespace compiler
3313 }  // namespace internal
3314 }  // namespace v8
3315