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