5 #include "src/base/adapters.h" 6 #include "src/base/bits.h" 7 #include "src/compiler/backend/instruction-selector-impl.h" 8 #include "src/compiler/node-matchers.h" 9 #include "src/compiler/node-properties.h" 21 bool CanBeImmediate(int32_t value)
const {
22 return Assembler::ImmediateFitsAddrMode1Instruction(value);
25 bool CanBeImmediate(
uint32_t value)
const {
26 return CanBeImmediate(bit_cast<int32_t>(value));
29 bool CanBeImmediate(
Node* node, InstructionCode opcode) {
31 if (!m.HasValue())
return false;
32 int32_t value = m.Value();
33 switch (ArchOpcodeField::decode(opcode)) {
38 return CanBeImmediate(value) || CanBeImmediate(~value);
44 return CanBeImmediate(value) || CanBeImmediate(-value);
51 return CanBeImmediate(value);
57 return value >= -1020 && value <= 1020 && (value % 4) == 0;
64 return value >= -4095 && value <= 4095;
69 return value >= -255 && value <= 255;
80 if (node->opcode() == IrOpcode::kLoadStackPointer) {
82 LocationOperand::REGISTER,
83 MachineRepresentation::kWord32, sp.code());
85 return UseRegister(node);
93 selector->Emit(opcode, g.DefineAsRegister(node),
94 g.UseRegister(node->InputAt(0)));
97 void VisitRRR(InstructionSelector* selector, ArchOpcode opcode,
Node* node) {
98 ArmOperandGenerator g(selector);
99 selector->Emit(opcode, g.DefineAsRegister(node),
100 g.UseRegister(node->InputAt(0)),
101 g.UseRegister(node->InputAt(1)));
104 void VisitRRRShuffle(InstructionSelector* selector, ArchOpcode opcode,
106 ArmOperandGenerator g(selector);
108 if (opcode == kArmS32x4ZipRight || opcode == kArmS32x4UnzipRight ||
109 opcode == kArmS32x4TransposeRight || opcode == kArmS16x8ZipRight ||
110 opcode == kArmS16x8UnzipRight || opcode == kArmS16x8TransposeRight ||
111 opcode == kArmS8x16ZipRight || opcode == kArmS8x16UnzipRight ||
112 opcode == kArmS8x16TransposeRight) {
113 Node* in0 = node->InputAt(0);
114 Node* in1 = node->InputAt(1);
115 node->ReplaceInput(0, in1);
116 node->ReplaceInput(1, in0);
120 selector->Emit(opcode, g.DefineSameAsFirst(node),
121 g.UseRegister(node->InputAt(0)),
122 g.UseRegister(node->InputAt(1)));
125 void VisitRRI(InstructionSelector* selector, ArchOpcode opcode, Node* node) {
126 ArmOperandGenerator g(selector);
127 int32_t imm = OpParameter<int32_t>(node->op());
128 selector->Emit(opcode, g.DefineAsRegister(node),
129 g.UseRegister(node->InputAt(0)), g.UseImmediate(imm));
132 void VisitRRIR(InstructionSelector* selector, ArchOpcode opcode, Node* node) {
133 ArmOperandGenerator g(selector);
134 int32_t imm = OpParameter<int32_t>(node->op());
135 selector->Emit(opcode, g.DefineAsRegister(node),
136 g.UseRegister(node->InputAt(0)), g.UseImmediate(imm),
137 g.UseRegister(node->InputAt(1)));
140 template <IrOpcode::Value kOpcode,
int kImmMin,
int kImmMax,
141 AddressingMode kImmMode, AddressingMode kRegMode>
142 bool TryMatchShift(InstructionSelector* selector,
143 InstructionCode* opcode_return, Node* node,
144 InstructionOperand* value_return,
145 InstructionOperand* shift_return) {
146 ArmOperandGenerator g(selector);
147 if (node->opcode() == kOpcode) {
148 Int32BinopMatcher m(node);
149 *value_return = g.UseRegister(m.left().node());
150 if (m.right().IsInRange(kImmMin, kImmMax)) {
151 *opcode_return |= AddressingModeField::encode(kImmMode);
152 *shift_return = g.UseImmediate(m.right().node());
154 *opcode_return |= AddressingModeField::encode(kRegMode);
155 *shift_return = g.UseRegister(m.right().node());
162 template <IrOpcode::Value kOpcode,
int kImmMin,
int kImmMax,
163 AddressingMode kImmMode>
164 bool TryMatchShiftImmediate(InstructionSelector* selector,
165 InstructionCode* opcode_return, Node* node,
166 InstructionOperand* value_return,
167 InstructionOperand* shift_return) {
168 ArmOperandGenerator g(selector);
169 if (node->opcode() == kOpcode) {
170 Int32BinopMatcher m(node);
171 if (m.right().IsInRange(kImmMin, kImmMax)) {
172 *opcode_return |= AddressingModeField::encode(kImmMode);
173 *value_return = g.UseRegister(m.left().node());
174 *shift_return = g.UseImmediate(m.right().node());
181 bool TryMatchROR(InstructionSelector* selector, InstructionCode* opcode_return,
182 Node* node, InstructionOperand* value_return,
183 InstructionOperand* shift_return) {
184 return TryMatchShift<IrOpcode::kWord32Ror, 1, 31, kMode_Operand2_R_ROR_I,
185 kMode_Operand2_R_ROR_R>(selector, opcode_return, node,
186 value_return, shift_return);
189 bool TryMatchASR(InstructionSelector* selector, InstructionCode* opcode_return,
190 Node* node, InstructionOperand* value_return,
191 InstructionOperand* shift_return) {
192 return TryMatchShift<IrOpcode::kWord32Sar, 1, 32, kMode_Operand2_R_ASR_I,
193 kMode_Operand2_R_ASR_R>(selector, opcode_return, node,
194 value_return, shift_return);
197 bool TryMatchLSL(InstructionSelector* selector, InstructionCode* opcode_return,
198 Node* node, InstructionOperand* value_return,
199 InstructionOperand* shift_return) {
200 return TryMatchShift<IrOpcode::kWord32Shl, 0, 31, kMode_Operand2_R_LSL_I,
201 kMode_Operand2_R_LSL_R>(selector, opcode_return, node,
202 value_return, shift_return);
205 bool TryMatchLSLImmediate(InstructionSelector* selector,
206 InstructionCode* opcode_return, Node* node,
207 InstructionOperand* value_return,
208 InstructionOperand* shift_return) {
209 return TryMatchShiftImmediate<IrOpcode::kWord32Shl, 0, 31,
210 kMode_Operand2_R_LSL_I>(
211 selector, opcode_return, node, value_return, shift_return);
214 bool TryMatchLSR(InstructionSelector* selector, InstructionCode* opcode_return,
215 Node* node, InstructionOperand* value_return,
216 InstructionOperand* shift_return) {
217 return TryMatchShift<IrOpcode::kWord32Shr, 1, 32, kMode_Operand2_R_LSR_I,
218 kMode_Operand2_R_LSR_R>(selector, opcode_return, node,
219 value_return, shift_return);
222 bool TryMatchShift(InstructionSelector* selector,
223 InstructionCode* opcode_return, Node* node,
224 InstructionOperand* value_return,
225 InstructionOperand* shift_return) {
227 TryMatchASR(selector, opcode_return, node, value_return, shift_return) ||
228 TryMatchLSL(selector, opcode_return, node, value_return, shift_return) ||
229 TryMatchLSR(selector, opcode_return, node, value_return, shift_return) ||
230 TryMatchROR(selector, opcode_return, node, value_return, shift_return));
233 bool TryMatchImmediateOrShift(InstructionSelector* selector,
234 InstructionCode* opcode_return, Node* node,
235 size_t* input_count_return,
236 InstructionOperand* inputs) {
237 ArmOperandGenerator g(selector);
238 if (g.CanBeImmediate(node, *opcode_return)) {
239 *opcode_return |= AddressingModeField::encode(kMode_Operand2_I);
240 inputs[0] = g.UseImmediate(node);
241 *input_count_return = 1;
244 if (TryMatchShift(selector, opcode_return, node, &inputs[0], &inputs[1])) {
245 *input_count_return = 2;
251 void VisitBinop(InstructionSelector* selector, Node* node,
252 InstructionCode opcode, InstructionCode reverse_opcode,
253 FlagsContinuation* cont) {
254 ArmOperandGenerator g(selector);
255 Int32BinopMatcher m(node);
256 InstructionOperand inputs[3];
257 size_t input_count = 0;
258 InstructionOperand outputs[1];
259 size_t output_count = 0;
261 if (m.left().node() == m.right().node()) {
269 InstructionOperand
const input = g.UseRegister(m.left().node());
270 opcode |= AddressingModeField::encode(kMode_Operand2_R);
271 inputs[input_count++] = input;
272 inputs[input_count++] = input;
273 }
else if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(),
274 &input_count, &inputs[1])) {
275 inputs[0] = g.UseRegister(m.left().node());
277 }
else if (TryMatchImmediateOrShift(selector, &reverse_opcode,
278 m.left().node(), &input_count,
280 inputs[0] = g.UseRegister(m.right().node());
281 opcode = reverse_opcode;
284 opcode |= AddressingModeField::encode(kMode_Operand2_R);
285 inputs[input_count++] = g.UseRegister(m.left().node());
286 inputs[input_count++] = g.UseRegister(m.right().node());
289 outputs[output_count++] = g.DefineAsRegister(node);
291 DCHECK_NE(0u, input_count);
292 DCHECK_EQ(1u, output_count);
293 DCHECK_GE(arraysize(inputs), input_count);
294 DCHECK_GE(arraysize(outputs), output_count);
295 DCHECK_NE(kMode_None, AddressingModeField::decode(opcode));
297 selector->EmitWithContinuation(opcode, output_count, outputs, input_count,
301 void VisitBinop(InstructionSelector* selector, Node* node,
302 InstructionCode opcode, InstructionCode reverse_opcode) {
303 FlagsContinuation cont;
304 VisitBinop(selector, node, opcode, reverse_opcode, &cont);
307 void EmitDiv(InstructionSelector* selector, ArchOpcode div_opcode,
308 ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode,
309 InstructionOperand result_operand, InstructionOperand left_operand,
310 InstructionOperand right_operand) {
311 ArmOperandGenerator g(selector);
312 if (selector->IsSupported(SUDIV)) {
313 selector->Emit(div_opcode, result_operand, left_operand, right_operand);
316 InstructionOperand left_double_operand = g.TempDoubleRegister();
317 InstructionOperand right_double_operand = g.TempDoubleRegister();
318 InstructionOperand result_double_operand = g.TempDoubleRegister();
319 selector->Emit(f64i32_opcode, left_double_operand, left_operand);
320 selector->Emit(f64i32_opcode, right_double_operand, right_operand);
321 selector->Emit(kArmVdivF64, result_double_operand, left_double_operand,
322 right_double_operand);
323 selector->Emit(i32f64_opcode, result_operand, result_double_operand);
326 void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode div_opcode,
327 ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode) {
328 ArmOperandGenerator g(selector);
329 Int32BinopMatcher m(node);
330 EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode,
331 g.DefineAsRegister(node), g.UseRegister(m.left().node()),
332 g.UseRegister(m.right().node()));
335 void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode div_opcode,
336 ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode) {
337 ArmOperandGenerator g(selector);
338 Int32BinopMatcher m(node);
339 InstructionOperand div_operand = g.TempRegister();
340 InstructionOperand result_operand = g.DefineAsRegister(node);
341 InstructionOperand left_operand = g.UseRegister(m.left().node());
342 InstructionOperand right_operand = g.UseRegister(m.right().node());
343 EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode, div_operand,
344 left_operand, right_operand);
345 if (selector->IsSupported(ARMv7)) {
346 selector->Emit(kArmMls, result_operand, div_operand, right_operand,
349 InstructionOperand mul_operand = g.TempRegister();
350 selector->Emit(kArmMul, mul_operand, div_operand, right_operand);
351 selector->Emit(kArmSub | AddressingModeField::encode(kMode_Operand2_R),
352 result_operand, left_operand, mul_operand);
356 void EmitLoad(InstructionSelector* selector, InstructionCode opcode,
357 InstructionOperand* output, Node* base, Node* index) {
358 ArmOperandGenerator g(selector);
359 InstructionOperand inputs[3];
360 size_t input_count = 2;
362 inputs[0] = g.UseRegister(base);
363 if (g.CanBeImmediate(index, opcode)) {
364 inputs[1] = g.UseImmediate(index);
365 opcode |= AddressingModeField::encode(kMode_Offset_RI);
366 }
else if ((opcode == kArmLdr) &&
367 TryMatchLSLImmediate(selector, &opcode, index, &inputs[1],
371 inputs[1] = g.UseRegister(index);
372 opcode |= AddressingModeField::encode(kMode_Offset_RR);
374 selector->Emit(opcode, 1, output, input_count, inputs);
377 void EmitStore(InstructionSelector* selector, InstructionCode opcode,
378 size_t input_count, InstructionOperand* inputs, Node* index) {
379 ArmOperandGenerator g(selector);
381 if (g.CanBeImmediate(index, opcode)) {
382 inputs[input_count++] = g.UseImmediate(index);
383 opcode |= AddressingModeField::encode(kMode_Offset_RI);
384 }
else if ((opcode == kArmStr) &&
385 TryMatchLSLImmediate(selector, &opcode, index, &inputs[2],
389 inputs[input_count++] = g.UseRegister(index);
390 opcode |= AddressingModeField::encode(kMode_Offset_RR);
392 selector->Emit(opcode, 0,
nullptr, input_count, inputs);
395 void VisitPairAtomicBinOp(InstructionSelector* selector, Node* node,
397 ArmOperandGenerator g(selector);
398 Node* base = node->InputAt(0);
399 Node* index = node->InputAt(1);
400 Node* value = node->InputAt(2);
401 Node* value_high = node->InputAt(3);
402 AddressingMode addressing_mode = kMode_Offset_RR;
403 InstructionOperand inputs[] = {
404 g.UseUniqueRegister(value), g.UseUniqueRegister(value_high),
405 g.UseUniqueRegister(base), g.UseUniqueRegister(index)};
406 Node* projection0 = NodeProperties::FindProjection(node, 0);
407 Node* projection1 = NodeProperties::FindProjection(node, 1);
408 InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
410 InstructionOperand outputs[] = {g.DefineAsFixed(projection0, r2),
411 g.DefineAsFixed(projection1, r3)};
412 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister(r6),
413 g.TempRegister(r7), g.TempRegister()};
414 selector->Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
415 arraysize(temps), temps);
416 }
else if (projection0) {
417 InstructionOperand outputs[] = {g.DefineAsFixed(projection0, r2)};
418 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister(r6),
419 g.TempRegister(r7), g.TempRegister(),
421 selector->Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
422 arraysize(temps), temps);
424 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister(r6),
425 g.TempRegister(r7), g.TempRegister(),
426 g.TempRegister(r2), g.TempRegister(r3)};
427 selector->Emit(code, 0,
nullptr, arraysize(inputs), inputs,
428 arraysize(temps), temps);
434 void InstructionSelector::VisitStackSlot(Node* node) {
435 StackSlotRepresentation rep = StackSlotRepresentationOf(node->op());
436 int slot = frame_->AllocateSpillSlot(rep.size());
437 OperandGenerator g(
this);
439 Emit(kArchStackSlot, g.DefineAsRegister(node),
440 sequence()->AddImmediate(Constant(slot)), 0,
nullptr);
443 void InstructionSelector::VisitDebugAbort(Node* node) {
444 ArmOperandGenerator g(
this);
445 Emit(kArchDebugAbort, g.NoOutput(), g.UseFixed(node->InputAt(0), r1));
448 void InstructionSelector::VisitLoad(Node* node) {
449 LoadRepresentation load_rep = LoadRepresentationOf(node->op());
450 ArmOperandGenerator g(
this);
451 Node* base = node->InputAt(0);
452 Node* index = node->InputAt(1);
454 InstructionCode opcode = kArchNop;
455 switch (load_rep.representation()) {
456 case MachineRepresentation::kFloat32:
457 opcode = kArmVldrF32;
459 case MachineRepresentation::kFloat64:
460 opcode = kArmVldrF64;
462 case MachineRepresentation::kBit:
463 case MachineRepresentation::kWord8:
464 opcode = load_rep.IsUnsigned() ? kArmLdrb : kArmLdrsb;
466 case MachineRepresentation::kWord16:
467 opcode = load_rep.IsUnsigned() ? kArmLdrh : kArmLdrsh;
469 case MachineRepresentation::kTaggedSigned:
470 case MachineRepresentation::kTaggedPointer:
471 case MachineRepresentation::kTagged:
472 case MachineRepresentation::kWord32:
475 case MachineRepresentation::kSimd128:
476 opcode = kArmVld1S128;
478 case MachineRepresentation::kWord64:
479 case MachineRepresentation::kNone:
483 if (node->opcode() == IrOpcode::kPoisonedLoad) {
484 CHECK_NE(poisoning_level_, PoisoningMitigationLevel::kDontPoison);
485 opcode |= MiscField::encode(kMemoryAccessPoisoned);
488 InstructionOperand output = g.DefineAsRegister(node);
489 EmitLoad(
this, opcode, &output, base, index);
492 void InstructionSelector::VisitPoisonedLoad(Node* node) { VisitLoad(node); }
494 void InstructionSelector::VisitProtectedLoad(Node* node) {
499 void InstructionSelector::VisitStore(Node* node) {
500 ArmOperandGenerator g(
this);
501 Node* base = node->InputAt(0);
502 Node* index = node->InputAt(1);
503 Node* value = node->InputAt(2);
505 StoreRepresentation store_rep = StoreRepresentationOf(node->op());
506 WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind();
507 MachineRepresentation rep = store_rep.representation();
509 if (write_barrier_kind != kNoWriteBarrier) {
510 DCHECK(CanBeTaggedPointer(rep));
511 AddressingMode addressing_mode;
512 InstructionOperand inputs[3];
513 size_t input_count = 0;
514 inputs[input_count++] = g.UseUniqueRegister(base);
517 if (g.CanBeImmediate(index, kArmAdd) && g.CanBeImmediate(index, kArmStr)) {
518 inputs[input_count++] = g.UseImmediate(index);
519 addressing_mode = kMode_Offset_RI;
521 inputs[input_count++] = g.UseUniqueRegister(index);
522 addressing_mode = kMode_Offset_RR;
524 inputs[input_count++] = g.UseUniqueRegister(value);
525 RecordWriteMode record_write_mode = RecordWriteMode::kValueIsAny;
526 switch (write_barrier_kind) {
527 case kNoWriteBarrier:
530 case kMapWriteBarrier:
531 record_write_mode = RecordWriteMode::kValueIsMap;
533 case kPointerWriteBarrier:
534 record_write_mode = RecordWriteMode::kValueIsPointer;
536 case kFullWriteBarrier:
537 record_write_mode = RecordWriteMode::kValueIsAny;
540 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
541 size_t const temp_count = arraysize(temps);
542 InstructionCode code = kArchStoreWithWriteBarrier;
543 code |= AddressingModeField::encode(addressing_mode);
544 code |= MiscField::encode(static_cast<int>(record_write_mode));
545 Emit(code, 0,
nullptr, input_count, inputs, temp_count, temps);
547 InstructionCode opcode = kArchNop;
549 case MachineRepresentation::kFloat32:
550 opcode = kArmVstrF32;
552 case MachineRepresentation::kFloat64:
553 opcode = kArmVstrF64;
555 case MachineRepresentation::kBit:
556 case MachineRepresentation::kWord8:
559 case MachineRepresentation::kWord16:
562 case MachineRepresentation::kTaggedSigned:
563 case MachineRepresentation::kTaggedPointer:
564 case MachineRepresentation::kTagged:
565 case MachineRepresentation::kWord32:
568 case MachineRepresentation::kSimd128:
569 opcode = kArmVst1S128;
571 case MachineRepresentation::kWord64:
572 case MachineRepresentation::kNone:
577 InstructionOperand inputs[4];
578 size_t input_count = 0;
579 inputs[input_count++] = g.UseRegister(value);
580 inputs[input_count++] = g.UseRegister(base);
581 EmitStore(
this, opcode, input_count, inputs, index);
585 void InstructionSelector::VisitProtectedStore(Node* node) {
590 void InstructionSelector::VisitUnalignedLoad(Node* node) {
591 MachineRepresentation load_rep =
592 LoadRepresentationOf(node->op()).representation();
593 ArmOperandGenerator g(
this);
594 Node* base = node->InputAt(0);
595 Node* index = node->InputAt(1);
597 InstructionCode opcode = kArmLdr;
603 case MachineRepresentation::kFloat32: {
604 InstructionOperand temp = g.TempRegister();
605 EmitLoad(
this, opcode, &temp, base, index);
606 Emit(kArmVmovF32U32, g.DefineAsRegister(node), temp);
609 case MachineRepresentation::kFloat64:
610 case MachineRepresentation::kSimd128: {
615 InstructionCode add_opcode = kArmAdd;
616 InstructionOperand inputs[3];
617 inputs[0] = g.UseRegister(base);
620 if (TryMatchImmediateOrShift(
this, &add_opcode, index, &input_count,
626 add_opcode |= AddressingModeField::encode(kMode_Operand2_R);
627 inputs[1] = g.UseRegister(index);
631 InstructionOperand addr = g.TempRegister();
632 Emit(add_opcode, 1, &addr, input_count, inputs);
634 if (CpuFeatures::IsSupported(NEON)) {
636 InstructionCode op = load_rep == MachineRepresentation::kFloat64
639 op |= AddressingModeField::encode(kMode_Operand2_R);
640 Emit(op, g.DefineAsRegister(node), addr);
642 DCHECK_NE(MachineRepresentation::kSimd128, load_rep);
644 InstructionOperand fp_lo = g.TempRegister();
645 InstructionOperand fp_hi = g.TempRegister();
646 opcode |= AddressingModeField::encode(kMode_Offset_RI);
647 Emit(opcode, fp_lo, addr, g.TempImmediate(0));
648 Emit(opcode, fp_hi, addr, g.TempImmediate(4));
649 Emit(kArmVmovF64U32U32, g.DefineAsRegister(node), fp_lo, fp_hi);
660 void InstructionSelector::VisitUnalignedStore(Node* node) {
661 ArmOperandGenerator g(
this);
662 Node* base = node->InputAt(0);
663 Node* index = node->InputAt(1);
664 Node* value = node->InputAt(2);
666 InstructionOperand inputs[4];
667 size_t input_count = 0;
669 UnalignedStoreRepresentation store_rep =
670 UnalignedStoreRepresentationOf(node->op());
677 case MachineRepresentation::kFloat32: {
678 inputs[input_count++] = g.TempRegister();
679 Emit(kArmVmovU32F32, inputs[0], g.UseRegister(value));
680 inputs[input_count++] = g.UseRegister(base);
681 EmitStore(
this, kArmStr, input_count, inputs, index);
684 case MachineRepresentation::kFloat64:
685 case MachineRepresentation::kSimd128: {
686 if (CpuFeatures::IsSupported(NEON)) {
687 InstructionOperand address = g.TempRegister();
690 InstructionCode add_opcode = kArmAdd;
691 InstructionOperand inputs[3];
692 inputs[0] = g.UseRegister(base);
695 if (TryMatchImmediateOrShift(
this, &add_opcode, index, &input_count,
701 add_opcode |= AddressingModeField::encode(kMode_Operand2_R);
702 inputs[1] = g.UseRegister(index);
706 Emit(add_opcode, 1, &address, input_count, inputs);
709 inputs[input_count++] = g.UseRegister(value);
710 inputs[input_count++] = address;
711 InstructionCode op = store_rep == MachineRepresentation::kFloat64
714 op |= AddressingModeField::encode(kMode_Operand2_R);
715 Emit(op, 0,
nullptr, input_count, inputs);
717 DCHECK_NE(MachineRepresentation::kSimd128, store_rep);
724 InstructionOperand fp[] = {g.TempRegister(), g.TempRegister()};
725 inputs[input_count++] = g.UseRegister(value);
726 Emit(kArmVmovU32U32F64, arraysize(fp), fp, input_count, inputs);
730 inputs[input_count++] =
732 EmitStore(
this, kArmStr, input_count, inputs, index);
735 InstructionOperand base4 = g.TempRegister();
736 Emit(kArmAdd | AddressingModeField::encode(kMode_Operand2_I), base4,
737 g.UseRegister(base), g.TempImmediate(4));
740 EmitStore(
this, kArmStr, input_count, inputs, index);
753 void EmitBic(InstructionSelector* selector, Node* node, Node* left,
755 ArmOperandGenerator g(selector);
756 InstructionCode opcode = kArmBic;
757 InstructionOperand value_operand;
758 InstructionOperand shift_operand;
759 if (TryMatchShift(selector, &opcode, right, &value_operand, &shift_operand)) {
760 selector->Emit(opcode, g.DefineAsRegister(node), g.UseRegister(left),
761 value_operand, shift_operand);
764 selector->Emit(opcode | AddressingModeField::encode(kMode_Operand2_R),
765 g.DefineAsRegister(node), g.UseRegister(left),
766 g.UseRegister(right));
769 void EmitUbfx(InstructionSelector* selector, Node* node, Node* left,
771 DCHECK_LE(1u, width);
772 DCHECK_LE(width, 32u - lsb);
773 ArmOperandGenerator g(selector);
774 selector->Emit(kArmUbfx, g.DefineAsRegister(node), g.UseRegister(left),
775 g.TempImmediate(lsb), g.TempImmediate(width));
780 void InstructionSelector::VisitWord32And(Node* node) {
781 ArmOperandGenerator g(
this);
782 Int32BinopMatcher m(node);
783 if (m.left().IsWord32Xor() && CanCover(node, m.left().node())) {
784 Int32BinopMatcher mleft(m.left().node());
785 if (mleft.right().Is(-1)) {
786 EmitBic(
this, node, m.right().node(), mleft.left().node());
790 if (m.right().IsWord32Xor() && CanCover(node, m.right().node())) {
791 Int32BinopMatcher mright(m.right().node());
792 if (mright.right().Is(-1)) {
793 EmitBic(
this, node, m.left().node(), mright.left().node());
797 if (m.right().HasValue()) {
798 uint32_t const value = m.right().Value();
799 uint32_t width = base::bits::CountPopulation(value);
800 uint32_t leading_zeros = base::bits::CountLeadingZeros32(value);
803 if (m.left().IsWord32Shr()) {
804 Int32BinopMatcher mshr(m.left().node());
805 if (mshr.right().HasValue()) {
806 uint32_t const shift = mshr.right().Value();
808 if (((shift == 8) || (shift == 16) || (shift == 24)) &&
812 Emit(kArmUxtb, g.DefineAsRegister(m.node()),
813 g.UseRegister(mshr.left().node()),
814 g.TempImmediate(mshr.right().Value()));
816 }
else if (((shift == 8) || (shift == 16)) && (value == 0xFFFF)) {
819 Emit(kArmUxth, g.DefineAsRegister(m.node()),
820 g.UseRegister(mshr.left().node()),
821 g.TempImmediate(mshr.right().Value()));
823 }
else if (IsSupported(ARMv7) && (width != 0) &&
824 ((leading_zeros + width) == 32)) {
826 DCHECK_EQ(0u, base::bits::CountTrailingZeros32(value));
827 if ((1 <= shift) && (shift <= 31)) {
832 EmitUbfx(
this, node, mshr.left().node(), shift,
833 std::min(width, 32 - shift));
838 }
else if (value == 0xFFFF) {
841 Emit(kArmUxth, g.DefineAsRegister(m.node()),
842 g.UseRegister(m.left().node()), g.TempImmediate(0));
845 if (g.CanBeImmediate(~value)) {
847 Emit(kArmBic | AddressingModeField::encode(kMode_Operand2_I),
848 g.DefineAsRegister(node), g.UseRegister(m.left().node()),
849 g.TempImmediate(~value));
852 if (!g.CanBeImmediate(value) && IsSupported(ARMv7)) {
856 if ((width != 0) && ((leading_zeros + width) == 32) &&
857 (9 <= leading_zeros) && (leading_zeros <= 23)) {
858 DCHECK_EQ(0u, base::bits::CountTrailingZeros32(value));
859 EmitUbfx(
this, node, m.left().node(), 0, width);
864 leading_zeros = base::bits::CountLeadingZeros32(~value);
865 uint32_t lsb = base::bits::CountTrailingZeros32(~value);
866 if ((leading_zeros + width + lsb) == 32) {
868 Emit(kArmBfc, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
869 g.TempImmediate(lsb), g.TempImmediate(width));
874 VisitBinop(
this, node, kArmAnd, kArmAnd);
877 void InstructionSelector::VisitWord32Or(Node* node) {
878 VisitBinop(
this, node, kArmOrr, kArmOrr);
881 void InstructionSelector::VisitWord32Xor(Node* node) {
882 ArmOperandGenerator g(
this);
883 Int32BinopMatcher m(node);
884 if (m.right().Is(-1)) {
885 InstructionCode opcode = kArmMvn;
886 InstructionOperand value_operand;
887 InstructionOperand shift_operand;
888 if (TryMatchShift(
this, &opcode, m.left().node(), &value_operand,
890 Emit(opcode, g.DefineAsRegister(node), value_operand, shift_operand);
893 Emit(opcode | AddressingModeField::encode(kMode_Operand2_R),
894 g.DefineAsRegister(node), g.UseRegister(m.left().node()));
897 VisitBinop(
this, node, kArmEor, kArmEor);
902 template <
typename TryMatchShift>
903 void VisitShift(InstructionSelector* selector, Node* node,
904 TryMatchShift try_match_shift, FlagsContinuation* cont) {
905 ArmOperandGenerator g(selector);
906 InstructionCode opcode = kArmMov;
907 InstructionOperand inputs[2];
908 size_t input_count = 2;
909 InstructionOperand outputs[1];
910 size_t output_count = 0;
912 CHECK(try_match_shift(selector, &opcode, node, &inputs[0], &inputs[1]));
914 outputs[output_count++] = g.DefineAsRegister(node);
916 DCHECK_NE(0u, input_count);
917 DCHECK_NE(0u, output_count);
918 DCHECK_GE(arraysize(inputs), input_count);
919 DCHECK_GE(arraysize(outputs), output_count);
920 DCHECK_NE(kMode_None, AddressingModeField::decode(opcode));
922 selector->EmitWithContinuation(opcode, output_count, outputs, input_count,
926 template <
typename TryMatchShift>
927 void VisitShift(InstructionSelector* selector, Node* node,
928 TryMatchShift try_match_shift) {
929 FlagsContinuation cont;
930 VisitShift(selector, node, try_match_shift, &cont);
935 void InstructionSelector::VisitWord32Shl(Node* node) {
936 VisitShift(
this, node, TryMatchLSL);
939 void InstructionSelector::VisitWord32Shr(Node* node) {
940 ArmOperandGenerator g(
this);
941 Int32BinopMatcher m(node);
942 if (IsSupported(ARMv7) && m.left().IsWord32And() &&
943 m.right().IsInRange(0, 31)) {
945 Int32BinopMatcher mleft(m.left().node());
946 if (mleft.right().HasValue()) {
947 uint32_t value = (mleft.right().Value() >> lsb) << lsb;
948 uint32_t width = base::bits::CountPopulation(value);
949 uint32_t msb = base::bits::CountLeadingZeros32(value);
950 if (msb + width + lsb == 32) {
951 DCHECK_EQ(lsb, base::bits::CountTrailingZeros32(value));
952 return EmitUbfx(
this, node, mleft.left().node(), lsb, width);
956 VisitShift(
this, node, TryMatchLSR);
959 void InstructionSelector::VisitWord32Sar(Node* node) {
960 ArmOperandGenerator g(
this);
961 Int32BinopMatcher m(node);
962 if (CanCover(m.node(), m.left().node()) && m.left().IsWord32Shl()) {
963 Int32BinopMatcher mleft(m.left().node());
964 if (m.right().HasValue() && mleft.right().HasValue()) {
966 uint32_t shl = mleft.right().Value();
967 if ((sar == shl) && (sar == 16)) {
968 Emit(kArmSxth, g.DefineAsRegister(node),
969 g.UseRegister(mleft.left().node()), g.TempImmediate(0));
971 }
else if ((sar == shl) && (sar == 24)) {
972 Emit(kArmSxtb, g.DefineAsRegister(node),
973 g.UseRegister(mleft.left().node()), g.TempImmediate(0));
975 }
else if (IsSupported(ARMv7) && (sar >= shl)) {
976 Emit(kArmSbfx, g.DefineAsRegister(node),
977 g.UseRegister(mleft.left().node()), g.TempImmediate(sar - shl),
978 g.TempImmediate(32 - sar));
983 VisitShift(
this, node, TryMatchASR);
986 void InstructionSelector::VisitInt32PairAdd(Node* node) {
987 ArmOperandGenerator g(
this);
989 Node* projection1 = NodeProperties::FindProjection(node, 1);
993 InstructionOperand inputs[] = {
994 g.UseRegister(node->InputAt(0)), g.UseUniqueRegister(node->InputAt(1)),
995 g.UseRegister(node->InputAt(2)), g.UseUniqueRegister(node->InputAt(3))};
997 InstructionOperand outputs[] = {
998 g.DefineAsRegister(node),
999 g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
1001 Emit(kArmAddPair, 2, outputs, 4, inputs);
1005 Emit(kArmAdd | AddressingModeField::encode(kMode_Operand2_R),
1006 g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)),
1007 g.UseRegister(node->InputAt(2)));
1011 void InstructionSelector::VisitInt32PairSub(Node* node) {
1012 ArmOperandGenerator g(
this);
1014 Node* projection1 = NodeProperties::FindProjection(node, 1);
1018 InstructionOperand inputs[] = {
1019 g.UseRegister(node->InputAt(0)), g.UseUniqueRegister(node->InputAt(1)),
1020 g.UseRegister(node->InputAt(2)), g.UseUniqueRegister(node->InputAt(3))};
1022 InstructionOperand outputs[] = {
1023 g.DefineAsRegister(node),
1024 g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
1026 Emit(kArmSubPair, 2, outputs, 4, inputs);
1030 Emit(kArmSub | AddressingModeField::encode(kMode_Operand2_R),
1031 g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)),
1032 g.UseRegister(node->InputAt(2)));
1036 void InstructionSelector::VisitInt32PairMul(Node* node) {
1037 ArmOperandGenerator g(
this);
1038 Node* projection1 = NodeProperties::FindProjection(node, 1);
1040 InstructionOperand inputs[] = {g.UseUniqueRegister(node->InputAt(0)),
1041 g.UseUniqueRegister(node->InputAt(1)),
1042 g.UseUniqueRegister(node->InputAt(2)),
1043 g.UseUniqueRegister(node->InputAt(3))};
1045 InstructionOperand outputs[] = {
1046 g.DefineAsRegister(node),
1047 g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
1049 Emit(kArmMulPair, 2, outputs, 4, inputs);
1053 Emit(kArmMul | AddressingModeField::encode(kMode_Operand2_R),
1054 g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)),
1055 g.UseRegister(node->InputAt(2)));
1061 void VisitWord32PairShift(InstructionSelector* selector, InstructionCode opcode,
1063 ArmOperandGenerator g(selector);
1066 Int32Matcher m(node->InputAt(2));
1067 InstructionOperand shift_operand;
1069 shift_operand = g.UseImmediate(m.node());
1071 shift_operand = g.UseUniqueRegister(m.node());
1074 InstructionOperand inputs[] = {g.UseUniqueRegister(node->InputAt(0)),
1075 g.UseUniqueRegister(node->InputAt(1)),
1078 Node* projection1 = NodeProperties::FindProjection(node, 1);
1080 InstructionOperand outputs[2];
1081 InstructionOperand temps[1];
1082 int32_t output_count = 0;
1083 int32_t temp_count = 0;
1085 outputs[output_count++] = g.DefineAsRegister(node);
1087 outputs[output_count++] = g.DefineAsRegister(projection1);
1089 temps[temp_count++] = g.TempRegister();
1092 selector->Emit(opcode, output_count, outputs, 3, inputs, temp_count, temps);
1095 void InstructionSelector::VisitWord32PairShl(Node* node) {
1096 VisitWord32PairShift(
this, kArmLslPair, node);
1099 void InstructionSelector::VisitWord32PairShr(Node* node) {
1100 VisitWord32PairShift(
this, kArmLsrPair, node);
1103 void InstructionSelector::VisitWord32PairSar(Node* node) {
1104 VisitWord32PairShift(
this, kArmAsrPair, node);
1107 void InstructionSelector::VisitWord32Ror(Node* node) {
1108 VisitShift(
this, node, TryMatchROR);
1111 void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); }
1113 void InstructionSelector::VisitWord32ReverseBits(Node* node) {
1114 DCHECK(IsSupported(ARMv7));
1115 VisitRR(
this, kArmRbit, node);
1118 void InstructionSelector::VisitWord64ReverseBytes(Node* node) { UNREACHABLE(); }
1120 void InstructionSelector::VisitWord32ReverseBytes(Node* node) {
1121 VisitRR(
this, kArmRev, node);
1124 void InstructionSelector::VisitWord32Popcnt(Node* node) { UNREACHABLE(); }
1126 void InstructionSelector::VisitSpeculationFence(Node* node) {
1127 ArmOperandGenerator g(
this);
1128 Emit(kArmDsbIsb, g.NoOutput());
1131 void InstructionSelector::VisitInt32Add(Node* node) {
1132 ArmOperandGenerator g(
this);
1133 Int32BinopMatcher m(node);
1134 if (CanCover(node, m.left().node())) {
1135 switch (m.left().opcode()) {
1136 case IrOpcode::kInt32Mul: {
1137 Int32BinopMatcher mleft(m.left().node());
1138 Emit(kArmMla, g.DefineAsRegister(node),
1139 g.UseRegister(mleft.left().node()),
1140 g.UseRegister(mleft.right().node()),
1141 g.UseRegister(m.right().node()));
1144 case IrOpcode::kInt32MulHigh: {
1145 Int32BinopMatcher mleft(m.left().node());
1146 Emit(kArmSmmla, g.DefineAsRegister(node),
1147 g.UseRegister(mleft.left().node()),
1148 g.UseRegister(mleft.right().node()),
1149 g.UseRegister(m.right().node()));
1152 case IrOpcode::kWord32And: {
1153 Int32BinopMatcher mleft(m.left().node());
1154 if (mleft.right().Is(0xFF)) {
1155 Emit(kArmUxtab, g.DefineAsRegister(node),
1156 g.UseRegister(m.right().node()),
1157 g.UseRegister(mleft.left().node()), g.TempImmediate(0));
1159 }
else if (mleft.right().Is(0xFFFF)) {
1160 Emit(kArmUxtah, g.DefineAsRegister(node),
1161 g.UseRegister(m.right().node()),
1162 g.UseRegister(mleft.left().node()), g.TempImmediate(0));
1167 case IrOpcode::kWord32Sar: {
1168 Int32BinopMatcher mleft(m.left().node());
1169 if (CanCover(mleft.node(), mleft.left().node()) &&
1170 mleft.left().IsWord32Shl()) {
1171 Int32BinopMatcher mleftleft(mleft.left().node());
1172 if (mleft.right().Is(24) && mleftleft.right().Is(24)) {
1173 Emit(kArmSxtab, g.DefineAsRegister(node),
1174 g.UseRegister(m.right().node()),
1175 g.UseRegister(mleftleft.left().node()), g.TempImmediate(0));
1177 }
else if (mleft.right().Is(16) && mleftleft.right().Is(16)) {
1178 Emit(kArmSxtah, g.DefineAsRegister(node),
1179 g.UseRegister(m.right().node()),
1180 g.UseRegister(mleftleft.left().node()), g.TempImmediate(0));
1190 if (CanCover(node, m.right().node())) {
1191 switch (m.right().opcode()) {
1192 case IrOpcode::kInt32Mul: {
1193 Int32BinopMatcher mright(m.right().node());
1194 Emit(kArmMla, g.DefineAsRegister(node),
1195 g.UseRegister(mright.left().node()),
1196 g.UseRegister(mright.right().node()),
1197 g.UseRegister(m.left().node()));
1200 case IrOpcode::kInt32MulHigh: {
1201 Int32BinopMatcher mright(m.right().node());
1202 Emit(kArmSmmla, g.DefineAsRegister(node),
1203 g.UseRegister(mright.left().node()),
1204 g.UseRegister(mright.right().node()),
1205 g.UseRegister(m.left().node()));
1208 case IrOpcode::kWord32And: {
1209 Int32BinopMatcher mright(m.right().node());
1210 if (mright.right().Is(0xFF)) {
1211 Emit(kArmUxtab, g.DefineAsRegister(node),
1212 g.UseRegister(m.left().node()),
1213 g.UseRegister(mright.left().node()), g.TempImmediate(0));
1215 }
else if (mright.right().Is(0xFFFF)) {
1216 Emit(kArmUxtah, g.DefineAsRegister(node),
1217 g.UseRegister(m.left().node()),
1218 g.UseRegister(mright.left().node()), g.TempImmediate(0));
1223 case IrOpcode::kWord32Sar: {
1224 Int32BinopMatcher mright(m.right().node());
1225 if (CanCover(mright.node(), mright.left().node()) &&
1226 mright.left().IsWord32Shl()) {
1227 Int32BinopMatcher mrightleft(mright.left().node());
1228 if (mright.right().Is(24) && mrightleft.right().Is(24)) {
1229 Emit(kArmSxtab, g.DefineAsRegister(node),
1230 g.UseRegister(m.left().node()),
1231 g.UseRegister(mrightleft.left().node()), g.TempImmediate(0));
1233 }
else if (mright.right().Is(16) && mrightleft.right().Is(16)) {
1234 Emit(kArmSxtah, g.DefineAsRegister(node),
1235 g.UseRegister(m.left().node()),
1236 g.UseRegister(mrightleft.left().node()), g.TempImmediate(0));
1246 VisitBinop(
this, node, kArmAdd, kArmAdd);
1249 void InstructionSelector::VisitInt32Sub(Node* node) {
1250 ArmOperandGenerator g(
this);
1251 Int32BinopMatcher m(node);
1252 if (IsSupported(ARMv7) && m.right().IsInt32Mul() &&
1253 CanCover(node, m.right().node())) {
1254 Int32BinopMatcher mright(m.right().node());
1255 Emit(kArmMls, g.DefineAsRegister(node), g.UseRegister(mright.left().node()),
1256 g.UseRegister(mright.right().node()), g.UseRegister(m.left().node()));
1259 VisitBinop(
this, node, kArmSub, kArmRsb);
1264 void EmitInt32MulWithOverflow(InstructionSelector* selector, Node* node,
1265 FlagsContinuation* cont) {
1266 ArmOperandGenerator g(selector);
1267 Int32BinopMatcher m(node);
1268 InstructionOperand result_operand = g.DefineAsRegister(node);
1269 InstructionOperand temp_operand = g.TempRegister();
1270 InstructionOperand outputs[] = {result_operand, temp_operand};
1271 InstructionOperand inputs[] = {g.UseRegister(m.left().node()),
1272 g.UseRegister(m.right().node())};
1273 selector->Emit(kArmSmull, 2, outputs, 2, inputs);
1276 InstructionOperand shift_31 = g.UseImmediate(31);
1277 InstructionCode opcode =
1278 kArmCmp | AddressingModeField::encode(kMode_Operand2_R_ASR_I);
1279 selector->EmitWithContinuation(opcode, temp_operand, result_operand, shift_31,
1285 void InstructionSelector::VisitInt32Mul(Node* node) {
1286 ArmOperandGenerator g(
this);
1287 Int32BinopMatcher m(node);
1288 if (m.right().HasValue() && m.right().Value() > 0) {
1289 int32_t value = m.right().Value();
1290 if (base::bits::IsPowerOfTwo(value - 1)) {
1291 Emit(kArmAdd | AddressingModeField::encode(kMode_Operand2_R_LSL_I),
1292 g.DefineAsRegister(node), g.UseRegister(m.left().node()),
1293 g.UseRegister(m.left().node()),
1294 g.TempImmediate(WhichPowerOf2(value - 1)));
1297 if (value < kMaxInt && base::bits::IsPowerOfTwo(value + 1)) {
1298 Emit(kArmRsb | AddressingModeField::encode(kMode_Operand2_R_LSL_I),
1299 g.DefineAsRegister(node), g.UseRegister(m.left().node()),
1300 g.UseRegister(m.left().node()),
1301 g.TempImmediate(WhichPowerOf2(value + 1)));
1305 VisitRRR(
this, kArmMul, node);
1308 void InstructionSelector::VisitUint32MulHigh(Node* node) {
1309 ArmOperandGenerator g(
this);
1310 InstructionOperand outputs[] = {g.TempRegister(), g.DefineAsRegister(node)};
1311 InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0)),
1312 g.UseRegister(node->InputAt(1))};
1313 Emit(kArmUmull, arraysize(outputs), outputs, arraysize(inputs), inputs);
1316 void InstructionSelector::VisitInt32Div(Node* node) {
1317 VisitDiv(
this, node, kArmSdiv, kArmVcvtF64S32, kArmVcvtS32F64);
1320 void InstructionSelector::VisitUint32Div(Node* node) {
1321 VisitDiv(
this, node, kArmUdiv, kArmVcvtF64U32, kArmVcvtU32F64);
1324 void InstructionSelector::VisitInt32Mod(Node* node) {
1325 VisitMod(
this, node, kArmSdiv, kArmVcvtF64S32, kArmVcvtS32F64);
1328 void InstructionSelector::VisitUint32Mod(Node* node) {
1329 VisitMod(
this, node, kArmUdiv, kArmVcvtF64U32, kArmVcvtU32F64);
1332 #define RR_OP_LIST(V) \ 1333 V(Word32Clz, kArmClz) \ 1334 V(ChangeFloat32ToFloat64, kArmVcvtF64F32) \ 1335 V(RoundInt32ToFloat32, kArmVcvtF32S32) \ 1336 V(RoundUint32ToFloat32, kArmVcvtF32U32) \ 1337 V(ChangeInt32ToFloat64, kArmVcvtF64S32) \ 1338 V(ChangeUint32ToFloat64, kArmVcvtF64U32) \ 1339 V(TruncateFloat32ToInt32, kArmVcvtS32F32) \ 1340 V(TruncateFloat32ToUint32, kArmVcvtU32F32) \ 1341 V(ChangeFloat64ToInt32, kArmVcvtS32F64) \ 1342 V(ChangeFloat64ToUint32, kArmVcvtU32F64) \ 1343 V(TruncateFloat64ToUint32, kArmVcvtU32F64) \ 1344 V(TruncateFloat64ToFloat32, kArmVcvtF32F64) \ 1345 V(TruncateFloat64ToWord32, kArchTruncateDoubleToI) \ 1346 V(RoundFloat64ToInt32, kArmVcvtS32F64) \ 1347 V(BitcastFloat32ToInt32, kArmVmovU32F32) \ 1348 V(BitcastInt32ToFloat32, kArmVmovF32U32) \ 1349 V(Float64ExtractLowWord32, kArmVmovLowU32F64) \ 1350 V(Float64ExtractHighWord32, kArmVmovHighU32F64) \ 1351 V(Float64SilenceNaN, kArmFloat64SilenceNaN) \ 1352 V(Float32Abs, kArmVabsF32) \ 1353 V(Float64Abs, kArmVabsF64) \ 1354 V(Float32Neg, kArmVnegF32) \ 1355 V(Float64Neg, kArmVnegF64) \ 1356 V(Float32Sqrt, kArmVsqrtF32) \ 1357 V(Float64Sqrt, kArmVsqrtF64) 1359 #define RR_OP_LIST_V8(V) \ 1360 V(Float32RoundDown, kArmVrintmF32) \ 1361 V(Float64RoundDown, kArmVrintmF64) \ 1362 V(Float32RoundUp, kArmVrintpF32) \ 1363 V(Float64RoundUp, kArmVrintpF64) \ 1364 V(Float32RoundTruncate, kArmVrintzF32) \ 1365 V(Float64RoundTruncate, kArmVrintzF64) \ 1366 V(Float64RoundTiesAway, kArmVrintaF64) \ 1367 V(Float32RoundTiesEven, kArmVrintnF32) \ 1368 V(Float64RoundTiesEven, kArmVrintnF64) 1370 #define RRR_OP_LIST(V) \ 1371 V(Int32MulHigh, kArmSmmul) \ 1372 V(Float32Mul, kArmVmulF32) \ 1373 V(Float64Mul, kArmVmulF64) \ 1374 V(Float32Div, kArmVdivF32) \ 1375 V(Float64Div, kArmVdivF64) \ 1376 V(Float32Max, kArmFloat32Max) \ 1377 V(Float64Max, kArmFloat64Max) \ 1378 V(Float32Min, kArmFloat32Min) \ 1379 V(Float64Min, kArmFloat64Min) 1381 #define RR_VISITOR(Name, opcode) \ 1382 void InstructionSelector::Visit##Name(Node* node) { \ 1383 VisitRR(this, opcode, node); \ 1385 RR_OP_LIST(RR_VISITOR)
1389 #define RR_VISITOR_V8(Name, opcode) \ 1390 void InstructionSelector::Visit##Name(Node* node) { \ 1391 DCHECK(CpuFeatures::IsSupported(ARMv8)); \ 1392 VisitRR(this, opcode, node); \ 1394 RR_OP_LIST_V8(RR_VISITOR_V8)
1395 #undef RR_VISITOR_V8 1396 #undef RR_OP_LIST_V8 1398 #define RRR_VISITOR(Name, opcode) \ 1399 void InstructionSelector::Visit##Name(Node* node) { \ 1400 VisitRRR(this, opcode, node); \ 1402 RRR_OP_LIST(RRR_VISITOR)
1406 void InstructionSelector::VisitFloat32Add(Node* node) {
1407 ArmOperandGenerator g(
this);
1408 Float32BinopMatcher m(node);
1409 if (m.left().IsFloat32Mul() && CanCover(node, m.left().node())) {
1410 Float32BinopMatcher mleft(m.left().node());
1411 Emit(kArmVmlaF32, g.DefineSameAsFirst(node),
1412 g.UseRegister(m.right().node()), g.UseRegister(mleft.left().node()),
1413 g.UseRegister(mleft.right().node()));
1416 if (m.right().IsFloat32Mul() && CanCover(node, m.right().node())) {
1417 Float32BinopMatcher mright(m.right().node());
1418 Emit(kArmVmlaF32, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
1419 g.UseRegister(mright.left().node()),
1420 g.UseRegister(mright.right().node()));
1423 VisitRRR(
this, kArmVaddF32, node);
1426 void InstructionSelector::VisitFloat64Add(Node* node) {
1427 ArmOperandGenerator g(
this);
1428 Float64BinopMatcher m(node);
1429 if (m.left().IsFloat64Mul() && CanCover(node, m.left().node())) {
1430 Float64BinopMatcher mleft(m.left().node());
1431 Emit(kArmVmlaF64, g.DefineSameAsFirst(node),
1432 g.UseRegister(m.right().node()), g.UseRegister(mleft.left().node()),
1433 g.UseRegister(mleft.right().node()));
1436 if (m.right().IsFloat64Mul() && CanCover(node, m.right().node())) {
1437 Float64BinopMatcher mright(m.right().node());
1438 Emit(kArmVmlaF64, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
1439 g.UseRegister(mright.left().node()),
1440 g.UseRegister(mright.right().node()));
1443 VisitRRR(
this, kArmVaddF64, node);
1446 void InstructionSelector::VisitFloat32Sub(Node* node) {
1447 ArmOperandGenerator g(
this);
1448 Float32BinopMatcher m(node);
1449 if (m.right().IsFloat32Mul() && CanCover(node, m.right().node())) {
1450 Float32BinopMatcher mright(m.right().node());
1451 Emit(kArmVmlsF32, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
1452 g.UseRegister(mright.left().node()),
1453 g.UseRegister(mright.right().node()));
1456 VisitRRR(
this, kArmVsubF32, node);
1459 void InstructionSelector::VisitFloat64Sub(Node* node) {
1460 ArmOperandGenerator g(
this);
1461 Float64BinopMatcher m(node);
1462 if (m.right().IsFloat64Mul() && CanCover(node, m.right().node())) {
1463 Float64BinopMatcher mright(m.right().node());
1464 Emit(kArmVmlsF64, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
1465 g.UseRegister(mright.left().node()),
1466 g.UseRegister(mright.right().node()));
1469 VisitRRR(
this, kArmVsubF64, node);
1472 void InstructionSelector::VisitFloat64Mod(Node* node) {
1473 ArmOperandGenerator g(
this);
1474 Emit(kArmVmodF64, g.DefineAsFixed(node, d0), g.UseFixed(node->InputAt(0), d0),
1475 g.UseFixed(node->InputAt(1), d1))
1479 void InstructionSelector::VisitFloat64Ieee754Binop(Node* node,
1480 InstructionCode opcode) {
1481 ArmOperandGenerator g(
this);
1482 Emit(opcode, g.DefineAsFixed(node, d0), g.UseFixed(node->InputAt(0), d0),
1483 g.UseFixed(node->InputAt(1), d1))
1487 void InstructionSelector::VisitFloat64Ieee754Unop(Node* node,
1488 InstructionCode opcode) {
1489 ArmOperandGenerator g(
this);
1490 Emit(opcode, g.DefineAsFixed(node, d0), g.UseFixed(node->InputAt(0), d0))
1494 void InstructionSelector::EmitPrepareArguments(
1495 ZoneVector<PushParameter>* arguments,
const CallDescriptor* call_descriptor,
1497 ArmOperandGenerator g(
this);
1500 if (call_descriptor->IsCFunctionCall()) {
1501 Emit(kArchPrepareCallCFunction | MiscField::encode(static_cast<int>(
1502 call_descriptor->ParameterCount())),
1503 0,
nullptr, 0,
nullptr);
1506 for (
size_t n = 0; n < arguments->size(); ++n) {
1507 PushParameter input = (*arguments)[n];
1509 int slot =
static_cast<int>(n);
1510 Emit(kArmPoke | MiscField::encode(slot), g.NoOutput(),
1511 g.UseRegister(input.node));
1516 for (PushParameter input : base::Reversed(*arguments)) {
1518 if (input.node ==
nullptr)
continue;
1519 Emit(kArmPush, g.NoOutput(), g.UseRegister(input.node));
1524 void InstructionSelector::EmitPrepareResults(
1525 ZoneVector<PushParameter>* results,
const CallDescriptor* call_descriptor,
1527 ArmOperandGenerator g(
this);
1529 int reverse_slot = 0;
1530 for (PushParameter output : *results) {
1531 if (!output.location.IsCallerFrameSlot())
continue;
1533 if (output.node !=
nullptr) {
1534 DCHECK(!call_descriptor->IsCFunctionCall());
1535 if (output.location.GetType() == MachineType::Float32()) {
1536 MarkAsFloat32(output.node);
1537 }
else if (output.location.GetType() == MachineType::Float64()) {
1538 MarkAsFloat64(output.node);
1540 Emit(kArmPeek, g.DefineAsRegister(output.node),
1541 g.UseImmediate(reverse_slot));
1543 reverse_slot += output.location.GetSizeInPointers();
1547 bool InstructionSelector::IsTailCallAddressImmediate() {
return false; }
1549 int InstructionSelector::GetTempsCountForTailCallFromJSFunction() {
return 3; }
1554 void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
1555 InstructionOperand left, InstructionOperand right,
1556 FlagsContinuation* cont) {
1557 selector->EmitWithContinuation(opcode, left, right, cont);
1561 void VisitFloat32Compare(InstructionSelector* selector, Node* node,
1562 FlagsContinuation* cont) {
1563 ArmOperandGenerator g(selector);
1564 Float32BinopMatcher m(node);
1565 if (m.right().Is(0.0f)) {
1566 VisitCompare(selector, kArmVcmpF32, g.UseRegister(m.left().node()),
1567 g.UseImmediate(m.right().node()), cont);
1568 }
else if (m.left().Is(0.0f)) {
1570 VisitCompare(selector, kArmVcmpF32, g.UseRegister(m.right().node()),
1571 g.UseImmediate(m.left().node()), cont);
1573 VisitCompare(selector, kArmVcmpF32, g.UseRegister(m.left().node()),
1574 g.UseRegister(m.right().node()), cont);
1579 void VisitFloat64Compare(InstructionSelector* selector, Node* node,
1580 FlagsContinuation* cont) {
1581 ArmOperandGenerator g(selector);
1582 Float64BinopMatcher m(node);
1583 if (m.right().Is(0.0)) {
1584 VisitCompare(selector, kArmVcmpF64, g.UseRegister(m.left().node()),
1585 g.UseImmediate(m.right().node()), cont);
1586 }
else if (m.left().Is(0.0)) {
1588 VisitCompare(selector, kArmVcmpF64, g.UseRegister(m.right().node()),
1589 g.UseImmediate(m.left().node()), cont);
1591 VisitCompare(selector, kArmVcmpF64, g.UseRegister(m.left().node()),
1592 g.UseRegister(m.right().node()), cont);
1604 bool CanUseFlagSettingBinop(FlagsCondition cond) {
1608 case kSignedLessThan:
1609 case kSignedGreaterThanOrEqual:
1610 case kUnsignedLessThanOrEqual:
1611 case kUnsignedGreaterThan:
1623 FlagsCondition MapForFlagSettingBinop(FlagsCondition cond) {
1624 DCHECK(CanUseFlagSettingBinop(cond));
1629 case kSignedLessThan:
1631 case kSignedGreaterThanOrEqual:
1632 return kPositiveOrZero;
1633 case kUnsignedLessThanOrEqual:
1635 case kUnsignedGreaterThan:
1648 void MaybeReplaceCmpZeroWithFlagSettingBinop(InstructionSelector* selector,
1649 Node** node, Node* binop,
1650 InstructionCode* opcode,
1651 FlagsCondition cond,
1652 FlagsContinuation* cont) {
1653 InstructionCode binop_opcode;
1654 InstructionCode no_output_opcode;
1655 switch (binop->opcode()) {
1656 case IrOpcode::kInt32Add:
1657 binop_opcode = kArmAdd;
1658 no_output_opcode = kArmCmn;
1660 case IrOpcode::kWord32And:
1661 binop_opcode = kArmAnd;
1662 no_output_opcode = kArmTst;
1664 case IrOpcode::kWord32Or:
1665 binop_opcode = kArmOrr;
1666 no_output_opcode = kArmOrr;
1668 case IrOpcode::kWord32Xor:
1669 binop_opcode = kArmEor;
1670 no_output_opcode = kArmTeq;
1676 if (selector->CanCover(*node, binop)) {
1678 cont->Overwrite(MapForFlagSettingBinop(cond));
1679 *opcode = no_output_opcode;
1681 }
else if (selector->IsOnlyUserOfNodeInSameBlock(*node, binop)) {
1685 cont->Overwrite(MapForFlagSettingBinop(cond));
1686 *opcode = binop_opcode;
1692 void VisitWordCompare(InstructionSelector* selector, Node* node,
1693 InstructionCode opcode, FlagsContinuation* cont) {
1694 ArmOperandGenerator g(selector);
1695 Int32BinopMatcher m(node);
1696 InstructionOperand inputs[3];
1697 size_t input_count = 0;
1698 InstructionOperand outputs[2];
1699 size_t output_count = 0;
1700 bool has_result = (opcode != kArmCmp) && (opcode != kArmCmn) &&
1701 (opcode != kArmTst) && (opcode != kArmTeq);
1703 if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(),
1704 &input_count, &inputs[1])) {
1705 inputs[0] = g.UseRegisterOrStackPointer(m.left().node());
1707 }
else if (TryMatchImmediateOrShift(selector, &opcode, m.left().node(),
1708 &input_count, &inputs[1])) {
1709 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
1710 inputs[0] = g.UseRegisterOrStackPointer(m.right().node());
1713 opcode |= AddressingModeField::encode(kMode_Operand2_R);
1714 inputs[input_count++] = g.UseRegisterOrStackPointer(m.left().node());
1715 inputs[input_count++] = g.UseRegisterOrStackPointer(m.right().node());
1719 if (cont->IsDeoptimize()) {
1723 outputs[output_count++] = g.DefineSameAsFirst(node);
1725 outputs[output_count++] = g.DefineAsRegister(node);
1729 DCHECK_NE(0u, input_count);
1730 DCHECK_GE(arraysize(inputs), input_count);
1731 DCHECK_GE(arraysize(outputs), output_count);
1733 selector->EmitWithContinuation(opcode, output_count, outputs, input_count,
1737 void VisitWordCompare(InstructionSelector* selector, Node* node,
1738 FlagsContinuation* cont) {
1739 InstructionCode opcode = kArmCmp;
1740 Int32BinopMatcher m(node);
1742 FlagsCondition cond = cont->condition();
1743 if (m.right().Is(0) && (m.left().IsInt32Add() || m.left().IsWord32Or() ||
1744 m.left().IsWord32And() || m.left().IsWord32Xor())) {
1746 if (CanUseFlagSettingBinop(cond)) {
1747 Node* binop = m.left().node();
1748 MaybeReplaceCmpZeroWithFlagSettingBinop(selector, &node, binop, &opcode,
1751 }
else if (m.left().Is(0) &&
1752 (m.right().IsInt32Add() || m.right().IsWord32Or() ||
1753 m.right().IsWord32And() || m.right().IsWord32Xor())) {
1756 cond = CommuteFlagsCondition(cond);
1757 if (CanUseFlagSettingBinop(cond)) {
1758 Node* binop = m.right().node();
1759 MaybeReplaceCmpZeroWithFlagSettingBinop(selector, &node, binop, &opcode,
1764 VisitWordCompare(selector, node, opcode, cont);
1770 void InstructionSelector::VisitWordCompareZero(Node* user, Node* value,
1771 FlagsContinuation* cont) {
1773 while (value->opcode() == IrOpcode::kWord32Equal && CanCover(user, value)) {
1774 Int32BinopMatcher m(value);
1775 if (!m.right().Is(0))
break;
1778 value = m.left().node();
1782 if (CanCover(user, value)) {
1783 switch (value->opcode()) {
1784 case IrOpcode::kWord32Equal:
1785 cont->OverwriteAndNegateIfEqual(kEqual);
1786 return VisitWordCompare(
this, value, cont);
1787 case IrOpcode::kInt32LessThan:
1788 cont->OverwriteAndNegateIfEqual(kSignedLessThan);
1789 return VisitWordCompare(
this, value, cont);
1790 case IrOpcode::kInt32LessThanOrEqual:
1791 cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
1792 return VisitWordCompare(
this, value, cont);
1793 case IrOpcode::kUint32LessThan:
1794 cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
1795 return VisitWordCompare(
this, value, cont);
1796 case IrOpcode::kUint32LessThanOrEqual:
1797 cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
1798 return VisitWordCompare(
this, value, cont);
1799 case IrOpcode::kFloat32Equal:
1800 cont->OverwriteAndNegateIfEqual(kEqual);
1801 return VisitFloat32Compare(
this, value, cont);
1802 case IrOpcode::kFloat32LessThan:
1803 cont->OverwriteAndNegateIfEqual(kFloatLessThan);
1804 return VisitFloat32Compare(
this, value, cont);
1805 case IrOpcode::kFloat32LessThanOrEqual:
1806 cont->OverwriteAndNegateIfEqual(kFloatLessThanOrEqual);
1807 return VisitFloat32Compare(
this, value, cont);
1808 case IrOpcode::kFloat64Equal:
1809 cont->OverwriteAndNegateIfEqual(kEqual);
1810 return VisitFloat64Compare(
this, value, cont);
1811 case IrOpcode::kFloat64LessThan:
1812 cont->OverwriteAndNegateIfEqual(kFloatLessThan);
1813 return VisitFloat64Compare(
this, value, cont);
1814 case IrOpcode::kFloat64LessThanOrEqual:
1815 cont->OverwriteAndNegateIfEqual(kFloatLessThanOrEqual);
1816 return VisitFloat64Compare(
this, value, cont);
1817 case IrOpcode::kProjection:
1820 if (ProjectionIndexOf(value->op()) == 1u) {
1826 Node*
const node = value->InputAt(0);
1827 Node*
const result = NodeProperties::FindProjection(node, 0);
1828 if (!result || IsDefined(result)) {
1829 switch (node->opcode()) {
1830 case IrOpcode::kInt32AddWithOverflow:
1831 cont->OverwriteAndNegateIfEqual(kOverflow);
1832 return VisitBinop(
this, node, kArmAdd, kArmAdd, cont);
1833 case IrOpcode::kInt32SubWithOverflow:
1834 cont->OverwriteAndNegateIfEqual(kOverflow);
1835 return VisitBinop(
this, node, kArmSub, kArmRsb, cont);
1836 case IrOpcode::kInt32MulWithOverflow:
1841 cont->OverwriteAndNegateIfEqual(kNotEqual);
1842 return EmitInt32MulWithOverflow(
this, node, cont);
1849 case IrOpcode::kInt32Add:
1850 return VisitWordCompare(
this, value, kArmCmn, cont);
1851 case IrOpcode::kInt32Sub:
1852 return VisitWordCompare(
this, value, kArmCmp, cont);
1853 case IrOpcode::kWord32And:
1854 return VisitWordCompare(
this, value, kArmTst, cont);
1855 case IrOpcode::kWord32Or:
1856 return VisitBinop(
this, value, kArmOrr, kArmOrr, cont);
1857 case IrOpcode::kWord32Xor:
1858 return VisitWordCompare(
this, value, kArmTeq, cont);
1859 case IrOpcode::kWord32Sar:
1860 return VisitShift(
this, value, TryMatchASR, cont);
1861 case IrOpcode::kWord32Shl:
1862 return VisitShift(
this, value, TryMatchLSL, cont);
1863 case IrOpcode::kWord32Shr:
1864 return VisitShift(
this, value, TryMatchLSR, cont);
1865 case IrOpcode::kWord32Ror:
1866 return VisitShift(
this, value, TryMatchROR, cont);
1872 if (user->opcode() == IrOpcode::kWord32Equal) {
1873 return VisitWordCompare(
this, user, cont);
1877 ArmOperandGenerator g(
this);
1878 InstructionCode
const opcode =
1879 kArmTst | AddressingModeField::encode(kMode_Operand2_R);
1880 InstructionOperand
const value_operand = g.UseRegister(value);
1881 EmitWithContinuation(opcode, value_operand, value_operand, cont);
1884 void InstructionSelector::VisitSwitch(Node* node,
const SwitchInfo& sw) {
1885 ArmOperandGenerator g(
this);
1886 InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
1889 if (enable_switch_jump_table_ == kEnableSwitchJumpTable) {
1890 static const size_t kMaxTableSwitchValueRange = 2 << 16;
1891 size_t table_space_cost = 4 + sw.value_range();
1892 size_t table_time_cost = 3;
1893 size_t lookup_space_cost = 3 + 2 * sw.case_count();
1894 size_t lookup_time_cost = sw.case_count();
1895 if (sw.case_count() > 0 &&
1896 table_space_cost + 3 * table_time_cost <=
1897 lookup_space_cost + 3 * lookup_time_cost &&
1898 sw.min_value() > std::numeric_limits<int32_t>::min() &&
1899 sw.value_range() <= kMaxTableSwitchValueRange) {
1900 InstructionOperand index_operand = value_operand;
1901 if (sw.min_value()) {
1902 index_operand = g.TempRegister();
1903 Emit(kArmSub | AddressingModeField::encode(kMode_Operand2_I),
1904 index_operand, value_operand, g.TempImmediate(sw.min_value()));
1907 return EmitTableSwitch(sw, index_operand);
1912 return EmitBinarySearchSwitch(sw, value_operand);
1915 void InstructionSelector::VisitWord32Equal(Node*
const node) {
1916 FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
1917 Int32BinopMatcher m(node);
1918 if (m.right().Is(0)) {
1919 return VisitWordCompareZero(m.node(), m.left().node(), &cont);
1921 VisitWordCompare(
this, node, &cont);
1924 void InstructionSelector::VisitInt32LessThan(Node* node) {
1925 FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node);
1926 VisitWordCompare(
this, node, &cont);
1929 void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
1930 FlagsContinuation cont =
1931 FlagsContinuation::ForSet(kSignedLessThanOrEqual, node);
1932 VisitWordCompare(
this, node, &cont);
1935 void InstructionSelector::VisitUint32LessThan(Node* node) {
1936 FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
1937 VisitWordCompare(
this, node, &cont);
1940 void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
1941 FlagsContinuation cont =
1942 FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
1943 VisitWordCompare(
this, node, &cont);
1946 void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
1947 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
1948 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
1949 return VisitBinop(
this, node, kArmAdd, kArmAdd, &cont);
1951 FlagsContinuation cont;
1952 VisitBinop(
this, node, kArmAdd, kArmAdd, &cont);
1955 void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
1956 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
1957 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
1958 return VisitBinop(
this, node, kArmSub, kArmRsb, &cont);
1960 FlagsContinuation cont;
1961 VisitBinop(
this, node, kArmSub, kArmRsb, &cont);
1964 void InstructionSelector::VisitInt32MulWithOverflow(Node* node) {
1965 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
1970 FlagsContinuation cont = FlagsContinuation::ForSet(kNotEqual, ovf);
1971 return EmitInt32MulWithOverflow(
this, node, &cont);
1973 FlagsContinuation cont;
1974 EmitInt32MulWithOverflow(
this, node, &cont);
1977 void InstructionSelector::VisitFloat32Equal(Node* node) {
1978 FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
1979 VisitFloat32Compare(
this, node, &cont);
1982 void InstructionSelector::VisitFloat32LessThan(Node* node) {
1983 FlagsContinuation cont = FlagsContinuation::ForSet(kFloatLessThan, node);
1984 VisitFloat32Compare(
this, node, &cont);
1987 void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) {
1988 FlagsContinuation cont =
1989 FlagsContinuation::ForSet(kFloatLessThanOrEqual, node);
1990 VisitFloat32Compare(
this, node, &cont);
1993 void InstructionSelector::VisitFloat64Equal(Node* node) {
1994 FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
1995 VisitFloat64Compare(
this, node, &cont);
1998 void InstructionSelector::VisitFloat64LessThan(Node* node) {
1999 FlagsContinuation cont = FlagsContinuation::ForSet(kFloatLessThan, node);
2000 VisitFloat64Compare(
this, node, &cont);
2003 void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
2004 FlagsContinuation cont =
2005 FlagsContinuation::ForSet(kFloatLessThanOrEqual, node);
2006 VisitFloat64Compare(
this, node, &cont);
2009 void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) {
2010 ArmOperandGenerator g(
this);
2011 Node* left = node->InputAt(0);
2012 Node* right = node->InputAt(1);
2013 if (left->opcode() == IrOpcode::kFloat64InsertHighWord32 &&
2014 CanCover(node, left)) {
2015 left = left->InputAt(1);
2016 Emit(kArmVmovF64U32U32, g.DefineAsRegister(node), g.UseRegister(right),
2017 g.UseRegister(left));
2020 Emit(kArmVmovLowF64U32, g.DefineSameAsFirst(node), g.UseRegister(left),
2021 g.UseRegister(right));
2024 void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
2025 ArmOperandGenerator g(
this);
2026 Node* left = node->InputAt(0);
2027 Node* right = node->InputAt(1);
2028 if (left->opcode() == IrOpcode::kFloat64InsertLowWord32 &&
2029 CanCover(node, left)) {
2030 left = left->InputAt(1);
2031 Emit(kArmVmovF64U32U32, g.DefineAsRegister(node), g.UseRegister(left),
2032 g.UseRegister(right));
2035 Emit(kArmVmovHighF64U32, g.DefineSameAsFirst(node), g.UseRegister(left),
2036 g.UseRegister(right));
2039 void InstructionSelector::VisitWord32AtomicLoad(Node* node) {
2040 LoadRepresentation load_rep = LoadRepresentationOf(node->op());
2041 ArmOperandGenerator g(
this);
2042 Node* base = node->InputAt(0);
2043 Node* index = node->InputAt(1);
2044 ArchOpcode opcode = kArchNop;
2045 switch (load_rep.representation()) {
2046 case MachineRepresentation::kWord8:
2048 load_rep.IsSigned() ? kWord32AtomicLoadInt8 : kWord32AtomicLoadUint8;
2050 case MachineRepresentation::kWord16:
2051 opcode = load_rep.IsSigned() ? kWord32AtomicLoadInt16
2052 : kWord32AtomicLoadUint16;
2054 case MachineRepresentation::kWord32:
2055 opcode = kWord32AtomicLoadWord32;
2061 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR),
2062 g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(index));
2065 void InstructionSelector::VisitWord32AtomicStore(Node* node) {
2066 MachineRepresentation rep = AtomicStoreRepresentationOf(node->op());
2067 ArmOperandGenerator g(
this);
2068 Node* base = node->InputAt(0);
2069 Node* index = node->InputAt(1);
2070 Node* value = node->InputAt(2);
2071 ArchOpcode opcode = kArchNop;
2073 case MachineRepresentation::kWord8:
2074 opcode = kWord32AtomicStoreWord8;
2076 case MachineRepresentation::kWord16:
2077 opcode = kWord32AtomicStoreWord16;
2079 case MachineRepresentation::kWord32:
2080 opcode = kWord32AtomicStoreWord32;
2087 AddressingMode addressing_mode = kMode_Offset_RR;
2088 InstructionOperand inputs[4];
2089 size_t input_count = 0;
2090 inputs[input_count++] = g.UseUniqueRegister(base);
2091 inputs[input_count++] = g.UseUniqueRegister(index);
2092 inputs[input_count++] = g.UseUniqueRegister(value);
2093 InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
2094 Emit(code, 0,
nullptr, input_count, inputs);
2097 void InstructionSelector::VisitWord32AtomicExchange(Node* node) {
2098 ArmOperandGenerator g(
this);
2099 Node* base = node->InputAt(0);
2100 Node* index = node->InputAt(1);
2101 Node* value = node->InputAt(2);
2102 ArchOpcode opcode = kArchNop;
2103 MachineType type = AtomicOpType(node->op());
2104 if (type == MachineType::Int8()) {
2105 opcode = kWord32AtomicExchangeInt8;
2106 }
else if (type == MachineType::Uint8()) {
2107 opcode = kWord32AtomicExchangeUint8;
2108 }
else if (type == MachineType::Int16()) {
2109 opcode = kWord32AtomicExchangeInt16;
2110 }
else if (type == MachineType::Uint16()) {
2111 opcode = kWord32AtomicExchangeUint16;
2112 }
else if (type == MachineType::Int32() || type == MachineType::Uint32()) {
2113 opcode = kWord32AtomicExchangeWord32;
2119 AddressingMode addressing_mode = kMode_Offset_RR;
2120 InstructionOperand inputs[3];
2121 size_t input_count = 0;
2122 inputs[input_count++] = g.UseRegister(base);
2123 inputs[input_count++] = g.UseRegister(index);
2124 inputs[input_count++] = g.UseUniqueRegister(value);
2125 InstructionOperand outputs[1];
2126 outputs[0] = g.DefineAsRegister(node);
2127 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
2128 InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
2129 Emit(code, 1, outputs, input_count, inputs, arraysize(temps), temps);
2132 void InstructionSelector::VisitWord32AtomicCompareExchange(Node* node) {
2133 ArmOperandGenerator g(
this);
2134 Node* base = node->InputAt(0);
2135 Node* index = node->InputAt(1);
2136 Node* old_value = node->InputAt(2);
2137 Node* new_value = node->InputAt(3);
2138 ArchOpcode opcode = kArchNop;
2139 MachineType type = AtomicOpType(node->op());
2140 if (type == MachineType::Int8()) {
2141 opcode = kWord32AtomicCompareExchangeInt8;
2142 }
else if (type == MachineType::Uint8()) {
2143 opcode = kWord32AtomicCompareExchangeUint8;
2144 }
else if (type == MachineType::Int16()) {
2145 opcode = kWord32AtomicCompareExchangeInt16;
2146 }
else if (type == MachineType::Uint16()) {
2147 opcode = kWord32AtomicCompareExchangeUint16;
2148 }
else if (type == MachineType::Int32() || type == MachineType::Uint32()) {
2149 opcode = kWord32AtomicCompareExchangeWord32;
2155 AddressingMode addressing_mode = kMode_Offset_RR;
2156 InstructionOperand inputs[4];
2157 size_t input_count = 0;
2158 inputs[input_count++] = g.UseRegister(base);
2159 inputs[input_count++] = g.UseRegister(index);
2160 inputs[input_count++] = g.UseUniqueRegister(old_value);
2161 inputs[input_count++] = g.UseUniqueRegister(new_value);
2162 InstructionOperand outputs[1];
2163 outputs[0] = g.DefineAsRegister(node);
2164 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister(),
2166 InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
2167 Emit(code, 1, outputs, input_count, inputs, arraysize(temps), temps);
2170 void InstructionSelector::VisitWord32AtomicBinaryOperation(
2171 Node* node, ArchOpcode int8_op, ArchOpcode uint8_op, ArchOpcode int16_op,
2172 ArchOpcode uint16_op, ArchOpcode word32_op) {
2173 ArmOperandGenerator g(
this);
2174 Node* base = node->InputAt(0);
2175 Node* index = node->InputAt(1);
2176 Node* value = node->InputAt(2);
2177 ArchOpcode opcode = kArchNop;
2178 MachineType type = AtomicOpType(node->op());
2179 if (type == MachineType::Int8()) {
2181 }
else if (type == MachineType::Uint8()) {
2183 }
else if (type == MachineType::Int16()) {
2185 }
else if (type == MachineType::Uint16()) {
2187 }
else if (type == MachineType::Int32() || type == MachineType::Uint32()) {
2194 AddressingMode addressing_mode = kMode_Offset_RR;
2195 InstructionOperand inputs[3];
2196 size_t input_count = 0;
2197 inputs[input_count++] = g.UseRegister(base);
2198 inputs[input_count++] = g.UseRegister(index);
2199 inputs[input_count++] = g.UseUniqueRegister(value);
2200 InstructionOperand outputs[1];
2201 outputs[0] = g.DefineAsRegister(node);
2202 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister(),
2204 InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
2205 Emit(code, 1, outputs, input_count, inputs, arraysize(temps), temps);
2208 #define VISIT_ATOMIC_BINOP(op) \ 2209 void InstructionSelector::VisitWord32Atomic##op(Node* node) { \ 2210 VisitWord32AtomicBinaryOperation( \ 2211 node, kWord32Atomic##op##Int8, kWord32Atomic##op##Uint8, \ 2212 kWord32Atomic##op##Int16, kWord32Atomic##op##Uint16, \ 2213 kWord32Atomic##op##Word32); \ 2215 VISIT_ATOMIC_BINOP(Add)
2216 VISIT_ATOMIC_BINOP(Sub)
2217 VISIT_ATOMIC_BINOP(And)
2218 VISIT_ATOMIC_BINOP(Or)
2219 VISIT_ATOMIC_BINOP(Xor)
2220 #undef VISIT_ATOMIC_BINOP 2222 void InstructionSelector::VisitWord32AtomicPairLoad(Node* node) {
2223 ArmOperandGenerator g(
this);
2224 Node* base = node->InputAt(0);
2225 Node* index = node->InputAt(1);
2226 AddressingMode addressing_mode = kMode_Offset_RR;
2227 InstructionCode code =
2228 kArmWord32AtomicPairLoad | AddressingModeField::encode(addressing_mode);
2229 InstructionOperand inputs[] = {g.UseUniqueRegister(base),
2230 g.UseUniqueRegister(index)};
2231 Node* projection0 = NodeProperties::FindProjection(node, 0);
2232 Node* projection1 = NodeProperties::FindProjection(node, 1);
2234 InstructionOperand outputs[] = {g.DefineAsFixed(projection0, r0),
2235 g.DefineAsFixed(projection1, r1)};
2236 InstructionOperand temps[] = {g.TempRegister()};
2237 Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
2238 arraysize(temps), temps);
2239 }
else if (projection0) {
2240 InstructionOperand outputs[] = {g.DefineAsFixed(projection0, r0)};
2241 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister(r1)};
2242 Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
2243 arraysize(temps), temps);
2245 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister(r0),
2246 g.TempRegister(r1)};
2247 Emit(code, 0,
nullptr, arraysize(inputs), inputs, arraysize(temps), temps);
2251 void InstructionSelector::VisitWord32AtomicPairStore(Node* node) {
2252 ArmOperandGenerator g(
this);
2253 Node* base = node->InputAt(0);
2254 Node* index = node->InputAt(1);
2255 Node* value_low = node->InputAt(2);
2256 Node* value_high = node->InputAt(3);
2257 AddressingMode addressing_mode = kMode_Offset_RR;
2258 InstructionOperand inputs[] = {
2259 g.UseUniqueRegister(base), g.UseUniqueRegister(index),
2260 g.UseFixed(value_low, r2), g.UseFixed(value_high, r3)};
2261 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister(r0),
2262 g.TempRegister(r1)};
2263 InstructionCode code =
2264 kArmWord32AtomicPairStore | AddressingModeField::encode(addressing_mode);
2265 Emit(code, 0,
nullptr, arraysize(inputs), inputs, arraysize(temps), temps);
2268 void InstructionSelector::VisitWord32AtomicPairAdd(Node* node) {
2269 VisitPairAtomicBinOp(
this, node, kArmWord32AtomicPairAdd);
2272 void InstructionSelector::VisitWord32AtomicPairSub(Node* node) {
2273 VisitPairAtomicBinOp(
this, node, kArmWord32AtomicPairSub);
2276 void InstructionSelector::VisitWord32AtomicPairAnd(Node* node) {
2277 VisitPairAtomicBinOp(
this, node, kArmWord32AtomicPairAnd);
2280 void InstructionSelector::VisitWord32AtomicPairOr(Node* node) {
2281 VisitPairAtomicBinOp(
this, node, kArmWord32AtomicPairOr);
2284 void InstructionSelector::VisitWord32AtomicPairXor(Node* node) {
2285 VisitPairAtomicBinOp(
this, node, kArmWord32AtomicPairXor);
2288 void InstructionSelector::VisitWord32AtomicPairExchange(Node* node) {
2289 ArmOperandGenerator g(
this);
2290 Node* base = node->InputAt(0);
2291 Node* index = node->InputAt(1);
2292 Node* value = node->InputAt(2);
2293 Node* value_high = node->InputAt(3);
2294 AddressingMode addressing_mode = kMode_Offset_RR;
2295 InstructionOperand inputs[] = {
2296 g.UseFixed(value, r0), g.UseFixed(value_high, r1),
2297 g.UseUniqueRegister(base), g.UseUniqueRegister(index)};
2298 InstructionCode code = kArmWord32AtomicPairExchange |
2299 AddressingModeField::encode(addressing_mode);
2300 Node* projection0 = NodeProperties::FindProjection(node, 0);
2301 Node* projection1 = NodeProperties::FindProjection(node, 1);
2303 InstructionOperand outputs[] = {g.DefineAsFixed(projection0, r6),
2304 g.DefineAsFixed(projection1, r7)};
2305 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
2306 Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
2307 arraysize(temps), temps);
2308 }
else if (projection0) {
2309 InstructionOperand outputs[] = {g.DefineAsFixed(projection0, r6)};
2310 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister(),
2311 g.TempRegister(r7)};
2312 Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
2313 arraysize(temps), temps);
2315 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister(),
2316 g.TempRegister(r6), g.TempRegister(r7)};
2317 Emit(code, 0,
nullptr, arraysize(inputs), inputs, arraysize(temps), temps);
2321 void InstructionSelector::VisitWord32AtomicPairCompareExchange(Node* node) {
2322 ArmOperandGenerator g(
this);
2323 AddressingMode addressing_mode = kMode_Offset_RR;
2324 InstructionOperand inputs[] = {g.UseFixed(node->InputAt(2), r4),
2325 g.UseFixed(node->InputAt(3), r5),
2326 g.UseFixed(node->InputAt(4), r8),
2327 g.UseFixed(node->InputAt(5), r9),
2328 g.UseUniqueRegister(node->InputAt(0)),
2329 g.UseUniqueRegister(node->InputAt(1))};
2330 InstructionCode code = kArmWord32AtomicPairCompareExchange |
2331 AddressingModeField::encode(addressing_mode);
2332 Node* projection0 = NodeProperties::FindProjection(node, 0);
2333 Node* projection1 = NodeProperties::FindProjection(node, 1);
2335 InstructionOperand outputs[] = {g.DefineAsFixed(projection0, r2),
2336 g.DefineAsFixed(projection1, r3)};
2337 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
2338 Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
2339 arraysize(temps), temps);
2340 }
else if (projection0) {
2341 InstructionOperand outputs[] = {
2342 g.DefineAsFixed(NodeProperties::FindProjection(node, 0), r2)};
2343 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister(),
2344 g.TempRegister(r3)};
2345 Emit(code, arraysize(outputs), outputs, arraysize(inputs), inputs,
2346 arraysize(temps), temps);
2348 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister(),
2349 g.TempRegister(r2), g.TempRegister(r3)};
2350 Emit(code, 0,
nullptr, arraysize(inputs), inputs, arraysize(temps), temps);
2354 #define SIMD_TYPE_LIST(V) \ 2360 #define SIMD_UNOP_LIST(V) \ 2361 V(F32x4SConvertI32x4, kArmF32x4SConvertI32x4) \ 2362 V(F32x4UConvertI32x4, kArmF32x4UConvertI32x4) \ 2363 V(F32x4Abs, kArmF32x4Abs) \ 2364 V(F32x4Neg, kArmF32x4Neg) \ 2365 V(F32x4RecipApprox, kArmF32x4RecipApprox) \ 2366 V(F32x4RecipSqrtApprox, kArmF32x4RecipSqrtApprox) \ 2367 V(I32x4SConvertF32x4, kArmI32x4SConvertF32x4) \ 2368 V(I32x4SConvertI16x8Low, kArmI32x4SConvertI16x8Low) \ 2369 V(I32x4SConvertI16x8High, kArmI32x4SConvertI16x8High) \ 2370 V(I32x4Neg, kArmI32x4Neg) \ 2371 V(I32x4UConvertF32x4, kArmI32x4UConvertF32x4) \ 2372 V(I32x4UConvertI16x8Low, kArmI32x4UConvertI16x8Low) \ 2373 V(I32x4UConvertI16x8High, kArmI32x4UConvertI16x8High) \ 2374 V(I16x8SConvertI8x16Low, kArmI16x8SConvertI8x16Low) \ 2375 V(I16x8SConvertI8x16High, kArmI16x8SConvertI8x16High) \ 2376 V(I16x8Neg, kArmI16x8Neg) \ 2377 V(I16x8UConvertI8x16Low, kArmI16x8UConvertI8x16Low) \ 2378 V(I16x8UConvertI8x16High, kArmI16x8UConvertI8x16High) \ 2379 V(I8x16Neg, kArmI8x16Neg) \ 2380 V(S128Not, kArmS128Not) \ 2381 V(S1x4AnyTrue, kArmS1x4AnyTrue) \ 2382 V(S1x4AllTrue, kArmS1x4AllTrue) \ 2383 V(S1x8AnyTrue, kArmS1x8AnyTrue) \ 2384 V(S1x8AllTrue, kArmS1x8AllTrue) \ 2385 V(S1x16AnyTrue, kArmS1x16AnyTrue) \ 2386 V(S1x16AllTrue, kArmS1x16AllTrue) 2388 #define SIMD_SHIFT_OP_LIST(V) \ 2399 #define SIMD_BINOP_LIST(V) \ 2400 V(F32x4Add, kArmF32x4Add) \ 2401 V(F32x4AddHoriz, kArmF32x4AddHoriz) \ 2402 V(F32x4Sub, kArmF32x4Sub) \ 2403 V(F32x4Mul, kArmF32x4Mul) \ 2404 V(F32x4Min, kArmF32x4Min) \ 2405 V(F32x4Max, kArmF32x4Max) \ 2406 V(F32x4Eq, kArmF32x4Eq) \ 2407 V(F32x4Ne, kArmF32x4Ne) \ 2408 V(F32x4Lt, kArmF32x4Lt) \ 2409 V(F32x4Le, kArmF32x4Le) \ 2410 V(I32x4Add, kArmI32x4Add) \ 2411 V(I32x4AddHoriz, kArmI32x4AddHoriz) \ 2412 V(I32x4Sub, kArmI32x4Sub) \ 2413 V(I32x4Mul, kArmI32x4Mul) \ 2414 V(I32x4MinS, kArmI32x4MinS) \ 2415 V(I32x4MaxS, kArmI32x4MaxS) \ 2416 V(I32x4Eq, kArmI32x4Eq) \ 2417 V(I32x4Ne, kArmI32x4Ne) \ 2418 V(I32x4GtS, kArmI32x4GtS) \ 2419 V(I32x4GeS, kArmI32x4GeS) \ 2420 V(I32x4MinU, kArmI32x4MinU) \ 2421 V(I32x4MaxU, kArmI32x4MaxU) \ 2422 V(I32x4GtU, kArmI32x4GtU) \ 2423 V(I32x4GeU, kArmI32x4GeU) \ 2424 V(I16x8SConvertI32x4, kArmI16x8SConvertI32x4) \ 2425 V(I16x8Add, kArmI16x8Add) \ 2426 V(I16x8AddSaturateS, kArmI16x8AddSaturateS) \ 2427 V(I16x8AddHoriz, kArmI16x8AddHoriz) \ 2428 V(I16x8Sub, kArmI16x8Sub) \ 2429 V(I16x8SubSaturateS, kArmI16x8SubSaturateS) \ 2430 V(I16x8Mul, kArmI16x8Mul) \ 2431 V(I16x8MinS, kArmI16x8MinS) \ 2432 V(I16x8MaxS, kArmI16x8MaxS) \ 2433 V(I16x8Eq, kArmI16x8Eq) \ 2434 V(I16x8Ne, kArmI16x8Ne) \ 2435 V(I16x8GtS, kArmI16x8GtS) \ 2436 V(I16x8GeS, kArmI16x8GeS) \ 2437 V(I16x8UConvertI32x4, kArmI16x8UConvertI32x4) \ 2438 V(I16x8AddSaturateU, kArmI16x8AddSaturateU) \ 2439 V(I16x8SubSaturateU, kArmI16x8SubSaturateU) \ 2440 V(I16x8MinU, kArmI16x8MinU) \ 2441 V(I16x8MaxU, kArmI16x8MaxU) \ 2442 V(I16x8GtU, kArmI16x8GtU) \ 2443 V(I16x8GeU, kArmI16x8GeU) \ 2444 V(I8x16SConvertI16x8, kArmI8x16SConvertI16x8) \ 2445 V(I8x16Add, kArmI8x16Add) \ 2446 V(I8x16AddSaturateS, kArmI8x16AddSaturateS) \ 2447 V(I8x16Sub, kArmI8x16Sub) \ 2448 V(I8x16SubSaturateS, kArmI8x16SubSaturateS) \ 2449 V(I8x16Mul, kArmI8x16Mul) \ 2450 V(I8x16MinS, kArmI8x16MinS) \ 2451 V(I8x16MaxS, kArmI8x16MaxS) \ 2452 V(I8x16Eq, kArmI8x16Eq) \ 2453 V(I8x16Ne, kArmI8x16Ne) \ 2454 V(I8x16GtS, kArmI8x16GtS) \ 2455 V(I8x16GeS, kArmI8x16GeS) \ 2456 V(I8x16UConvertI16x8, kArmI8x16UConvertI16x8) \ 2457 V(I8x16AddSaturateU, kArmI8x16AddSaturateU) \ 2458 V(I8x16SubSaturateU, kArmI8x16SubSaturateU) \ 2459 V(I8x16MinU, kArmI8x16MinU) \ 2460 V(I8x16MaxU, kArmI8x16MaxU) \ 2461 V(I8x16GtU, kArmI8x16GtU) \ 2462 V(I8x16GeU, kArmI8x16GeU) \ 2463 V(S128And, kArmS128And) \ 2464 V(S128Or, kArmS128Or) \ 2465 V(S128Xor, kArmS128Xor) 2467 void InstructionSelector::VisitS128Zero(Node* node) {
2468 ArmOperandGenerator g(
this);
2469 Emit(kArmS128Zero, g.DefineAsRegister(node), g.DefineAsRegister(node));
2472 #define SIMD_VISIT_SPLAT(Type) \ 2473 void InstructionSelector::Visit##Type##Splat(Node* node) { \ 2474 VisitRR(this, kArm##Type##Splat, node); \ 2476 SIMD_TYPE_LIST(SIMD_VISIT_SPLAT)
2477 #undef SIMD_VISIT_SPLAT 2479 #define SIMD_VISIT_EXTRACT_LANE(Type) \ 2480 void InstructionSelector::Visit##Type##ExtractLane(Node* node) { \ 2481 VisitRRI(this, kArm##Type##ExtractLane, node); \ 2483 SIMD_TYPE_LIST(SIMD_VISIT_EXTRACT_LANE)
2484 #undef SIMD_VISIT_EXTRACT_LANE 2486 #define SIMD_VISIT_REPLACE_LANE(Type) \ 2487 void InstructionSelector::Visit##Type##ReplaceLane(Node* node) { \ 2488 VisitRRIR(this, kArm##Type##ReplaceLane, node); \ 2490 SIMD_TYPE_LIST(SIMD_VISIT_REPLACE_LANE)
2491 #undef SIMD_VISIT_REPLACE_LANE 2492 #undef SIMD_TYPE_LIST 2494 #define SIMD_VISIT_UNOP(Name, instruction) \ 2495 void InstructionSelector::Visit##Name(Node* node) { \ 2496 VisitRR(this, instruction, node); \ 2498 SIMD_UNOP_LIST(SIMD_VISIT_UNOP)
2499 #undef SIMD_VISIT_UNOP 2500 #undef SIMD_UNOP_LIST 2502 #define SIMD_VISIT_SHIFT_OP(Name) \ 2503 void InstructionSelector::Visit##Name(Node* node) { \ 2504 VisitRRI(this, kArm##Name, node); \ 2506 SIMD_SHIFT_OP_LIST(SIMD_VISIT_SHIFT_OP)
2507 #undef SIMD_VISIT_SHIFT_OP 2508 #undef SIMD_SHIFT_OP_LIST 2510 #define SIMD_VISIT_BINOP(Name, instruction) \ 2511 void InstructionSelector::Visit##Name(Node* node) { \ 2512 VisitRRR(this, instruction, node); \ 2514 SIMD_BINOP_LIST(SIMD_VISIT_BINOP)
2515 #undef SIMD_VISIT_BINOP 2516 #undef SIMD_BINOP_LIST 2518 void InstructionSelector::VisitS128Select(Node* node) {
2519 ArmOperandGenerator g(
this);
2520 Emit(kArmS128Select, g.DefineSameAsFirst(node),
2521 g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)),
2522 g.UseRegister(node->InputAt(2)));
2527 struct ShuffleEntry {
2528 uint8_t shuffle[kSimd128Size];
2532 static const ShuffleEntry arch_shuffles[] = {
2533 {{0, 1, 2, 3, 16, 17, 18, 19, 4, 5, 6, 7, 20, 21, 22, 23},
2535 {{8, 9, 10, 11, 24, 25, 26, 27, 12, 13, 14, 15, 28, 29, 30, 31},
2537 {{0, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19, 24, 25, 26, 27},
2538 kArmS32x4UnzipLeft},
2539 {{4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23, 28, 29, 30, 31},
2540 kArmS32x4UnzipRight},
2541 {{0, 1, 2, 3, 16, 17, 18, 19, 8, 9, 10, 11, 24, 25, 26, 27},
2542 kArmS32x4TransposeLeft},
2543 {{4, 5, 6, 7, 20, 21, 22, 23, 12, 13, 14, 15, 28, 29, 30, 31},
2544 kArmS32x4TransposeRight},
2545 {{4, 5, 6, 7, 0, 1, 2, 3, 12, 13, 14, 15, 8, 9, 10, 11}, kArmS32x2Reverse},
2547 {{0, 1, 16, 17, 2, 3, 18, 19, 4, 5, 20, 21, 6, 7, 22, 23},
2549 {{8, 9, 24, 25, 10, 11, 26, 27, 12, 13, 28, 29, 14, 15, 30, 31},
2551 {{0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21, 24, 25, 28, 29},
2552 kArmS16x8UnzipLeft},
2553 {{2, 3, 6, 7, 10, 11, 14, 15, 18, 19, 22, 23, 26, 27, 30, 31},
2554 kArmS16x8UnzipRight},
2555 {{0, 1, 16, 17, 4, 5, 20, 21, 8, 9, 24, 25, 12, 13, 28, 29},
2556 kArmS16x8TransposeLeft},
2557 {{2, 3, 18, 19, 6, 7, 22, 23, 10, 11, 26, 27, 14, 15, 30, 31},
2558 kArmS16x8TransposeRight},
2559 {{6, 7, 4, 5, 2, 3, 0, 1, 14, 15, 12, 13, 10, 11, 8, 9}, kArmS16x4Reverse},
2560 {{2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13}, kArmS16x2Reverse},
2562 {{0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23},
2564 {{8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30, 15, 31},
2566 {{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30},
2567 kArmS8x16UnzipLeft},
2568 {{1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31},
2569 kArmS8x16UnzipRight},
2570 {{0, 16, 2, 18, 4, 20, 6, 22, 8, 24, 10, 26, 12, 28, 14, 30},
2571 kArmS8x16TransposeLeft},
2572 {{1, 17, 3, 19, 5, 21, 7, 23, 9, 25, 11, 27, 13, 29, 15, 31},
2573 kArmS8x16TransposeRight},
2574 {{7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8}, kArmS8x8Reverse},
2575 {{3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12}, kArmS8x4Reverse},
2576 {{1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14}, kArmS8x2Reverse}};
2578 bool TryMatchArchShuffle(
const uint8_t* shuffle,
const ShuffleEntry* table,
2579 size_t num_entries,
bool is_swizzle,
2580 ArchOpcode* opcode) {
2581 uint8_t mask = is_swizzle ? kSimd128Size - 1 : 2 * kSimd128Size - 1;
2582 for (
size_t i = 0;
i < num_entries; ++
i) {
2583 const ShuffleEntry& entry = table[
i];
2585 for (; j < kSimd128Size; ++j) {
2586 if ((entry.shuffle[j] & mask) != (shuffle[j] & mask)) {
2590 if (j == kSimd128Size) {
2591 *opcode = entry.opcode;
2598 void ArrangeShuffleTable(ArmOperandGenerator* g, Node* input0, Node* input1,
2599 InstructionOperand* src0, InstructionOperand* src1) {
2600 if (input0 == input1) {
2602 *src0 = *src1 = g->UseRegister(input0);
2605 *src0 = g->UseFixed(input0, q0);
2606 *src1 = g->UseFixed(input1, q1);
2612 void InstructionSelector::VisitS8x16Shuffle(Node* node) {
2613 uint8_t shuffle[kSimd128Size];
2615 CanonicalizeShuffle(node, shuffle, &is_swizzle);
2616 Node* input0 = node->InputAt(0);
2617 Node* input1 = node->InputAt(1);
2618 uint8_t shuffle32x4[4];
2619 ArmOperandGenerator g(
this);
2621 if (TryMatch32x4Shuffle(shuffle, shuffle32x4)) {
2622 if (TryMatchDup<4>(shuffle, &index)) {
2623 DCHECK_GT(4, index);
2624 Emit(kArmS128Dup, g.DefineAsRegister(node), g.UseRegister(input0),
2625 g.UseImmediate(Neon32), g.UseImmediate(index % 4));
2626 }
else if (TryMatchIdentity(shuffle)) {
2631 InstructionOperand src0 = g.UseUniqueRegister(input0);
2632 InstructionOperand src1 = is_swizzle ? src0 : g.UseUniqueRegister(input1);
2633 Emit(kArmS32x4Shuffle, g.DefineAsRegister(node), src0, src1,
2634 g.UseImmediate(Pack4Lanes(shuffle32x4)));
2638 if (TryMatchDup<8>(shuffle, &index)) {
2639 DCHECK_GT(8, index);
2640 Emit(kArmS128Dup, g.DefineAsRegister(node), g.UseRegister(input0),
2641 g.UseImmediate(Neon16), g.UseImmediate(index % 8));
2644 if (TryMatchDup<16>(shuffle, &index)) {
2645 DCHECK_GT(16, index);
2646 Emit(kArmS128Dup, g.DefineAsRegister(node), g.UseRegister(input0),
2647 g.UseImmediate(Neon8), g.UseImmediate(index % 16));
2651 if (TryMatchArchShuffle(shuffle, arch_shuffles, arraysize(arch_shuffles),
2652 is_swizzle, &opcode)) {
2653 VisitRRRShuffle(
this, opcode, node);
2657 if (TryMatchConcat(shuffle, &offset)) {
2658 Emit(kArmS8x16Concat, g.DefineAsRegister(node), g.UseRegister(input0),
2659 g.UseRegister(input1), g.UseImmediate(offset));
2663 InstructionOperand src0, src1;
2664 ArrangeShuffleTable(&g, input0, input1, &src0, &src1);
2665 Emit(kArmS8x16Shuffle, g.DefineAsRegister(node), src0, src1,
2666 g.UseImmediate(Pack4Lanes(shuffle)),
2667 g.UseImmediate(Pack4Lanes(shuffle + 4)),
2668 g.UseImmediate(Pack4Lanes(shuffle + 8)),
2669 g.UseImmediate(Pack4Lanes(shuffle + 12)));
2672 void InstructionSelector::VisitSignExtendWord8ToInt32(Node* node) {
2673 ArmOperandGenerator g(
this);
2674 Emit(kArmSxtb, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
2675 g.TempImmediate(0));
2678 void InstructionSelector::VisitSignExtendWord16ToInt32(Node* node) {
2679 ArmOperandGenerator g(
this);
2680 Emit(kArmSxth, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
2681 g.TempImmediate(0));
2684 void InstructionSelector::VisitInt32AbsWithOverflow(Node* node) {
2688 void InstructionSelector::VisitInt64AbsWithOverflow(Node* node) {
2693 MachineOperatorBuilder::Flags
2694 InstructionSelector::SupportedMachineOperatorFlags() {
2695 MachineOperatorBuilder::Flags flags =
2696 MachineOperatorBuilder::kSpeculationFence;
2697 if (CpuFeatures::IsSupported(SUDIV)) {
2700 flags |= MachineOperatorBuilder::kInt32DivIsSafe |
2701 MachineOperatorBuilder::kUint32DivIsSafe;
2703 if (CpuFeatures::IsSupported(ARMv7)) {
2704 flags |= MachineOperatorBuilder::kWord32ReverseBits;
2706 if (CpuFeatures::IsSupported(ARMv8)) {
2707 flags |= MachineOperatorBuilder::kFloat32RoundDown |
2708 MachineOperatorBuilder::kFloat64RoundDown |
2709 MachineOperatorBuilder::kFloat32RoundUp |
2710 MachineOperatorBuilder::kFloat64RoundUp |
2711 MachineOperatorBuilder::kFloat32RoundTruncate |
2712 MachineOperatorBuilder::kFloat64RoundTruncate |
2713 MachineOperatorBuilder::kFloat64RoundTiesAway |
2714 MachineOperatorBuilder::kFloat32RoundTiesEven |
2715 MachineOperatorBuilder::kFloat64RoundTiesEven;
2721 MachineOperatorBuilder::AlignmentRequirements
2722 InstructionSelector::AlignmentRequirements() {
2723 EnumSet<MachineRepresentation> req_aligned;
2724 req_aligned.Add(MachineRepresentation::kFloat32);
2725 req_aligned.Add(MachineRepresentation::kFloat64);
2726 return MachineOperatorBuilder::AlignmentRequirements::
2727 SomeUnalignedAccessUnsupported(req_aligned, req_aligned);