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