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/assembler-inl.h"
6 #include "src/compiler/instruction-selector-impl.h"
7 #include "src/compiler/node-matchers.h"
8 #include "src/compiler/node-properties.h"
9 
10 namespace v8 {
11 namespace internal {
12 namespace compiler {
13 
14 enum ImmediateMode {
15   kArithmeticImm,  // 12 bit unsigned immediate shifted left 0 or 12 bits
16   kShift32Imm,     // 0 - 31
17   kShift64Imm,     // 0 - 63
18   kLogical32Imm,
19   kLogical64Imm,
20   kLoadStoreImm8,   // signed 8 bit or 12 bit unsigned scaled by access size
21   kLoadStoreImm16,
22   kLoadStoreImm32,
23   kLoadStoreImm64,
24   kNoImmediate
25 };
26 
27 
28 // Adds Arm64-specific methods for generating operands.
29 class Arm64OperandGenerator final : public OperandGenerator {
30  public:
Arm64OperandGenerator(InstructionSelector * selector)31   explicit Arm64OperandGenerator(InstructionSelector* selector)
32       : OperandGenerator(selector) {}
33 
UseOperand(Node * node,ImmediateMode mode)34   InstructionOperand UseOperand(Node* node, ImmediateMode mode) {
35     if (CanBeImmediate(node, mode)) {
36       return UseImmediate(node);
37     }
38     return UseRegister(node);
39   }
40 
41   // Use the zero register if the node has the immediate value zero, otherwise
42   // assign a register.
UseRegisterOrImmediateZero(Node * node)43   InstructionOperand UseRegisterOrImmediateZero(Node* node) {
44     if ((IsIntegerConstant(node) && (GetIntegerConstantValue(node) == 0)) ||
45         (IsFloatConstant(node) &&
46          (bit_cast<int64_t>(GetFloatConstantValue(node)) == 0))) {
47       return UseImmediate(node);
48     }
49     return UseRegister(node);
50   }
51 
52   // Use the stack pointer if the node is LoadStackPointer, otherwise assign a
53   // register.
UseRegisterOrStackPointer(Node * node,bool sp_allowed)54   InstructionOperand UseRegisterOrStackPointer(Node* node, bool sp_allowed) {
55     if (sp_allowed && node->opcode() == IrOpcode::kLoadStackPointer)
56       return LocationOperand(LocationOperand::EXPLICIT,
57                              LocationOperand::REGISTER,
58                              MachineRepresentation::kWord64, sp.code());
59     return UseRegister(node);
60   }
61 
62   // Use the provided node if it has the required value, or create a
63   // TempImmediate otherwise.
UseImmediateOrTemp(Node * node,int32_t value)64   InstructionOperand UseImmediateOrTemp(Node* node, int32_t value) {
65     if (GetIntegerConstantValue(node) == value) {
66       return UseImmediate(node);
67     }
68     return TempImmediate(value);
69   }
70 
IsIntegerConstant(Node * node)71   bool IsIntegerConstant(Node* node) {
72     return (node->opcode() == IrOpcode::kInt32Constant) ||
73            (node->opcode() == IrOpcode::kInt64Constant);
74   }
75 
GetIntegerConstantValue(Node * node)76   int64_t GetIntegerConstantValue(Node* node) {
77     if (node->opcode() == IrOpcode::kInt32Constant) {
78       return OpParameter<int32_t>(node->op());
79     }
80     DCHECK_EQ(IrOpcode::kInt64Constant, node->opcode());
81     return OpParameter<int64_t>(node->op());
82   }
83 
IsFloatConstant(Node * node)84   bool IsFloatConstant(Node* node) {
85     return (node->opcode() == IrOpcode::kFloat32Constant) ||
86            (node->opcode() == IrOpcode::kFloat64Constant);
87   }
88 
GetFloatConstantValue(Node * node)89   double GetFloatConstantValue(Node* node) {
90     if (node->opcode() == IrOpcode::kFloat32Constant) {
91       return OpParameter<float>(node->op());
92     }
93     DCHECK_EQ(IrOpcode::kFloat64Constant, node->opcode());
94     return OpParameter<double>(node->op());
95   }
96 
CanBeImmediate(Node * node,ImmediateMode mode)97   bool CanBeImmediate(Node* node, ImmediateMode mode) {
98     return IsIntegerConstant(node) &&
99            CanBeImmediate(GetIntegerConstantValue(node), mode);
100   }
101 
CanBeImmediate(int64_t value,ImmediateMode mode)102   bool CanBeImmediate(int64_t value, ImmediateMode mode) {
103     unsigned ignored;
104     switch (mode) {
105       case kLogical32Imm:
106         // TODO(dcarney): some unencodable values can be handled by
107         // switching instructions.
108         return Assembler::IsImmLogical(static_cast<uint64_t>(value), 32,
109                                        &ignored, &ignored, &ignored);
110       case kLogical64Imm:
111         return Assembler::IsImmLogical(static_cast<uint64_t>(value), 64,
112                                        &ignored, &ignored, &ignored);
113       case kArithmeticImm:
114         return Assembler::IsImmAddSub(value);
115       case kLoadStoreImm8:
116         return IsLoadStoreImmediate(value, 0);
117       case kLoadStoreImm16:
118         return IsLoadStoreImmediate(value, 1);
119       case kLoadStoreImm32:
120         return IsLoadStoreImmediate(value, 2);
121       case kLoadStoreImm64:
122         return IsLoadStoreImmediate(value, 3);
123       case kNoImmediate:
124         return false;
125       case kShift32Imm:  // Fall through.
126       case kShift64Imm:
127         // Shift operations only observe the bottom 5 or 6 bits of the value.
128         // All possible shifts can be encoded by discarding bits which have no
129         // effect.
130         return true;
131     }
132     return false;
133   }
134 
CanBeLoadStoreShiftImmediate(Node * node,MachineRepresentation rep)135   bool CanBeLoadStoreShiftImmediate(Node* node, MachineRepresentation rep) {
136     // TODO(arm64): Load and Store on 128 bit Q registers is not supported yet.
137     DCHECK_GT(MachineRepresentation::kSimd128, rep);
138     return IsIntegerConstant(node) &&
139            (GetIntegerConstantValue(node) == ElementSizeLog2Of(rep));
140   }
141 
142  private:
IsLoadStoreImmediate(int64_t value,unsigned size)143   bool IsLoadStoreImmediate(int64_t value, unsigned size) {
144     return Assembler::IsImmLSScaled(value, size) ||
145            Assembler::IsImmLSUnscaled(value);
146   }
147 };
148 
149 
150 namespace {
151 
VisitRR(InstructionSelector * selector,ArchOpcode opcode,Node * node)152 void VisitRR(InstructionSelector* selector, ArchOpcode opcode, Node* node) {
153   Arm64OperandGenerator g(selector);
154   selector->Emit(opcode, g.DefineAsRegister(node),
155                  g.UseRegister(node->InputAt(0)));
156 }
157 
158 
VisitRRR(InstructionSelector * selector,ArchOpcode opcode,Node * node)159 void VisitRRR(InstructionSelector* selector, ArchOpcode opcode, Node* node) {
160   Arm64OperandGenerator g(selector);
161   selector->Emit(opcode, g.DefineAsRegister(node),
162                  g.UseRegister(node->InputAt(0)),
163                  g.UseRegister(node->InputAt(1)));
164 }
165 
VisitRRI(InstructionSelector * selector,ArchOpcode opcode,Node * node)166 void VisitRRI(InstructionSelector* selector, ArchOpcode opcode, Node* node) {
167   Arm64OperandGenerator g(selector);
168   int32_t imm = OpParameter<int32_t>(node->op());
169   selector->Emit(opcode, g.DefineAsRegister(node),
170                  g.UseRegister(node->InputAt(0)), g.UseImmediate(imm));
171 }
172 
VisitRRO(InstructionSelector * selector,ArchOpcode opcode,Node * node,ImmediateMode operand_mode)173 void VisitRRO(InstructionSelector* selector, ArchOpcode opcode, Node* node,
174               ImmediateMode operand_mode) {
175   Arm64OperandGenerator g(selector);
176   selector->Emit(opcode, g.DefineAsRegister(node),
177                  g.UseRegister(node->InputAt(0)),
178                  g.UseOperand(node->InputAt(1), operand_mode));
179 }
180 
VisitRRIR(InstructionSelector * selector,ArchOpcode opcode,Node * node)181 void VisitRRIR(InstructionSelector* selector, ArchOpcode opcode, Node* node) {
182   Arm64OperandGenerator g(selector);
183   int32_t imm = OpParameter<int32_t>(node->op());
184   selector->Emit(opcode, g.DefineAsRegister(node),
185                  g.UseRegister(node->InputAt(0)), g.UseImmediate(imm),
186                  g.UseRegister(node->InputAt(1)));
187 }
188 
189 struct ExtendingLoadMatcher {
ExtendingLoadMatcherv8::internal::compiler::__anon47426b030111::ExtendingLoadMatcher190   ExtendingLoadMatcher(Node* node, InstructionSelector* selector)
191       : matches_(false), selector_(selector), base_(nullptr), immediate_(0) {
192     Initialize(node);
193   }
194 
Matchesv8::internal::compiler::__anon47426b030111::ExtendingLoadMatcher195   bool Matches() const { return matches_; }
196 
basev8::internal::compiler::__anon47426b030111::ExtendingLoadMatcher197   Node* base() const {
198     DCHECK(Matches());
199     return base_;
200   }
immediatev8::internal::compiler::__anon47426b030111::ExtendingLoadMatcher201   int64_t immediate() const {
202     DCHECK(Matches());
203     return immediate_;
204   }
opcodev8::internal::compiler::__anon47426b030111::ExtendingLoadMatcher205   ArchOpcode opcode() const {
206     DCHECK(Matches());
207     return opcode_;
208   }
209 
210  private:
211   bool matches_;
212   InstructionSelector* selector_;
213   Node* base_;
214   int64_t immediate_;
215   ArchOpcode opcode_;
216 
Initializev8::internal::compiler::__anon47426b030111::ExtendingLoadMatcher217   void Initialize(Node* node) {
218     Int64BinopMatcher m(node);
219     // When loading a 64-bit value and shifting by 32, we should
220     // just load and sign-extend the interesting 4 bytes instead.
221     // This happens, for example, when we're loading and untagging SMIs.
222     DCHECK(m.IsWord64Sar());
223     if (m.left().IsLoad() && m.right().Is(32) &&
224         selector_->CanCover(m.node(), m.left().node())) {
225       Arm64OperandGenerator g(selector_);
226       Node* load = m.left().node();
227       Node* offset = load->InputAt(1);
228       base_ = load->InputAt(0);
229       opcode_ = kArm64Ldrsw;
230       if (g.IsIntegerConstant(offset)) {
231         immediate_ = g.GetIntegerConstantValue(offset) + 4;
232         matches_ = g.CanBeImmediate(immediate_, kLoadStoreImm32);
233       }
234     }
235   }
236 };
237 
TryMatchExtendingLoad(InstructionSelector * selector,Node * node)238 bool TryMatchExtendingLoad(InstructionSelector* selector, Node* node) {
239   ExtendingLoadMatcher m(node, selector);
240   return m.Matches();
241 }
242 
TryEmitExtendingLoad(InstructionSelector * selector,Node * node)243 bool TryEmitExtendingLoad(InstructionSelector* selector, Node* node) {
244   ExtendingLoadMatcher m(node, selector);
245   Arm64OperandGenerator g(selector);
246   if (m.Matches()) {
247     InstructionOperand inputs[2];
248     inputs[0] = g.UseRegister(m.base());
249     InstructionCode opcode =
250         m.opcode() | AddressingModeField::encode(kMode_MRI);
251     DCHECK(is_int32(m.immediate()));
252     inputs[1] = g.TempImmediate(static_cast<int32_t>(m.immediate()));
253     InstructionOperand outputs[] = {g.DefineAsRegister(node)};
254     selector->Emit(opcode, arraysize(outputs), outputs, arraysize(inputs),
255                    inputs);
256     return true;
257   }
258   return false;
259 }
260 
TryMatchAnyShift(InstructionSelector * selector,Node * node,Node * input_node,InstructionCode * opcode,bool try_ror)261 bool TryMatchAnyShift(InstructionSelector* selector, Node* node,
262                       Node* input_node, InstructionCode* opcode, bool try_ror) {
263   Arm64OperandGenerator g(selector);
264 
265   if (!selector->CanCover(node, input_node)) return false;
266   if (input_node->InputCount() != 2) return false;
267   if (!g.IsIntegerConstant(input_node->InputAt(1))) return false;
268 
269   switch (input_node->opcode()) {
270     case IrOpcode::kWord32Shl:
271     case IrOpcode::kWord64Shl:
272       *opcode |= AddressingModeField::encode(kMode_Operand2_R_LSL_I);
273       return true;
274     case IrOpcode::kWord32Shr:
275     case IrOpcode::kWord64Shr:
276       *opcode |= AddressingModeField::encode(kMode_Operand2_R_LSR_I);
277       return true;
278     case IrOpcode::kWord32Sar:
279       *opcode |= AddressingModeField::encode(kMode_Operand2_R_ASR_I);
280       return true;
281     case IrOpcode::kWord64Sar:
282       if (TryMatchExtendingLoad(selector, input_node)) return false;
283       *opcode |= AddressingModeField::encode(kMode_Operand2_R_ASR_I);
284       return true;
285     case IrOpcode::kWord32Ror:
286     case IrOpcode::kWord64Ror:
287       if (try_ror) {
288         *opcode |= AddressingModeField::encode(kMode_Operand2_R_ROR_I);
289         return true;
290       }
291       return false;
292     default:
293       return false;
294   }
295 }
296 
297 
TryMatchAnyExtend(Arm64OperandGenerator * g,InstructionSelector * selector,Node * node,Node * left_node,Node * right_node,InstructionOperand * left_op,InstructionOperand * right_op,InstructionCode * opcode)298 bool TryMatchAnyExtend(Arm64OperandGenerator* g, InstructionSelector* selector,
299                        Node* node, Node* left_node, Node* right_node,
300                        InstructionOperand* left_op,
301                        InstructionOperand* right_op, InstructionCode* opcode) {
302   if (!selector->CanCover(node, right_node)) return false;
303 
304   NodeMatcher nm(right_node);
305 
306   if (nm.IsWord32And()) {
307     Int32BinopMatcher mright(right_node);
308     if (mright.right().Is(0xFF) || mright.right().Is(0xFFFF)) {
309       int32_t mask = mright.right().Value();
310       *left_op = g->UseRegister(left_node);
311       *right_op = g->UseRegister(mright.left().node());
312       *opcode |= AddressingModeField::encode(
313           (mask == 0xFF) ? kMode_Operand2_R_UXTB : kMode_Operand2_R_UXTH);
314       return true;
315     }
316   } else if (nm.IsWord32Sar()) {
317     Int32BinopMatcher mright(right_node);
318     if (selector->CanCover(mright.node(), mright.left().node()) &&
319         mright.left().IsWord32Shl()) {
320       Int32BinopMatcher mleft_of_right(mright.left().node());
321       if ((mright.right().Is(16) && mleft_of_right.right().Is(16)) ||
322           (mright.right().Is(24) && mleft_of_right.right().Is(24))) {
323         int32_t shift = mright.right().Value();
324         *left_op = g->UseRegister(left_node);
325         *right_op = g->UseRegister(mleft_of_right.left().node());
326         *opcode |= AddressingModeField::encode(
327             (shift == 24) ? kMode_Operand2_R_SXTB : kMode_Operand2_R_SXTH);
328         return true;
329       }
330     }
331   }
332   return false;
333 }
334 
TryMatchLoadStoreShift(Arm64OperandGenerator * g,InstructionSelector * selector,MachineRepresentation rep,Node * node,Node * index,InstructionOperand * index_op,InstructionOperand * shift_immediate_op)335 bool TryMatchLoadStoreShift(Arm64OperandGenerator* g,
336                             InstructionSelector* selector,
337                             MachineRepresentation rep, Node* node, Node* index,
338                             InstructionOperand* index_op,
339                             InstructionOperand* shift_immediate_op) {
340   if (!selector->CanCover(node, index)) return false;
341   if (index->InputCount() != 2) return false;
342   Node* left = index->InputAt(0);
343   Node* right = index->InputAt(1);
344   switch (index->opcode()) {
345     case IrOpcode::kWord32Shl:
346     case IrOpcode::kWord64Shl:
347       if (!g->CanBeLoadStoreShiftImmediate(right, rep)) {
348         return false;
349       }
350       *index_op = g->UseRegister(left);
351       *shift_immediate_op = g->UseImmediate(right);
352       return true;
353     default:
354       return false;
355   }
356 }
357 
358 // Bitfields describing binary operator properties:
359 // CanCommuteField is true if we can switch the two operands, potentially
360 // requiring commuting the flags continuation condition.
361 typedef BitField8<bool, 1, 1> CanCommuteField;
362 // MustCommuteCondField is true when we need to commute the flags continuation
363 // condition in order to switch the operands.
364 typedef BitField8<bool, 2, 1> MustCommuteCondField;
365 // IsComparisonField is true when the operation is a comparison and has no other
366 // result other than the condition.
367 typedef BitField8<bool, 3, 1> IsComparisonField;
368 // IsAddSubField is true when an instruction is encoded as ADD or SUB.
369 typedef BitField8<bool, 4, 1> IsAddSubField;
370 
371 // Get properties of a binary operator.
GetBinopProperties(InstructionCode opcode)372 uint8_t GetBinopProperties(InstructionCode opcode) {
373   uint8_t result = 0;
374   switch (opcode) {
375     case kArm64Cmp32:
376     case kArm64Cmp:
377       // We can commute CMP by switching the inputs and commuting
378       // the flags continuation.
379       result = CanCommuteField::update(result, true);
380       result = MustCommuteCondField::update(result, true);
381       result = IsComparisonField::update(result, true);
382       // The CMP and CMN instructions are encoded as SUB or ADD
383       // with zero output register, and therefore support the same
384       // operand modes.
385       result = IsAddSubField::update(result, true);
386       break;
387     case kArm64Cmn32:
388     case kArm64Cmn:
389       result = CanCommuteField::update(result, true);
390       result = IsComparisonField::update(result, true);
391       result = IsAddSubField::update(result, true);
392       break;
393     case kArm64Add32:
394     case kArm64Add:
395       result = CanCommuteField::update(result, true);
396       result = IsAddSubField::update(result, true);
397       break;
398     case kArm64Sub32:
399     case kArm64Sub:
400       result = IsAddSubField::update(result, true);
401       break;
402     case kArm64Tst32:
403     case kArm64Tst:
404       result = CanCommuteField::update(result, true);
405       result = IsComparisonField::update(result, true);
406       break;
407     case kArm64And32:
408     case kArm64And:
409     case kArm64Or32:
410     case kArm64Or:
411     case kArm64Eor32:
412     case kArm64Eor:
413       result = CanCommuteField::update(result, true);
414       break;
415     default:
416       UNREACHABLE();
417   }
418   DCHECK_IMPLIES(MustCommuteCondField::decode(result),
419                  CanCommuteField::decode(result));
420   return result;
421 }
422 
423 // Shared routine for multiple binary operations.
424 template <typename Matcher>
VisitBinop(InstructionSelector * selector,Node * node,InstructionCode opcode,ImmediateMode operand_mode,FlagsContinuation * cont)425 void VisitBinop(InstructionSelector* selector, Node* node,
426                 InstructionCode opcode, ImmediateMode operand_mode,
427                 FlagsContinuation* cont) {
428   Arm64OperandGenerator g(selector);
429   InstructionOperand inputs[3];
430   size_t input_count = 0;
431   InstructionOperand outputs[1];
432   size_t output_count = 0;
433 
434   Node* left_node = node->InputAt(0);
435   Node* right_node = node->InputAt(1);
436 
437   uint8_t properties = GetBinopProperties(opcode);
438   bool can_commute = CanCommuteField::decode(properties);
439   bool must_commute_cond = MustCommuteCondField::decode(properties);
440   bool is_add_sub = IsAddSubField::decode(properties);
441 
442   if (g.CanBeImmediate(right_node, operand_mode)) {
443     inputs[input_count++] = g.UseRegister(left_node);
444     inputs[input_count++] = g.UseImmediate(right_node);
445   } else if (can_commute && g.CanBeImmediate(left_node, operand_mode)) {
446     if (must_commute_cond) cont->Commute();
447     inputs[input_count++] = g.UseRegister(right_node);
448     inputs[input_count++] = g.UseImmediate(left_node);
449   } else if (is_add_sub &&
450              TryMatchAnyExtend(&g, selector, node, left_node, right_node,
451                                &inputs[0], &inputs[1], &opcode)) {
452     input_count += 2;
453   } else if (is_add_sub && can_commute &&
454              TryMatchAnyExtend(&g, selector, node, right_node, left_node,
455                                &inputs[0], &inputs[1], &opcode)) {
456     if (must_commute_cond) cont->Commute();
457     input_count += 2;
458   } else if (TryMatchAnyShift(selector, node, right_node, &opcode,
459                               !is_add_sub)) {
460     Matcher m_shift(right_node);
461     inputs[input_count++] = g.UseRegisterOrImmediateZero(left_node);
462     inputs[input_count++] = g.UseRegister(m_shift.left().node());
463     // We only need at most the last 6 bits of the shift.
464     inputs[input_count++] =
465         g.UseImmediate(static_cast<int>(m_shift.right().Value() & 0x3F));
466   } else if (can_commute && TryMatchAnyShift(selector, node, left_node, &opcode,
467                                              !is_add_sub)) {
468     if (must_commute_cond) cont->Commute();
469     Matcher m_shift(left_node);
470     inputs[input_count++] = g.UseRegisterOrImmediateZero(right_node);
471     inputs[input_count++] = g.UseRegister(m_shift.left().node());
472     // We only need at most the last 6 bits of the shift.
473     inputs[input_count++] =
474         g.UseImmediate(static_cast<int>(m_shift.right().Value() & 0x3F));
475   } else {
476     inputs[input_count++] = g.UseRegisterOrImmediateZero(left_node);
477     inputs[input_count++] = g.UseRegister(right_node);
478   }
479 
480   if (!IsComparisonField::decode(properties)) {
481     outputs[output_count++] = g.DefineAsRegister(node);
482   }
483 
484   DCHECK_NE(0u, input_count);
485   DCHECK((output_count != 0) || IsComparisonField::decode(properties));
486   DCHECK_GE(arraysize(inputs), input_count);
487   DCHECK_GE(arraysize(outputs), output_count);
488 
489   selector->EmitWithContinuation(opcode, output_count, outputs, input_count,
490                                  inputs, cont);
491 }
492 
493 
494 // Shared routine for multiple binary operations.
495 template <typename Matcher>
VisitBinop(InstructionSelector * selector,Node * node,ArchOpcode opcode,ImmediateMode operand_mode)496 void VisitBinop(InstructionSelector* selector, Node* node, ArchOpcode opcode,
497                 ImmediateMode operand_mode) {
498   FlagsContinuation cont;
499   VisitBinop<Matcher>(selector, node, opcode, operand_mode, &cont);
500 }
501 
502 
503 template <typename Matcher>
VisitAddSub(InstructionSelector * selector,Node * node,ArchOpcode opcode,ArchOpcode negate_opcode)504 void VisitAddSub(InstructionSelector* selector, Node* node, ArchOpcode opcode,
505                  ArchOpcode negate_opcode) {
506   Arm64OperandGenerator g(selector);
507   Matcher m(node);
508   if (m.right().HasValue() && (m.right().Value() < 0) &&
509       g.CanBeImmediate(-m.right().Value(), kArithmeticImm)) {
510     selector->Emit(negate_opcode, g.DefineAsRegister(node),
511                    g.UseRegister(m.left().node()),
512                    g.TempImmediate(static_cast<int32_t>(-m.right().Value())));
513   } else {
514     VisitBinop<Matcher>(selector, node, opcode, kArithmeticImm);
515   }
516 }
517 
518 
519 // For multiplications by immediate of the form x * (2^k + 1), where k > 0,
520 // return the value of k, otherwise return zero. This is used to reduce the
521 // multiplication to addition with left shift: x + (x << k).
522 template <typename Matcher>
LeftShiftForReducedMultiply(Matcher * m)523 int32_t LeftShiftForReducedMultiply(Matcher* m) {
524   DCHECK(m->IsInt32Mul() || m->IsInt64Mul());
525   if (m->right().HasValue() && m->right().Value() >= 3) {
526     uint64_t value_minus_one = m->right().Value() - 1;
527     if (base::bits::IsPowerOfTwo(value_minus_one)) {
528       return WhichPowerOf2(value_minus_one);
529     }
530   }
531   return 0;
532 }
533 
534 }  // namespace
535 
VisitStackSlot(Node * node)536 void InstructionSelector::VisitStackSlot(Node* node) {
537   StackSlotRepresentation rep = StackSlotRepresentationOf(node->op());
538   int slot = frame_->AllocateSpillSlot(rep.size());
539   OperandGenerator g(this);
540 
541   Emit(kArchStackSlot, g.DefineAsRegister(node),
542        sequence()->AddImmediate(Constant(slot)), 0, nullptr);
543 }
544 
VisitDebugAbort(Node * node)545 void InstructionSelector::VisitDebugAbort(Node* node) {
546   Arm64OperandGenerator g(this);
547   Emit(kArchDebugAbort, g.NoOutput(), g.UseFixed(node->InputAt(0), x1));
548 }
549 
EmitLoad(InstructionSelector * selector,Node * node,InstructionCode opcode,ImmediateMode immediate_mode,MachineRepresentation rep,Node * output=nullptr)550 void EmitLoad(InstructionSelector* selector, Node* node, InstructionCode opcode,
551               ImmediateMode immediate_mode, MachineRepresentation rep,
552               Node* output = nullptr) {
553   Arm64OperandGenerator g(selector);
554   Node* base = node->InputAt(0);
555   Node* index = node->InputAt(1);
556   InstructionOperand inputs[3];
557   size_t input_count = 0;
558   InstructionOperand outputs[1];
559 
560   // If output is not nullptr, use that as the output register. This
561   // is used when we merge a conversion into the load.
562   outputs[0] = g.DefineAsRegister(output == nullptr ? node : output);
563 
564   if (selector->CanAddressRelativeToRootsRegister()) {
565     ExternalReferenceMatcher m(base);
566     if (m.HasValue() && g.IsIntegerConstant(index)) {
567       ptrdiff_t const delta =
568           g.GetIntegerConstantValue(index) +
569           TurboAssemblerBase::RootRegisterOffsetForExternalReference(
570               selector->isolate(), m.Value());
571       input_count = 1;
572       // Check that the delta is a 32-bit integer due to the limitations of
573       // immediate operands.
574       if (is_int32(delta)) {
575         inputs[0] = g.UseImmediate(static_cast<int32_t>(delta));
576         opcode |= AddressingModeField::encode(kMode_Root);
577         selector->Emit(opcode, arraysize(outputs), outputs, input_count,
578                        inputs);
579         return;
580       }
581     }
582   }
583 
584   inputs[0] = g.UseRegister(base);
585 
586   if (g.CanBeImmediate(index, immediate_mode)) {
587     input_count = 2;
588     inputs[1] = g.UseImmediate(index);
589     opcode |= AddressingModeField::encode(kMode_MRI);
590   } else if (TryMatchLoadStoreShift(&g, selector, rep, node, index, &inputs[1],
591                                     &inputs[2])) {
592     input_count = 3;
593     opcode |= AddressingModeField::encode(kMode_Operand2_R_LSL_I);
594   } else {
595     input_count = 2;
596     inputs[1] = g.UseRegister(index);
597     opcode |= AddressingModeField::encode(kMode_MRR);
598   }
599 
600   selector->Emit(opcode, arraysize(outputs), outputs, input_count, inputs);
601 }
602 
VisitLoad(Node * node)603 void InstructionSelector::VisitLoad(Node* node) {
604   InstructionCode opcode = kArchNop;
605   ImmediateMode immediate_mode = kNoImmediate;
606   LoadRepresentation load_rep = LoadRepresentationOf(node->op());
607   MachineRepresentation rep = load_rep.representation();
608   switch (rep) {
609     case MachineRepresentation::kFloat32:
610       opcode = kArm64LdrS;
611       immediate_mode = kLoadStoreImm32;
612       break;
613     case MachineRepresentation::kFloat64:
614       opcode = kArm64LdrD;
615       immediate_mode = kLoadStoreImm64;
616       break;
617     case MachineRepresentation::kBit:  // Fall through.
618     case MachineRepresentation::kWord8:
619       opcode = load_rep.IsSigned() ? kArm64Ldrsb : kArm64Ldrb;
620       immediate_mode = kLoadStoreImm8;
621       break;
622     case MachineRepresentation::kWord16:
623       opcode = load_rep.IsSigned() ? kArm64Ldrsh : kArm64Ldrh;
624       immediate_mode = kLoadStoreImm16;
625       break;
626     case MachineRepresentation::kWord32:
627       opcode = kArm64LdrW;
628       immediate_mode = kLoadStoreImm32;
629       break;
630     case MachineRepresentation::kTaggedSigned:   // Fall through.
631     case MachineRepresentation::kTaggedPointer:  // Fall through.
632     case MachineRepresentation::kTagged:  // Fall through.
633     case MachineRepresentation::kWord64:
634       opcode = kArm64Ldr;
635       immediate_mode = kLoadStoreImm64;
636       break;
637     case MachineRepresentation::kSimd128:
638       opcode = kArm64LdrQ;
639       immediate_mode = kNoImmediate;
640       break;
641     case MachineRepresentation::kNone:
642       UNREACHABLE();
643       return;
644   }
645   if (node->opcode() == IrOpcode::kPoisonedLoad) {
646     CHECK_NE(poisoning_level_, PoisoningMitigationLevel::kDontPoison);
647     opcode |= MiscField::encode(kMemoryAccessPoisoned);
648   }
649 
650   EmitLoad(this, node, opcode, immediate_mode, rep);
651 }
652 
VisitPoisonedLoad(Node * node)653 void InstructionSelector::VisitPoisonedLoad(Node* node) { VisitLoad(node); }
654 
VisitProtectedLoad(Node * node)655 void InstructionSelector::VisitProtectedLoad(Node* node) {
656   // TODO(eholk)
657   UNIMPLEMENTED();
658 }
659 
VisitStore(Node * node)660 void InstructionSelector::VisitStore(Node* node) {
661   Arm64OperandGenerator g(this);
662   Node* base = node->InputAt(0);
663   Node* index = node->InputAt(1);
664   Node* value = node->InputAt(2);
665 
666   StoreRepresentation store_rep = StoreRepresentationOf(node->op());
667   WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind();
668   MachineRepresentation rep = store_rep.representation();
669 
670   // TODO(arm64): I guess this could be done in a better way.
671   if (write_barrier_kind != kNoWriteBarrier) {
672     DCHECK(CanBeTaggedPointer(rep));
673     AddressingMode addressing_mode;
674     InstructionOperand inputs[3];
675     size_t input_count = 0;
676     inputs[input_count++] = g.UseUniqueRegister(base);
677     // OutOfLineRecordWrite uses the index in an arithmetic instruction, so we
678     // must check kArithmeticImm as well as kLoadStoreImm64.
679     if (g.CanBeImmediate(index, kArithmeticImm) &&
680         g.CanBeImmediate(index, kLoadStoreImm64)) {
681       inputs[input_count++] = g.UseImmediate(index);
682       addressing_mode = kMode_MRI;
683     } else {
684       inputs[input_count++] = g.UseUniqueRegister(index);
685       addressing_mode = kMode_MRR;
686     }
687     inputs[input_count++] = g.UseUniqueRegister(value);
688     RecordWriteMode record_write_mode = RecordWriteMode::kValueIsAny;
689     switch (write_barrier_kind) {
690       case kNoWriteBarrier:
691         UNREACHABLE();
692         break;
693       case kMapWriteBarrier:
694         record_write_mode = RecordWriteMode::kValueIsMap;
695         break;
696       case kPointerWriteBarrier:
697         record_write_mode = RecordWriteMode::kValueIsPointer;
698         break;
699       case kFullWriteBarrier:
700         record_write_mode = RecordWriteMode::kValueIsAny;
701         break;
702     }
703     InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
704     size_t const temp_count = arraysize(temps);
705     InstructionCode code = kArchStoreWithWriteBarrier;
706     code |= AddressingModeField::encode(addressing_mode);
707     code |= MiscField::encode(static_cast<int>(record_write_mode));
708     Emit(code, 0, nullptr, input_count, inputs, temp_count, temps);
709   } else {
710     InstructionOperand inputs[4];
711     size_t input_count = 0;
712     InstructionCode opcode = kArchNop;
713     ImmediateMode immediate_mode = kNoImmediate;
714     switch (rep) {
715       case MachineRepresentation::kFloat32:
716         opcode = kArm64StrS;
717         immediate_mode = kLoadStoreImm32;
718         break;
719       case MachineRepresentation::kFloat64:
720         opcode = kArm64StrD;
721         immediate_mode = kLoadStoreImm64;
722         break;
723       case MachineRepresentation::kBit:  // Fall through.
724       case MachineRepresentation::kWord8:
725         opcode = kArm64Strb;
726         immediate_mode = kLoadStoreImm8;
727         break;
728       case MachineRepresentation::kWord16:
729         opcode = kArm64Strh;
730         immediate_mode = kLoadStoreImm16;
731         break;
732       case MachineRepresentation::kWord32:
733         opcode = kArm64StrW;
734         immediate_mode = kLoadStoreImm32;
735         break;
736       case MachineRepresentation::kTaggedSigned:   // Fall through.
737       case MachineRepresentation::kTaggedPointer:  // Fall through.
738       case MachineRepresentation::kTagged:  // Fall through.
739       case MachineRepresentation::kWord64:
740         opcode = kArm64Str;
741         immediate_mode = kLoadStoreImm64;
742         break;
743       case MachineRepresentation::kSimd128:
744         opcode = kArm64StrQ;
745         immediate_mode = kNoImmediate;
746         break;
747       case MachineRepresentation::kNone:
748         UNREACHABLE();
749         return;
750     }
751 
752     inputs[0] = g.UseRegisterOrImmediateZero(value);
753     inputs[1] = g.UseRegister(base);
754 
755     if (g.CanBeImmediate(index, immediate_mode)) {
756       input_count = 3;
757       inputs[2] = g.UseImmediate(index);
758       opcode |= AddressingModeField::encode(kMode_MRI);
759     } else if (TryMatchLoadStoreShift(&g, this, rep, node, index, &inputs[2],
760                                       &inputs[3])) {
761       input_count = 4;
762       opcode |= AddressingModeField::encode(kMode_Operand2_R_LSL_I);
763     } else {
764       input_count = 3;
765       inputs[2] = g.UseRegister(index);
766       opcode |= AddressingModeField::encode(kMode_MRR);
767     }
768 
769     Emit(opcode, 0, nullptr, input_count, inputs);
770   }
771 }
772 
VisitProtectedStore(Node * node)773 void InstructionSelector::VisitProtectedStore(Node* node) {
774   // TODO(eholk)
775   UNIMPLEMENTED();
776 }
777 
778 // Architecture supports unaligned access, therefore VisitLoad is used instead
VisitUnalignedLoad(Node * node)779 void InstructionSelector::VisitUnalignedLoad(Node* node) { UNREACHABLE(); }
780 
781 // Architecture supports unaligned access, therefore VisitStore is used instead
VisitUnalignedStore(Node * node)782 void InstructionSelector::VisitUnalignedStore(Node* node) { UNREACHABLE(); }
783 
784 template <typename Matcher>
VisitLogical(InstructionSelector * selector,Node * node,Matcher * m,ArchOpcode opcode,bool left_can_cover,bool right_can_cover,ImmediateMode imm_mode)785 static void VisitLogical(InstructionSelector* selector, Node* node, Matcher* m,
786                          ArchOpcode opcode, bool left_can_cover,
787                          bool right_can_cover, ImmediateMode imm_mode) {
788   Arm64OperandGenerator g(selector);
789 
790   // Map instruction to equivalent operation with inverted right input.
791   ArchOpcode inv_opcode = opcode;
792   switch (opcode) {
793     case kArm64And32:
794       inv_opcode = kArm64Bic32;
795       break;
796     case kArm64And:
797       inv_opcode = kArm64Bic;
798       break;
799     case kArm64Or32:
800       inv_opcode = kArm64Orn32;
801       break;
802     case kArm64Or:
803       inv_opcode = kArm64Orn;
804       break;
805     case kArm64Eor32:
806       inv_opcode = kArm64Eon32;
807       break;
808     case kArm64Eor:
809       inv_opcode = kArm64Eon;
810       break;
811     default:
812       UNREACHABLE();
813   }
814 
815   // Select Logical(y, ~x) for Logical(Xor(x, -1), y).
816   if ((m->left().IsWord32Xor() || m->left().IsWord64Xor()) && left_can_cover) {
817     Matcher mleft(m->left().node());
818     if (mleft.right().Is(-1)) {
819       // TODO(all): support shifted operand on right.
820       selector->Emit(inv_opcode, g.DefineAsRegister(node),
821                      g.UseRegister(m->right().node()),
822                      g.UseRegister(mleft.left().node()));
823       return;
824     }
825   }
826 
827   // Select Logical(x, ~y) for Logical(x, Xor(y, -1)).
828   if ((m->right().IsWord32Xor() || m->right().IsWord64Xor()) &&
829       right_can_cover) {
830     Matcher mright(m->right().node());
831     if (mright.right().Is(-1)) {
832       // TODO(all): support shifted operand on right.
833       selector->Emit(inv_opcode, g.DefineAsRegister(node),
834                      g.UseRegister(m->left().node()),
835                      g.UseRegister(mright.left().node()));
836       return;
837     }
838   }
839 
840   if (m->IsWord32Xor() && m->right().Is(-1)) {
841     selector->Emit(kArm64Not32, g.DefineAsRegister(node),
842                    g.UseRegister(m->left().node()));
843   } else if (m->IsWord64Xor() && m->right().Is(-1)) {
844     selector->Emit(kArm64Not, g.DefineAsRegister(node),
845                    g.UseRegister(m->left().node()));
846   } else {
847     VisitBinop<Matcher>(selector, node, opcode, imm_mode);
848   }
849 }
850 
851 
VisitWord32And(Node * node)852 void InstructionSelector::VisitWord32And(Node* node) {
853   Arm64OperandGenerator g(this);
854   Int32BinopMatcher m(node);
855   if (m.left().IsWord32Shr() && CanCover(node, m.left().node()) &&
856       m.right().HasValue()) {
857     uint32_t mask = m.right().Value();
858     uint32_t mask_width = base::bits::CountPopulation(mask);
859     uint32_t mask_msb = base::bits::CountLeadingZeros32(mask);
860     if ((mask_width != 0) && (mask_width != 32) &&
861         (mask_msb + mask_width == 32)) {
862       // The mask must be contiguous, and occupy the least-significant bits.
863       DCHECK_EQ(0u, base::bits::CountTrailingZeros32(mask));
864 
865       // Select Ubfx for And(Shr(x, imm), mask) where the mask is in the least
866       // significant bits.
867       Int32BinopMatcher mleft(m.left().node());
868       if (mleft.right().HasValue()) {
869         // Any shift value can match; int32 shifts use `value % 32`.
870         uint32_t lsb = mleft.right().Value() & 0x1F;
871 
872         // Ubfx cannot extract bits past the register size, however since
873         // shifting the original value would have introduced some zeros we can
874         // still use ubfx with a smaller mask and the remaining bits will be
875         // zeros.
876         if (lsb + mask_width > 32) mask_width = 32 - lsb;
877 
878         Emit(kArm64Ubfx32, g.DefineAsRegister(node),
879              g.UseRegister(mleft.left().node()),
880              g.UseImmediateOrTemp(mleft.right().node(), lsb),
881              g.TempImmediate(mask_width));
882         return;
883       }
884       // Other cases fall through to the normal And operation.
885     }
886   }
887   VisitLogical<Int32BinopMatcher>(
888       this, node, &m, kArm64And32, CanCover(node, m.left().node()),
889       CanCover(node, m.right().node()), kLogical32Imm);
890 }
891 
892 
VisitWord64And(Node * node)893 void InstructionSelector::VisitWord64And(Node* node) {
894   Arm64OperandGenerator g(this);
895   Int64BinopMatcher m(node);
896   if (m.left().IsWord64Shr() && CanCover(node, m.left().node()) &&
897       m.right().HasValue()) {
898     uint64_t mask = m.right().Value();
899     uint64_t mask_width = base::bits::CountPopulation(mask);
900     uint64_t mask_msb = base::bits::CountLeadingZeros64(mask);
901     if ((mask_width != 0) && (mask_width != 64) &&
902         (mask_msb + mask_width == 64)) {
903       // The mask must be contiguous, and occupy the least-significant bits.
904       DCHECK_EQ(0u, base::bits::CountTrailingZeros64(mask));
905 
906       // Select Ubfx for And(Shr(x, imm), mask) where the mask is in the least
907       // significant bits.
908       Int64BinopMatcher mleft(m.left().node());
909       if (mleft.right().HasValue()) {
910         // Any shift value can match; int64 shifts use `value % 64`.
911         uint32_t lsb = static_cast<uint32_t>(mleft.right().Value() & 0x3F);
912 
913         // Ubfx cannot extract bits past the register size, however since
914         // shifting the original value would have introduced some zeros we can
915         // still use ubfx with a smaller mask and the remaining bits will be
916         // zeros.
917         if (lsb + mask_width > 64) mask_width = 64 - lsb;
918 
919         Emit(kArm64Ubfx, g.DefineAsRegister(node),
920              g.UseRegister(mleft.left().node()),
921              g.UseImmediateOrTemp(mleft.right().node(), lsb),
922              g.TempImmediate(static_cast<int32_t>(mask_width)));
923         return;
924       }
925       // Other cases fall through to the normal And operation.
926     }
927   }
928   VisitLogical<Int64BinopMatcher>(
929       this, node, &m, kArm64And, CanCover(node, m.left().node()),
930       CanCover(node, m.right().node()), kLogical64Imm);
931 }
932 
933 
VisitWord32Or(Node * node)934 void InstructionSelector::VisitWord32Or(Node* node) {
935   Int32BinopMatcher m(node);
936   VisitLogical<Int32BinopMatcher>(
937       this, node, &m, kArm64Or32, CanCover(node, m.left().node()),
938       CanCover(node, m.right().node()), kLogical32Imm);
939 }
940 
941 
VisitWord64Or(Node * node)942 void InstructionSelector::VisitWord64Or(Node* node) {
943   Int64BinopMatcher m(node);
944   VisitLogical<Int64BinopMatcher>(
945       this, node, &m, kArm64Or, CanCover(node, m.left().node()),
946       CanCover(node, m.right().node()), kLogical64Imm);
947 }
948 
949 
VisitWord32Xor(Node * node)950 void InstructionSelector::VisitWord32Xor(Node* node) {
951   Int32BinopMatcher m(node);
952   VisitLogical<Int32BinopMatcher>(
953       this, node, &m, kArm64Eor32, CanCover(node, m.left().node()),
954       CanCover(node, m.right().node()), kLogical32Imm);
955 }
956 
957 
VisitWord64Xor(Node * node)958 void InstructionSelector::VisitWord64Xor(Node* node) {
959   Int64BinopMatcher m(node);
960   VisitLogical<Int64BinopMatcher>(
961       this, node, &m, kArm64Eor, CanCover(node, m.left().node()),
962       CanCover(node, m.right().node()), kLogical64Imm);
963 }
964 
965 
VisitWord32Shl(Node * node)966 void InstructionSelector::VisitWord32Shl(Node* node) {
967   Int32BinopMatcher m(node);
968   if (m.left().IsWord32And() && CanCover(node, m.left().node()) &&
969       m.right().IsInRange(1, 31)) {
970     Arm64OperandGenerator g(this);
971     Int32BinopMatcher mleft(m.left().node());
972     if (mleft.right().HasValue()) {
973       uint32_t mask = mleft.right().Value();
974       uint32_t mask_width = base::bits::CountPopulation(mask);
975       uint32_t mask_msb = base::bits::CountLeadingZeros32(mask);
976       if ((mask_width != 0) && (mask_msb + mask_width == 32)) {
977         uint32_t shift = m.right().Value();
978         DCHECK_EQ(0u, base::bits::CountTrailingZeros32(mask));
979         DCHECK_NE(0u, shift);
980 
981         if ((shift + mask_width) >= 32) {
982           // If the mask is contiguous and reaches or extends beyond the top
983           // bit, only the shift is needed.
984           Emit(kArm64Lsl32, g.DefineAsRegister(node),
985                g.UseRegister(mleft.left().node()),
986                g.UseImmediate(m.right().node()));
987           return;
988         } else {
989           // Select Ubfiz for Shl(And(x, mask), imm) where the mask is
990           // contiguous, and the shift immediate non-zero.
991           Emit(kArm64Ubfiz32, g.DefineAsRegister(node),
992                g.UseRegister(mleft.left().node()),
993                g.UseImmediate(m.right().node()), g.TempImmediate(mask_width));
994           return;
995         }
996       }
997     }
998   }
999   VisitRRO(this, kArm64Lsl32, node, kShift32Imm);
1000 }
1001 
1002 
VisitWord64Shl(Node * node)1003 void InstructionSelector::VisitWord64Shl(Node* node) {
1004   Arm64OperandGenerator g(this);
1005   Int64BinopMatcher m(node);
1006   if ((m.left().IsChangeInt32ToInt64() || m.left().IsChangeUint32ToUint64()) &&
1007       m.right().IsInRange(32, 63) && CanCover(node, m.left().node())) {
1008     // There's no need to sign/zero-extend to 64-bit if we shift out the upper
1009     // 32 bits anyway.
1010     Emit(kArm64Lsl, g.DefineAsRegister(node),
1011          g.UseRegister(m.left().node()->InputAt(0)),
1012          g.UseImmediate(m.right().node()));
1013     return;
1014   }
1015   VisitRRO(this, kArm64Lsl, node, kShift64Imm);
1016 }
1017 
1018 
1019 namespace {
1020 
TryEmitBitfieldExtract32(InstructionSelector * selector,Node * node)1021 bool TryEmitBitfieldExtract32(InstructionSelector* selector, Node* node) {
1022   Arm64OperandGenerator g(selector);
1023   Int32BinopMatcher m(node);
1024   if (selector->CanCover(node, m.left().node()) && m.left().IsWord32Shl()) {
1025     // Select Ubfx or Sbfx for (x << (K & 0x1F)) OP (K & 0x1F), where
1026     // OP is >>> or >> and (K & 0x1F) != 0.
1027     Int32BinopMatcher mleft(m.left().node());
1028     if (mleft.right().HasValue() && m.right().HasValue() &&
1029         (mleft.right().Value() & 0x1F) != 0 &&
1030         (mleft.right().Value() & 0x1F) == (m.right().Value() & 0x1F)) {
1031       DCHECK(m.IsWord32Shr() || m.IsWord32Sar());
1032       ArchOpcode opcode = m.IsWord32Sar() ? kArm64Sbfx32 : kArm64Ubfx32;
1033 
1034       int right_val = m.right().Value() & 0x1F;
1035       DCHECK_NE(right_val, 0);
1036 
1037       selector->Emit(opcode, g.DefineAsRegister(node),
1038                      g.UseRegister(mleft.left().node()), g.TempImmediate(0),
1039                      g.TempImmediate(32 - right_val));
1040       return true;
1041     }
1042   }
1043   return false;
1044 }
1045 
1046 }  // namespace
1047 
1048 
VisitWord32Shr(Node * node)1049 void InstructionSelector::VisitWord32Shr(Node* node) {
1050   Int32BinopMatcher m(node);
1051   if (m.left().IsWord32And() && m.right().HasValue()) {
1052     uint32_t lsb = m.right().Value() & 0x1F;
1053     Int32BinopMatcher mleft(m.left().node());
1054     if (mleft.right().HasValue() && mleft.right().Value() != 0) {
1055       // Select Ubfx for Shr(And(x, mask), imm) where the result of the mask is
1056       // shifted into the least-significant bits.
1057       uint32_t mask = (mleft.right().Value() >> lsb) << lsb;
1058       unsigned mask_width = base::bits::CountPopulation(mask);
1059       unsigned mask_msb = base::bits::CountLeadingZeros32(mask);
1060       if ((mask_msb + mask_width + lsb) == 32) {
1061         Arm64OperandGenerator g(this);
1062         DCHECK_EQ(lsb, base::bits::CountTrailingZeros32(mask));
1063         Emit(kArm64Ubfx32, g.DefineAsRegister(node),
1064              g.UseRegister(mleft.left().node()),
1065              g.UseImmediateOrTemp(m.right().node(), lsb),
1066              g.TempImmediate(mask_width));
1067         return;
1068       }
1069     }
1070   } else if (TryEmitBitfieldExtract32(this, node)) {
1071     return;
1072   }
1073 
1074   if (m.left().IsUint32MulHigh() && m.right().HasValue() &&
1075       CanCover(node, node->InputAt(0))) {
1076     // Combine this shift with the multiply and shift that would be generated
1077     // by Uint32MulHigh.
1078     Arm64OperandGenerator g(this);
1079     Node* left = m.left().node();
1080     int shift = m.right().Value() & 0x1F;
1081     InstructionOperand const smull_operand = g.TempRegister();
1082     Emit(kArm64Umull, smull_operand, g.UseRegister(left->InputAt(0)),
1083          g.UseRegister(left->InputAt(1)));
1084     Emit(kArm64Lsr, g.DefineAsRegister(node), smull_operand,
1085          g.TempImmediate(32 + shift));
1086     return;
1087   }
1088 
1089   VisitRRO(this, kArm64Lsr32, node, kShift32Imm);
1090 }
1091 
1092 
VisitWord64Shr(Node * node)1093 void InstructionSelector::VisitWord64Shr(Node* node) {
1094   Int64BinopMatcher m(node);
1095   if (m.left().IsWord64And() && m.right().HasValue()) {
1096     uint32_t lsb = m.right().Value() & 0x3F;
1097     Int64BinopMatcher mleft(m.left().node());
1098     if (mleft.right().HasValue() && mleft.right().Value() != 0) {
1099       // Select Ubfx for Shr(And(x, mask), imm) where the result of the mask is
1100       // shifted into the least-significant bits.
1101       uint64_t mask = (mleft.right().Value() >> lsb) << lsb;
1102       unsigned mask_width = base::bits::CountPopulation(mask);
1103       unsigned mask_msb = base::bits::CountLeadingZeros64(mask);
1104       if ((mask_msb + mask_width + lsb) == 64) {
1105         Arm64OperandGenerator g(this);
1106         DCHECK_EQ(lsb, base::bits::CountTrailingZeros64(mask));
1107         Emit(kArm64Ubfx, g.DefineAsRegister(node),
1108              g.UseRegister(mleft.left().node()),
1109              g.UseImmediateOrTemp(m.right().node(), lsb),
1110              g.TempImmediate(mask_width));
1111         return;
1112       }
1113     }
1114   }
1115   VisitRRO(this, kArm64Lsr, node, kShift64Imm);
1116 }
1117 
1118 
VisitWord32Sar(Node * node)1119 void InstructionSelector::VisitWord32Sar(Node* node) {
1120   if (TryEmitBitfieldExtract32(this, node)) {
1121     return;
1122   }
1123 
1124   Int32BinopMatcher m(node);
1125   if (m.left().IsInt32MulHigh() && m.right().HasValue() &&
1126       CanCover(node, node->InputAt(0))) {
1127     // Combine this shift with the multiply and shift that would be generated
1128     // by Int32MulHigh.
1129     Arm64OperandGenerator g(this);
1130     Node* left = m.left().node();
1131     int shift = m.right().Value() & 0x1F;
1132     InstructionOperand const smull_operand = g.TempRegister();
1133     Emit(kArm64Smull, smull_operand, g.UseRegister(left->InputAt(0)),
1134          g.UseRegister(left->InputAt(1)));
1135     Emit(kArm64Asr, g.DefineAsRegister(node), smull_operand,
1136          g.TempImmediate(32 + shift));
1137     return;
1138   }
1139 
1140   if (m.left().IsInt32Add() && m.right().HasValue() &&
1141       CanCover(node, node->InputAt(0))) {
1142     Node* add_node = m.left().node();
1143     Int32BinopMatcher madd_node(add_node);
1144     if (madd_node.left().IsInt32MulHigh() &&
1145         CanCover(add_node, madd_node.left().node())) {
1146       // Combine the shift that would be generated by Int32MulHigh with the add
1147       // on the left of this Sar operation. We do it here, as the result of the
1148       // add potentially has 33 bits, so we have to ensure the result is
1149       // truncated by being the input to this 32-bit Sar operation.
1150       Arm64OperandGenerator g(this);
1151       Node* mul_node = madd_node.left().node();
1152 
1153       InstructionOperand const smull_operand = g.TempRegister();
1154       Emit(kArm64Smull, smull_operand, g.UseRegister(mul_node->InputAt(0)),
1155            g.UseRegister(mul_node->InputAt(1)));
1156 
1157       InstructionOperand const add_operand = g.TempRegister();
1158       Emit(kArm64Add | AddressingModeField::encode(kMode_Operand2_R_ASR_I),
1159            add_operand, g.UseRegister(add_node->InputAt(1)), smull_operand,
1160            g.TempImmediate(32));
1161 
1162       Emit(kArm64Asr32, g.DefineAsRegister(node), add_operand,
1163            g.UseImmediate(node->InputAt(1)));
1164       return;
1165     }
1166   }
1167 
1168   VisitRRO(this, kArm64Asr32, node, kShift32Imm);
1169 }
1170 
1171 
VisitWord64Sar(Node * node)1172 void InstructionSelector::VisitWord64Sar(Node* node) {
1173   if (TryEmitExtendingLoad(this, node)) return;
1174   VisitRRO(this, kArm64Asr, node, kShift64Imm);
1175 }
1176 
1177 
VisitWord32Ror(Node * node)1178 void InstructionSelector::VisitWord32Ror(Node* node) {
1179   VisitRRO(this, kArm64Ror32, node, kShift32Imm);
1180 }
1181 
1182 
VisitWord64Ror(Node * node)1183 void InstructionSelector::VisitWord64Ror(Node* node) {
1184   VisitRRO(this, kArm64Ror, node, kShift64Imm);
1185 }
1186 
1187 #define RR_OP_LIST(V)                                         \
1188   V(Word64Clz, kArm64Clz)                                     \
1189   V(Word32Clz, kArm64Clz32)                                   \
1190   V(Word32ReverseBits, kArm64Rbit32)                          \
1191   V(Word64ReverseBits, kArm64Rbit)                            \
1192   V(Word32ReverseBytes, kArm64Rev32)                          \
1193   V(Word64ReverseBytes, kArm64Rev)                            \
1194   V(ChangeFloat32ToFloat64, kArm64Float32ToFloat64)           \
1195   V(RoundInt32ToFloat32, kArm64Int32ToFloat32)                \
1196   V(RoundUint32ToFloat32, kArm64Uint32ToFloat32)              \
1197   V(ChangeInt32ToFloat64, kArm64Int32ToFloat64)               \
1198   V(ChangeUint32ToFloat64, kArm64Uint32ToFloat64)             \
1199   V(TruncateFloat32ToInt32, kArm64Float32ToInt32)             \
1200   V(ChangeFloat64ToInt32, kArm64Float64ToInt32)               \
1201   V(TruncateFloat32ToUint32, kArm64Float32ToUint32)           \
1202   V(ChangeFloat64ToUint32, kArm64Float64ToUint32)             \
1203   V(ChangeFloat64ToUint64, kArm64Float64ToUint64)             \
1204   V(TruncateFloat64ToUint32, kArm64Float64ToUint32)           \
1205   V(TruncateFloat64ToFloat32, kArm64Float64ToFloat32)         \
1206   V(TruncateFloat64ToWord32, kArchTruncateDoubleToI)          \
1207   V(RoundFloat64ToInt32, kArm64Float64ToInt32)                \
1208   V(RoundInt64ToFloat32, kArm64Int64ToFloat32)                \
1209   V(RoundInt64ToFloat64, kArm64Int64ToFloat64)                \
1210   V(RoundUint64ToFloat32, kArm64Uint64ToFloat32)              \
1211   V(RoundUint64ToFloat64, kArm64Uint64ToFloat64)              \
1212   V(BitcastFloat32ToInt32, kArm64Float64ExtractLowWord32)     \
1213   V(BitcastFloat64ToInt64, kArm64U64MoveFloat64)              \
1214   V(BitcastInt32ToFloat32, kArm64Float64MoveU64)              \
1215   V(BitcastInt64ToFloat64, kArm64Float64MoveU64)              \
1216   V(Float32Abs, kArm64Float32Abs)                             \
1217   V(Float64Abs, kArm64Float64Abs)                             \
1218   V(Float32Sqrt, kArm64Float32Sqrt)                           \
1219   V(Float64Sqrt, kArm64Float64Sqrt)                           \
1220   V(Float32RoundDown, kArm64Float32RoundDown)                 \
1221   V(Float64RoundDown, kArm64Float64RoundDown)                 \
1222   V(Float32RoundUp, kArm64Float32RoundUp)                     \
1223   V(Float64RoundUp, kArm64Float64RoundUp)                     \
1224   V(Float32RoundTruncate, kArm64Float32RoundTruncate)         \
1225   V(Float64RoundTruncate, kArm64Float64RoundTruncate)         \
1226   V(Float64RoundTiesAway, kArm64Float64RoundTiesAway)         \
1227   V(Float32RoundTiesEven, kArm64Float32RoundTiesEven)         \
1228   V(Float64RoundTiesEven, kArm64Float64RoundTiesEven)         \
1229   V(Float32Neg, kArm64Float32Neg)                             \
1230   V(Float64Neg, kArm64Float64Neg)                             \
1231   V(Float64ExtractLowWord32, kArm64Float64ExtractLowWord32)   \
1232   V(Float64ExtractHighWord32, kArm64Float64ExtractHighWord32) \
1233   V(Float64SilenceNaN, kArm64Float64SilenceNaN)
1234 
1235 #define RRR_OP_LIST(V)            \
1236   V(Int32Div, kArm64Idiv32)       \
1237   V(Int64Div, kArm64Idiv)         \
1238   V(Uint32Div, kArm64Udiv32)      \
1239   V(Uint64Div, kArm64Udiv)        \
1240   V(Int32Mod, kArm64Imod32)       \
1241   V(Int64Mod, kArm64Imod)         \
1242   V(Uint32Mod, kArm64Umod32)      \
1243   V(Uint64Mod, kArm64Umod)        \
1244   V(Float32Add, kArm64Float32Add) \
1245   V(Float64Add, kArm64Float64Add) \
1246   V(Float32Sub, kArm64Float32Sub) \
1247   V(Float64Sub, kArm64Float64Sub) \
1248   V(Float32Mul, kArm64Float32Mul) \
1249   V(Float64Mul, kArm64Float64Mul) \
1250   V(Float32Div, kArm64Float32Div) \
1251   V(Float64Div, kArm64Float64Div) \
1252   V(Float32Max, kArm64Float32Max) \
1253   V(Float64Max, kArm64Float64Max) \
1254   V(Float32Min, kArm64Float32Min) \
1255   V(Float64Min, kArm64Float64Min)
1256 
1257 #define RR_VISITOR(Name, opcode)                      \
1258   void InstructionSelector::Visit##Name(Node* node) { \
1259     VisitRR(this, opcode, node);                      \
1260   }
1261 RR_OP_LIST(RR_VISITOR)
1262 #undef RR_VISITOR
1263 #undef RR_OP_LIST
1264 
1265 #define RRR_VISITOR(Name, opcode)                     \
1266   void InstructionSelector::Visit##Name(Node* node) { \
1267     VisitRRR(this, opcode, node);                     \
1268   }
RRR_OP_LIST(RRR_VISITOR)1269 RRR_OP_LIST(RRR_VISITOR)
1270 #undef RRR_VISITOR
1271 #undef RRR_OP_LIST
1272 
1273 void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); }
1274 
VisitWord64Ctz(Node * node)1275 void InstructionSelector::VisitWord64Ctz(Node* node) { UNREACHABLE(); }
1276 
VisitWord32Popcnt(Node * node)1277 void InstructionSelector::VisitWord32Popcnt(Node* node) { UNREACHABLE(); }
1278 
VisitWord64Popcnt(Node * node)1279 void InstructionSelector::VisitWord64Popcnt(Node* node) { UNREACHABLE(); }
1280 
VisitSpeculationFence(Node * node)1281 void InstructionSelector::VisitSpeculationFence(Node* node) {
1282   Arm64OperandGenerator g(this);
1283   Emit(kArm64DsbIsb, g.NoOutput());
1284 }
1285 
VisitInt32Add(Node * node)1286 void InstructionSelector::VisitInt32Add(Node* node) {
1287   Arm64OperandGenerator g(this);
1288   Int32BinopMatcher m(node);
1289   // Select Madd(x, y, z) for Add(Mul(x, y), z).
1290   if (m.left().IsInt32Mul() && CanCover(node, m.left().node())) {
1291     Int32BinopMatcher mleft(m.left().node());
1292     // Check multiply can't be later reduced to addition with shift.
1293     if (LeftShiftForReducedMultiply(&mleft) == 0) {
1294       Emit(kArm64Madd32, g.DefineAsRegister(node),
1295            g.UseRegister(mleft.left().node()),
1296            g.UseRegister(mleft.right().node()),
1297            g.UseRegister(m.right().node()));
1298       return;
1299     }
1300   }
1301   // Select Madd(x, y, z) for Add(z, Mul(x, y)).
1302   if (m.right().IsInt32Mul() && CanCover(node, m.right().node())) {
1303     Int32BinopMatcher mright(m.right().node());
1304     // Check multiply can't be later reduced to addition with shift.
1305     if (LeftShiftForReducedMultiply(&mright) == 0) {
1306       Emit(kArm64Madd32, g.DefineAsRegister(node),
1307            g.UseRegister(mright.left().node()),
1308            g.UseRegister(mright.right().node()),
1309            g.UseRegister(m.left().node()));
1310       return;
1311     }
1312   }
1313   VisitAddSub<Int32BinopMatcher>(this, node, kArm64Add32, kArm64Sub32);
1314 }
1315 
1316 
VisitInt64Add(Node * node)1317 void InstructionSelector::VisitInt64Add(Node* node) {
1318   Arm64OperandGenerator g(this);
1319   Int64BinopMatcher m(node);
1320   // Select Madd(x, y, z) for Add(Mul(x, y), z).
1321   if (m.left().IsInt64Mul() && CanCover(node, m.left().node())) {
1322     Int64BinopMatcher mleft(m.left().node());
1323     // Check multiply can't be later reduced to addition with shift.
1324     if (LeftShiftForReducedMultiply(&mleft) == 0) {
1325       Emit(kArm64Madd, g.DefineAsRegister(node),
1326            g.UseRegister(mleft.left().node()),
1327            g.UseRegister(mleft.right().node()),
1328            g.UseRegister(m.right().node()));
1329       return;
1330     }
1331   }
1332   // Select Madd(x, y, z) for Add(z, Mul(x, y)).
1333   if (m.right().IsInt64Mul() && CanCover(node, m.right().node())) {
1334     Int64BinopMatcher mright(m.right().node());
1335     // Check multiply can't be later reduced to addition with shift.
1336     if (LeftShiftForReducedMultiply(&mright) == 0) {
1337       Emit(kArm64Madd, g.DefineAsRegister(node),
1338            g.UseRegister(mright.left().node()),
1339            g.UseRegister(mright.right().node()),
1340            g.UseRegister(m.left().node()));
1341       return;
1342     }
1343   }
1344   VisitAddSub<Int64BinopMatcher>(this, node, kArm64Add, kArm64Sub);
1345 }
1346 
1347 
VisitInt32Sub(Node * node)1348 void InstructionSelector::VisitInt32Sub(Node* node) {
1349   Arm64OperandGenerator g(this);
1350   Int32BinopMatcher m(node);
1351 
1352   // Select Msub(x, y, a) for Sub(a, Mul(x, y)).
1353   if (m.right().IsInt32Mul() && CanCover(node, m.right().node())) {
1354     Int32BinopMatcher mright(m.right().node());
1355     // Check multiply can't be later reduced to addition with shift.
1356     if (LeftShiftForReducedMultiply(&mright) == 0) {
1357       Emit(kArm64Msub32, g.DefineAsRegister(node),
1358            g.UseRegister(mright.left().node()),
1359            g.UseRegister(mright.right().node()),
1360            g.UseRegister(m.left().node()));
1361       return;
1362     }
1363   }
1364 
1365   VisitAddSub<Int32BinopMatcher>(this, node, kArm64Sub32, kArm64Add32);
1366 }
1367 
1368 
VisitInt64Sub(Node * node)1369 void InstructionSelector::VisitInt64Sub(Node* node) {
1370   Arm64OperandGenerator g(this);
1371   Int64BinopMatcher m(node);
1372 
1373   // Select Msub(x, y, a) for Sub(a, Mul(x, y)).
1374   if (m.right().IsInt64Mul() && CanCover(node, m.right().node())) {
1375     Int64BinopMatcher mright(m.right().node());
1376     // Check multiply can't be later reduced to addition with shift.
1377     if (LeftShiftForReducedMultiply(&mright) == 0) {
1378       Emit(kArm64Msub, g.DefineAsRegister(node),
1379            g.UseRegister(mright.left().node()),
1380            g.UseRegister(mright.right().node()),
1381            g.UseRegister(m.left().node()));
1382       return;
1383     }
1384   }
1385 
1386   VisitAddSub<Int64BinopMatcher>(this, node, kArm64Sub, kArm64Add);
1387 }
1388 
1389 namespace {
1390 
EmitInt32MulWithOverflow(InstructionSelector * selector,Node * node,FlagsContinuation * cont)1391 void EmitInt32MulWithOverflow(InstructionSelector* selector, Node* node,
1392                               FlagsContinuation* cont) {
1393   Arm64OperandGenerator g(selector);
1394   Int32BinopMatcher m(node);
1395   InstructionOperand result = g.DefineAsRegister(node);
1396   InstructionOperand left = g.UseRegister(m.left().node());
1397   InstructionOperand right = g.UseRegister(m.right().node());
1398   selector->Emit(kArm64Smull, result, left, right);
1399 
1400   InstructionCode opcode =
1401       kArm64Cmp | AddressingModeField::encode(kMode_Operand2_R_SXTW);
1402   selector->EmitWithContinuation(opcode, result, result, cont);
1403 }
1404 
1405 }  // namespace
1406 
VisitInt32Mul(Node * node)1407 void InstructionSelector::VisitInt32Mul(Node* node) {
1408   Arm64OperandGenerator g(this);
1409   Int32BinopMatcher m(node);
1410 
1411   // First, try to reduce the multiplication to addition with left shift.
1412   // x * (2^k + 1) -> x + (x << k)
1413   int32_t shift = LeftShiftForReducedMultiply(&m);
1414   if (shift > 0) {
1415     Emit(kArm64Add32 | AddressingModeField::encode(kMode_Operand2_R_LSL_I),
1416          g.DefineAsRegister(node), g.UseRegister(m.left().node()),
1417          g.UseRegister(m.left().node()), g.TempImmediate(shift));
1418     return;
1419   }
1420 
1421   if (m.left().IsInt32Sub() && CanCover(node, m.left().node())) {
1422     Int32BinopMatcher mleft(m.left().node());
1423 
1424     // Select Mneg(x, y) for Mul(Sub(0, x), y).
1425     if (mleft.left().Is(0)) {
1426       Emit(kArm64Mneg32, g.DefineAsRegister(node),
1427            g.UseRegister(mleft.right().node()),
1428            g.UseRegister(m.right().node()));
1429       return;
1430     }
1431   }
1432 
1433   if (m.right().IsInt32Sub() && CanCover(node, m.right().node())) {
1434     Int32BinopMatcher mright(m.right().node());
1435 
1436     // Select Mneg(x, y) for Mul(x, Sub(0, y)).
1437     if (mright.left().Is(0)) {
1438       Emit(kArm64Mneg32, g.DefineAsRegister(node),
1439            g.UseRegister(m.left().node()),
1440            g.UseRegister(mright.right().node()));
1441       return;
1442     }
1443   }
1444 
1445   VisitRRR(this, kArm64Mul32, node);
1446 }
1447 
1448 
VisitInt64Mul(Node * node)1449 void InstructionSelector::VisitInt64Mul(Node* node) {
1450   Arm64OperandGenerator g(this);
1451   Int64BinopMatcher m(node);
1452 
1453   // First, try to reduce the multiplication to addition with left shift.
1454   // x * (2^k + 1) -> x + (x << k)
1455   int32_t shift = LeftShiftForReducedMultiply(&m);
1456   if (shift > 0) {
1457     Emit(kArm64Add | AddressingModeField::encode(kMode_Operand2_R_LSL_I),
1458          g.DefineAsRegister(node), g.UseRegister(m.left().node()),
1459          g.UseRegister(m.left().node()), g.TempImmediate(shift));
1460     return;
1461   }
1462 
1463   if (m.left().IsInt64Sub() && CanCover(node, m.left().node())) {
1464     Int64BinopMatcher mleft(m.left().node());
1465 
1466     // Select Mneg(x, y) for Mul(Sub(0, x), y).
1467     if (mleft.left().Is(0)) {
1468       Emit(kArm64Mneg, g.DefineAsRegister(node),
1469            g.UseRegister(mleft.right().node()),
1470            g.UseRegister(m.right().node()));
1471       return;
1472     }
1473   }
1474 
1475   if (m.right().IsInt64Sub() && CanCover(node, m.right().node())) {
1476     Int64BinopMatcher mright(m.right().node());
1477 
1478     // Select Mneg(x, y) for Mul(x, Sub(0, y)).
1479     if (mright.left().Is(0)) {
1480       Emit(kArm64Mneg, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
1481            g.UseRegister(mright.right().node()));
1482       return;
1483     }
1484   }
1485 
1486   VisitRRR(this, kArm64Mul, node);
1487 }
1488 
VisitInt32MulHigh(Node * node)1489 void InstructionSelector::VisitInt32MulHigh(Node* node) {
1490   Arm64OperandGenerator g(this);
1491   InstructionOperand const smull_operand = g.TempRegister();
1492   Emit(kArm64Smull, smull_operand, g.UseRegister(node->InputAt(0)),
1493        g.UseRegister(node->InputAt(1)));
1494   Emit(kArm64Asr, g.DefineAsRegister(node), smull_operand, g.TempImmediate(32));
1495 }
1496 
1497 
VisitUint32MulHigh(Node * node)1498 void InstructionSelector::VisitUint32MulHigh(Node* node) {
1499   Arm64OperandGenerator g(this);
1500   InstructionOperand const smull_operand = g.TempRegister();
1501   Emit(kArm64Umull, smull_operand, g.UseRegister(node->InputAt(0)),
1502        g.UseRegister(node->InputAt(1)));
1503   Emit(kArm64Lsr, g.DefineAsRegister(node), smull_operand, g.TempImmediate(32));
1504 }
1505 
1506 
VisitTryTruncateFloat32ToInt64(Node * node)1507 void InstructionSelector::VisitTryTruncateFloat32ToInt64(Node* node) {
1508   Arm64OperandGenerator g(this);
1509 
1510   InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0))};
1511   InstructionOperand outputs[2];
1512   size_t output_count = 0;
1513   outputs[output_count++] = g.DefineAsRegister(node);
1514 
1515   Node* success_output = NodeProperties::FindProjection(node, 1);
1516   if (success_output) {
1517     outputs[output_count++] = g.DefineAsRegister(success_output);
1518   }
1519 
1520   Emit(kArm64Float32ToInt64, output_count, outputs, 1, inputs);
1521 }
1522 
1523 
VisitTryTruncateFloat64ToInt64(Node * node)1524 void InstructionSelector::VisitTryTruncateFloat64ToInt64(Node* node) {
1525   Arm64OperandGenerator g(this);
1526 
1527   InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0))};
1528   InstructionOperand outputs[2];
1529   size_t output_count = 0;
1530   outputs[output_count++] = g.DefineAsRegister(node);
1531 
1532   Node* success_output = NodeProperties::FindProjection(node, 1);
1533   if (success_output) {
1534     outputs[output_count++] = g.DefineAsRegister(success_output);
1535   }
1536 
1537   Emit(kArm64Float64ToInt64, output_count, outputs, 1, inputs);
1538 }
1539 
1540 
VisitTryTruncateFloat32ToUint64(Node * node)1541 void InstructionSelector::VisitTryTruncateFloat32ToUint64(Node* node) {
1542   Arm64OperandGenerator g(this);
1543 
1544   InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0))};
1545   InstructionOperand outputs[2];
1546   size_t output_count = 0;
1547   outputs[output_count++] = g.DefineAsRegister(node);
1548 
1549   Node* success_output = NodeProperties::FindProjection(node, 1);
1550   if (success_output) {
1551     outputs[output_count++] = g.DefineAsRegister(success_output);
1552   }
1553 
1554   Emit(kArm64Float32ToUint64, output_count, outputs, 1, inputs);
1555 }
1556 
1557 
VisitTryTruncateFloat64ToUint64(Node * node)1558 void InstructionSelector::VisitTryTruncateFloat64ToUint64(Node* node) {
1559   Arm64OperandGenerator g(this);
1560 
1561   InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0))};
1562   InstructionOperand outputs[2];
1563   size_t output_count = 0;
1564   outputs[output_count++] = g.DefineAsRegister(node);
1565 
1566   Node* success_output = NodeProperties::FindProjection(node, 1);
1567   if (success_output) {
1568     outputs[output_count++] = g.DefineAsRegister(success_output);
1569   }
1570 
1571   Emit(kArm64Float64ToUint64, output_count, outputs, 1, inputs);
1572 }
1573 
1574 
VisitChangeInt32ToInt64(Node * node)1575 void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
1576   Node* value = node->InputAt(0);
1577   if (value->opcode() == IrOpcode::kLoad && CanCover(node, value)) {
1578     // Generate sign-extending load.
1579     LoadRepresentation load_rep = LoadRepresentationOf(value->op());
1580     MachineRepresentation rep = load_rep.representation();
1581     InstructionCode opcode = kArchNop;
1582     ImmediateMode immediate_mode = kNoImmediate;
1583     switch (rep) {
1584       case MachineRepresentation::kBit:  // Fall through.
1585       case MachineRepresentation::kWord8:
1586         opcode = load_rep.IsSigned() ? kArm64Ldrsb : kArm64Ldrb;
1587         immediate_mode = kLoadStoreImm8;
1588         break;
1589       case MachineRepresentation::kWord16:
1590         opcode = load_rep.IsSigned() ? kArm64Ldrsh : kArm64Ldrh;
1591         immediate_mode = kLoadStoreImm16;
1592         break;
1593       case MachineRepresentation::kWord32:
1594         opcode = kArm64Ldrsw;
1595         immediate_mode = kLoadStoreImm32;
1596         break;
1597       default:
1598         UNREACHABLE();
1599         return;
1600     }
1601     EmitLoad(this, value, opcode, immediate_mode, rep, node);
1602   } else {
1603     VisitRR(this, kArm64Sxtw, node);
1604   }
1605 }
1606 
1607 
VisitChangeUint32ToUint64(Node * node)1608 void InstructionSelector::VisitChangeUint32ToUint64(Node* node) {
1609   Arm64OperandGenerator g(this);
1610   Node* value = node->InputAt(0);
1611   switch (value->opcode()) {
1612     case IrOpcode::kWord32And:
1613     case IrOpcode::kWord32Or:
1614     case IrOpcode::kWord32Xor:
1615     case IrOpcode::kWord32Shl:
1616     case IrOpcode::kWord32Shr:
1617     case IrOpcode::kWord32Sar:
1618     case IrOpcode::kWord32Ror:
1619     case IrOpcode::kWord32Equal:
1620     case IrOpcode::kInt32Add:
1621     case IrOpcode::kInt32AddWithOverflow:
1622     case IrOpcode::kInt32Sub:
1623     case IrOpcode::kInt32SubWithOverflow:
1624     case IrOpcode::kInt32Mul:
1625     case IrOpcode::kInt32MulHigh:
1626     case IrOpcode::kInt32Div:
1627     case IrOpcode::kInt32Mod:
1628     case IrOpcode::kInt32LessThan:
1629     case IrOpcode::kInt32LessThanOrEqual:
1630     case IrOpcode::kUint32Div:
1631     case IrOpcode::kUint32LessThan:
1632     case IrOpcode::kUint32LessThanOrEqual:
1633     case IrOpcode::kUint32Mod:
1634     case IrOpcode::kUint32MulHigh: {
1635       // 32-bit operations will write their result in a W register (implicitly
1636       // clearing the top 32-bit of the corresponding X register) so the
1637       // zero-extension is a no-op.
1638       Emit(kArchNop, g.DefineSameAsFirst(node), g.Use(value));
1639       return;
1640     }
1641     case IrOpcode::kLoad: {
1642       // As for the operations above, a 32-bit load will implicitly clear the
1643       // top 32 bits of the destination register.
1644       LoadRepresentation load_rep = LoadRepresentationOf(value->op());
1645       switch (load_rep.representation()) {
1646         case MachineRepresentation::kWord8:
1647         case MachineRepresentation::kWord16:
1648         case MachineRepresentation::kWord32:
1649           Emit(kArchNop, g.DefineSameAsFirst(node), g.Use(value));
1650           return;
1651         default:
1652           break;
1653       }
1654       break;
1655     }
1656     default:
1657       break;
1658   }
1659   Emit(kArm64Mov32, g.DefineAsRegister(node), g.UseRegister(value));
1660 }
1661 
VisitTruncateInt64ToInt32(Node * node)1662 void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) {
1663   Arm64OperandGenerator g(this);
1664   Node* value = node->InputAt(0);
1665   // The top 32 bits in the 64-bit register will be undefined, and
1666   // must not be used by a dependent node.
1667   Emit(kArchNop, g.DefineSameAsFirst(node), g.UseRegister(value));
1668 }
1669 
VisitFloat64Mod(Node * node)1670 void InstructionSelector::VisitFloat64Mod(Node* node) {
1671   Arm64OperandGenerator g(this);
1672   Emit(kArm64Float64Mod, g.DefineAsFixed(node, d0),
1673        g.UseFixed(node->InputAt(0), d0),
1674        g.UseFixed(node->InputAt(1), d1))->MarkAsCall();
1675 }
1676 
VisitFloat64Ieee754Binop(Node * node,InstructionCode opcode)1677 void InstructionSelector::VisitFloat64Ieee754Binop(Node* node,
1678                                                    InstructionCode opcode) {
1679   Arm64OperandGenerator g(this);
1680   Emit(opcode, g.DefineAsFixed(node, d0), g.UseFixed(node->InputAt(0), d0),
1681        g.UseFixed(node->InputAt(1), d1))
1682       ->MarkAsCall();
1683 }
1684 
VisitFloat64Ieee754Unop(Node * node,InstructionCode opcode)1685 void InstructionSelector::VisitFloat64Ieee754Unop(Node* node,
1686                                                   InstructionCode opcode) {
1687   Arm64OperandGenerator g(this);
1688   Emit(opcode, g.DefineAsFixed(node, d0), g.UseFixed(node->InputAt(0), d0))
1689       ->MarkAsCall();
1690 }
1691 
EmitPrepareArguments(ZoneVector<PushParameter> * arguments,const CallDescriptor * call_descriptor,Node * node)1692 void InstructionSelector::EmitPrepareArguments(
1693     ZoneVector<PushParameter>* arguments, const CallDescriptor* call_descriptor,
1694     Node* node) {
1695   Arm64OperandGenerator g(this);
1696 
1697   // `arguments` includes alignment "holes". This means that slots bigger than
1698   // kPointerSize, e.g. Simd128, will span across multiple arguments.
1699   int claim_count = static_cast<int>(arguments->size());
1700   int slot = claim_count - 1;
1701   claim_count = RoundUp(claim_count, 2);
1702   // Bump the stack pointer(s).
1703   if (claim_count > 0) {
1704     // TODO(titzer): claim and poke probably take small immediates.
1705     // TODO(titzer): it would be better to bump the sp here only
1706     //               and emit paired stores with increment for non c frames.
1707     Emit(kArm64Claim, g.NoOutput(), g.TempImmediate(claim_count));
1708   }
1709 
1710   if (claim_count > 0) {
1711     // Store padding, which might be overwritten.
1712     Emit(kArm64Poke, g.NoOutput(), g.UseImmediate(0),
1713          g.TempImmediate(claim_count - 1));
1714   }
1715 
1716   // Poke the arguments into the stack.
1717   while (slot >= 0) {
1718     Node* input_node = (*arguments)[slot].node;
1719     // Skip any alignment holes in pushed nodes.
1720     if (input_node != nullptr) {
1721       Emit(kArm64Poke, g.NoOutput(), g.UseRegister(input_node),
1722            g.TempImmediate(slot));
1723     }
1724     slot--;
1725     // TODO(ahaas): Poke arguments in pairs if two subsequent arguments have the
1726     //              same type.
1727     // Emit(kArm64PokePair, g.NoOutput(), g.UseRegister((*arguments)[slot]),
1728     //      g.UseRegister((*arguments)[slot - 1]), g.TempImmediate(slot));
1729     // slot -= 2;
1730   }
1731 }
1732 
EmitPrepareResults(ZoneVector<PushParameter> * results,const CallDescriptor * call_descriptor,Node * node)1733 void InstructionSelector::EmitPrepareResults(
1734     ZoneVector<PushParameter>* results, const CallDescriptor* call_descriptor,
1735     Node* node) {
1736   Arm64OperandGenerator g(this);
1737 
1738   int reverse_slot = 0;
1739   for (PushParameter output : *results) {
1740     if (!output.location.IsCallerFrameSlot()) continue;
1741     reverse_slot += output.location.GetSizeInPointers();
1742     // Skip any alignment holes in nodes.
1743     if (output.node == nullptr) continue;
1744     DCHECK(!call_descriptor->IsCFunctionCall());
1745 
1746     if (output.location.GetType() == MachineType::Float32()) {
1747       MarkAsFloat32(output.node);
1748     } else if (output.location.GetType() == MachineType::Float64()) {
1749       MarkAsFloat64(output.node);
1750     }
1751 
1752     Emit(kArm64Peek, g.DefineAsRegister(output.node),
1753          g.UseImmediate(reverse_slot));
1754   }
1755 }
1756 
IsTailCallAddressImmediate()1757 bool InstructionSelector::IsTailCallAddressImmediate() { return false; }
1758 
GetTempsCountForTailCallFromJSFunction()1759 int InstructionSelector::GetTempsCountForTailCallFromJSFunction() { return 3; }
1760 
1761 namespace {
1762 
1763 // Shared routine for multiple compare operations.
VisitCompare(InstructionSelector * selector,InstructionCode opcode,InstructionOperand left,InstructionOperand right,FlagsContinuation * cont)1764 void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
1765                   InstructionOperand left, InstructionOperand right,
1766                   FlagsContinuation* cont) {
1767   selector->EmitWithContinuation(opcode, left, right, cont);
1768 }
1769 
1770 
1771 // Shared routine for multiple word compare operations.
VisitWordCompare(InstructionSelector * selector,Node * node,InstructionCode opcode,FlagsContinuation * cont,bool commutative,ImmediateMode immediate_mode)1772 void VisitWordCompare(InstructionSelector* selector, Node* node,
1773                       InstructionCode opcode, FlagsContinuation* cont,
1774                       bool commutative, ImmediateMode immediate_mode) {
1775   Arm64OperandGenerator g(selector);
1776   Node* left = node->InputAt(0);
1777   Node* right = node->InputAt(1);
1778 
1779   if (right->opcode() == IrOpcode::kLoadStackPointer ||
1780       g.CanBeImmediate(left, immediate_mode)) {
1781     if (!commutative) cont->Commute();
1782     std::swap(left, right);
1783   }
1784 
1785   // Match immediates on left or right side of comparison.
1786   if (g.CanBeImmediate(right, immediate_mode)) {
1787     VisitCompare(selector, opcode,
1788                  g.UseRegisterOrStackPointer(left, opcode == kArm64Cmp),
1789                  g.UseImmediate(right), cont);
1790   } else {
1791     VisitCompare(selector, opcode,
1792                  g.UseRegisterOrStackPointer(left, opcode == kArm64Cmp),
1793                  g.UseRegister(right), cont);
1794   }
1795 }
1796 
1797 // This function checks whether we can convert:
1798 // ((a <op> b) cmp 0), b.<cond>
1799 // to:
1800 // (a <ops> b), b.<cond'>
1801 // where <ops> is the flag setting version of <op>.
1802 // We only generate conditions <cond'> that are a combination of the N
1803 // and Z flags. This avoids the need to make this function dependent on
1804 // the flag-setting operation.
CanUseFlagSettingBinop(FlagsCondition cond)1805 bool CanUseFlagSettingBinop(FlagsCondition cond) {
1806   switch (cond) {
1807     case kEqual:
1808     case kNotEqual:
1809     case kSignedLessThan:
1810     case kSignedGreaterThanOrEqual:
1811     case kUnsignedLessThanOrEqual:  // x <= 0 -> x == 0
1812     case kUnsignedGreaterThan:      // x > 0 -> x != 0
1813       return true;
1814     default:
1815       return false;
1816   }
1817 }
1818 
1819 // Map <cond> to <cond'> so that the following transformation is possible:
1820 // ((a <op> b) cmp 0), b.<cond>
1821 // to:
1822 // (a <ops> b), b.<cond'>
1823 // where <ops> is the flag setting version of <op>.
MapForFlagSettingBinop(FlagsCondition cond)1824 FlagsCondition MapForFlagSettingBinop(FlagsCondition cond) {
1825   DCHECK(CanUseFlagSettingBinop(cond));
1826   switch (cond) {
1827     case kEqual:
1828     case kNotEqual:
1829       return cond;
1830     case kSignedLessThan:
1831       return kNegative;
1832     case kSignedGreaterThanOrEqual:
1833       return kPositiveOrZero;
1834     case kUnsignedLessThanOrEqual:  // x <= 0 -> x == 0
1835       return kEqual;
1836     case kUnsignedGreaterThan:  // x > 0 -> x != 0
1837       return kNotEqual;
1838     default:
1839       UNREACHABLE();
1840   }
1841 }
1842 
1843 // This function checks if we can perform the transformation:
1844 // ((a <op> b) cmp 0), b.<cond>
1845 // to:
1846 // (a <ops> b), b.<cond'>
1847 // where <ops> is the flag setting version of <op>, and if so,
1848 // updates {node}, {opcode} and {cont} accordingly.
MaybeReplaceCmpZeroWithFlagSettingBinop(InstructionSelector * selector,Node ** node,Node * binop,ArchOpcode * opcode,FlagsCondition cond,FlagsContinuation * cont,ImmediateMode * immediate_mode)1849 void MaybeReplaceCmpZeroWithFlagSettingBinop(InstructionSelector* selector,
1850                                              Node** node, Node* binop,
1851                                              ArchOpcode* opcode,
1852                                              FlagsCondition cond,
1853                                              FlagsContinuation* cont,
1854                                              ImmediateMode* immediate_mode) {
1855   ArchOpcode binop_opcode;
1856   ArchOpcode no_output_opcode;
1857   ImmediateMode binop_immediate_mode;
1858   switch (binop->opcode()) {
1859     case IrOpcode::kInt32Add:
1860       binop_opcode = kArm64Add32;
1861       no_output_opcode = kArm64Cmn32;
1862       binop_immediate_mode = kArithmeticImm;
1863       break;
1864     case IrOpcode::kWord32And:
1865       binop_opcode = kArm64And32;
1866       no_output_opcode = kArm64Tst32;
1867       binop_immediate_mode = kLogical32Imm;
1868       break;
1869     default:
1870       UNREACHABLE();
1871       return;
1872   }
1873   if (selector->CanCover(*node, binop)) {
1874     // The comparison is the only user of the add or and, so we can generate
1875     // a cmn or tst instead.
1876     cont->Overwrite(MapForFlagSettingBinop(cond));
1877     *opcode = no_output_opcode;
1878     *node = binop;
1879     *immediate_mode = binop_immediate_mode;
1880   } else if (selector->IsOnlyUserOfNodeInSameBlock(*node, binop)) {
1881     // We can also handle the case where the add and the compare are in the
1882     // same basic block, and the compare is the only use of add in this basic
1883     // block (the add has users in other basic blocks).
1884     cont->Overwrite(MapForFlagSettingBinop(cond));
1885     *opcode = binop_opcode;
1886     *node = binop;
1887     *immediate_mode = binop_immediate_mode;
1888   }
1889 }
1890 
1891 // Map {cond} to kEqual or kNotEqual, so that we can select
1892 // either TBZ or TBNZ when generating code for:
1893 // (x cmp 0), b.{cond}
MapForTbz(FlagsCondition cond)1894 FlagsCondition MapForTbz(FlagsCondition cond) {
1895   switch (cond) {
1896     case kSignedLessThan:  // generate TBNZ
1897       return kNotEqual;
1898     case kSignedGreaterThanOrEqual:  // generate TBZ
1899       return kEqual;
1900     default:
1901       UNREACHABLE();
1902   }
1903 }
1904 
1905 // Map {cond} to kEqual or kNotEqual, so that we can select
1906 // either CBZ or CBNZ when generating code for:
1907 // (x cmp 0), b.{cond}
MapForCbz(FlagsCondition cond)1908 FlagsCondition MapForCbz(FlagsCondition cond) {
1909   switch (cond) {
1910     case kEqual:     // generate CBZ
1911     case kNotEqual:  // generate CBNZ
1912       return cond;
1913     case kUnsignedLessThanOrEqual:  // generate CBZ
1914       return kEqual;
1915     case kUnsignedGreaterThan:  // generate CBNZ
1916       return kNotEqual;
1917     default:
1918       UNREACHABLE();
1919   }
1920 }
1921 
EmitBranchOrDeoptimize(InstructionSelector * selector,InstructionCode opcode,InstructionOperand value,FlagsContinuation * cont)1922 void EmitBranchOrDeoptimize(InstructionSelector* selector,
1923                             InstructionCode opcode, InstructionOperand value,
1924                             FlagsContinuation* cont) {
1925   DCHECK(cont->IsBranch() || cont->IsDeoptimize());
1926   selector->EmitWithContinuation(opcode, value, cont);
1927 }
1928 
1929 // Try to emit TBZ, TBNZ, CBZ or CBNZ for certain comparisons of {node}
1930 // against {value}, depending on the condition.
TryEmitCbzOrTbz(InstructionSelector * selector,Node * node,uint32_t value,Node * user,FlagsCondition cond,FlagsContinuation * cont)1931 bool TryEmitCbzOrTbz(InstructionSelector* selector, Node* node, uint32_t value,
1932                      Node* user, FlagsCondition cond, FlagsContinuation* cont) {
1933   // Branch poisoning requires flags to be set, so when it's enabled for
1934   // a particular branch, we shouldn't be applying the cbz/tbz optimization.
1935   DCHECK(!cont->IsPoisoned());
1936   // Only handle branches and deoptimisations.
1937   if (!cont->IsBranch() && !cont->IsDeoptimize()) return false;
1938 
1939   switch (cond) {
1940     case kSignedLessThan:
1941     case kSignedGreaterThanOrEqual: {
1942       // Here we handle sign tests, aka. comparisons with zero.
1943       if (value != 0) return false;
1944       // We don't generate TBZ/TBNZ for deoptimisations, as they have a
1945       // shorter range than conditional branches and generating them for
1946       // deoptimisations results in more veneers.
1947       if (cont->IsDeoptimize()) return false;
1948       Arm64OperandGenerator g(selector);
1949       cont->Overwrite(MapForTbz(cond));
1950       Int32Matcher m(node);
1951       if (m.IsFloat64ExtractHighWord32() && selector->CanCover(user, node)) {
1952         // SignedLessThan(Float64ExtractHighWord32(x), 0) and
1953         // SignedGreaterThanOrEqual(Float64ExtractHighWord32(x), 0) essentially
1954         // check the sign bit of a 64-bit floating point value.
1955         InstructionOperand temp = g.TempRegister();
1956         selector->Emit(kArm64U64MoveFloat64, temp,
1957                        g.UseRegister(node->InputAt(0)));
1958         selector->EmitWithContinuation(kArm64TestAndBranch, temp,
1959                                        g.TempImmediate(63), cont);
1960         return true;
1961       }
1962       selector->EmitWithContinuation(kArm64TestAndBranch32, g.UseRegister(node),
1963                                      g.TempImmediate(31), cont);
1964       return true;
1965     }
1966     case kEqual:
1967     case kNotEqual: {
1968       if (node->opcode() == IrOpcode::kWord32And) {
1969         // Emit a tbz/tbnz if we are comparing with a single-bit mask:
1970         //   Branch(Word32Equal(Word32And(x, 1 << N), 1 << N), true, false)
1971         Int32BinopMatcher m_and(node);
1972         if (cont->IsBranch() && base::bits::IsPowerOfTwo(value) &&
1973             m_and.right().Is(value) && selector->CanCover(user, node)) {
1974           Arm64OperandGenerator g(selector);
1975           // In the code generator, Equal refers to a bit being cleared. We want
1976           // the opposite here so negate the condition.
1977           cont->Negate();
1978           selector->EmitWithContinuation(
1979               kArm64TestAndBranch32, g.UseRegister(m_and.left().node()),
1980               g.TempImmediate(base::bits::CountTrailingZeros(value)), cont);
1981           return true;
1982         }
1983       }
1984       V8_FALLTHROUGH;
1985     }
1986     case kUnsignedLessThanOrEqual:
1987     case kUnsignedGreaterThan: {
1988       if (value != 0) return false;
1989       Arm64OperandGenerator g(selector);
1990       cont->Overwrite(MapForCbz(cond));
1991       EmitBranchOrDeoptimize(selector, kArm64CompareAndBranch32,
1992                              g.UseRegister(node), cont);
1993       return true;
1994     }
1995     default:
1996       return false;
1997   }
1998 }
1999 
VisitWord32Compare(InstructionSelector * selector,Node * node,FlagsContinuation * cont)2000 void VisitWord32Compare(InstructionSelector* selector, Node* node,
2001                         FlagsContinuation* cont) {
2002   Int32BinopMatcher m(node);
2003   FlagsCondition cond = cont->condition();
2004   if (!cont->IsPoisoned()) {
2005     if (m.right().HasValue()) {
2006       if (TryEmitCbzOrTbz(selector, m.left().node(), m.right().Value(), node,
2007                           cond, cont)) {
2008         return;
2009       }
2010     } else if (m.left().HasValue()) {
2011       FlagsCondition commuted_cond = CommuteFlagsCondition(cond);
2012       if (TryEmitCbzOrTbz(selector, m.right().node(), m.left().Value(), node,
2013                           commuted_cond, cont)) {
2014         return;
2015       }
2016     }
2017   }
2018   ArchOpcode opcode = kArm64Cmp32;
2019   ImmediateMode immediate_mode = kArithmeticImm;
2020   if (m.right().Is(0) && (m.left().IsInt32Add() || m.left().IsWord32And())) {
2021     // Emit flag setting add/and instructions for comparisons against zero.
2022     if (CanUseFlagSettingBinop(cond)) {
2023       Node* binop = m.left().node();
2024       MaybeReplaceCmpZeroWithFlagSettingBinop(selector, &node, binop, &opcode,
2025                                               cond, cont, &immediate_mode);
2026     }
2027   } else if (m.left().Is(0) &&
2028              (m.right().IsInt32Add() || m.right().IsWord32And())) {
2029     // Same as above, but we need to commute the condition before we
2030     // continue with the rest of the checks.
2031     FlagsCondition commuted_cond = CommuteFlagsCondition(cond);
2032     if (CanUseFlagSettingBinop(commuted_cond)) {
2033       Node* binop = m.right().node();
2034       MaybeReplaceCmpZeroWithFlagSettingBinop(selector, &node, binop, &opcode,
2035                                               commuted_cond, cont,
2036                                               &immediate_mode);
2037     }
2038   } else if (m.right().IsInt32Sub() && (cond == kEqual || cond == kNotEqual)) {
2039     // Select negated compare for comparisons with negated right input.
2040     // Only do this for kEqual and kNotEqual, which do not depend on the
2041     // C and V flags, as those flags will be different with CMN when the
2042     // right-hand side of the original subtraction is INT_MIN.
2043     Node* sub = m.right().node();
2044     Int32BinopMatcher msub(sub);
2045     if (msub.left().Is(0)) {
2046       bool can_cover = selector->CanCover(node, sub);
2047       node->ReplaceInput(1, msub.right().node());
2048       // Even if the comparison node covers the subtraction, after the input
2049       // replacement above, the node still won't cover the input to the
2050       // subtraction; the subtraction still uses it.
2051       // In order to get shifted operations to work, we must remove the rhs
2052       // input to the subtraction, as TryMatchAnyShift requires this node to
2053       // cover the input shift. We do this by setting it to the lhs input,
2054       // as we know it's zero, and the result of the subtraction isn't used by
2055       // any other node.
2056       if (can_cover) sub->ReplaceInput(1, msub.left().node());
2057       opcode = kArm64Cmn32;
2058     }
2059   }
2060   VisitBinop<Int32BinopMatcher>(selector, node, opcode, immediate_mode, cont);
2061 }
2062 
2063 
VisitWordTest(InstructionSelector * selector,Node * node,InstructionCode opcode,FlagsContinuation * cont)2064 void VisitWordTest(InstructionSelector* selector, Node* node,
2065                    InstructionCode opcode, FlagsContinuation* cont) {
2066   Arm64OperandGenerator g(selector);
2067   VisitCompare(selector, opcode, g.UseRegister(node), g.UseRegister(node),
2068                cont);
2069 }
2070 
2071 
VisitWord32Test(InstructionSelector * selector,Node * node,FlagsContinuation * cont)2072 void VisitWord32Test(InstructionSelector* selector, Node* node,
2073                      FlagsContinuation* cont) {
2074   VisitWordTest(selector, node, kArm64Tst32, cont);
2075 }
2076 
2077 
VisitWord64Test(InstructionSelector * selector,Node * node,FlagsContinuation * cont)2078 void VisitWord64Test(InstructionSelector* selector, Node* node,
2079                      FlagsContinuation* cont) {
2080   VisitWordTest(selector, node, kArm64Tst, cont);
2081 }
2082 
2083 template <typename Matcher>
2084 struct TestAndBranchMatcher {
TestAndBranchMatcherv8::internal::compiler::__anon47426b030411::TestAndBranchMatcher2085   TestAndBranchMatcher(Node* node, FlagsContinuation* cont)
2086       : matches_(false), cont_(cont), matcher_(node) {
2087     Initialize();
2088   }
Matchesv8::internal::compiler::__anon47426b030411::TestAndBranchMatcher2089   bool Matches() const { return matches_; }
2090 
bitv8::internal::compiler::__anon47426b030411::TestAndBranchMatcher2091   unsigned bit() const {
2092     DCHECK(Matches());
2093     return base::bits::CountTrailingZeros(matcher_.right().Value());
2094   }
2095 
inputv8::internal::compiler::__anon47426b030411::TestAndBranchMatcher2096   Node* input() const {
2097     DCHECK(Matches());
2098     return matcher_.left().node();
2099   }
2100 
2101  private:
2102   bool matches_;
2103   FlagsContinuation* cont_;
2104   Matcher matcher_;
2105 
Initializev8::internal::compiler::__anon47426b030411::TestAndBranchMatcher2106   void Initialize() {
2107     if (cont_->IsBranch() && !cont_->IsPoisoned() &&
2108         matcher_.right().HasValue() &&
2109         base::bits::IsPowerOfTwo(matcher_.right().Value())) {
2110       // If the mask has only one bit set, we can use tbz/tbnz.
2111       DCHECK((cont_->condition() == kEqual) ||
2112              (cont_->condition() == kNotEqual));
2113       matches_ = true;
2114     } else {
2115       matches_ = false;
2116     }
2117   }
2118 };
2119 
2120 // Shared routine for multiple float32 compare operations.
VisitFloat32Compare(InstructionSelector * selector,Node * node,FlagsContinuation * cont)2121 void VisitFloat32Compare(InstructionSelector* selector, Node* node,
2122                          FlagsContinuation* cont) {
2123   Arm64OperandGenerator g(selector);
2124   Float32BinopMatcher m(node);
2125   if (m.right().Is(0.0f)) {
2126     VisitCompare(selector, kArm64Float32Cmp, g.UseRegister(m.left().node()),
2127                  g.UseImmediate(m.right().node()), cont);
2128   } else if (m.left().Is(0.0f)) {
2129     cont->Commute();
2130     VisitCompare(selector, kArm64Float32Cmp, g.UseRegister(m.right().node()),
2131                  g.UseImmediate(m.left().node()), cont);
2132   } else {
2133     VisitCompare(selector, kArm64Float32Cmp, g.UseRegister(m.left().node()),
2134                  g.UseRegister(m.right().node()), cont);
2135   }
2136 }
2137 
2138 
2139 // Shared routine for multiple float64 compare operations.
VisitFloat64Compare(InstructionSelector * selector,Node * node,FlagsContinuation * cont)2140 void VisitFloat64Compare(InstructionSelector* selector, Node* node,
2141                          FlagsContinuation* cont) {
2142   Arm64OperandGenerator g(selector);
2143   Float64BinopMatcher m(node);
2144   if (m.right().Is(0.0)) {
2145     VisitCompare(selector, kArm64Float64Cmp, g.UseRegister(m.left().node()),
2146                  g.UseImmediate(m.right().node()), cont);
2147   } else if (m.left().Is(0.0)) {
2148     cont->Commute();
2149     VisitCompare(selector, kArm64Float64Cmp, g.UseRegister(m.right().node()),
2150                  g.UseImmediate(m.left().node()), cont);
2151   } else {
2152     VisitCompare(selector, kArm64Float64Cmp, g.UseRegister(m.left().node()),
2153                  g.UseRegister(m.right().node()), cont);
2154   }
2155 }
2156 
VisitAtomicExchange(InstructionSelector * selector,Node * node,ArchOpcode opcode)2157 void VisitAtomicExchange(InstructionSelector* selector, Node* node,
2158                          ArchOpcode opcode) {
2159   Arm64OperandGenerator g(selector);
2160   Node* base = node->InputAt(0);
2161   Node* index = node->InputAt(1);
2162   Node* value = node->InputAt(2);
2163   InstructionOperand inputs[] = {g.UseRegister(base), g.UseRegister(index),
2164                                  g.UseUniqueRegister(value)};
2165   InstructionOperand outputs[] = {g.DefineAsRegister(node)};
2166   InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
2167   InstructionCode code = opcode | AddressingModeField::encode(kMode_MRR);
2168   selector->Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
2169                  arraysize(temps), temps);
2170 }
2171 
VisitAtomicCompareExchange(InstructionSelector * selector,Node * node,ArchOpcode opcode)2172 void VisitAtomicCompareExchange(InstructionSelector* selector, Node* node,
2173                                 ArchOpcode opcode) {
2174   Arm64OperandGenerator g(selector);
2175   Node* base = node->InputAt(0);
2176   Node* index = node->InputAt(1);
2177   Node* old_value = node->InputAt(2);
2178   Node* new_value = node->InputAt(3);
2179   InstructionOperand inputs[] = {g.UseRegister(base), g.UseRegister(index),
2180                                  g.UseUniqueRegister(old_value),
2181                                  g.UseUniqueRegister(new_value)};
2182   InstructionOperand outputs[] = {g.DefineAsRegister(node)};
2183   InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
2184   InstructionCode code = opcode | AddressingModeField::encode(kMode_MRR);
2185   selector->Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
2186                  arraysize(temps), temps);
2187 }
2188 
VisitAtomicLoad(InstructionSelector * selector,Node * node,ArchOpcode opcode)2189 void VisitAtomicLoad(InstructionSelector* selector, Node* node,
2190                      ArchOpcode opcode) {
2191   Arm64OperandGenerator g(selector);
2192   Node* base = node->InputAt(0);
2193   Node* index = node->InputAt(1);
2194   InstructionOperand inputs[] = {g.UseRegister(base), g.UseRegister(index)};
2195   InstructionOperand outputs[] = {g.DefineAsRegister(node)};
2196   InstructionOperand temps[] = {g.TempRegister()};
2197   InstructionCode code = opcode | AddressingModeField::encode(kMode_MRR);
2198   selector->Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
2199                  arraysize(temps), temps);
2200 }
2201 
VisitAtomicStore(InstructionSelector * selector,Node * node,ArchOpcode opcode)2202 void VisitAtomicStore(InstructionSelector* selector, Node* node,
2203                       ArchOpcode opcode) {
2204   Arm64OperandGenerator g(selector);
2205   Node* base = node->InputAt(0);
2206   Node* index = node->InputAt(1);
2207   Node* value = node->InputAt(2);
2208   InstructionOperand inputs[] = {g.UseRegister(base), g.UseRegister(index),
2209                                  g.UseUniqueRegister(value)};
2210   InstructionOperand temps[] = {g.TempRegister()};
2211   InstructionCode code = opcode | AddressingModeField::encode(kMode_MRR);
2212   selector->Emit(code, 0, nullptr, arraysize(inputs), inputs, arraysize(temps),
2213                  temps);
2214 }
2215 
VisitAtomicBinop(InstructionSelector * selector,Node * node,ArchOpcode opcode)2216 void VisitAtomicBinop(InstructionSelector* selector, Node* node,
2217                       ArchOpcode opcode) {
2218   Arm64OperandGenerator g(selector);
2219   Node* base = node->InputAt(0);
2220   Node* index = node->InputAt(1);
2221   Node* value = node->InputAt(2);
2222   AddressingMode addressing_mode = kMode_MRR;
2223   InstructionOperand inputs[] = {g.UseRegister(base), g.UseRegister(index),
2224                                  g.UseUniqueRegister(value)};
2225   InstructionOperand outputs[] = {g.DefineAsRegister(node)};
2226   InstructionOperand temps[] = {g.TempRegister(), g.TempRegister(),
2227                                 g.TempRegister()};
2228   InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
2229   selector->Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
2230                  arraysize(temps), temps);
2231 }
2232 
2233 }  // namespace
2234 
VisitWordCompareZero(Node * user,Node * value,FlagsContinuation * cont)2235 void InstructionSelector::VisitWordCompareZero(Node* user, Node* value,
2236                                                FlagsContinuation* cont) {
2237   Arm64OperandGenerator g(this);
2238   // Try to combine with comparisons against 0 by simply inverting the branch.
2239   while (value->opcode() == IrOpcode::kWord32Equal && CanCover(user, value)) {
2240     Int32BinopMatcher m(value);
2241     if (!m.right().Is(0)) break;
2242 
2243     user = value;
2244     value = m.left().node();
2245     cont->Negate();
2246   }
2247 
2248   // Try to match bit checks to create TBZ/TBNZ instructions.
2249   // Unlike the switch below, CanCover check is not needed here.
2250   // If there are several uses of the given operation, we will generate a TBZ
2251   // instruction for each. This is useful even if there are other uses of the
2252   // arithmetic result, because it moves dependencies further back.
2253   switch (value->opcode()) {
2254     case IrOpcode::kWord64Equal: {
2255       Int64BinopMatcher m(value);
2256       if (m.right().Is(0)) {
2257         Node* const left = m.left().node();
2258         if (left->opcode() == IrOpcode::kWord64And) {
2259           // Attempt to merge the Word64Equal(Word64And(x, y), 0) comparison
2260           // into a tbz/tbnz instruction.
2261           TestAndBranchMatcher<Uint64BinopMatcher> tbm(left, cont);
2262           if (tbm.Matches()) {
2263             Arm64OperandGenerator gen(this);
2264             cont->OverwriteAndNegateIfEqual(kEqual);
2265             this->EmitWithContinuation(kArm64TestAndBranch,
2266                                        gen.UseRegister(tbm.input()),
2267                                        gen.TempImmediate(tbm.bit()), cont);
2268             return;
2269           }
2270         }
2271       }
2272       break;
2273     }
2274     case IrOpcode::kWord32And: {
2275       TestAndBranchMatcher<Uint32BinopMatcher> tbm(value, cont);
2276       if (tbm.Matches()) {
2277         Arm64OperandGenerator gen(this);
2278         this->EmitWithContinuation(kArm64TestAndBranch32,
2279                                    gen.UseRegister(tbm.input()),
2280                                    gen.TempImmediate(tbm.bit()), cont);
2281         return;
2282       }
2283       break;
2284     }
2285     case IrOpcode::kWord64And: {
2286       TestAndBranchMatcher<Uint64BinopMatcher> tbm(value, cont);
2287       if (tbm.Matches()) {
2288         Arm64OperandGenerator gen(this);
2289         this->EmitWithContinuation(kArm64TestAndBranch,
2290                                    gen.UseRegister(tbm.input()),
2291                                    gen.TempImmediate(tbm.bit()), cont);
2292         return;
2293       }
2294       break;
2295     }
2296     default:
2297       break;
2298   }
2299 
2300   if (CanCover(user, value)) {
2301     switch (value->opcode()) {
2302       case IrOpcode::kWord32Equal:
2303         cont->OverwriteAndNegateIfEqual(kEqual);
2304         return VisitWord32Compare(this, value, cont);
2305       case IrOpcode::kInt32LessThan:
2306         cont->OverwriteAndNegateIfEqual(kSignedLessThan);
2307         return VisitWord32Compare(this, value, cont);
2308       case IrOpcode::kInt32LessThanOrEqual:
2309         cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
2310         return VisitWord32Compare(this, value, cont);
2311       case IrOpcode::kUint32LessThan:
2312         cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
2313         return VisitWord32Compare(this, value, cont);
2314       case IrOpcode::kUint32LessThanOrEqual:
2315         cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
2316         return VisitWord32Compare(this, value, cont);
2317       case IrOpcode::kWord64Equal: {
2318         cont->OverwriteAndNegateIfEqual(kEqual);
2319         Int64BinopMatcher m(value);
2320         if (m.right().Is(0)) {
2321           Node* const left = m.left().node();
2322           if (CanCover(value, left) && left->opcode() == IrOpcode::kWord64And) {
2323             return VisitWordCompare(this, left, kArm64Tst, cont, true,
2324                                     kLogical64Imm);
2325           }
2326           // Merge the Word64Equal(x, 0) comparison into a cbz instruction.
2327           if ((cont->IsBranch() || cont->IsDeoptimize()) &&
2328               !cont->IsPoisoned()) {
2329             EmitBranchOrDeoptimize(this, kArm64CompareAndBranch,
2330                                    g.UseRegister(left), cont);
2331             return;
2332           }
2333         }
2334         return VisitWordCompare(this, value, kArm64Cmp, cont, false,
2335                                 kArithmeticImm);
2336       }
2337       case IrOpcode::kInt64LessThan:
2338         cont->OverwriteAndNegateIfEqual(kSignedLessThan);
2339         return VisitWordCompare(this, value, kArm64Cmp, cont, false,
2340                                 kArithmeticImm);
2341       case IrOpcode::kInt64LessThanOrEqual:
2342         cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
2343         return VisitWordCompare(this, value, kArm64Cmp, cont, false,
2344                                 kArithmeticImm);
2345       case IrOpcode::kUint64LessThan:
2346         cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
2347         return VisitWordCompare(this, value, kArm64Cmp, cont, false,
2348                                 kArithmeticImm);
2349       case IrOpcode::kUint64LessThanOrEqual:
2350         cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
2351         return VisitWordCompare(this, value, kArm64Cmp, cont, false,
2352                                 kArithmeticImm);
2353       case IrOpcode::kFloat32Equal:
2354         cont->OverwriteAndNegateIfEqual(kEqual);
2355         return VisitFloat32Compare(this, value, cont);
2356       case IrOpcode::kFloat32LessThan:
2357         cont->OverwriteAndNegateIfEqual(kFloatLessThan);
2358         return VisitFloat32Compare(this, value, cont);
2359       case IrOpcode::kFloat32LessThanOrEqual:
2360         cont->OverwriteAndNegateIfEqual(kFloatLessThanOrEqual);
2361         return VisitFloat32Compare(this, value, cont);
2362       case IrOpcode::kFloat64Equal:
2363         cont->OverwriteAndNegateIfEqual(kEqual);
2364         return VisitFloat64Compare(this, value, cont);
2365       case IrOpcode::kFloat64LessThan:
2366         cont->OverwriteAndNegateIfEqual(kFloatLessThan);
2367         return VisitFloat64Compare(this, value, cont);
2368       case IrOpcode::kFloat64LessThanOrEqual:
2369         cont->OverwriteAndNegateIfEqual(kFloatLessThanOrEqual);
2370         return VisitFloat64Compare(this, value, cont);
2371       case IrOpcode::kProjection:
2372         // Check if this is the overflow output projection of an
2373         // <Operation>WithOverflow node.
2374         if (ProjectionIndexOf(value->op()) == 1u) {
2375           // We cannot combine the <Operation>WithOverflow with this branch
2376           // unless the 0th projection (the use of the actual value of the
2377           // <Operation> is either nullptr, which means there's no use of the
2378           // actual value, or was already defined, which means it is scheduled
2379           // *AFTER* this branch).
2380           Node* const node = value->InputAt(0);
2381           Node* const result = NodeProperties::FindProjection(node, 0);
2382           if (result == nullptr || IsDefined(result)) {
2383             switch (node->opcode()) {
2384               case IrOpcode::kInt32AddWithOverflow:
2385                 cont->OverwriteAndNegateIfEqual(kOverflow);
2386                 return VisitBinop<Int32BinopMatcher>(this, node, kArm64Add32,
2387                                                      kArithmeticImm, cont);
2388               case IrOpcode::kInt32SubWithOverflow:
2389                 cont->OverwriteAndNegateIfEqual(kOverflow);
2390                 return VisitBinop<Int32BinopMatcher>(this, node, kArm64Sub32,
2391                                                      kArithmeticImm, cont);
2392               case IrOpcode::kInt32MulWithOverflow:
2393                 // ARM64 doesn't set the overflow flag for multiplication, so we
2394                 // need to test on kNotEqual. Here is the code sequence used:
2395                 //   smull result, left, right
2396                 //   cmp result.X(), Operand(result, SXTW)
2397                 cont->OverwriteAndNegateIfEqual(kNotEqual);
2398                 return EmitInt32MulWithOverflow(this, node, cont);
2399               case IrOpcode::kInt64AddWithOverflow:
2400                 cont->OverwriteAndNegateIfEqual(kOverflow);
2401                 return VisitBinop<Int64BinopMatcher>(this, node, kArm64Add,
2402                                                      kArithmeticImm, cont);
2403               case IrOpcode::kInt64SubWithOverflow:
2404                 cont->OverwriteAndNegateIfEqual(kOverflow);
2405                 return VisitBinop<Int64BinopMatcher>(this, node, kArm64Sub,
2406                                                      kArithmeticImm, cont);
2407               default:
2408                 break;
2409             }
2410           }
2411         }
2412         break;
2413       case IrOpcode::kInt32Add:
2414         return VisitWordCompare(this, value, kArm64Cmn32, cont, true,
2415                                 kArithmeticImm);
2416       case IrOpcode::kInt32Sub:
2417         return VisitWord32Compare(this, value, cont);
2418       case IrOpcode::kWord32And:
2419         return VisitWordCompare(this, value, kArm64Tst32, cont, true,
2420                                 kLogical32Imm);
2421       case IrOpcode::kWord64And:
2422         return VisitWordCompare(this, value, kArm64Tst, cont, true,
2423                                 kLogical64Imm);
2424       default:
2425         break;
2426     }
2427   }
2428 
2429   // Branch could not be combined with a compare, compare against 0 and branch.
2430   if (!cont->IsPoisoned() && cont->IsBranch()) {
2431     Emit(cont->Encode(kArm64CompareAndBranch32), g.NoOutput(),
2432          g.UseRegister(value), g.Label(cont->true_block()),
2433          g.Label(cont->false_block()));
2434   } else {
2435     EmitWithContinuation(cont->Encode(kArm64Tst32), g.UseRegister(value),
2436                          g.UseRegister(value), cont);
2437   }
2438 }
2439 
VisitSwitch(Node * node,const SwitchInfo & sw)2440 void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
2441   Arm64OperandGenerator g(this);
2442   InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
2443 
2444   // Emit either ArchTableSwitch or ArchLookupSwitch.
2445   if (enable_switch_jump_table_ == kEnableSwitchJumpTable) {
2446     static const size_t kMaxTableSwitchValueRange = 2 << 16;
2447     size_t table_space_cost = 4 + sw.value_range();
2448     size_t table_time_cost = 3;
2449     size_t lookup_space_cost = 3 + 2 * sw.case_count();
2450     size_t lookup_time_cost = sw.case_count();
2451     if (sw.case_count() > 0 &&
2452         table_space_cost + 3 * table_time_cost <=
2453             lookup_space_cost + 3 * lookup_time_cost &&
2454         sw.min_value() > std::numeric_limits<int32_t>::min() &&
2455         sw.value_range() <= kMaxTableSwitchValueRange) {
2456       InstructionOperand index_operand = value_operand;
2457       if (sw.min_value()) {
2458         index_operand = g.TempRegister();
2459         Emit(kArm64Sub32, index_operand, value_operand,
2460              g.TempImmediate(sw.min_value()));
2461       }
2462       // Generate a table lookup.
2463       return EmitTableSwitch(sw, index_operand);
2464     }
2465   }
2466 
2467   // Generate a tree of conditional jumps.
2468   return EmitBinarySearchSwitch(sw, value_operand);
2469 }
2470 
VisitWord32Equal(Node * const node)2471 void InstructionSelector::VisitWord32Equal(Node* const node) {
2472   Node* const user = node;
2473   FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
2474   Int32BinopMatcher m(user);
2475   if (m.right().Is(0)) {
2476     Node* const value = m.left().node();
2477     if (CanCover(user, value)) {
2478       switch (value->opcode()) {
2479         case IrOpcode::kInt32Add:
2480         case IrOpcode::kWord32And:
2481           return VisitWord32Compare(this, node, &cont);
2482         case IrOpcode::kInt32Sub:
2483           return VisitWordCompare(this, value, kArm64Cmp32, &cont, false,
2484                                   kArithmeticImm);
2485         case IrOpcode::kWord32Equal: {
2486           // Word32Equal(Word32Equal(x, y), 0) => Word32Compare(x, y, ne).
2487           Int32BinopMatcher mequal(value);
2488           node->ReplaceInput(0, mequal.left().node());
2489           node->ReplaceInput(1, mequal.right().node());
2490           cont.Negate();
2491           // {node} still does not cover its new operands, because {mequal} is
2492           // still using them.
2493           // Since we won't generate any more code for {mequal}, set its
2494           // operands to zero to make sure {node} can cover them.
2495           // This improves pattern matching in VisitWord32Compare.
2496           mequal.node()->ReplaceInput(0, m.right().node());
2497           mequal.node()->ReplaceInput(1, m.right().node());
2498           return VisitWord32Compare(this, node, &cont);
2499         }
2500         default:
2501           break;
2502       }
2503       return VisitWord32Test(this, value, &cont);
2504     }
2505   }
2506   VisitWord32Compare(this, node, &cont);
2507 }
2508 
2509 
VisitInt32LessThan(Node * node)2510 void InstructionSelector::VisitInt32LessThan(Node* node) {
2511   FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node);
2512   VisitWord32Compare(this, node, &cont);
2513 }
2514 
2515 
VisitInt32LessThanOrEqual(Node * node)2516 void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
2517   FlagsContinuation cont =
2518       FlagsContinuation::ForSet(kSignedLessThanOrEqual, node);
2519   VisitWord32Compare(this, node, &cont);
2520 }
2521 
2522 
VisitUint32LessThan(Node * node)2523 void InstructionSelector::VisitUint32LessThan(Node* node) {
2524   FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
2525   VisitWord32Compare(this, node, &cont);
2526 }
2527 
2528 
VisitUint32LessThanOrEqual(Node * node)2529 void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
2530   FlagsContinuation cont =
2531       FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
2532   VisitWord32Compare(this, node, &cont);
2533 }
2534 
2535 
VisitWord64Equal(Node * const node)2536 void InstructionSelector::VisitWord64Equal(Node* const node) {
2537   Node* const user = node;
2538   FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
2539   Int64BinopMatcher m(user);
2540   if (m.right().Is(0)) {
2541     Node* const value = m.left().node();
2542     if (CanCover(user, value)) {
2543       switch (value->opcode()) {
2544         case IrOpcode::kWord64And:
2545           return VisitWordCompare(this, value, kArm64Tst, &cont, true,
2546                                   kLogical64Imm);
2547         default:
2548           break;
2549       }
2550       return VisitWord64Test(this, value, &cont);
2551     }
2552   }
2553   VisitWordCompare(this, node, kArm64Cmp, &cont, false, kArithmeticImm);
2554 }
2555 
2556 
VisitInt32AddWithOverflow(Node * node)2557 void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
2558   if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
2559     FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
2560     return VisitBinop<Int32BinopMatcher>(this, node, kArm64Add32,
2561                                          kArithmeticImm, &cont);
2562   }
2563   FlagsContinuation cont;
2564   VisitBinop<Int32BinopMatcher>(this, node, kArm64Add32, kArithmeticImm, &cont);
2565 }
2566 
2567 
VisitInt32SubWithOverflow(Node * node)2568 void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
2569   if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
2570     FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
2571     return VisitBinop<Int32BinopMatcher>(this, node, kArm64Sub32,
2572                                          kArithmeticImm, &cont);
2573   }
2574   FlagsContinuation cont;
2575   VisitBinop<Int32BinopMatcher>(this, node, kArm64Sub32, kArithmeticImm, &cont);
2576 }
2577 
VisitInt32MulWithOverflow(Node * node)2578 void InstructionSelector::VisitInt32MulWithOverflow(Node* node) {
2579   if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
2580     // ARM64 doesn't set the overflow flag for multiplication, so we need to
2581     // test on kNotEqual. Here is the code sequence used:
2582     //   smull result, left, right
2583     //   cmp result.X(), Operand(result, SXTW)
2584     FlagsContinuation cont = FlagsContinuation::ForSet(kNotEqual, ovf);
2585     return EmitInt32MulWithOverflow(this, node, &cont);
2586   }
2587   FlagsContinuation cont;
2588   EmitInt32MulWithOverflow(this, node, &cont);
2589 }
2590 
VisitInt64AddWithOverflow(Node * node)2591 void InstructionSelector::VisitInt64AddWithOverflow(Node* node) {
2592   if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
2593     FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
2594     return VisitBinop<Int64BinopMatcher>(this, node, kArm64Add, kArithmeticImm,
2595                                          &cont);
2596   }
2597   FlagsContinuation cont;
2598   VisitBinop<Int64BinopMatcher>(this, node, kArm64Add, kArithmeticImm, &cont);
2599 }
2600 
2601 
VisitInt64SubWithOverflow(Node * node)2602 void InstructionSelector::VisitInt64SubWithOverflow(Node* node) {
2603   if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
2604     FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
2605     return VisitBinop<Int64BinopMatcher>(this, node, kArm64Sub, kArithmeticImm,
2606                                          &cont);
2607   }
2608   FlagsContinuation cont;
2609   VisitBinop<Int64BinopMatcher>(this, node, kArm64Sub, kArithmeticImm, &cont);
2610 }
2611 
2612 
VisitInt64LessThan(Node * node)2613 void InstructionSelector::VisitInt64LessThan(Node* node) {
2614   FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node);
2615   VisitWordCompare(this, node, kArm64Cmp, &cont, false, kArithmeticImm);
2616 }
2617 
2618 
VisitInt64LessThanOrEqual(Node * node)2619 void InstructionSelector::VisitInt64LessThanOrEqual(Node* node) {
2620   FlagsContinuation cont =
2621       FlagsContinuation::ForSet(kSignedLessThanOrEqual, node);
2622   VisitWordCompare(this, node, kArm64Cmp, &cont, false, kArithmeticImm);
2623 }
2624 
2625 
VisitUint64LessThan(Node * node)2626 void InstructionSelector::VisitUint64LessThan(Node* node) {
2627   FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
2628   VisitWordCompare(this, node, kArm64Cmp, &cont, false, kArithmeticImm);
2629 }
2630 
2631 
VisitUint64LessThanOrEqual(Node * node)2632 void InstructionSelector::VisitUint64LessThanOrEqual(Node* node) {
2633   FlagsContinuation cont =
2634       FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
2635   VisitWordCompare(this, node, kArm64Cmp, &cont, false, kArithmeticImm);
2636 }
2637 
2638 
VisitFloat32Equal(Node * node)2639 void InstructionSelector::VisitFloat32Equal(Node* node) {
2640   FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
2641   VisitFloat32Compare(this, node, &cont);
2642 }
2643 
2644 
VisitFloat32LessThan(Node * node)2645 void InstructionSelector::VisitFloat32LessThan(Node* node) {
2646   FlagsContinuation cont = FlagsContinuation::ForSet(kFloatLessThan, node);
2647   VisitFloat32Compare(this, node, &cont);
2648 }
2649 
2650 
VisitFloat32LessThanOrEqual(Node * node)2651 void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) {
2652   FlagsContinuation cont =
2653       FlagsContinuation::ForSet(kFloatLessThanOrEqual, node);
2654   VisitFloat32Compare(this, node, &cont);
2655 }
2656 
2657 
VisitFloat64Equal(Node * node)2658 void InstructionSelector::VisitFloat64Equal(Node* node) {
2659   FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
2660   VisitFloat64Compare(this, node, &cont);
2661 }
2662 
2663 
VisitFloat64LessThan(Node * node)2664 void InstructionSelector::VisitFloat64LessThan(Node* node) {
2665   FlagsContinuation cont = FlagsContinuation::ForSet(kFloatLessThan, node);
2666   VisitFloat64Compare(this, node, &cont);
2667 }
2668 
2669 
VisitFloat64LessThanOrEqual(Node * node)2670 void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
2671   FlagsContinuation cont =
2672       FlagsContinuation::ForSet(kFloatLessThanOrEqual, node);
2673   VisitFloat64Compare(this, node, &cont);
2674 }
2675 
VisitFloat64InsertLowWord32(Node * node)2676 void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) {
2677   Arm64OperandGenerator g(this);
2678   Node* left = node->InputAt(0);
2679   Node* right = node->InputAt(1);
2680   if (left->opcode() == IrOpcode::kFloat64InsertHighWord32 &&
2681       CanCover(node, left)) {
2682     Node* right_of_left = left->InputAt(1);
2683     Emit(kArm64Bfi, g.DefineSameAsFirst(right), g.UseRegister(right),
2684          g.UseRegister(right_of_left), g.TempImmediate(32),
2685          g.TempImmediate(32));
2686     Emit(kArm64Float64MoveU64, g.DefineAsRegister(node), g.UseRegister(right));
2687     return;
2688   }
2689   Emit(kArm64Float64InsertLowWord32, g.DefineSameAsFirst(node),
2690        g.UseRegister(left), g.UseRegister(right));
2691 }
2692 
2693 
VisitFloat64InsertHighWord32(Node * node)2694 void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
2695   Arm64OperandGenerator g(this);
2696   Node* left = node->InputAt(0);
2697   Node* right = node->InputAt(1);
2698   if (left->opcode() == IrOpcode::kFloat64InsertLowWord32 &&
2699       CanCover(node, left)) {
2700     Node* right_of_left = left->InputAt(1);
2701     Emit(kArm64Bfi, g.DefineSameAsFirst(left), g.UseRegister(right_of_left),
2702          g.UseRegister(right), g.TempImmediate(32), g.TempImmediate(32));
2703     Emit(kArm64Float64MoveU64, g.DefineAsRegister(node), g.UseRegister(left));
2704     return;
2705   }
2706   Emit(kArm64Float64InsertHighWord32, g.DefineSameAsFirst(node),
2707        g.UseRegister(left), g.UseRegister(right));
2708 }
2709 
VisitWord32AtomicLoad(Node * node)2710 void InstructionSelector::VisitWord32AtomicLoad(Node* node) {
2711   LoadRepresentation load_rep = LoadRepresentationOf(node->op());
2712   ArchOpcode opcode = kArchNop;
2713   switch (load_rep.representation()) {
2714     case MachineRepresentation::kWord8:
2715       opcode =
2716           load_rep.IsSigned() ? kWord32AtomicLoadInt8 : kWord32AtomicLoadUint8;
2717       break;
2718     case MachineRepresentation::kWord16:
2719       opcode = load_rep.IsSigned() ? kWord32AtomicLoadInt16
2720                                    : kWord32AtomicLoadUint16;
2721       break;
2722     case MachineRepresentation::kWord32:
2723       opcode = kWord32AtomicLoadWord32;
2724       break;
2725     default:
2726       UNREACHABLE();
2727       return;
2728   }
2729   VisitAtomicLoad(this, node, opcode);
2730 }
2731 
VisitWord64AtomicLoad(Node * node)2732 void InstructionSelector::VisitWord64AtomicLoad(Node* node) {
2733   LoadRepresentation load_rep = LoadRepresentationOf(node->op());
2734   ArchOpcode opcode = kArchNop;
2735   switch (load_rep.representation()) {
2736     case MachineRepresentation::kWord8:
2737       opcode = kArm64Word64AtomicLoadUint8;
2738       break;
2739     case MachineRepresentation::kWord16:
2740       opcode = kArm64Word64AtomicLoadUint16;
2741       break;
2742     case MachineRepresentation::kWord32:
2743       opcode = kArm64Word64AtomicLoadUint32;
2744       break;
2745     case MachineRepresentation::kWord64:
2746       opcode = kArm64Word64AtomicLoadUint64;
2747       break;
2748     default:
2749       UNREACHABLE();
2750       return;
2751   }
2752   VisitAtomicLoad(this, node, opcode);
2753 }
2754 
VisitWord32AtomicStore(Node * node)2755 void InstructionSelector::VisitWord32AtomicStore(Node* node) {
2756   MachineRepresentation rep = AtomicStoreRepresentationOf(node->op());
2757   ArchOpcode opcode = kArchNop;
2758   switch (rep) {
2759     case MachineRepresentation::kWord8:
2760       opcode = kWord32AtomicStoreWord8;
2761       break;
2762     case MachineRepresentation::kWord16:
2763       opcode = kWord32AtomicStoreWord16;
2764       break;
2765     case MachineRepresentation::kWord32:
2766       opcode = kWord32AtomicStoreWord32;
2767       break;
2768     default:
2769       UNREACHABLE();
2770       return;
2771   }
2772   VisitAtomicStore(this, node, opcode);
2773 }
2774 
VisitWord64AtomicStore(Node * node)2775 void InstructionSelector::VisitWord64AtomicStore(Node* node) {
2776   MachineRepresentation rep = AtomicStoreRepresentationOf(node->op());
2777   ArchOpcode opcode = kArchNop;
2778   switch (rep) {
2779     case MachineRepresentation::kWord8:
2780       opcode = kArm64Word64AtomicStoreWord8;
2781       break;
2782     case MachineRepresentation::kWord16:
2783       opcode = kArm64Word64AtomicStoreWord16;
2784       break;
2785     case MachineRepresentation::kWord32:
2786       opcode = kArm64Word64AtomicStoreWord32;
2787       break;
2788     case MachineRepresentation::kWord64:
2789       opcode = kArm64Word64AtomicStoreWord64;
2790       break;
2791     default:
2792       UNREACHABLE();
2793       return;
2794   }
2795   VisitAtomicStore(this, node, opcode);
2796 }
2797 
VisitWord32AtomicExchange(Node * node)2798 void InstructionSelector::VisitWord32AtomicExchange(Node* node) {
2799   ArchOpcode opcode = kArchNop;
2800   MachineType type = AtomicOpType(node->op());
2801   if (type == MachineType::Int8()) {
2802     opcode = kWord32AtomicExchangeInt8;
2803   } else if (type == MachineType::Uint8()) {
2804     opcode = kWord32AtomicExchangeUint8;
2805   } else if (type == MachineType::Int16()) {
2806     opcode = kWord32AtomicExchangeInt16;
2807   } else if (type == MachineType::Uint16()) {
2808     opcode = kWord32AtomicExchangeUint16;
2809   } else if (type == MachineType::Int32() || type == MachineType::Uint32()) {
2810     opcode = kWord32AtomicExchangeWord32;
2811   } else {
2812     UNREACHABLE();
2813     return;
2814   }
2815   VisitAtomicExchange(this, node, opcode);
2816 }
2817 
VisitWord64AtomicExchange(Node * node)2818 void InstructionSelector::VisitWord64AtomicExchange(Node* node) {
2819   ArchOpcode opcode = kArchNop;
2820   MachineType type = AtomicOpType(node->op());
2821   if (type == MachineType::Uint8()) {
2822     opcode = kArm64Word64AtomicExchangeUint8;
2823   } else if (type == MachineType::Uint16()) {
2824     opcode = kArm64Word64AtomicExchangeUint16;
2825   } else if (type == MachineType::Uint32()) {
2826     opcode = kArm64Word64AtomicExchangeUint32;
2827   } else if (type == MachineType::Uint64()) {
2828     opcode = kArm64Word64AtomicExchangeUint64;
2829   } else {
2830     UNREACHABLE();
2831     return;
2832   }
2833   VisitAtomicExchange(this, node, opcode);
2834 }
2835 
VisitWord32AtomicCompareExchange(Node * node)2836 void InstructionSelector::VisitWord32AtomicCompareExchange(Node* node) {
2837   ArchOpcode opcode = kArchNop;
2838   MachineType type = AtomicOpType(node->op());
2839   if (type == MachineType::Int8()) {
2840     opcode = kWord32AtomicCompareExchangeInt8;
2841   } else if (type == MachineType::Uint8()) {
2842     opcode = kWord32AtomicCompareExchangeUint8;
2843   } else if (type == MachineType::Int16()) {
2844     opcode = kWord32AtomicCompareExchangeInt16;
2845   } else if (type == MachineType::Uint16()) {
2846     opcode = kWord32AtomicCompareExchangeUint16;
2847   } else if (type == MachineType::Int32() || type == MachineType::Uint32()) {
2848     opcode = kWord32AtomicCompareExchangeWord32;
2849   } else {
2850     UNREACHABLE();
2851     return;
2852   }
2853   VisitAtomicCompareExchange(this, node, opcode);
2854 }
2855 
VisitWord64AtomicCompareExchange(Node * node)2856 void InstructionSelector::VisitWord64AtomicCompareExchange(Node* node) {
2857   ArchOpcode opcode = kArchNop;
2858   MachineType type = AtomicOpType(node->op());
2859   if (type == MachineType::Uint8()) {
2860     opcode = kArm64Word64AtomicCompareExchangeUint8;
2861   } else if (type == MachineType::Uint16()) {
2862     opcode = kArm64Word64AtomicCompareExchangeUint16;
2863   } else if (type == MachineType::Uint32()) {
2864     opcode = kArm64Word64AtomicCompareExchangeUint32;
2865   } else if (type == MachineType::Uint64()) {
2866     opcode = kArm64Word64AtomicCompareExchangeUint64;
2867   } else {
2868     UNREACHABLE();
2869     return;
2870   }
2871   VisitAtomicCompareExchange(this, node, opcode);
2872 }
2873 
VisitWord32AtomicBinaryOperation(Node * node,ArchOpcode int8_op,ArchOpcode uint8_op,ArchOpcode int16_op,ArchOpcode uint16_op,ArchOpcode word32_op)2874 void InstructionSelector::VisitWord32AtomicBinaryOperation(
2875     Node* node, ArchOpcode int8_op, ArchOpcode uint8_op, ArchOpcode int16_op,
2876     ArchOpcode uint16_op, ArchOpcode word32_op) {
2877   ArchOpcode opcode = kArchNop;
2878   MachineType type = AtomicOpType(node->op());
2879   if (type == MachineType::Int8()) {
2880     opcode = int8_op;
2881   } else if (type == MachineType::Uint8()) {
2882     opcode = uint8_op;
2883   } else if (type == MachineType::Int16()) {
2884     opcode = int16_op;
2885   } else if (type == MachineType::Uint16()) {
2886     opcode = uint16_op;
2887   } else if (type == MachineType::Int32() || type == MachineType::Uint32()) {
2888     opcode = word32_op;
2889   } else {
2890     UNREACHABLE();
2891     return;
2892   }
2893   VisitAtomicBinop(this, node, opcode);
2894 }
2895 
2896 #define VISIT_ATOMIC_BINOP(op)                                   \
2897   void InstructionSelector::VisitWord32Atomic##op(Node* node) {  \
2898     VisitWord32AtomicBinaryOperation(                            \
2899         node, kWord32Atomic##op##Int8, kWord32Atomic##op##Uint8, \
2900         kWord32Atomic##op##Int16, kWord32Atomic##op##Uint16,     \
2901         kWord32Atomic##op##Word32);                              \
2902   }
2903 VISIT_ATOMIC_BINOP(Add)
VISIT_ATOMIC_BINOP(Sub)2904 VISIT_ATOMIC_BINOP(Sub)
2905 VISIT_ATOMIC_BINOP(And)
2906 VISIT_ATOMIC_BINOP(Or)
2907 VISIT_ATOMIC_BINOP(Xor)
2908 #undef VISIT_ATOMIC_BINOP
2909 
2910 void InstructionSelector::VisitWord64AtomicBinaryOperation(
2911     Node* node, ArchOpcode uint8_op, ArchOpcode uint16_op, ArchOpcode uint32_op,
2912     ArchOpcode uint64_op) {
2913   ArchOpcode opcode = kArchNop;
2914   MachineType type = AtomicOpType(node->op());
2915   if (type == MachineType::Uint8()) {
2916     opcode = uint8_op;
2917   } else if (type == MachineType::Uint16()) {
2918     opcode = uint16_op;
2919   } else if (type == MachineType::Uint32()) {
2920     opcode = uint32_op;
2921   } else if (type == MachineType::Uint64()) {
2922     opcode = uint64_op;
2923   } else {
2924     UNREACHABLE();
2925     return;
2926   }
2927   VisitAtomicBinop(this, node, opcode);
2928 }
2929 
2930 #define VISIT_ATOMIC_BINOP(op)                                               \
2931   void InstructionSelector::VisitWord64Atomic##op(Node* node) {              \
2932     VisitWord64AtomicBinaryOperation(                                        \
2933         node, kArm64Word64Atomic##op##Uint8, kArm64Word64Atomic##op##Uint16, \
2934         kArm64Word64Atomic##op##Uint32, kArm64Word64Atomic##op##Uint64);     \
2935   }
2936 VISIT_ATOMIC_BINOP(Add)
VISIT_ATOMIC_BINOP(Sub)2937 VISIT_ATOMIC_BINOP(Sub)
2938 VISIT_ATOMIC_BINOP(And)
2939 VISIT_ATOMIC_BINOP(Or)
2940 VISIT_ATOMIC_BINOP(Xor)
2941 #undef VISIT_ATOMIC_BINOP
2942 
2943 void InstructionSelector::VisitInt32AbsWithOverflow(Node* node) {
2944   UNREACHABLE();
2945 }
2946 
VisitInt64AbsWithOverflow(Node * node)2947 void InstructionSelector::VisitInt64AbsWithOverflow(Node* node) {
2948   UNREACHABLE();
2949 }
2950 
2951 #define SIMD_TYPE_LIST(V) \
2952   V(F32x4)                \
2953   V(I32x4)                \
2954   V(I16x8)                \
2955   V(I8x16)
2956 
2957 #define SIMD_UNOP_LIST(V)                                 \
2958   V(F32x4SConvertI32x4, kArm64F32x4SConvertI32x4)         \
2959   V(F32x4UConvertI32x4, kArm64F32x4UConvertI32x4)         \
2960   V(F32x4Abs, kArm64F32x4Abs)                             \
2961   V(F32x4Neg, kArm64F32x4Neg)                             \
2962   V(F32x4RecipApprox, kArm64F32x4RecipApprox)             \
2963   V(F32x4RecipSqrtApprox, kArm64F32x4RecipSqrtApprox)     \
2964   V(I32x4SConvertF32x4, kArm64I32x4SConvertF32x4)         \
2965   V(I32x4SConvertI16x8Low, kArm64I32x4SConvertI16x8Low)   \
2966   V(I32x4SConvertI16x8High, kArm64I32x4SConvertI16x8High) \
2967   V(I32x4Neg, kArm64I32x4Neg)                             \
2968   V(I32x4UConvertF32x4, kArm64I32x4UConvertF32x4)         \
2969   V(I32x4UConvertI16x8Low, kArm64I32x4UConvertI16x8Low)   \
2970   V(I32x4UConvertI16x8High, kArm64I32x4UConvertI16x8High) \
2971   V(I16x8SConvertI8x16Low, kArm64I16x8SConvertI8x16Low)   \
2972   V(I16x8SConvertI8x16High, kArm64I16x8SConvertI8x16High) \
2973   V(I16x8Neg, kArm64I16x8Neg)                             \
2974   V(I16x8UConvertI8x16Low, kArm64I16x8UConvertI8x16Low)   \
2975   V(I16x8UConvertI8x16High, kArm64I16x8UConvertI8x16High) \
2976   V(I8x16Neg, kArm64I8x16Neg)                             \
2977   V(S128Not, kArm64S128Not)                               \
2978   V(S1x4AnyTrue, kArm64S1x4AnyTrue)                       \
2979   V(S1x4AllTrue, kArm64S1x4AllTrue)                       \
2980   V(S1x8AnyTrue, kArm64S1x8AnyTrue)                       \
2981   V(S1x8AllTrue, kArm64S1x8AllTrue)                       \
2982   V(S1x16AnyTrue, kArm64S1x16AnyTrue)                     \
2983   V(S1x16AllTrue, kArm64S1x16AllTrue)
2984 
2985 #define SIMD_SHIFT_OP_LIST(V) \
2986   V(I32x4Shl)                 \
2987   V(I32x4ShrS)                \
2988   V(I32x4ShrU)                \
2989   V(I16x8Shl)                 \
2990   V(I16x8ShrS)                \
2991   V(I16x8ShrU)                \
2992   V(I8x16Shl)                 \
2993   V(I8x16ShrS)                \
2994   V(I8x16ShrU)
2995 
2996 #define SIMD_BINOP_LIST(V)                        \
2997   V(F32x4Add, kArm64F32x4Add)                     \
2998   V(F32x4AddHoriz, kArm64F32x4AddHoriz)           \
2999   V(F32x4Sub, kArm64F32x4Sub)                     \
3000   V(F32x4Mul, kArm64F32x4Mul)                     \
3001   V(F32x4Min, kArm64F32x4Min)                     \
3002   V(F32x4Max, kArm64F32x4Max)                     \
3003   V(F32x4Eq, kArm64F32x4Eq)                       \
3004   V(F32x4Ne, kArm64F32x4Ne)                       \
3005   V(F32x4Lt, kArm64F32x4Lt)                       \
3006   V(F32x4Le, kArm64F32x4Le)                       \
3007   V(I32x4Add, kArm64I32x4Add)                     \
3008   V(I32x4AddHoriz, kArm64I32x4AddHoriz)           \
3009   V(I32x4Sub, kArm64I32x4Sub)                     \
3010   V(I32x4Mul, kArm64I32x4Mul)                     \
3011   V(I32x4MinS, kArm64I32x4MinS)                   \
3012   V(I32x4MaxS, kArm64I32x4MaxS)                   \
3013   V(I32x4Eq, kArm64I32x4Eq)                       \
3014   V(I32x4Ne, kArm64I32x4Ne)                       \
3015   V(I32x4GtS, kArm64I32x4GtS)                     \
3016   V(I32x4GeS, kArm64I32x4GeS)                     \
3017   V(I32x4MinU, kArm64I32x4MinU)                   \
3018   V(I32x4MaxU, kArm64I32x4MaxU)                   \
3019   V(I32x4GtU, kArm64I32x4GtU)                     \
3020   V(I32x4GeU, kArm64I32x4GeU)                     \
3021   V(I16x8SConvertI32x4, kArm64I16x8SConvertI32x4) \
3022   V(I16x8Add, kArm64I16x8Add)                     \
3023   V(I16x8AddSaturateS, kArm64I16x8AddSaturateS)   \
3024   V(I16x8AddHoriz, kArm64I16x8AddHoriz)           \
3025   V(I16x8Sub, kArm64I16x8Sub)                     \
3026   V(I16x8SubSaturateS, kArm64I16x8SubSaturateS)   \
3027   V(I16x8Mul, kArm64I16x8Mul)                     \
3028   V(I16x8MinS, kArm64I16x8MinS)                   \
3029   V(I16x8MaxS, kArm64I16x8MaxS)                   \
3030   V(I16x8Eq, kArm64I16x8Eq)                       \
3031   V(I16x8Ne, kArm64I16x8Ne)                       \
3032   V(I16x8GtS, kArm64I16x8GtS)                     \
3033   V(I16x8GeS, kArm64I16x8GeS)                     \
3034   V(I16x8UConvertI32x4, kArm64I16x8UConvertI32x4) \
3035   V(I16x8AddSaturateU, kArm64I16x8AddSaturateU)   \
3036   V(I16x8SubSaturateU, kArm64I16x8SubSaturateU)   \
3037   V(I16x8MinU, kArm64I16x8MinU)                   \
3038   V(I16x8MaxU, kArm64I16x8MaxU)                   \
3039   V(I16x8GtU, kArm64I16x8GtU)                     \
3040   V(I16x8GeU, kArm64I16x8GeU)                     \
3041   V(I8x16SConvertI16x8, kArm64I8x16SConvertI16x8) \
3042   V(I8x16Add, kArm64I8x16Add)                     \
3043   V(I8x16AddSaturateS, kArm64I8x16AddSaturateS)   \
3044   V(I8x16Sub, kArm64I8x16Sub)                     \
3045   V(I8x16SubSaturateS, kArm64I8x16SubSaturateS)   \
3046   V(I8x16Mul, kArm64I8x16Mul)                     \
3047   V(I8x16MinS, kArm64I8x16MinS)                   \
3048   V(I8x16MaxS, kArm64I8x16MaxS)                   \
3049   V(I8x16Eq, kArm64I8x16Eq)                       \
3050   V(I8x16Ne, kArm64I8x16Ne)                       \
3051   V(I8x16GtS, kArm64I8x16GtS)                     \
3052   V(I8x16GeS, kArm64I8x16GeS)                     \
3053   V(I8x16UConvertI16x8, kArm64I8x16UConvertI16x8) \
3054   V(I8x16AddSaturateU, kArm64I8x16AddSaturateU)   \
3055   V(I8x16SubSaturateU, kArm64I8x16SubSaturateU)   \
3056   V(I8x16MinU, kArm64I8x16MinU)                   \
3057   V(I8x16MaxU, kArm64I8x16MaxU)                   \
3058   V(I8x16GtU, kArm64I8x16GtU)                     \
3059   V(I8x16GeU, kArm64I8x16GeU)                     \
3060   V(S128And, kArm64S128And)                       \
3061   V(S128Or, kArm64S128Or)                         \
3062   V(S128Xor, kArm64S128Xor)
3063 
VisitS128Zero(Node * node)3064 void InstructionSelector::VisitS128Zero(Node* node) {
3065   Arm64OperandGenerator g(this);
3066   Emit(kArm64S128Zero, g.DefineAsRegister(node), g.DefineAsRegister(node));
3067 }
3068 
3069 #define SIMD_VISIT_SPLAT(Type)                               \
3070   void InstructionSelector::Visit##Type##Splat(Node* node) { \
3071     VisitRR(this, kArm64##Type##Splat, node);                \
3072   }
3073 SIMD_TYPE_LIST(SIMD_VISIT_SPLAT)
3074 #undef SIMD_VISIT_SPLAT
3075 
3076 #define SIMD_VISIT_EXTRACT_LANE(Type)                              \
3077   void InstructionSelector::Visit##Type##ExtractLane(Node* node) { \
3078     VisitRRI(this, kArm64##Type##ExtractLane, node);               \
3079   }
SIMD_TYPE_LIST(SIMD_VISIT_EXTRACT_LANE)3080 SIMD_TYPE_LIST(SIMD_VISIT_EXTRACT_LANE)
3081 #undef SIMD_VISIT_EXTRACT_LANE
3082 
3083 #define SIMD_VISIT_REPLACE_LANE(Type)                              \
3084   void InstructionSelector::Visit##Type##ReplaceLane(Node* node) { \
3085     VisitRRIR(this, kArm64##Type##ReplaceLane, node);              \
3086   }
3087 SIMD_TYPE_LIST(SIMD_VISIT_REPLACE_LANE)
3088 #undef SIMD_VISIT_REPLACE_LANE
3089 #undef SIMD_TYPE_LIST
3090 
3091 #define SIMD_VISIT_UNOP(Name, instruction)            \
3092   void InstructionSelector::Visit##Name(Node* node) { \
3093     VisitRR(this, instruction, node);                 \
3094   }
3095 SIMD_UNOP_LIST(SIMD_VISIT_UNOP)
3096 #undef SIMD_VISIT_UNOP
3097 #undef SIMD_UNOP_LIST
3098 
3099 #define SIMD_VISIT_SHIFT_OP(Name)                     \
3100   void InstructionSelector::Visit##Name(Node* node) { \
3101     VisitRRI(this, kArm64##Name, node);               \
3102   }
3103 SIMD_SHIFT_OP_LIST(SIMD_VISIT_SHIFT_OP)
3104 #undef SIMD_VISIT_SHIFT_OP
3105 #undef SIMD_SHIFT_OP_LIST
3106 
3107 #define SIMD_VISIT_BINOP(Name, instruction)           \
3108   void InstructionSelector::Visit##Name(Node* node) { \
3109     VisitRRR(this, instruction, node);                \
3110   }
3111 SIMD_BINOP_LIST(SIMD_VISIT_BINOP)
3112 #undef SIMD_VISIT_BINOP
3113 #undef SIMD_BINOP_LIST
3114 
3115 void InstructionSelector::VisitS128Select(Node* node) {
3116   Arm64OperandGenerator g(this);
3117   Emit(kArm64S128Select, g.DefineSameAsFirst(node),
3118        g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)),
3119        g.UseRegister(node->InputAt(2)));
3120 }
3121 
3122 namespace {
3123 
3124 struct ShuffleEntry {
3125   uint8_t shuffle[kSimd128Size];
3126   ArchOpcode opcode;
3127 };
3128 
3129 static const ShuffleEntry arch_shuffles[] = {
3130     {{0, 1, 2, 3, 16, 17, 18, 19, 4, 5, 6, 7, 20, 21, 22, 23},
3131      kArm64S32x4ZipLeft},
3132     {{8, 9, 10, 11, 24, 25, 26, 27, 12, 13, 14, 15, 28, 29, 30, 31},
3133      kArm64S32x4ZipRight},
3134     {{0, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19, 24, 25, 26, 27},
3135      kArm64S32x4UnzipLeft},
3136     {{4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23, 28, 29, 30, 31},
3137      kArm64S32x4UnzipRight},
3138     {{0, 1, 2, 3, 16, 17, 18, 19, 8, 9, 10, 11, 24, 25, 26, 27},
3139      kArm64S32x4TransposeLeft},
3140     {{4, 5, 6, 7, 20, 21, 22, 23, 12, 13, 14, 15, 21, 22, 23, 24},
3141      kArm64S32x4TransposeRight},
3142     {{4, 5, 6, 7, 0, 1, 2, 3, 12, 13, 14, 15, 8, 9, 10, 11},
3143      kArm64S32x2Reverse},
3144 
3145     {{0, 1, 16, 17, 2, 3, 18, 19, 4, 5, 20, 21, 6, 7, 22, 23},
3146      kArm64S16x8ZipLeft},
3147     {{8, 9, 24, 25, 10, 11, 26, 27, 12, 13, 28, 29, 14, 15, 30, 31},
3148      kArm64S16x8ZipRight},
3149     {{0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21, 24, 25, 28, 29},
3150      kArm64S16x8UnzipLeft},
3151     {{2, 3, 6, 7, 10, 11, 14, 15, 18, 19, 22, 23, 26, 27, 30, 31},
3152      kArm64S16x8UnzipRight},
3153     {{0, 1, 16, 17, 4, 5, 20, 21, 8, 9, 24, 25, 12, 13, 28, 29},
3154      kArm64S16x8TransposeLeft},
3155     {{2, 3, 18, 19, 6, 7, 22, 23, 10, 11, 26, 27, 14, 15, 30, 31},
3156      kArm64S16x8TransposeRight},
3157     {{6, 7, 4, 5, 2, 3, 0, 1, 14, 15, 12, 13, 10, 11, 8, 9},
3158      kArm64S16x4Reverse},
3159     {{2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13},
3160      kArm64S16x2Reverse},
3161 
3162     {{0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23},
3163      kArm64S8x16ZipLeft},
3164     {{8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30, 15, 31},
3165      kArm64S8x16ZipRight},
3166     {{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30},
3167      kArm64S8x16UnzipLeft},
3168     {{1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31},
3169      kArm64S8x16UnzipRight},
3170     {{0, 16, 2, 18, 4, 20, 6, 22, 8, 24, 10, 26, 12, 28, 14, 30},
3171      kArm64S8x16TransposeLeft},
3172     {{1, 17, 3, 19, 5, 21, 7, 23, 9, 25, 11, 27, 13, 29, 15, 31},
3173      kArm64S8x16TransposeRight},
3174     {{7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8}, kArm64S8x8Reverse},
3175     {{3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12}, kArm64S8x4Reverse},
3176     {{1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14},
3177      kArm64S8x2Reverse}};
3178 
TryMatchArchShuffle(const uint8_t * shuffle,const ShuffleEntry * table,size_t num_entries,bool is_swizzle,ArchOpcode * opcode)3179 bool TryMatchArchShuffle(const uint8_t* shuffle, const ShuffleEntry* table,
3180                          size_t num_entries, bool is_swizzle,
3181                          ArchOpcode* opcode) {
3182   uint8_t mask = is_swizzle ? kSimd128Size - 1 : 2 * kSimd128Size - 1;
3183   for (size_t i = 0; i < num_entries; i++) {
3184     const ShuffleEntry& entry = table[i];
3185     int j = 0;
3186     for (; j < kSimd128Size; j++) {
3187       if ((entry.shuffle[j] & mask) != (shuffle[j] & mask)) {
3188         break;
3189       }
3190     }
3191     if (j == kSimd128Size) {
3192       *opcode = entry.opcode;
3193       return true;
3194     }
3195   }
3196   return false;
3197 }
3198 
ArrangeShuffleTable(Arm64OperandGenerator * g,Node * input0,Node * input1,InstructionOperand * src0,InstructionOperand * src1)3199 void ArrangeShuffleTable(Arm64OperandGenerator* g, Node* input0, Node* input1,
3200                          InstructionOperand* src0, InstructionOperand* src1) {
3201   if (input0 == input1) {
3202     // Unary, any q-register can be the table.
3203     *src0 = *src1 = g->UseRegister(input0);
3204   } else {
3205     // Binary, table registers must be consecutive.
3206     *src0 = g->UseFixed(input0, fp_fixed1);
3207     *src1 = g->UseFixed(input1, fp_fixed2);
3208   }
3209 }
3210 
3211 }  // namespace
3212 
VisitS8x16Shuffle(Node * node)3213 void InstructionSelector::VisitS8x16Shuffle(Node* node) {
3214   uint8_t shuffle[kSimd128Size];
3215   bool is_swizzle;
3216   CanonicalizeShuffle(node, shuffle, &is_swizzle);
3217   uint8_t shuffle32x4[4];
3218   Arm64OperandGenerator g(this);
3219   ArchOpcode opcode;
3220   if (TryMatchArchShuffle(shuffle, arch_shuffles, arraysize(arch_shuffles),
3221                           is_swizzle, &opcode)) {
3222     VisitRRR(this, opcode, node);
3223     return;
3224   }
3225   Node* input0 = node->InputAt(0);
3226   Node* input1 = node->InputAt(1);
3227   uint8_t offset;
3228   if (TryMatchConcat(shuffle, &offset)) {
3229     Emit(kArm64S8x16Concat, g.DefineAsRegister(node), g.UseRegister(input0),
3230          g.UseRegister(input1), g.UseImmediate(offset));
3231     return;
3232   }
3233   int index = 0;
3234   if (TryMatch32x4Shuffle(shuffle, shuffle32x4)) {
3235     if (TryMatchDup<4>(shuffle, &index)) {
3236       DCHECK_GT(4, index);
3237       Emit(kArm64S128Dup, g.DefineAsRegister(node), g.UseRegister(input0),
3238            g.UseImmediate(4), g.UseImmediate(index % 4));
3239     } else if (TryMatchIdentity(shuffle)) {
3240       EmitIdentity(node);
3241     } else {
3242       Emit(kArm64S32x4Shuffle, g.DefineAsRegister(node), g.UseRegister(input0),
3243            g.UseRegister(input1), g.UseImmediate(Pack4Lanes(shuffle32x4)));
3244     }
3245     return;
3246   }
3247   if (TryMatchDup<8>(shuffle, &index)) {
3248     DCHECK_GT(8, index);
3249     Emit(kArm64S128Dup, g.DefineAsRegister(node), g.UseRegister(input0),
3250          g.UseImmediate(8), g.UseImmediate(index % 8));
3251     return;
3252   }
3253   if (TryMatchDup<16>(shuffle, &index)) {
3254     DCHECK_GT(16, index);
3255     Emit(kArm64S128Dup, g.DefineAsRegister(node), g.UseRegister(input0),
3256          g.UseImmediate(16), g.UseImmediate(index % 16));
3257     return;
3258   }
3259   // Code generator uses vtbl, arrange sources to form a valid lookup table.
3260   InstructionOperand src0, src1;
3261   ArrangeShuffleTable(&g, input0, input1, &src0, &src1);
3262   Emit(kArm64S8x16Shuffle, g.DefineAsRegister(node), src0, src1,
3263        g.UseImmediate(Pack4Lanes(shuffle)),
3264        g.UseImmediate(Pack4Lanes(shuffle + 4)),
3265        g.UseImmediate(Pack4Lanes(shuffle + 8)),
3266        g.UseImmediate(Pack4Lanes(shuffle + 12)));
3267 }
3268 
VisitSignExtendWord8ToInt32(Node * node)3269 void InstructionSelector::VisitSignExtendWord8ToInt32(Node* node) {
3270   VisitRR(this, kArm64Sxtb32, node);
3271 }
3272 
VisitSignExtendWord16ToInt32(Node * node)3273 void InstructionSelector::VisitSignExtendWord16ToInt32(Node* node) {
3274   VisitRR(this, kArm64Sxth32, node);
3275 }
3276 
VisitSignExtendWord8ToInt64(Node * node)3277 void InstructionSelector::VisitSignExtendWord8ToInt64(Node* node) {
3278   VisitRR(this, kArm64Sxtb, node);
3279 }
3280 
VisitSignExtendWord16ToInt64(Node * node)3281 void InstructionSelector::VisitSignExtendWord16ToInt64(Node* node) {
3282   VisitRR(this, kArm64Sxth, node);
3283 }
3284 
VisitSignExtendWord32ToInt64(Node * node)3285 void InstructionSelector::VisitSignExtendWord32ToInt64(Node* node) {
3286   VisitRR(this, kArm64Sxtw, node);
3287 }
3288 
3289 // static
3290 MachineOperatorBuilder::Flags
SupportedMachineOperatorFlags()3291 InstructionSelector::SupportedMachineOperatorFlags() {
3292   return MachineOperatorBuilder::kFloat32RoundDown |
3293          MachineOperatorBuilder::kFloat64RoundDown |
3294          MachineOperatorBuilder::kFloat32RoundUp |
3295          MachineOperatorBuilder::kFloat64RoundUp |
3296          MachineOperatorBuilder::kFloat32RoundTruncate |
3297          MachineOperatorBuilder::kFloat64RoundTruncate |
3298          MachineOperatorBuilder::kFloat64RoundTiesAway |
3299          MachineOperatorBuilder::kFloat32RoundTiesEven |
3300          MachineOperatorBuilder::kFloat64RoundTiesEven |
3301          MachineOperatorBuilder::kWord32ShiftIsSafe |
3302          MachineOperatorBuilder::kInt32DivIsSafe |
3303          MachineOperatorBuilder::kUint32DivIsSafe |
3304          MachineOperatorBuilder::kWord32ReverseBits |
3305          MachineOperatorBuilder::kWord64ReverseBits |
3306          MachineOperatorBuilder::kSpeculationFence;
3307 }
3308 
3309 // static
3310 MachineOperatorBuilder::AlignmentRequirements
AlignmentRequirements()3311 InstructionSelector::AlignmentRequirements() {
3312   return MachineOperatorBuilder::AlignmentRequirements::
3313       FullUnalignedAccessSupport();
3314 }
3315 
3316 }  // namespace compiler
3317 }  // namespace internal
3318 }  // namespace v8
3319