1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/base/adapters.h"
6 #include "src/base/bits.h"
7 #include "src/compiler/instruction-selector-impl.h"
8 #include "src/compiler/node-matchers.h"
9 #include "src/compiler/node-properties.h"
10
11 namespace v8 {
12 namespace internal {
13 namespace compiler {
14
15 // Adds Arm-specific methods for generating InstructionOperands.
16 class ArmOperandGenerator : public OperandGenerator {
17 public:
ArmOperandGenerator(InstructionSelector * selector)18 explicit ArmOperandGenerator(InstructionSelector* selector)
19 : OperandGenerator(selector) {}
20
CanBeImmediate(int32_t value) const21 bool CanBeImmediate(int32_t value) const {
22 return Assembler::ImmediateFitsAddrMode1Instruction(value);
23 }
24
CanBeImmediate(uint32_t value) const25 bool CanBeImmediate(uint32_t value) const {
26 return CanBeImmediate(bit_cast<int32_t>(value));
27 }
28
CanBeImmediate(Node * node,InstructionCode opcode)29 bool CanBeImmediate(Node* node, InstructionCode opcode) {
30 Int32Matcher m(node);
31 if (!m.HasValue()) return false;
32 int32_t value = m.Value();
33 switch (ArchOpcodeField::decode(opcode)) {
34 case kArmAnd:
35 case kArmMov:
36 case kArmMvn:
37 case kArmBic:
38 return CanBeImmediate(value) || CanBeImmediate(~value);
39
40 case kArmAdd:
41 case kArmSub:
42 case kArmCmp:
43 case kArmCmn:
44 return CanBeImmediate(value) || CanBeImmediate(-value);
45
46 case kArmTst:
47 case kArmTeq:
48 case kArmOrr:
49 case kArmEor:
50 case kArmRsb:
51 return CanBeImmediate(value);
52
53 case kArmVldrF32:
54 case kArmVstrF32:
55 case kArmVldrF64:
56 case kArmVstrF64:
57 return value >= -1020 && value <= 1020 && (value % 4) == 0;
58
59 case kArmLdrb:
60 case kArmLdrsb:
61 case kArmStrb:
62 case kArmLdr:
63 case kArmStr:
64 return value >= -4095 && value <= 4095;
65
66 case kArmLdrh:
67 case kArmLdrsh:
68 case kArmStrh:
69 return value >= -255 && value <= 255;
70
71 default:
72 break;
73 }
74 return false;
75 }
76 };
77
78
79 namespace {
80
VisitRR(InstructionSelector * selector,ArchOpcode opcode,Node * node)81 void VisitRR(InstructionSelector* selector, ArchOpcode opcode, Node* node) {
82 ArmOperandGenerator g(selector);
83 selector->Emit(opcode, g.DefineAsRegister(node),
84 g.UseRegister(node->InputAt(0)));
85 }
86
87
VisitRRR(InstructionSelector * selector,ArchOpcode opcode,Node * node)88 void VisitRRR(InstructionSelector* selector, ArchOpcode opcode, Node* node) {
89 ArmOperandGenerator g(selector);
90 selector->Emit(opcode, g.DefineAsRegister(node),
91 g.UseRegister(node->InputAt(0)),
92 g.UseRegister(node->InputAt(1)));
93 }
94
95
96 template <IrOpcode::Value kOpcode, int kImmMin, int kImmMax,
97 AddressingMode kImmMode, AddressingMode kRegMode>
TryMatchShift(InstructionSelector * selector,InstructionCode * opcode_return,Node * node,InstructionOperand * value_return,InstructionOperand * shift_return)98 bool TryMatchShift(InstructionSelector* selector,
99 InstructionCode* opcode_return, Node* node,
100 InstructionOperand* value_return,
101 InstructionOperand* shift_return) {
102 ArmOperandGenerator g(selector);
103 if (node->opcode() == kOpcode) {
104 Int32BinopMatcher m(node);
105 *value_return = g.UseRegister(m.left().node());
106 if (m.right().IsInRange(kImmMin, kImmMax)) {
107 *opcode_return |= AddressingModeField::encode(kImmMode);
108 *shift_return = g.UseImmediate(m.right().node());
109 } else {
110 *opcode_return |= AddressingModeField::encode(kRegMode);
111 *shift_return = g.UseRegister(m.right().node());
112 }
113 return true;
114 }
115 return false;
116 }
117
118 template <IrOpcode::Value kOpcode, int kImmMin, int kImmMax,
119 AddressingMode kImmMode>
TryMatchShiftImmediate(InstructionSelector * selector,InstructionCode * opcode_return,Node * node,InstructionOperand * value_return,InstructionOperand * shift_return)120 bool TryMatchShiftImmediate(InstructionSelector* selector,
121 InstructionCode* opcode_return, Node* node,
122 InstructionOperand* value_return,
123 InstructionOperand* shift_return) {
124 ArmOperandGenerator g(selector);
125 if (node->opcode() == kOpcode) {
126 Int32BinopMatcher m(node);
127 if (m.right().IsInRange(kImmMin, kImmMax)) {
128 *opcode_return |= AddressingModeField::encode(kImmMode);
129 *value_return = g.UseRegister(m.left().node());
130 *shift_return = g.UseImmediate(m.right().node());
131 return true;
132 }
133 }
134 return false;
135 }
136
TryMatchROR(InstructionSelector * selector,InstructionCode * opcode_return,Node * node,InstructionOperand * value_return,InstructionOperand * shift_return)137 bool TryMatchROR(InstructionSelector* selector, InstructionCode* opcode_return,
138 Node* node, InstructionOperand* value_return,
139 InstructionOperand* shift_return) {
140 return TryMatchShift<IrOpcode::kWord32Ror, 1, 31, kMode_Operand2_R_ROR_I,
141 kMode_Operand2_R_ROR_R>(selector, opcode_return, node,
142 value_return, shift_return);
143 }
144
145
TryMatchASR(InstructionSelector * selector,InstructionCode * opcode_return,Node * node,InstructionOperand * value_return,InstructionOperand * shift_return)146 bool TryMatchASR(InstructionSelector* selector, InstructionCode* opcode_return,
147 Node* node, InstructionOperand* value_return,
148 InstructionOperand* shift_return) {
149 return TryMatchShift<IrOpcode::kWord32Sar, 1, 32, kMode_Operand2_R_ASR_I,
150 kMode_Operand2_R_ASR_R>(selector, opcode_return, node,
151 value_return, shift_return);
152 }
153
154
TryMatchLSL(InstructionSelector * selector,InstructionCode * opcode_return,Node * node,InstructionOperand * value_return,InstructionOperand * shift_return)155 bool TryMatchLSL(InstructionSelector* selector, InstructionCode* opcode_return,
156 Node* node, InstructionOperand* value_return,
157 InstructionOperand* shift_return) {
158 return TryMatchShift<IrOpcode::kWord32Shl, 0, 31, kMode_Operand2_R_LSL_I,
159 kMode_Operand2_R_LSL_R>(selector, opcode_return, node,
160 value_return, shift_return);
161 }
162
TryMatchLSLImmediate(InstructionSelector * selector,InstructionCode * opcode_return,Node * node,InstructionOperand * value_return,InstructionOperand * shift_return)163 bool TryMatchLSLImmediate(InstructionSelector* selector,
164 InstructionCode* opcode_return, Node* node,
165 InstructionOperand* value_return,
166 InstructionOperand* shift_return) {
167 return TryMatchShiftImmediate<IrOpcode::kWord32Shl, 0, 31,
168 kMode_Operand2_R_LSL_I>(
169 selector, opcode_return, node, value_return, shift_return);
170 }
171
TryMatchLSR(InstructionSelector * selector,InstructionCode * opcode_return,Node * node,InstructionOperand * value_return,InstructionOperand * shift_return)172 bool TryMatchLSR(InstructionSelector* selector, InstructionCode* opcode_return,
173 Node* node, InstructionOperand* value_return,
174 InstructionOperand* shift_return) {
175 return TryMatchShift<IrOpcode::kWord32Shr, 1, 32, kMode_Operand2_R_LSR_I,
176 kMode_Operand2_R_LSR_R>(selector, opcode_return, node,
177 value_return, shift_return);
178 }
179
180
TryMatchShift(InstructionSelector * selector,InstructionCode * opcode_return,Node * node,InstructionOperand * value_return,InstructionOperand * shift_return)181 bool TryMatchShift(InstructionSelector* selector,
182 InstructionCode* opcode_return, Node* node,
183 InstructionOperand* value_return,
184 InstructionOperand* shift_return) {
185 return (
186 TryMatchASR(selector, opcode_return, node, value_return, shift_return) ||
187 TryMatchLSL(selector, opcode_return, node, value_return, shift_return) ||
188 TryMatchLSR(selector, opcode_return, node, value_return, shift_return) ||
189 TryMatchROR(selector, opcode_return, node, value_return, shift_return));
190 }
191
192
TryMatchImmediateOrShift(InstructionSelector * selector,InstructionCode * opcode_return,Node * node,size_t * input_count_return,InstructionOperand * inputs)193 bool TryMatchImmediateOrShift(InstructionSelector* selector,
194 InstructionCode* opcode_return, Node* node,
195 size_t* input_count_return,
196 InstructionOperand* inputs) {
197 ArmOperandGenerator g(selector);
198 if (g.CanBeImmediate(node, *opcode_return)) {
199 *opcode_return |= AddressingModeField::encode(kMode_Operand2_I);
200 inputs[0] = g.UseImmediate(node);
201 *input_count_return = 1;
202 return true;
203 }
204 if (TryMatchShift(selector, opcode_return, node, &inputs[0], &inputs[1])) {
205 *input_count_return = 2;
206 return true;
207 }
208 return false;
209 }
210
211
VisitBinop(InstructionSelector * selector,Node * node,InstructionCode opcode,InstructionCode reverse_opcode,FlagsContinuation * cont)212 void VisitBinop(InstructionSelector* selector, Node* node,
213 InstructionCode opcode, InstructionCode reverse_opcode,
214 FlagsContinuation* cont) {
215 ArmOperandGenerator g(selector);
216 Int32BinopMatcher m(node);
217 InstructionOperand inputs[5];
218 size_t input_count = 0;
219 InstructionOperand outputs[2];
220 size_t output_count = 0;
221
222 if (m.left().node() == m.right().node()) {
223 // If both inputs refer to the same operand, enforce allocating a register
224 // for both of them to ensure that we don't end up generating code like
225 // this:
226 //
227 // mov r0, r1, asr #16
228 // adds r0, r0, r1, asr #16
229 // bvs label
230 InstructionOperand const input = g.UseRegister(m.left().node());
231 opcode |= AddressingModeField::encode(kMode_Operand2_R);
232 inputs[input_count++] = input;
233 inputs[input_count++] = input;
234 } else if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(),
235 &input_count, &inputs[1])) {
236 inputs[0] = g.UseRegister(m.left().node());
237 input_count++;
238 } else if (TryMatchImmediateOrShift(selector, &reverse_opcode,
239 m.left().node(), &input_count,
240 &inputs[1])) {
241 inputs[0] = g.UseRegister(m.right().node());
242 opcode = reverse_opcode;
243 input_count++;
244 } else {
245 opcode |= AddressingModeField::encode(kMode_Operand2_R);
246 inputs[input_count++] = g.UseRegister(m.left().node());
247 inputs[input_count++] = g.UseRegister(m.right().node());
248 }
249
250 if (cont->IsBranch()) {
251 inputs[input_count++] = g.Label(cont->true_block());
252 inputs[input_count++] = g.Label(cont->false_block());
253 }
254
255 outputs[output_count++] = g.DefineAsRegister(node);
256 if (cont->IsSet()) {
257 outputs[output_count++] = g.DefineAsRegister(cont->result());
258 }
259
260 DCHECK_NE(0u, input_count);
261 DCHECK_NE(0u, output_count);
262 DCHECK_GE(arraysize(inputs), input_count);
263 DCHECK_GE(arraysize(outputs), output_count);
264 DCHECK_NE(kMode_None, AddressingModeField::decode(opcode));
265
266 opcode = cont->Encode(opcode);
267 if (cont->IsDeoptimize()) {
268 selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
269 cont->reason(), cont->frame_state());
270 } else {
271 selector->Emit(opcode, output_count, outputs, input_count, inputs);
272 }
273 }
274
275
VisitBinop(InstructionSelector * selector,Node * node,InstructionCode opcode,InstructionCode reverse_opcode)276 void VisitBinop(InstructionSelector* selector, Node* node,
277 InstructionCode opcode, InstructionCode reverse_opcode) {
278 FlagsContinuation cont;
279 VisitBinop(selector, node, opcode, reverse_opcode, &cont);
280 }
281
282
EmitDiv(InstructionSelector * selector,ArchOpcode div_opcode,ArchOpcode f64i32_opcode,ArchOpcode i32f64_opcode,InstructionOperand result_operand,InstructionOperand left_operand,InstructionOperand right_operand)283 void EmitDiv(InstructionSelector* selector, ArchOpcode div_opcode,
284 ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode,
285 InstructionOperand result_operand, InstructionOperand left_operand,
286 InstructionOperand right_operand) {
287 ArmOperandGenerator g(selector);
288 if (selector->IsSupported(SUDIV)) {
289 selector->Emit(div_opcode, result_operand, left_operand, right_operand);
290 return;
291 }
292 InstructionOperand left_double_operand = g.TempDoubleRegister();
293 InstructionOperand right_double_operand = g.TempDoubleRegister();
294 InstructionOperand result_double_operand = g.TempDoubleRegister();
295 selector->Emit(f64i32_opcode, left_double_operand, left_operand);
296 selector->Emit(f64i32_opcode, right_double_operand, right_operand);
297 selector->Emit(kArmVdivF64, result_double_operand, left_double_operand,
298 right_double_operand);
299 selector->Emit(i32f64_opcode, result_operand, result_double_operand);
300 }
301
302
VisitDiv(InstructionSelector * selector,Node * node,ArchOpcode div_opcode,ArchOpcode f64i32_opcode,ArchOpcode i32f64_opcode)303 void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode div_opcode,
304 ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode) {
305 ArmOperandGenerator g(selector);
306 Int32BinopMatcher m(node);
307 EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode,
308 g.DefineAsRegister(node), g.UseRegister(m.left().node()),
309 g.UseRegister(m.right().node()));
310 }
311
312
VisitMod(InstructionSelector * selector,Node * node,ArchOpcode div_opcode,ArchOpcode f64i32_opcode,ArchOpcode i32f64_opcode)313 void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode div_opcode,
314 ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode) {
315 ArmOperandGenerator g(selector);
316 Int32BinopMatcher m(node);
317 InstructionOperand div_operand = g.TempRegister();
318 InstructionOperand result_operand = g.DefineAsRegister(node);
319 InstructionOperand left_operand = g.UseRegister(m.left().node());
320 InstructionOperand right_operand = g.UseRegister(m.right().node());
321 EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode, div_operand,
322 left_operand, right_operand);
323 if (selector->IsSupported(ARMv7)) {
324 selector->Emit(kArmMls, result_operand, div_operand, right_operand,
325 left_operand);
326 } else {
327 InstructionOperand mul_operand = g.TempRegister();
328 selector->Emit(kArmMul, mul_operand, div_operand, right_operand);
329 selector->Emit(kArmSub | AddressingModeField::encode(kMode_Operand2_R),
330 result_operand, left_operand, mul_operand);
331 }
332 }
333
EmitLoad(InstructionSelector * selector,InstructionCode opcode,InstructionOperand * output,Node * base,Node * index)334 void EmitLoad(InstructionSelector* selector, InstructionCode opcode,
335 InstructionOperand* output, Node* base, Node* index) {
336 ArmOperandGenerator g(selector);
337 InstructionOperand inputs[3];
338 size_t input_count = 2;
339
340 inputs[0] = g.UseRegister(base);
341 if (g.CanBeImmediate(index, opcode)) {
342 inputs[1] = g.UseImmediate(index);
343 opcode |= AddressingModeField::encode(kMode_Offset_RI);
344 } else if ((opcode == kArmLdr) &&
345 TryMatchLSLImmediate(selector, &opcode, index, &inputs[1],
346 &inputs[2])) {
347 input_count = 3;
348 } else {
349 inputs[1] = g.UseRegister(index);
350 opcode |= AddressingModeField::encode(kMode_Offset_RR);
351 }
352 selector->Emit(opcode, 1, output, input_count, inputs);
353 }
354
EmitStore(InstructionSelector * selector,InstructionCode opcode,size_t input_count,InstructionOperand * inputs,Node * index)355 void EmitStore(InstructionSelector* selector, InstructionCode opcode,
356 size_t input_count, InstructionOperand* inputs,
357 Node* index) {
358 ArmOperandGenerator g(selector);
359
360 if (g.CanBeImmediate(index, opcode)) {
361 inputs[input_count++] = g.UseImmediate(index);
362 opcode |= AddressingModeField::encode(kMode_Offset_RI);
363 } else if ((opcode == kArmStr) &&
364 TryMatchLSLImmediate(selector, &opcode, index, &inputs[2],
365 &inputs[3])) {
366 input_count = 4;
367 } else {
368 inputs[input_count++] = g.UseRegister(index);
369 opcode |= AddressingModeField::encode(kMode_Offset_RR);
370 }
371 selector->Emit(opcode, 0, nullptr, input_count, inputs);
372 }
373
374 } // namespace
375
376
VisitLoad(Node * node)377 void InstructionSelector::VisitLoad(Node* node) {
378 LoadRepresentation load_rep = LoadRepresentationOf(node->op());
379 ArmOperandGenerator g(this);
380 Node* base = node->InputAt(0);
381 Node* index = node->InputAt(1);
382
383 InstructionCode opcode = kArchNop;
384 switch (load_rep.representation()) {
385 case MachineRepresentation::kFloat32:
386 opcode = kArmVldrF32;
387 break;
388 case MachineRepresentation::kFloat64:
389 opcode = kArmVldrF64;
390 break;
391 case MachineRepresentation::kBit: // Fall through.
392 case MachineRepresentation::kWord8:
393 opcode = load_rep.IsUnsigned() ? kArmLdrb : kArmLdrsb;
394 break;
395 case MachineRepresentation::kWord16:
396 opcode = load_rep.IsUnsigned() ? kArmLdrh : kArmLdrsh;
397 break;
398 case MachineRepresentation::kTaggedSigned: // Fall through.
399 case MachineRepresentation::kTaggedPointer: // Fall through.
400 case MachineRepresentation::kTagged: // Fall through.
401 case MachineRepresentation::kWord32:
402 opcode = kArmLdr;
403 break;
404 case MachineRepresentation::kWord64: // Fall through.
405 case MachineRepresentation::kSimd128: // Fall through.
406 case MachineRepresentation::kNone:
407 UNREACHABLE();
408 return;
409 }
410
411 InstructionOperand output = g.DefineAsRegister(node);
412 EmitLoad(this, opcode, &output, base, index);
413 }
414
VisitProtectedLoad(Node * node)415 void InstructionSelector::VisitProtectedLoad(Node* node) {
416 // TODO(eholk)
417 UNIMPLEMENTED();
418 }
419
VisitStore(Node * node)420 void InstructionSelector::VisitStore(Node* node) {
421 ArmOperandGenerator g(this);
422 Node* base = node->InputAt(0);
423 Node* index = node->InputAt(1);
424 Node* value = node->InputAt(2);
425
426 StoreRepresentation store_rep = StoreRepresentationOf(node->op());
427 WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind();
428 MachineRepresentation rep = store_rep.representation();
429
430 if (write_barrier_kind != kNoWriteBarrier) {
431 DCHECK(CanBeTaggedPointer(rep));
432 AddressingMode addressing_mode;
433 InstructionOperand inputs[3];
434 size_t input_count = 0;
435 inputs[input_count++] = g.UseUniqueRegister(base);
436 // OutOfLineRecordWrite uses the index in an 'add' instruction as well as
437 // for the store itself, so we must check compatibility with both.
438 if (g.CanBeImmediate(index, kArmAdd) && g.CanBeImmediate(index, kArmStr)) {
439 inputs[input_count++] = g.UseImmediate(index);
440 addressing_mode = kMode_Offset_RI;
441 } else {
442 inputs[input_count++] = g.UseUniqueRegister(index);
443 addressing_mode = kMode_Offset_RR;
444 }
445 inputs[input_count++] = g.UseUniqueRegister(value);
446 RecordWriteMode record_write_mode = RecordWriteMode::kValueIsAny;
447 switch (write_barrier_kind) {
448 case kNoWriteBarrier:
449 UNREACHABLE();
450 break;
451 case kMapWriteBarrier:
452 record_write_mode = RecordWriteMode::kValueIsMap;
453 break;
454 case kPointerWriteBarrier:
455 record_write_mode = RecordWriteMode::kValueIsPointer;
456 break;
457 case kFullWriteBarrier:
458 record_write_mode = RecordWriteMode::kValueIsAny;
459 break;
460 }
461 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
462 size_t const temp_count = arraysize(temps);
463 InstructionCode code = kArchStoreWithWriteBarrier;
464 code |= AddressingModeField::encode(addressing_mode);
465 code |= MiscField::encode(static_cast<int>(record_write_mode));
466 Emit(code, 0, nullptr, input_count, inputs, temp_count, temps);
467 } else {
468 InstructionCode opcode = kArchNop;
469 switch (rep) {
470 case MachineRepresentation::kFloat32:
471 opcode = kArmVstrF32;
472 break;
473 case MachineRepresentation::kFloat64:
474 opcode = kArmVstrF64;
475 break;
476 case MachineRepresentation::kBit: // Fall through.
477 case MachineRepresentation::kWord8:
478 opcode = kArmStrb;
479 break;
480 case MachineRepresentation::kWord16:
481 opcode = kArmStrh;
482 break;
483 case MachineRepresentation::kTaggedSigned: // Fall through.
484 case MachineRepresentation::kTaggedPointer: // Fall through.
485 case MachineRepresentation::kTagged: // Fall through.
486 case MachineRepresentation::kWord32:
487 opcode = kArmStr;
488 break;
489 case MachineRepresentation::kWord64: // Fall through.
490 case MachineRepresentation::kSimd128: // Fall through.
491 case MachineRepresentation::kNone:
492 UNREACHABLE();
493 return;
494 }
495
496 InstructionOperand inputs[4];
497 size_t input_count = 0;
498 inputs[input_count++] = g.UseRegister(value);
499 inputs[input_count++] = g.UseRegister(base);
500 EmitStore(this, opcode, input_count, inputs, index);
501 }
502 }
503
VisitUnalignedLoad(Node * node)504 void InstructionSelector::VisitUnalignedLoad(Node* node) {
505 UnalignedLoadRepresentation load_rep =
506 UnalignedLoadRepresentationOf(node->op());
507 ArmOperandGenerator g(this);
508 Node* base = node->InputAt(0);
509 Node* index = node->InputAt(1);
510
511 InstructionCode opcode = kArmLdr;
512 // Only floating point loads need to be specially handled; integer loads
513 // support unaligned access. We support unaligned FP loads by loading to
514 // integer registers first, then moving to the destination FP register.
515 switch (load_rep.representation()) {
516 case MachineRepresentation::kFloat32: {
517 InstructionOperand temp = g.TempRegister();
518 EmitLoad(this, opcode, &temp, base, index);
519 Emit(kArmVmovF32U32, g.DefineAsRegister(node), temp);
520 return;
521 }
522 case MachineRepresentation::kFloat64: {
523 // TODO(arm): use vld1.8 for this when NEON is available.
524 // Compute the address of the least-significant half of the FP value.
525 // We assume that the base node is unlikely to be an encodable immediate
526 // or the result of a shift operation, so only consider the addressing
527 // mode that should be used for the index node.
528 InstructionCode add_opcode = kArmAdd;
529 InstructionOperand inputs[3];
530 inputs[0] = g.UseRegister(base);
531
532 size_t input_count;
533 if (TryMatchImmediateOrShift(this, &add_opcode, index, &input_count,
534 &inputs[1])) {
535 // input_count has been set by TryMatchImmediateOrShift(), so increment
536 // it to account for the base register in inputs[0].
537 input_count++;
538 } else {
539 add_opcode |= AddressingModeField::encode(kMode_Operand2_R);
540 inputs[1] = g.UseRegister(index);
541 input_count = 2; // Base register and index.
542 }
543
544 InstructionOperand addr = g.TempRegister();
545 Emit(add_opcode, 1, &addr, input_count, inputs);
546
547 // Load both halves and move to an FP register.
548 InstructionOperand fp_lo = g.TempRegister();
549 InstructionOperand fp_hi = g.TempRegister();
550 opcode |= AddressingModeField::encode(kMode_Offset_RI);
551 Emit(opcode, fp_lo, addr, g.TempImmediate(0));
552 Emit(opcode, fp_hi, addr, g.TempImmediate(4));
553 Emit(kArmVmovF64U32U32, g.DefineAsRegister(node), fp_lo, fp_hi);
554 return;
555 }
556 default:
557 // All other cases should support unaligned accesses.
558 UNREACHABLE();
559 return;
560 }
561 }
562
VisitUnalignedStore(Node * node)563 void InstructionSelector::VisitUnalignedStore(Node* node) {
564 ArmOperandGenerator g(this);
565 Node* base = node->InputAt(0);
566 Node* index = node->InputAt(1);
567 Node* value = node->InputAt(2);
568
569 InstructionOperand inputs[4];
570 size_t input_count = 0;
571
572 UnalignedStoreRepresentation store_rep =
573 UnalignedStoreRepresentationOf(node->op());
574
575 // Only floating point stores need to be specially handled; integer stores
576 // support unaligned access. We support unaligned FP stores by moving the
577 // value to integer registers first, then storing to the destination address.
578 switch (store_rep) {
579 case MachineRepresentation::kFloat32: {
580 inputs[input_count++] = g.TempRegister();
581 Emit(kArmVmovU32F32, inputs[0], g.UseRegister(value));
582 inputs[input_count++] = g.UseRegister(base);
583 EmitStore(this, kArmStr, input_count, inputs, index);
584 return;
585 }
586 case MachineRepresentation::kFloat64: {
587 // TODO(arm): use vst1.8 for this when NEON is available.
588 // Store a 64-bit floating point value using two 32-bit integer stores.
589 // Computing the store address here would require three live temporary
590 // registers (fp<63:32>, fp<31:0>, address), so compute base + 4 after
591 // storing the least-significant half of the value.
592
593 // First, move the 64-bit FP value into two temporary integer registers.
594 InstructionOperand fp[] = {g.TempRegister(), g.TempRegister()};
595 inputs[input_count++] = g.UseRegister(value);
596 Emit(kArmVmovU32U32F64, arraysize(fp), fp, input_count,
597 inputs);
598
599 // Store the least-significant half.
600 inputs[0] = fp[0]; // Low 32-bits of FP value.
601 inputs[input_count++] = g.UseRegister(base); // First store base address.
602 EmitStore(this, kArmStr, input_count, inputs, index);
603
604 // Store the most-significant half.
605 InstructionOperand base4 = g.TempRegister();
606 Emit(kArmAdd | AddressingModeField::encode(kMode_Operand2_I), base4,
607 g.UseRegister(base), g.TempImmediate(4)); // Compute base + 4.
608 inputs[0] = fp[1]; // High 32-bits of FP value.
609 inputs[1] = base4; // Second store base + 4 address.
610 EmitStore(this, kArmStr, input_count, inputs, index);
611 return;
612 }
613 default:
614 // All other cases should support unaligned accesses.
615 UNREACHABLE();
616 return;
617 }
618 }
619
VisitCheckedLoad(Node * node)620 void InstructionSelector::VisitCheckedLoad(Node* node) {
621 CheckedLoadRepresentation load_rep = CheckedLoadRepresentationOf(node->op());
622 ArmOperandGenerator g(this);
623 Node* const buffer = node->InputAt(0);
624 Node* const offset = node->InputAt(1);
625 Node* const length = node->InputAt(2);
626 ArchOpcode opcode = kArchNop;
627 switch (load_rep.representation()) {
628 case MachineRepresentation::kWord8:
629 opcode = load_rep.IsSigned() ? kCheckedLoadInt8 : kCheckedLoadUint8;
630 break;
631 case MachineRepresentation::kWord16:
632 opcode = load_rep.IsSigned() ? kCheckedLoadInt16 : kCheckedLoadUint16;
633 break;
634 case MachineRepresentation::kWord32:
635 opcode = kCheckedLoadWord32;
636 break;
637 case MachineRepresentation::kFloat32:
638 opcode = kCheckedLoadFloat32;
639 break;
640 case MachineRepresentation::kFloat64:
641 opcode = kCheckedLoadFloat64;
642 break;
643 case MachineRepresentation::kBit: // Fall through.
644 case MachineRepresentation::kTaggedSigned: // Fall through.
645 case MachineRepresentation::kTaggedPointer: // Fall through.
646 case MachineRepresentation::kTagged: // Fall through.
647 case MachineRepresentation::kWord64: // Fall through.
648 case MachineRepresentation::kSimd128: // Fall through.
649 case MachineRepresentation::kNone:
650 UNREACHABLE();
651 return;
652 }
653 InstructionOperand offset_operand = g.UseRegister(offset);
654 InstructionOperand length_operand = g.CanBeImmediate(length, kArmCmp)
655 ? g.UseImmediate(length)
656 : g.UseRegister(length);
657 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR),
658 g.DefineAsRegister(node), offset_operand, length_operand,
659 g.UseRegister(buffer), offset_operand);
660 }
661
662
VisitCheckedStore(Node * node)663 void InstructionSelector::VisitCheckedStore(Node* node) {
664 MachineRepresentation rep = CheckedStoreRepresentationOf(node->op());
665 ArmOperandGenerator g(this);
666 Node* const buffer = node->InputAt(0);
667 Node* const offset = node->InputAt(1);
668 Node* const length = node->InputAt(2);
669 Node* const value = node->InputAt(3);
670 ArchOpcode opcode = kArchNop;
671 switch (rep) {
672 case MachineRepresentation::kWord8:
673 opcode = kCheckedStoreWord8;
674 break;
675 case MachineRepresentation::kWord16:
676 opcode = kCheckedStoreWord16;
677 break;
678 case MachineRepresentation::kWord32:
679 opcode = kCheckedStoreWord32;
680 break;
681 case MachineRepresentation::kFloat32:
682 opcode = kCheckedStoreFloat32;
683 break;
684 case MachineRepresentation::kFloat64:
685 opcode = kCheckedStoreFloat64;
686 break;
687 case MachineRepresentation::kBit: // Fall through.
688 case MachineRepresentation::kTaggedSigned: // Fall through.
689 case MachineRepresentation::kTaggedPointer: // Fall through.
690 case MachineRepresentation::kTagged: // Fall through.
691 case MachineRepresentation::kWord64: // Fall through.
692 case MachineRepresentation::kSimd128: // Fall through.
693 case MachineRepresentation::kNone:
694 UNREACHABLE();
695 return;
696 }
697 InstructionOperand offset_operand = g.UseRegister(offset);
698 InstructionOperand length_operand = g.CanBeImmediate(length, kArmCmp)
699 ? g.UseImmediate(length)
700 : g.UseRegister(length);
701 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), g.NoOutput(),
702 offset_operand, length_operand, g.UseRegister(value),
703 g.UseRegister(buffer), offset_operand);
704 }
705
706
707 namespace {
708
EmitBic(InstructionSelector * selector,Node * node,Node * left,Node * right)709 void EmitBic(InstructionSelector* selector, Node* node, Node* left,
710 Node* right) {
711 ArmOperandGenerator g(selector);
712 InstructionCode opcode = kArmBic;
713 InstructionOperand value_operand;
714 InstructionOperand shift_operand;
715 if (TryMatchShift(selector, &opcode, right, &value_operand, &shift_operand)) {
716 selector->Emit(opcode, g.DefineAsRegister(node), g.UseRegister(left),
717 value_operand, shift_operand);
718 return;
719 }
720 selector->Emit(opcode | AddressingModeField::encode(kMode_Operand2_R),
721 g.DefineAsRegister(node), g.UseRegister(left),
722 g.UseRegister(right));
723 }
724
725
EmitUbfx(InstructionSelector * selector,Node * node,Node * left,uint32_t lsb,uint32_t width)726 void EmitUbfx(InstructionSelector* selector, Node* node, Node* left,
727 uint32_t lsb, uint32_t width) {
728 DCHECK_LE(1u, width);
729 DCHECK_LE(width, 32u - lsb);
730 ArmOperandGenerator g(selector);
731 selector->Emit(kArmUbfx, g.DefineAsRegister(node), g.UseRegister(left),
732 g.TempImmediate(lsb), g.TempImmediate(width));
733 }
734
735 } // namespace
736
737
VisitWord32And(Node * node)738 void InstructionSelector::VisitWord32And(Node* node) {
739 ArmOperandGenerator g(this);
740 Int32BinopMatcher m(node);
741 if (m.left().IsWord32Xor() && CanCover(node, m.left().node())) {
742 Int32BinopMatcher mleft(m.left().node());
743 if (mleft.right().Is(-1)) {
744 EmitBic(this, node, m.right().node(), mleft.left().node());
745 return;
746 }
747 }
748 if (m.right().IsWord32Xor() && CanCover(node, m.right().node())) {
749 Int32BinopMatcher mright(m.right().node());
750 if (mright.right().Is(-1)) {
751 EmitBic(this, node, m.left().node(), mright.left().node());
752 return;
753 }
754 }
755 if (m.right().HasValue()) {
756 uint32_t const value = m.right().Value();
757 uint32_t width = base::bits::CountPopulation32(value);
758 uint32_t leading_zeros = base::bits::CountLeadingZeros32(value);
759
760 // Try to merge SHR operations on the left hand input into this AND.
761 if (m.left().IsWord32Shr()) {
762 Int32BinopMatcher mshr(m.left().node());
763 if (mshr.right().HasValue()) {
764 uint32_t const shift = mshr.right().Value();
765
766 if (((shift == 8) || (shift == 16) || (shift == 24)) &&
767 ((value == 0xff) || (value == 0xffff))) {
768 // Merge SHR into AND by emitting a UXTB or UXTH instruction with a
769 // bytewise rotation.
770 Emit((value == 0xff) ? kArmUxtb : kArmUxth,
771 g.DefineAsRegister(m.node()), g.UseRegister(mshr.left().node()),
772 g.TempImmediate(mshr.right().Value()));
773 return;
774 } else if (IsSupported(ARMv7) && (width != 0) &&
775 ((leading_zeros + width) == 32)) {
776 // Merge Shr into And by emitting a UBFX instruction.
777 DCHECK_EQ(0u, base::bits::CountTrailingZeros32(value));
778 if ((1 <= shift) && (shift <= 31)) {
779 // UBFX cannot extract bits past the register size, however since
780 // shifting the original value would have introduced some zeros we
781 // can still use UBFX with a smaller mask and the remaining bits
782 // will be zeros.
783 EmitUbfx(this, node, mshr.left().node(), shift,
784 std::min(width, 32 - shift));
785 return;
786 }
787 }
788 }
789 } else if (value == 0xffff) {
790 // Emit UXTH for this AND. We don't bother testing for UXTB, as it's no
791 // better than AND 0xff for this operation.
792 Emit(kArmUxth, g.DefineAsRegister(m.node()),
793 g.UseRegister(m.left().node()), g.TempImmediate(0));
794 return;
795 }
796 if (g.CanBeImmediate(~value)) {
797 // Emit BIC for this AND by inverting the immediate value first.
798 Emit(kArmBic | AddressingModeField::encode(kMode_Operand2_I),
799 g.DefineAsRegister(node), g.UseRegister(m.left().node()),
800 g.TempImmediate(~value));
801 return;
802 }
803 if (!g.CanBeImmediate(value) && IsSupported(ARMv7)) {
804 // If value has 9 to 23 contiguous set bits, and has the lsb set, we can
805 // replace this AND with UBFX. Other contiguous bit patterns have already
806 // been handled by BIC or will be handled by AND.
807 if ((width != 0) && ((leading_zeros + width) == 32) &&
808 (9 <= leading_zeros) && (leading_zeros <= 23)) {
809 DCHECK_EQ(0u, base::bits::CountTrailingZeros32(value));
810 EmitUbfx(this, node, m.left().node(), 0, width);
811 return;
812 }
813
814 width = 32 - width;
815 leading_zeros = base::bits::CountLeadingZeros32(~value);
816 uint32_t lsb = base::bits::CountTrailingZeros32(~value);
817 if ((leading_zeros + width + lsb) == 32) {
818 // This AND can be replaced with BFC.
819 Emit(kArmBfc, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
820 g.TempImmediate(lsb), g.TempImmediate(width));
821 return;
822 }
823 }
824 }
825 VisitBinop(this, node, kArmAnd, kArmAnd);
826 }
827
828
VisitWord32Or(Node * node)829 void InstructionSelector::VisitWord32Or(Node* node) {
830 VisitBinop(this, node, kArmOrr, kArmOrr);
831 }
832
833
VisitWord32Xor(Node * node)834 void InstructionSelector::VisitWord32Xor(Node* node) {
835 ArmOperandGenerator g(this);
836 Int32BinopMatcher m(node);
837 if (m.right().Is(-1)) {
838 InstructionCode opcode = kArmMvn;
839 InstructionOperand value_operand;
840 InstructionOperand shift_operand;
841 if (TryMatchShift(this, &opcode, m.left().node(), &value_operand,
842 &shift_operand)) {
843 Emit(opcode, g.DefineAsRegister(node), value_operand, shift_operand);
844 return;
845 }
846 Emit(opcode | AddressingModeField::encode(kMode_Operand2_R),
847 g.DefineAsRegister(node), g.UseRegister(m.left().node()));
848 return;
849 }
850 VisitBinop(this, node, kArmEor, kArmEor);
851 }
852
853
854 namespace {
855
856 template <typename TryMatchShift>
VisitShift(InstructionSelector * selector,Node * node,TryMatchShift try_match_shift,FlagsContinuation * cont)857 void VisitShift(InstructionSelector* selector, Node* node,
858 TryMatchShift try_match_shift, FlagsContinuation* cont) {
859 ArmOperandGenerator g(selector);
860 InstructionCode opcode = kArmMov;
861 InstructionOperand inputs[4];
862 size_t input_count = 2;
863 InstructionOperand outputs[2];
864 size_t output_count = 0;
865
866 CHECK(try_match_shift(selector, &opcode, node, &inputs[0], &inputs[1]));
867
868 if (cont->IsBranch()) {
869 inputs[input_count++] = g.Label(cont->true_block());
870 inputs[input_count++] = g.Label(cont->false_block());
871 }
872
873 outputs[output_count++] = g.DefineAsRegister(node);
874 if (cont->IsSet()) {
875 outputs[output_count++] = g.DefineAsRegister(cont->result());
876 }
877
878 DCHECK_NE(0u, input_count);
879 DCHECK_NE(0u, output_count);
880 DCHECK_GE(arraysize(inputs), input_count);
881 DCHECK_GE(arraysize(outputs), output_count);
882 DCHECK_NE(kMode_None, AddressingModeField::decode(opcode));
883
884 opcode = cont->Encode(opcode);
885 if (cont->IsDeoptimize()) {
886 selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
887 cont->reason(), cont->frame_state());
888 } else {
889 selector->Emit(opcode, output_count, outputs, input_count, inputs);
890 }
891 }
892
893
894 template <typename TryMatchShift>
VisitShift(InstructionSelector * selector,Node * node,TryMatchShift try_match_shift)895 void VisitShift(InstructionSelector* selector, Node* node,
896 TryMatchShift try_match_shift) {
897 FlagsContinuation cont;
898 VisitShift(selector, node, try_match_shift, &cont);
899 }
900
901 } // namespace
902
903
VisitWord32Shl(Node * node)904 void InstructionSelector::VisitWord32Shl(Node* node) {
905 VisitShift(this, node, TryMatchLSL);
906 }
907
908
VisitWord32Shr(Node * node)909 void InstructionSelector::VisitWord32Shr(Node* node) {
910 ArmOperandGenerator g(this);
911 Int32BinopMatcher m(node);
912 if (IsSupported(ARMv7) && m.left().IsWord32And() &&
913 m.right().IsInRange(0, 31)) {
914 uint32_t lsb = m.right().Value();
915 Int32BinopMatcher mleft(m.left().node());
916 if (mleft.right().HasValue()) {
917 uint32_t value = (mleft.right().Value() >> lsb) << lsb;
918 uint32_t width = base::bits::CountPopulation32(value);
919 uint32_t msb = base::bits::CountLeadingZeros32(value);
920 if (msb + width + lsb == 32) {
921 DCHECK_EQ(lsb, base::bits::CountTrailingZeros32(value));
922 return EmitUbfx(this, node, mleft.left().node(), lsb, width);
923 }
924 }
925 }
926 VisitShift(this, node, TryMatchLSR);
927 }
928
929
VisitWord32Sar(Node * node)930 void InstructionSelector::VisitWord32Sar(Node* node) {
931 ArmOperandGenerator g(this);
932 Int32BinopMatcher m(node);
933 if (CanCover(m.node(), m.left().node()) && m.left().IsWord32Shl()) {
934 Int32BinopMatcher mleft(m.left().node());
935 if (m.right().HasValue() && mleft.right().HasValue()) {
936 uint32_t sar = m.right().Value();
937 uint32_t shl = mleft.right().Value();
938 if ((sar == shl) && (sar == 16)) {
939 Emit(kArmSxth, g.DefineAsRegister(node),
940 g.UseRegister(mleft.left().node()), g.TempImmediate(0));
941 return;
942 } else if ((sar == shl) && (sar == 24)) {
943 Emit(kArmSxtb, g.DefineAsRegister(node),
944 g.UseRegister(mleft.left().node()), g.TempImmediate(0));
945 return;
946 } else if (IsSupported(ARMv7) && (sar >= shl)) {
947 Emit(kArmSbfx, g.DefineAsRegister(node),
948 g.UseRegister(mleft.left().node()), g.TempImmediate(sar - shl),
949 g.TempImmediate(32 - sar));
950 return;
951 }
952 }
953 }
954 VisitShift(this, node, TryMatchASR);
955 }
956
VisitInt32PairAdd(Node * node)957 void InstructionSelector::VisitInt32PairAdd(Node* node) {
958 ArmOperandGenerator g(this);
959
960 Node* projection1 = NodeProperties::FindProjection(node, 1);
961 if (projection1) {
962 // We use UseUniqueRegister here to avoid register sharing with the output
963 // registers.
964 InstructionOperand inputs[] = {
965 g.UseRegister(node->InputAt(0)), g.UseUniqueRegister(node->InputAt(1)),
966 g.UseRegister(node->InputAt(2)), g.UseUniqueRegister(node->InputAt(3))};
967
968 InstructionOperand outputs[] = {
969 g.DefineAsRegister(node),
970 g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
971
972 Emit(kArmAddPair, 2, outputs, 4, inputs);
973 } else {
974 // The high word of the result is not used, so we emit the standard 32 bit
975 // instruction.
976 Emit(kArmAdd | AddressingModeField::encode(kMode_Operand2_R),
977 g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)),
978 g.UseRegister(node->InputAt(2)));
979 }
980 }
981
VisitInt32PairSub(Node * node)982 void InstructionSelector::VisitInt32PairSub(Node* node) {
983 ArmOperandGenerator g(this);
984
985 Node* projection1 = NodeProperties::FindProjection(node, 1);
986 if (projection1) {
987 // We use UseUniqueRegister here to avoid register sharing with the output
988 // register.
989 InstructionOperand inputs[] = {
990 g.UseRegister(node->InputAt(0)), g.UseUniqueRegister(node->InputAt(1)),
991 g.UseRegister(node->InputAt(2)), g.UseUniqueRegister(node->InputAt(3))};
992
993 InstructionOperand outputs[] = {
994 g.DefineAsRegister(node),
995 g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
996
997 Emit(kArmSubPair, 2, outputs, 4, inputs);
998 } else {
999 // The high word of the result is not used, so we emit the standard 32 bit
1000 // instruction.
1001 Emit(kArmSub | AddressingModeField::encode(kMode_Operand2_R),
1002 g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)),
1003 g.UseRegister(node->InputAt(2)));
1004 }
1005 }
1006
VisitInt32PairMul(Node * node)1007 void InstructionSelector::VisitInt32PairMul(Node* node) {
1008 ArmOperandGenerator g(this);
1009 Node* projection1 = NodeProperties::FindProjection(node, 1);
1010 if (projection1) {
1011 InstructionOperand inputs[] = {g.UseUniqueRegister(node->InputAt(0)),
1012 g.UseUniqueRegister(node->InputAt(1)),
1013 g.UseUniqueRegister(node->InputAt(2)),
1014 g.UseUniqueRegister(node->InputAt(3))};
1015
1016 InstructionOperand outputs[] = {
1017 g.DefineAsRegister(node),
1018 g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
1019
1020 Emit(kArmMulPair, 2, outputs, 4, inputs);
1021 } else {
1022 // The high word of the result is not used, so we emit the standard 32 bit
1023 // instruction.
1024 Emit(kArmMul | AddressingModeField::encode(kMode_Operand2_R),
1025 g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)),
1026 g.UseRegister(node->InputAt(2)));
1027 }
1028 }
1029
1030 namespace {
1031 // Shared routine for multiple shift operations.
VisitWord32PairShift(InstructionSelector * selector,InstructionCode opcode,Node * node)1032 void VisitWord32PairShift(InstructionSelector* selector, InstructionCode opcode,
1033 Node* node) {
1034 ArmOperandGenerator g(selector);
1035 // We use g.UseUniqueRegister here to guarantee that there is
1036 // no register aliasing of input registers with output registers.
1037 Int32Matcher m(node->InputAt(2));
1038 InstructionOperand shift_operand;
1039 if (m.HasValue()) {
1040 shift_operand = g.UseImmediate(m.node());
1041 } else {
1042 shift_operand = g.UseUniqueRegister(m.node());
1043 }
1044
1045 InstructionOperand inputs[] = {g.UseUniqueRegister(node->InputAt(0)),
1046 g.UseUniqueRegister(node->InputAt(1)),
1047 shift_operand};
1048
1049 Node* projection1 = NodeProperties::FindProjection(node, 1);
1050
1051 InstructionOperand outputs[2];
1052 InstructionOperand temps[1];
1053 int32_t output_count = 0;
1054 int32_t temp_count = 0;
1055
1056 outputs[output_count++] = g.DefineAsRegister(node);
1057 if (projection1) {
1058 outputs[output_count++] = g.DefineAsRegister(projection1);
1059 } else {
1060 temps[temp_count++] = g.TempRegister();
1061 }
1062
1063 selector->Emit(opcode, output_count, outputs, 3, inputs, temp_count, temps);
1064 }
1065 } // namespace
VisitWord32PairShl(Node * node)1066 void InstructionSelector::VisitWord32PairShl(Node* node) {
1067 VisitWord32PairShift(this, kArmLslPair, node);
1068 }
1069
VisitWord32PairShr(Node * node)1070 void InstructionSelector::VisitWord32PairShr(Node* node) {
1071 VisitWord32PairShift(this, kArmLsrPair, node);
1072 }
1073
VisitWord32PairSar(Node * node)1074 void InstructionSelector::VisitWord32PairSar(Node* node) {
1075 VisitWord32PairShift(this, kArmAsrPair, node);
1076 }
1077
VisitWord32Ror(Node * node)1078 void InstructionSelector::VisitWord32Ror(Node* node) {
1079 VisitShift(this, node, TryMatchROR);
1080 }
1081
1082
VisitWord32Clz(Node * node)1083 void InstructionSelector::VisitWord32Clz(Node* node) {
1084 VisitRR(this, kArmClz, node);
1085 }
1086
1087
VisitWord32Ctz(Node * node)1088 void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); }
1089
1090
VisitWord32ReverseBits(Node * node)1091 void InstructionSelector::VisitWord32ReverseBits(Node* node) {
1092 DCHECK(IsSupported(ARMv7));
1093 VisitRR(this, kArmRbit, node);
1094 }
1095
VisitWord64ReverseBytes(Node * node)1096 void InstructionSelector::VisitWord64ReverseBytes(Node* node) { UNREACHABLE(); }
1097
VisitWord32ReverseBytes(Node * node)1098 void InstructionSelector::VisitWord32ReverseBytes(Node* node) { UNREACHABLE(); }
1099
VisitWord32Popcnt(Node * node)1100 void InstructionSelector::VisitWord32Popcnt(Node* node) { UNREACHABLE(); }
1101
1102
VisitInt32Add(Node * node)1103 void InstructionSelector::VisitInt32Add(Node* node) {
1104 ArmOperandGenerator g(this);
1105 Int32BinopMatcher m(node);
1106 if (CanCover(node, m.left().node())) {
1107 switch (m.left().opcode()) {
1108 case IrOpcode::kInt32Mul: {
1109 Int32BinopMatcher mleft(m.left().node());
1110 Emit(kArmMla, g.DefineAsRegister(node),
1111 g.UseRegister(mleft.left().node()),
1112 g.UseRegister(mleft.right().node()),
1113 g.UseRegister(m.right().node()));
1114 return;
1115 }
1116 case IrOpcode::kInt32MulHigh: {
1117 Int32BinopMatcher mleft(m.left().node());
1118 Emit(kArmSmmla, g.DefineAsRegister(node),
1119 g.UseRegister(mleft.left().node()),
1120 g.UseRegister(mleft.right().node()),
1121 g.UseRegister(m.right().node()));
1122 return;
1123 }
1124 case IrOpcode::kWord32And: {
1125 Int32BinopMatcher mleft(m.left().node());
1126 if (mleft.right().Is(0xff)) {
1127 Emit(kArmUxtab, g.DefineAsRegister(node),
1128 g.UseRegister(m.right().node()),
1129 g.UseRegister(mleft.left().node()), g.TempImmediate(0));
1130 return;
1131 } else if (mleft.right().Is(0xffff)) {
1132 Emit(kArmUxtah, g.DefineAsRegister(node),
1133 g.UseRegister(m.right().node()),
1134 g.UseRegister(mleft.left().node()), g.TempImmediate(0));
1135 return;
1136 }
1137 }
1138 case IrOpcode::kWord32Sar: {
1139 Int32BinopMatcher mleft(m.left().node());
1140 if (CanCover(mleft.node(), mleft.left().node()) &&
1141 mleft.left().IsWord32Shl()) {
1142 Int32BinopMatcher mleftleft(mleft.left().node());
1143 if (mleft.right().Is(24) && mleftleft.right().Is(24)) {
1144 Emit(kArmSxtab, g.DefineAsRegister(node),
1145 g.UseRegister(m.right().node()),
1146 g.UseRegister(mleftleft.left().node()), g.TempImmediate(0));
1147 return;
1148 } else if (mleft.right().Is(16) && mleftleft.right().Is(16)) {
1149 Emit(kArmSxtah, g.DefineAsRegister(node),
1150 g.UseRegister(m.right().node()),
1151 g.UseRegister(mleftleft.left().node()), g.TempImmediate(0));
1152 return;
1153 }
1154 }
1155 }
1156 default:
1157 break;
1158 }
1159 }
1160 if (CanCover(node, m.right().node())) {
1161 switch (m.right().opcode()) {
1162 case IrOpcode::kInt32Mul: {
1163 Int32BinopMatcher mright(m.right().node());
1164 Emit(kArmMla, g.DefineAsRegister(node),
1165 g.UseRegister(mright.left().node()),
1166 g.UseRegister(mright.right().node()),
1167 g.UseRegister(m.left().node()));
1168 return;
1169 }
1170 case IrOpcode::kInt32MulHigh: {
1171 Int32BinopMatcher mright(m.right().node());
1172 Emit(kArmSmmla, g.DefineAsRegister(node),
1173 g.UseRegister(mright.left().node()),
1174 g.UseRegister(mright.right().node()),
1175 g.UseRegister(m.left().node()));
1176 return;
1177 }
1178 case IrOpcode::kWord32And: {
1179 Int32BinopMatcher mright(m.right().node());
1180 if (mright.right().Is(0xff)) {
1181 Emit(kArmUxtab, g.DefineAsRegister(node),
1182 g.UseRegister(m.left().node()),
1183 g.UseRegister(mright.left().node()), g.TempImmediate(0));
1184 return;
1185 } else if (mright.right().Is(0xffff)) {
1186 Emit(kArmUxtah, g.DefineAsRegister(node),
1187 g.UseRegister(m.left().node()),
1188 g.UseRegister(mright.left().node()), g.TempImmediate(0));
1189 return;
1190 }
1191 }
1192 case IrOpcode::kWord32Sar: {
1193 Int32BinopMatcher mright(m.right().node());
1194 if (CanCover(mright.node(), mright.left().node()) &&
1195 mright.left().IsWord32Shl()) {
1196 Int32BinopMatcher mrightleft(mright.left().node());
1197 if (mright.right().Is(24) && mrightleft.right().Is(24)) {
1198 Emit(kArmSxtab, g.DefineAsRegister(node),
1199 g.UseRegister(m.left().node()),
1200 g.UseRegister(mrightleft.left().node()), g.TempImmediate(0));
1201 return;
1202 } else if (mright.right().Is(16) && mrightleft.right().Is(16)) {
1203 Emit(kArmSxtah, g.DefineAsRegister(node),
1204 g.UseRegister(m.left().node()),
1205 g.UseRegister(mrightleft.left().node()), g.TempImmediate(0));
1206 return;
1207 }
1208 }
1209 }
1210 default:
1211 break;
1212 }
1213 }
1214 VisitBinop(this, node, kArmAdd, kArmAdd);
1215 }
1216
1217
VisitInt32Sub(Node * node)1218 void InstructionSelector::VisitInt32Sub(Node* node) {
1219 ArmOperandGenerator g(this);
1220 Int32BinopMatcher m(node);
1221 if (IsSupported(ARMv7) && m.right().IsInt32Mul() &&
1222 CanCover(node, m.right().node())) {
1223 Int32BinopMatcher mright(m.right().node());
1224 Emit(kArmMls, g.DefineAsRegister(node), g.UseRegister(mright.left().node()),
1225 g.UseRegister(mright.right().node()), g.UseRegister(m.left().node()));
1226 return;
1227 }
1228 VisitBinop(this, node, kArmSub, kArmRsb);
1229 }
1230
1231 namespace {
1232
EmitInt32MulWithOverflow(InstructionSelector * selector,Node * node,FlagsContinuation * cont)1233 void EmitInt32MulWithOverflow(InstructionSelector* selector, Node* node,
1234 FlagsContinuation* cont) {
1235 ArmOperandGenerator g(selector);
1236 Int32BinopMatcher m(node);
1237 InstructionOperand result_operand = g.DefineAsRegister(node);
1238 InstructionOperand temp_operand = g.TempRegister();
1239 InstructionOperand outputs[] = {result_operand, temp_operand};
1240 InstructionOperand inputs[] = {g.UseRegister(m.left().node()),
1241 g.UseRegister(m.right().node())};
1242 selector->Emit(kArmSmull, 2, outputs, 2, inputs);
1243
1244 // result operand needs shift operator.
1245 InstructionOperand shift_31 = g.UseImmediate(31);
1246 InstructionCode opcode = cont->Encode(kArmCmp) |
1247 AddressingModeField::encode(kMode_Operand2_R_ASR_I);
1248 if (cont->IsBranch()) {
1249 selector->Emit(opcode, g.NoOutput(), temp_operand, result_operand, shift_31,
1250 g.Label(cont->true_block()), g.Label(cont->false_block()));
1251 } else if (cont->IsDeoptimize()) {
1252 InstructionOperand in[] = {temp_operand, result_operand, shift_31};
1253 selector->EmitDeoptimize(opcode, 0, nullptr, 3, in, cont->reason(),
1254 cont->frame_state());
1255 } else {
1256 DCHECK(cont->IsSet());
1257 selector->Emit(opcode, g.DefineAsRegister(cont->result()), temp_operand,
1258 result_operand, shift_31);
1259 }
1260 }
1261
1262 } // namespace
1263
VisitInt32Mul(Node * node)1264 void InstructionSelector::VisitInt32Mul(Node* node) {
1265 ArmOperandGenerator g(this);
1266 Int32BinopMatcher m(node);
1267 if (m.right().HasValue() && m.right().Value() > 0) {
1268 int32_t value = m.right().Value();
1269 if (base::bits::IsPowerOfTwo32(value - 1)) {
1270 Emit(kArmAdd | AddressingModeField::encode(kMode_Operand2_R_LSL_I),
1271 g.DefineAsRegister(node), g.UseRegister(m.left().node()),
1272 g.UseRegister(m.left().node()),
1273 g.TempImmediate(WhichPowerOf2(value - 1)));
1274 return;
1275 }
1276 if (value < kMaxInt && base::bits::IsPowerOfTwo32(value + 1)) {
1277 Emit(kArmRsb | AddressingModeField::encode(kMode_Operand2_R_LSL_I),
1278 g.DefineAsRegister(node), g.UseRegister(m.left().node()),
1279 g.UseRegister(m.left().node()),
1280 g.TempImmediate(WhichPowerOf2(value + 1)));
1281 return;
1282 }
1283 }
1284 VisitRRR(this, kArmMul, node);
1285 }
1286
1287
VisitInt32MulHigh(Node * node)1288 void InstructionSelector::VisitInt32MulHigh(Node* node) {
1289 VisitRRR(this, kArmSmmul, node);
1290 }
1291
1292
VisitUint32MulHigh(Node * node)1293 void InstructionSelector::VisitUint32MulHigh(Node* node) {
1294 ArmOperandGenerator g(this);
1295 InstructionOperand outputs[] = {g.TempRegister(), g.DefineAsRegister(node)};
1296 InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0)),
1297 g.UseRegister(node->InputAt(1))};
1298 Emit(kArmUmull, arraysize(outputs), outputs, arraysize(inputs), inputs);
1299 }
1300
1301
VisitInt32Div(Node * node)1302 void InstructionSelector::VisitInt32Div(Node* node) {
1303 VisitDiv(this, node, kArmSdiv, kArmVcvtF64S32, kArmVcvtS32F64);
1304 }
1305
1306
VisitUint32Div(Node * node)1307 void InstructionSelector::VisitUint32Div(Node* node) {
1308 VisitDiv(this, node, kArmUdiv, kArmVcvtF64U32, kArmVcvtU32F64);
1309 }
1310
1311
VisitInt32Mod(Node * node)1312 void InstructionSelector::VisitInt32Mod(Node* node) {
1313 VisitMod(this, node, kArmSdiv, kArmVcvtF64S32, kArmVcvtS32F64);
1314 }
1315
1316
VisitUint32Mod(Node * node)1317 void InstructionSelector::VisitUint32Mod(Node* node) {
1318 VisitMod(this, node, kArmUdiv, kArmVcvtF64U32, kArmVcvtU32F64);
1319 }
1320
1321
VisitChangeFloat32ToFloat64(Node * node)1322 void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
1323 VisitRR(this, kArmVcvtF64F32, node);
1324 }
1325
1326
VisitRoundInt32ToFloat32(Node * node)1327 void InstructionSelector::VisitRoundInt32ToFloat32(Node* node) {
1328 VisitRR(this, kArmVcvtF32S32, node);
1329 }
1330
1331
VisitRoundUint32ToFloat32(Node * node)1332 void InstructionSelector::VisitRoundUint32ToFloat32(Node* node) {
1333 VisitRR(this, kArmVcvtF32U32, node);
1334 }
1335
1336
VisitChangeInt32ToFloat64(Node * node)1337 void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
1338 VisitRR(this, kArmVcvtF64S32, node);
1339 }
1340
1341
VisitChangeUint32ToFloat64(Node * node)1342 void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
1343 VisitRR(this, kArmVcvtF64U32, node);
1344 }
1345
1346
VisitTruncateFloat32ToInt32(Node * node)1347 void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) {
1348 VisitRR(this, kArmVcvtS32F32, node);
1349 }
1350
1351
VisitTruncateFloat32ToUint32(Node * node)1352 void InstructionSelector::VisitTruncateFloat32ToUint32(Node* node) {
1353 VisitRR(this, kArmVcvtU32F32, node);
1354 }
1355
1356
VisitChangeFloat64ToInt32(Node * node)1357 void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
1358 VisitRR(this, kArmVcvtS32F64, node);
1359 }
1360
1361
VisitChangeFloat64ToUint32(Node * node)1362 void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
1363 VisitRR(this, kArmVcvtU32F64, node);
1364 }
1365
VisitTruncateFloat64ToUint32(Node * node)1366 void InstructionSelector::VisitTruncateFloat64ToUint32(Node* node) {
1367 VisitRR(this, kArmVcvtU32F64, node);
1368 }
VisitTruncateFloat64ToFloat32(Node * node)1369 void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
1370 VisitRR(this, kArmVcvtF32F64, node);
1371 }
1372
VisitTruncateFloat64ToWord32(Node * node)1373 void InstructionSelector::VisitTruncateFloat64ToWord32(Node* node) {
1374 VisitRR(this, kArchTruncateDoubleToI, node);
1375 }
1376
VisitRoundFloat64ToInt32(Node * node)1377 void InstructionSelector::VisitRoundFloat64ToInt32(Node* node) {
1378 VisitRR(this, kArmVcvtS32F64, node);
1379 }
1380
VisitBitcastFloat32ToInt32(Node * node)1381 void InstructionSelector::VisitBitcastFloat32ToInt32(Node* node) {
1382 VisitRR(this, kArmVmovU32F32, node);
1383 }
1384
VisitBitcastInt32ToFloat32(Node * node)1385 void InstructionSelector::VisitBitcastInt32ToFloat32(Node* node) {
1386 VisitRR(this, kArmVmovF32U32, node);
1387 }
1388
VisitFloat32Add(Node * node)1389 void InstructionSelector::VisitFloat32Add(Node* node) {
1390 ArmOperandGenerator g(this);
1391 Float32BinopMatcher m(node);
1392 if (m.left().IsFloat32Mul() && CanCover(node, m.left().node())) {
1393 Float32BinopMatcher mleft(m.left().node());
1394 Emit(kArmVmlaF32, g.DefineSameAsFirst(node),
1395 g.UseRegister(m.right().node()), g.UseRegister(mleft.left().node()),
1396 g.UseRegister(mleft.right().node()));
1397 return;
1398 }
1399 if (m.right().IsFloat32Mul() && CanCover(node, m.right().node())) {
1400 Float32BinopMatcher mright(m.right().node());
1401 Emit(kArmVmlaF32, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
1402 g.UseRegister(mright.left().node()),
1403 g.UseRegister(mright.right().node()));
1404 return;
1405 }
1406 VisitRRR(this, kArmVaddF32, node);
1407 }
1408
1409
VisitFloat64Add(Node * node)1410 void InstructionSelector::VisitFloat64Add(Node* node) {
1411 ArmOperandGenerator g(this);
1412 Float64BinopMatcher m(node);
1413 if (m.left().IsFloat64Mul() && CanCover(node, m.left().node())) {
1414 Float64BinopMatcher mleft(m.left().node());
1415 Emit(kArmVmlaF64, g.DefineSameAsFirst(node),
1416 g.UseRegister(m.right().node()), g.UseRegister(mleft.left().node()),
1417 g.UseRegister(mleft.right().node()));
1418 return;
1419 }
1420 if (m.right().IsFloat64Mul() && CanCover(node, m.right().node())) {
1421 Float64BinopMatcher mright(m.right().node());
1422 Emit(kArmVmlaF64, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
1423 g.UseRegister(mright.left().node()),
1424 g.UseRegister(mright.right().node()));
1425 return;
1426 }
1427 VisitRRR(this, kArmVaddF64, node);
1428 }
1429
VisitFloat32Sub(Node * node)1430 void InstructionSelector::VisitFloat32Sub(Node* node) {
1431 ArmOperandGenerator g(this);
1432 Float32BinopMatcher m(node);
1433 if (m.right().IsFloat32Mul() && CanCover(node, m.right().node())) {
1434 Float32BinopMatcher mright(m.right().node());
1435 Emit(kArmVmlsF32, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
1436 g.UseRegister(mright.left().node()),
1437 g.UseRegister(mright.right().node()));
1438 return;
1439 }
1440 VisitRRR(this, kArmVsubF32, node);
1441 }
1442
VisitFloat64Sub(Node * node)1443 void InstructionSelector::VisitFloat64Sub(Node* node) {
1444 ArmOperandGenerator g(this);
1445 Float64BinopMatcher m(node);
1446 if (m.right().IsFloat64Mul() && CanCover(node, m.right().node())) {
1447 Float64BinopMatcher mright(m.right().node());
1448 Emit(kArmVmlsF64, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
1449 g.UseRegister(mright.left().node()),
1450 g.UseRegister(mright.right().node()));
1451 return;
1452 }
1453 VisitRRR(this, kArmVsubF64, node);
1454 }
1455
VisitFloat32Mul(Node * node)1456 void InstructionSelector::VisitFloat32Mul(Node* node) {
1457 VisitRRR(this, kArmVmulF32, node);
1458 }
1459
1460
VisitFloat64Mul(Node * node)1461 void InstructionSelector::VisitFloat64Mul(Node* node) {
1462 VisitRRR(this, kArmVmulF64, node);
1463 }
1464
1465
VisitFloat32Div(Node * node)1466 void InstructionSelector::VisitFloat32Div(Node* node) {
1467 VisitRRR(this, kArmVdivF32, node);
1468 }
1469
1470
VisitFloat64Div(Node * node)1471 void InstructionSelector::VisitFloat64Div(Node* node) {
1472 VisitRRR(this, kArmVdivF64, node);
1473 }
1474
1475
VisitFloat64Mod(Node * node)1476 void InstructionSelector::VisitFloat64Mod(Node* node) {
1477 ArmOperandGenerator g(this);
1478 Emit(kArmVmodF64, g.DefineAsFixed(node, d0), g.UseFixed(node->InputAt(0), d0),
1479 g.UseFixed(node->InputAt(1), d1))->MarkAsCall();
1480 }
1481
VisitFloat32Max(Node * node)1482 void InstructionSelector::VisitFloat32Max(Node* node) {
1483 VisitRRR(this, kArmFloat32Max, node);
1484 }
1485
VisitFloat64Max(Node * node)1486 void InstructionSelector::VisitFloat64Max(Node* node) {
1487 VisitRRR(this, kArmFloat64Max, node);
1488 }
1489
VisitFloat64SilenceNaN(Node * node)1490 void InstructionSelector::VisitFloat64SilenceNaN(Node* node) {
1491 VisitRR(this, kArmFloat64SilenceNaN, node);
1492 }
1493
VisitFloat32Min(Node * node)1494 void InstructionSelector::VisitFloat32Min(Node* node) {
1495 VisitRRR(this, kArmFloat32Min, node);
1496 }
1497
VisitFloat64Min(Node * node)1498 void InstructionSelector::VisitFloat64Min(Node* node) {
1499 VisitRRR(this, kArmFloat64Min, node);
1500 }
1501
VisitFloat32Abs(Node * node)1502 void InstructionSelector::VisitFloat32Abs(Node* node) {
1503 VisitRR(this, kArmVabsF32, node);
1504 }
1505
1506
VisitFloat64Abs(Node * node)1507 void InstructionSelector::VisitFloat64Abs(Node* node) {
1508 VisitRR(this, kArmVabsF64, node);
1509 }
1510
VisitFloat32Sqrt(Node * node)1511 void InstructionSelector::VisitFloat32Sqrt(Node* node) {
1512 VisitRR(this, kArmVsqrtF32, node);
1513 }
1514
1515
VisitFloat64Sqrt(Node * node)1516 void InstructionSelector::VisitFloat64Sqrt(Node* node) {
1517 VisitRR(this, kArmVsqrtF64, node);
1518 }
1519
1520
VisitFloat32RoundDown(Node * node)1521 void InstructionSelector::VisitFloat32RoundDown(Node* node) {
1522 DCHECK(CpuFeatures::IsSupported(ARMv8));
1523 VisitRR(this, kArmVrintmF32, node);
1524 }
1525
1526
VisitFloat64RoundDown(Node * node)1527 void InstructionSelector::VisitFloat64RoundDown(Node* node) {
1528 DCHECK(CpuFeatures::IsSupported(ARMv8));
1529 VisitRR(this, kArmVrintmF64, node);
1530 }
1531
1532
VisitFloat32RoundUp(Node * node)1533 void InstructionSelector::VisitFloat32RoundUp(Node* node) {
1534 DCHECK(CpuFeatures::IsSupported(ARMv8));
1535 VisitRR(this, kArmVrintpF32, node);
1536 }
1537
1538
VisitFloat64RoundUp(Node * node)1539 void InstructionSelector::VisitFloat64RoundUp(Node* node) {
1540 DCHECK(CpuFeatures::IsSupported(ARMv8));
1541 VisitRR(this, kArmVrintpF64, node);
1542 }
1543
1544
VisitFloat32RoundTruncate(Node * node)1545 void InstructionSelector::VisitFloat32RoundTruncate(Node* node) {
1546 DCHECK(CpuFeatures::IsSupported(ARMv8));
1547 VisitRR(this, kArmVrintzF32, node);
1548 }
1549
1550
VisitFloat64RoundTruncate(Node * node)1551 void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
1552 DCHECK(CpuFeatures::IsSupported(ARMv8));
1553 VisitRR(this, kArmVrintzF64, node);
1554 }
1555
1556
VisitFloat64RoundTiesAway(Node * node)1557 void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
1558 DCHECK(CpuFeatures::IsSupported(ARMv8));
1559 VisitRR(this, kArmVrintaF64, node);
1560 }
1561
1562
VisitFloat32RoundTiesEven(Node * node)1563 void InstructionSelector::VisitFloat32RoundTiesEven(Node* node) {
1564 DCHECK(CpuFeatures::IsSupported(ARMv8));
1565 VisitRR(this, kArmVrintnF32, node);
1566 }
1567
1568
VisitFloat64RoundTiesEven(Node * node)1569 void InstructionSelector::VisitFloat64RoundTiesEven(Node* node) {
1570 DCHECK(CpuFeatures::IsSupported(ARMv8));
1571 VisitRR(this, kArmVrintnF64, node);
1572 }
1573
VisitFloat32Neg(Node * node)1574 void InstructionSelector::VisitFloat32Neg(Node* node) {
1575 VisitRR(this, kArmVnegF32, node);
1576 }
1577
VisitFloat64Neg(Node * node)1578 void InstructionSelector::VisitFloat64Neg(Node* node) {
1579 VisitRR(this, kArmVnegF64, node);
1580 }
1581
VisitFloat64Ieee754Binop(Node * node,InstructionCode opcode)1582 void InstructionSelector::VisitFloat64Ieee754Binop(Node* node,
1583 InstructionCode opcode) {
1584 ArmOperandGenerator g(this);
1585 Emit(opcode, g.DefineAsFixed(node, d0), g.UseFixed(node->InputAt(0), d0),
1586 g.UseFixed(node->InputAt(1), d1))
1587 ->MarkAsCall();
1588 }
1589
VisitFloat64Ieee754Unop(Node * node,InstructionCode opcode)1590 void InstructionSelector::VisitFloat64Ieee754Unop(Node* node,
1591 InstructionCode opcode) {
1592 ArmOperandGenerator g(this);
1593 Emit(opcode, g.DefineAsFixed(node, d0), g.UseFixed(node->InputAt(0), d0))
1594 ->MarkAsCall();
1595 }
1596
EmitPrepareArguments(ZoneVector<PushParameter> * arguments,const CallDescriptor * descriptor,Node * node)1597 void InstructionSelector::EmitPrepareArguments(
1598 ZoneVector<PushParameter>* arguments, const CallDescriptor* descriptor,
1599 Node* node) {
1600 ArmOperandGenerator g(this);
1601
1602 // Prepare for C function call.
1603 if (descriptor->IsCFunctionCall()) {
1604 Emit(kArchPrepareCallCFunction |
1605 MiscField::encode(static_cast<int>(descriptor->ParameterCount())),
1606 0, nullptr, 0, nullptr);
1607
1608 // Poke any stack arguments.
1609 for (size_t n = 0; n < arguments->size(); ++n) {
1610 PushParameter input = (*arguments)[n];
1611 if (input.node()) {
1612 int slot = static_cast<int>(n);
1613 Emit(kArmPoke | MiscField::encode(slot), g.NoOutput(),
1614 g.UseRegister(input.node()));
1615 }
1616 }
1617 } else {
1618 // Push any stack arguments.
1619 for (PushParameter input : base::Reversed(*arguments)) {
1620 // Skip any alignment holes in pushed nodes.
1621 if (input.node() == nullptr) continue;
1622 Emit(kArmPush, g.NoOutput(), g.UseRegister(input.node()));
1623 }
1624 }
1625 }
1626
1627
IsTailCallAddressImmediate()1628 bool InstructionSelector::IsTailCallAddressImmediate() { return false; }
1629
GetTempsCountForTailCallFromJSFunction()1630 int InstructionSelector::GetTempsCountForTailCallFromJSFunction() { return 3; }
1631
1632 namespace {
1633
1634 // Shared routine for multiple compare operations.
VisitCompare(InstructionSelector * selector,InstructionCode opcode,InstructionOperand left,InstructionOperand right,FlagsContinuation * cont)1635 void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
1636 InstructionOperand left, InstructionOperand right,
1637 FlagsContinuation* cont) {
1638 ArmOperandGenerator g(selector);
1639 opcode = cont->Encode(opcode);
1640 if (cont->IsBranch()) {
1641 selector->Emit(opcode, g.NoOutput(), left, right,
1642 g.Label(cont->true_block()), g.Label(cont->false_block()));
1643 } else if (cont->IsDeoptimize()) {
1644 selector->EmitDeoptimize(opcode, g.NoOutput(), left, right, cont->reason(),
1645 cont->frame_state());
1646 } else {
1647 DCHECK(cont->IsSet());
1648 selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
1649 }
1650 }
1651
1652
1653 // Shared routine for multiple float32 compare operations.
VisitFloat32Compare(InstructionSelector * selector,Node * node,FlagsContinuation * cont)1654 void VisitFloat32Compare(InstructionSelector* selector, Node* node,
1655 FlagsContinuation* cont) {
1656 ArmOperandGenerator g(selector);
1657 Float32BinopMatcher m(node);
1658 if (m.right().Is(0.0f)) {
1659 VisitCompare(selector, kArmVcmpF32, g.UseRegister(m.left().node()),
1660 g.UseImmediate(m.right().node()), cont);
1661 } else if (m.left().Is(0.0f)) {
1662 cont->Commute();
1663 VisitCompare(selector, kArmVcmpF32, g.UseRegister(m.right().node()),
1664 g.UseImmediate(m.left().node()), cont);
1665 } else {
1666 VisitCompare(selector, kArmVcmpF32, g.UseRegister(m.left().node()),
1667 g.UseRegister(m.right().node()), cont);
1668 }
1669 }
1670
1671
1672 // Shared routine for multiple float64 compare operations.
VisitFloat64Compare(InstructionSelector * selector,Node * node,FlagsContinuation * cont)1673 void VisitFloat64Compare(InstructionSelector* selector, Node* node,
1674 FlagsContinuation* cont) {
1675 ArmOperandGenerator g(selector);
1676 Float64BinopMatcher m(node);
1677 if (m.right().Is(0.0)) {
1678 VisitCompare(selector, kArmVcmpF64, g.UseRegister(m.left().node()),
1679 g.UseImmediate(m.right().node()), cont);
1680 } else if (m.left().Is(0.0)) {
1681 cont->Commute();
1682 VisitCompare(selector, kArmVcmpF64, g.UseRegister(m.right().node()),
1683 g.UseImmediate(m.left().node()), cont);
1684 } else {
1685 VisitCompare(selector, kArmVcmpF64, g.UseRegister(m.left().node()),
1686 g.UseRegister(m.right().node()), cont);
1687 }
1688 }
1689
1690 // Check whether we can convert:
1691 // ((a <op> b) cmp 0), b.<cond>
1692 // to:
1693 // (a <ops> b), b.<cond'>
1694 // where <ops> is the flag setting version of <op>.
1695 // We only generate conditions <cond'> that are a combination of the N
1696 // and Z flags. This avoids the need to make this function dependent on
1697 // the flag-setting operation.
CanUseFlagSettingBinop(FlagsCondition cond)1698 bool CanUseFlagSettingBinop(FlagsCondition cond) {
1699 switch (cond) {
1700 case kEqual:
1701 case kNotEqual:
1702 case kSignedLessThan:
1703 case kSignedGreaterThanOrEqual:
1704 case kUnsignedLessThanOrEqual: // x <= 0 -> x == 0
1705 case kUnsignedGreaterThan: // x > 0 -> x != 0
1706 return true;
1707 default:
1708 return false;
1709 }
1710 }
1711
1712 // Map <cond> to <cond'> so that the following transformation is possible:
1713 // ((a <op> b) cmp 0), b.<cond>
1714 // to:
1715 // (a <ops> b), b.<cond'>
1716 // where <ops> is the flag setting version of <op>.
MapForFlagSettingBinop(FlagsCondition cond)1717 FlagsCondition MapForFlagSettingBinop(FlagsCondition cond) {
1718 DCHECK(CanUseFlagSettingBinop(cond));
1719 switch (cond) {
1720 case kEqual:
1721 case kNotEqual:
1722 return cond;
1723 case kSignedLessThan:
1724 return kNegative;
1725 case kSignedGreaterThanOrEqual:
1726 return kPositiveOrZero;
1727 case kUnsignedLessThanOrEqual: // x <= 0 -> x == 0
1728 return kEqual;
1729 case kUnsignedGreaterThan: // x > 0 -> x != 0
1730 return kNotEqual;
1731 default:
1732 UNREACHABLE();
1733 return cond;
1734 }
1735 }
1736
1737 // Check if we can perform the transformation:
1738 // ((a <op> b) cmp 0), b.<cond>
1739 // to:
1740 // (a <ops> b), b.<cond'>
1741 // where <ops> is the flag setting version of <op>, and if so,
1742 // updates {node}, {opcode} and {cont} accordingly.
MaybeReplaceCmpZeroWithFlagSettingBinop(InstructionSelector * selector,Node ** node,Node * binop,InstructionCode * opcode,FlagsCondition cond,FlagsContinuation * cont)1743 void MaybeReplaceCmpZeroWithFlagSettingBinop(InstructionSelector* selector,
1744 Node** node, Node* binop,
1745 InstructionCode* opcode,
1746 FlagsCondition cond,
1747 FlagsContinuation* cont) {
1748 InstructionCode binop_opcode;
1749 InstructionCode no_output_opcode;
1750 switch (binop->opcode()) {
1751 case IrOpcode::kInt32Add:
1752 binop_opcode = kArmAdd;
1753 no_output_opcode = kArmCmn;
1754 break;
1755 case IrOpcode::kWord32And:
1756 binop_opcode = kArmAnd;
1757 no_output_opcode = kArmTst;
1758 break;
1759 case IrOpcode::kWord32Or:
1760 binop_opcode = kArmOrr;
1761 no_output_opcode = kArmOrr;
1762 break;
1763 case IrOpcode::kWord32Xor:
1764 binop_opcode = kArmEor;
1765 no_output_opcode = kArmTeq;
1766 break;
1767 default:
1768 UNREACHABLE();
1769 return;
1770 }
1771 if (selector->CanCover(*node, binop)) {
1772 // The comparison is the only user of {node}.
1773 cont->Overwrite(MapForFlagSettingBinop(cond));
1774 *opcode = no_output_opcode;
1775 *node = binop;
1776 } else if (selector->IsOnlyUserOfNodeInSameBlock(*node, binop)) {
1777 // We can also handle the case where the {node} and the comparison are in
1778 // the same basic block, and the comparison is the only user of {node} in
1779 // this basic block ({node} has users in other basic blocks).
1780 cont->Overwrite(MapForFlagSettingBinop(cond));
1781 *opcode = binop_opcode;
1782 *node = binop;
1783 }
1784 }
1785
1786 // Shared routine for multiple word compare operations.
VisitWordCompare(InstructionSelector * selector,Node * node,InstructionCode opcode,FlagsContinuation * cont)1787 void VisitWordCompare(InstructionSelector* selector, Node* node,
1788 InstructionCode opcode, FlagsContinuation* cont) {
1789 ArmOperandGenerator g(selector);
1790 Int32BinopMatcher m(node);
1791 InstructionOperand inputs[5];
1792 size_t input_count = 0;
1793 InstructionOperand outputs[2];
1794 size_t output_count = 0;
1795 bool has_result = (opcode != kArmCmp) && (opcode != kArmCmn) &&
1796 (opcode != kArmTst) && (opcode != kArmTeq);
1797
1798 if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(),
1799 &input_count, &inputs[1])) {
1800 inputs[0] = g.UseRegister(m.left().node());
1801 input_count++;
1802 } else if (TryMatchImmediateOrShift(selector, &opcode, m.left().node(),
1803 &input_count, &inputs[1])) {
1804 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
1805 inputs[0] = g.UseRegister(m.right().node());
1806 input_count++;
1807 } else {
1808 opcode |= AddressingModeField::encode(kMode_Operand2_R);
1809 inputs[input_count++] = g.UseRegister(m.left().node());
1810 inputs[input_count++] = g.UseRegister(m.right().node());
1811 }
1812
1813 if (has_result) {
1814 if (cont->IsDeoptimize()) {
1815 // If we can deoptimize as a result of the binop, we need to make sure
1816 // that the deopt inputs are not overwritten by the binop result. One way
1817 // to achieve that is to declare the output register as same-as-first.
1818 outputs[output_count++] = g.DefineSameAsFirst(node);
1819 } else {
1820 outputs[output_count++] = g.DefineAsRegister(node);
1821 }
1822 }
1823
1824 if (cont->IsBranch()) {
1825 inputs[input_count++] = g.Label(cont->true_block());
1826 inputs[input_count++] = g.Label(cont->false_block());
1827 } else if (cont->IsSet()) {
1828 outputs[output_count++] = g.DefineAsRegister(cont->result());
1829 }
1830
1831 DCHECK_NE(0u, input_count);
1832 DCHECK_GE(arraysize(inputs), input_count);
1833 DCHECK_GE(arraysize(outputs), output_count);
1834
1835 opcode = cont->Encode(opcode);
1836 if (cont->IsDeoptimize()) {
1837 selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
1838 cont->reason(), cont->frame_state());
1839 } else {
1840 selector->Emit(opcode, output_count, outputs, input_count, inputs);
1841 }
1842 }
1843
1844
VisitWordCompare(InstructionSelector * selector,Node * node,FlagsContinuation * cont)1845 void VisitWordCompare(InstructionSelector* selector, Node* node,
1846 FlagsContinuation* cont) {
1847 InstructionCode opcode = kArmCmp;
1848 Int32BinopMatcher m(node);
1849
1850 FlagsCondition cond = cont->condition();
1851 if (m.right().Is(0) && (m.left().IsInt32Add() || m.left().IsWord32Or() ||
1852 m.left().IsWord32And() || m.left().IsWord32Xor())) {
1853 // Emit flag setting instructions for comparisons against zero.
1854 if (CanUseFlagSettingBinop(cond)) {
1855 Node* binop = m.left().node();
1856 MaybeReplaceCmpZeroWithFlagSettingBinop(selector, &node, binop, &opcode,
1857 cond, cont);
1858 }
1859 } else if (m.left().Is(0) &&
1860 (m.right().IsInt32Add() || m.right().IsWord32Or() ||
1861 m.right().IsWord32And() || m.right().IsWord32Xor())) {
1862 // Same as above, but we need to commute the condition before we
1863 // continue with the rest of the checks.
1864 cond = CommuteFlagsCondition(cond);
1865 if (CanUseFlagSettingBinop(cond)) {
1866 Node* binop = m.right().node();
1867 MaybeReplaceCmpZeroWithFlagSettingBinop(selector, &node, binop, &opcode,
1868 cond, cont);
1869 }
1870 }
1871
1872 VisitWordCompare(selector, node, opcode, cont);
1873 }
1874
1875
1876 // Shared routine for word comparisons against zero.
VisitWordCompareZero(InstructionSelector * selector,Node * user,Node * value,FlagsContinuation * cont)1877 void VisitWordCompareZero(InstructionSelector* selector, Node* user,
1878 Node* value, FlagsContinuation* cont) {
1879 // Try to combine with comparisons against 0 by simply inverting the branch.
1880 while (value->opcode() == IrOpcode::kWord32Equal &&
1881 selector->CanCover(user, value)) {
1882 Int32BinopMatcher m(value);
1883 if (!m.right().Is(0)) break;
1884
1885 user = value;
1886 value = m.left().node();
1887 cont->Negate();
1888 }
1889
1890 if (selector->CanCover(user, value)) {
1891 switch (value->opcode()) {
1892 case IrOpcode::kWord32Equal:
1893 cont->OverwriteAndNegateIfEqual(kEqual);
1894 return VisitWordCompare(selector, value, cont);
1895 case IrOpcode::kInt32LessThan:
1896 cont->OverwriteAndNegateIfEqual(kSignedLessThan);
1897 return VisitWordCompare(selector, value, cont);
1898 case IrOpcode::kInt32LessThanOrEqual:
1899 cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
1900 return VisitWordCompare(selector, value, cont);
1901 case IrOpcode::kUint32LessThan:
1902 cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
1903 return VisitWordCompare(selector, value, cont);
1904 case IrOpcode::kUint32LessThanOrEqual:
1905 cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
1906 return VisitWordCompare(selector, value, cont);
1907 case IrOpcode::kFloat32Equal:
1908 cont->OverwriteAndNegateIfEqual(kEqual);
1909 return VisitFloat32Compare(selector, value, cont);
1910 case IrOpcode::kFloat32LessThan:
1911 cont->OverwriteAndNegateIfEqual(kFloatLessThan);
1912 return VisitFloat32Compare(selector, value, cont);
1913 case IrOpcode::kFloat32LessThanOrEqual:
1914 cont->OverwriteAndNegateIfEqual(kFloatLessThanOrEqual);
1915 return VisitFloat32Compare(selector, value, cont);
1916 case IrOpcode::kFloat64Equal:
1917 cont->OverwriteAndNegateIfEqual(kEqual);
1918 return VisitFloat64Compare(selector, value, cont);
1919 case IrOpcode::kFloat64LessThan:
1920 cont->OverwriteAndNegateIfEqual(kFloatLessThan);
1921 return VisitFloat64Compare(selector, value, cont);
1922 case IrOpcode::kFloat64LessThanOrEqual:
1923 cont->OverwriteAndNegateIfEqual(kFloatLessThanOrEqual);
1924 return VisitFloat64Compare(selector, value, cont);
1925 case IrOpcode::kProjection:
1926 // Check if this is the overflow output projection of an
1927 // <Operation>WithOverflow node.
1928 if (ProjectionIndexOf(value->op()) == 1u) {
1929 // We cannot combine the <Operation>WithOverflow with this branch
1930 // unless the 0th projection (the use of the actual value of the
1931 // <Operation> is either nullptr, which means there's no use of the
1932 // actual value, or was already defined, which means it is scheduled
1933 // *AFTER* this branch).
1934 Node* const node = value->InputAt(0);
1935 Node* const result = NodeProperties::FindProjection(node, 0);
1936 if (!result || selector->IsDefined(result)) {
1937 switch (node->opcode()) {
1938 case IrOpcode::kInt32AddWithOverflow:
1939 cont->OverwriteAndNegateIfEqual(kOverflow);
1940 return VisitBinop(selector, node, kArmAdd, kArmAdd, cont);
1941 case IrOpcode::kInt32SubWithOverflow:
1942 cont->OverwriteAndNegateIfEqual(kOverflow);
1943 return VisitBinop(selector, node, kArmSub, kArmRsb, cont);
1944 case IrOpcode::kInt32MulWithOverflow:
1945 // ARM doesn't set the overflow flag for multiplication, so we
1946 // need to test on kNotEqual. Here is the code sequence used:
1947 // smull resultlow, resulthigh, left, right
1948 // cmp resulthigh, Operand(resultlow, ASR, 31)
1949 cont->OverwriteAndNegateIfEqual(kNotEqual);
1950 return EmitInt32MulWithOverflow(selector, node, cont);
1951 default:
1952 break;
1953 }
1954 }
1955 }
1956 break;
1957 case IrOpcode::kInt32Add:
1958 return VisitWordCompare(selector, value, kArmCmn, cont);
1959 case IrOpcode::kInt32Sub:
1960 return VisitWordCompare(selector, value, kArmCmp, cont);
1961 case IrOpcode::kWord32And:
1962 return VisitWordCompare(selector, value, kArmTst, cont);
1963 case IrOpcode::kWord32Or:
1964 return VisitBinop(selector, value, kArmOrr, kArmOrr, cont);
1965 case IrOpcode::kWord32Xor:
1966 return VisitWordCompare(selector, value, kArmTeq, cont);
1967 case IrOpcode::kWord32Sar:
1968 return VisitShift(selector, value, TryMatchASR, cont);
1969 case IrOpcode::kWord32Shl:
1970 return VisitShift(selector, value, TryMatchLSL, cont);
1971 case IrOpcode::kWord32Shr:
1972 return VisitShift(selector, value, TryMatchLSR, cont);
1973 case IrOpcode::kWord32Ror:
1974 return VisitShift(selector, value, TryMatchROR, cont);
1975 default:
1976 break;
1977 }
1978 }
1979
1980 if (user->opcode() == IrOpcode::kWord32Equal) {
1981 return VisitWordCompare(selector, user, cont);
1982 }
1983
1984 // Continuation could not be combined with a compare, emit compare against 0.
1985 ArmOperandGenerator g(selector);
1986 InstructionCode const opcode =
1987 cont->Encode(kArmTst) | AddressingModeField::encode(kMode_Operand2_R);
1988 InstructionOperand const value_operand = g.UseRegister(value);
1989 if (cont->IsBranch()) {
1990 selector->Emit(opcode, g.NoOutput(), value_operand, value_operand,
1991 g.Label(cont->true_block()), g.Label(cont->false_block()));
1992 } else if (cont->IsDeoptimize()) {
1993 selector->EmitDeoptimize(opcode, g.NoOutput(), value_operand, value_operand,
1994 cont->reason(), cont->frame_state());
1995 } else {
1996 DCHECK(cont->IsSet());
1997 selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand,
1998 value_operand);
1999 }
2000 }
2001
2002 } // namespace
2003
VisitBranch(Node * branch,BasicBlock * tbranch,BasicBlock * fbranch)2004 void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
2005 BasicBlock* fbranch) {
2006 FlagsContinuation cont(kNotEqual, tbranch, fbranch);
2007 VisitWordCompareZero(this, branch, branch->InputAt(0), &cont);
2008 }
2009
VisitDeoptimizeIf(Node * node)2010 void InstructionSelector::VisitDeoptimizeIf(Node* node) {
2011 FlagsContinuation cont = FlagsContinuation::ForDeoptimize(
2012 kNotEqual, DeoptimizeReasonOf(node->op()), node->InputAt(1));
2013 VisitWordCompareZero(this, node, node->InputAt(0), &cont);
2014 }
2015
VisitDeoptimizeUnless(Node * node)2016 void InstructionSelector::VisitDeoptimizeUnless(Node* node) {
2017 FlagsContinuation cont = FlagsContinuation::ForDeoptimize(
2018 kEqual, DeoptimizeReasonOf(node->op()), node->InputAt(1));
2019 VisitWordCompareZero(this, node, node->InputAt(0), &cont);
2020 }
2021
VisitSwitch(Node * node,const SwitchInfo & sw)2022 void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
2023 ArmOperandGenerator g(this);
2024 InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
2025
2026 // Emit either ArchTableSwitch or ArchLookupSwitch.
2027 size_t table_space_cost = 4 + sw.value_range;
2028 size_t table_time_cost = 3;
2029 size_t lookup_space_cost = 3 + 2 * sw.case_count;
2030 size_t lookup_time_cost = sw.case_count;
2031 if (sw.case_count > 0 &&
2032 table_space_cost + 3 * table_time_cost <=
2033 lookup_space_cost + 3 * lookup_time_cost &&
2034 sw.min_value > std::numeric_limits<int32_t>::min()) {
2035 InstructionOperand index_operand = value_operand;
2036 if (sw.min_value) {
2037 index_operand = g.TempRegister();
2038 Emit(kArmSub | AddressingModeField::encode(kMode_Operand2_I),
2039 index_operand, value_operand, g.TempImmediate(sw.min_value));
2040 }
2041 // Generate a table lookup.
2042 return EmitTableSwitch(sw, index_operand);
2043 }
2044
2045 // Generate a sequence of conditional jumps.
2046 return EmitLookupSwitch(sw, value_operand);
2047 }
2048
2049
VisitWord32Equal(Node * const node)2050 void InstructionSelector::VisitWord32Equal(Node* const node) {
2051 FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
2052 Int32BinopMatcher m(node);
2053 if (m.right().Is(0)) {
2054 return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
2055 }
2056 VisitWordCompare(this, node, &cont);
2057 }
2058
2059
VisitInt32LessThan(Node * node)2060 void InstructionSelector::VisitInt32LessThan(Node* node) {
2061 FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node);
2062 VisitWordCompare(this, node, &cont);
2063 }
2064
2065
VisitInt32LessThanOrEqual(Node * node)2066 void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
2067 FlagsContinuation cont =
2068 FlagsContinuation::ForSet(kSignedLessThanOrEqual, node);
2069 VisitWordCompare(this, node, &cont);
2070 }
2071
2072
VisitUint32LessThan(Node * node)2073 void InstructionSelector::VisitUint32LessThan(Node* node) {
2074 FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
2075 VisitWordCompare(this, node, &cont);
2076 }
2077
2078
VisitUint32LessThanOrEqual(Node * node)2079 void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
2080 FlagsContinuation cont =
2081 FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
2082 VisitWordCompare(this, node, &cont);
2083 }
2084
2085
VisitInt32AddWithOverflow(Node * node)2086 void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
2087 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
2088 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
2089 return VisitBinop(this, node, kArmAdd, kArmAdd, &cont);
2090 }
2091 FlagsContinuation cont;
2092 VisitBinop(this, node, kArmAdd, kArmAdd, &cont);
2093 }
2094
VisitInt32SubWithOverflow(Node * node)2095 void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
2096 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
2097 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
2098 return VisitBinop(this, node, kArmSub, kArmRsb, &cont);
2099 }
2100 FlagsContinuation cont;
2101 VisitBinop(this, node, kArmSub, kArmRsb, &cont);
2102 }
2103
VisitInt32MulWithOverflow(Node * node)2104 void InstructionSelector::VisitInt32MulWithOverflow(Node* node) {
2105 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
2106 // ARM doesn't set the overflow flag for multiplication, so we need to test
2107 // on kNotEqual. Here is the code sequence used:
2108 // smull resultlow, resulthigh, left, right
2109 // cmp resulthigh, Operand(resultlow, ASR, 31)
2110 FlagsContinuation cont = FlagsContinuation::ForSet(kNotEqual, ovf);
2111 return EmitInt32MulWithOverflow(this, node, &cont);
2112 }
2113 FlagsContinuation cont;
2114 EmitInt32MulWithOverflow(this, node, &cont);
2115 }
2116
VisitFloat32Equal(Node * node)2117 void InstructionSelector::VisitFloat32Equal(Node* node) {
2118 FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
2119 VisitFloat32Compare(this, node, &cont);
2120 }
2121
2122
VisitFloat32LessThan(Node * node)2123 void InstructionSelector::VisitFloat32LessThan(Node* node) {
2124 FlagsContinuation cont = FlagsContinuation::ForSet(kFloatLessThan, node);
2125 VisitFloat32Compare(this, node, &cont);
2126 }
2127
2128
VisitFloat32LessThanOrEqual(Node * node)2129 void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) {
2130 FlagsContinuation cont =
2131 FlagsContinuation::ForSet(kFloatLessThanOrEqual, node);
2132 VisitFloat32Compare(this, node, &cont);
2133 }
2134
2135
VisitFloat64Equal(Node * node)2136 void InstructionSelector::VisitFloat64Equal(Node* node) {
2137 FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
2138 VisitFloat64Compare(this, node, &cont);
2139 }
2140
2141
VisitFloat64LessThan(Node * node)2142 void InstructionSelector::VisitFloat64LessThan(Node* node) {
2143 FlagsContinuation cont = FlagsContinuation::ForSet(kFloatLessThan, node);
2144 VisitFloat64Compare(this, node, &cont);
2145 }
2146
2147
VisitFloat64LessThanOrEqual(Node * node)2148 void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
2149 FlagsContinuation cont =
2150 FlagsContinuation::ForSet(kFloatLessThanOrEqual, node);
2151 VisitFloat64Compare(this, node, &cont);
2152 }
2153
2154
VisitFloat64ExtractLowWord32(Node * node)2155 void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) {
2156 VisitRR(this, kArmVmovLowU32F64, node);
2157 }
2158
2159
VisitFloat64ExtractHighWord32(Node * node)2160 void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) {
2161 VisitRR(this, kArmVmovHighU32F64, node);
2162 }
2163
2164
VisitFloat64InsertLowWord32(Node * node)2165 void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) {
2166 ArmOperandGenerator g(this);
2167 Node* left = node->InputAt(0);
2168 Node* right = node->InputAt(1);
2169 if (left->opcode() == IrOpcode::kFloat64InsertHighWord32 &&
2170 CanCover(node, left)) {
2171 left = left->InputAt(1);
2172 Emit(kArmVmovF64U32U32, g.DefineAsRegister(node), g.UseRegister(right),
2173 g.UseRegister(left));
2174 return;
2175 }
2176 Emit(kArmVmovLowF64U32, g.DefineSameAsFirst(node), g.UseRegister(left),
2177 g.UseRegister(right));
2178 }
2179
2180
VisitFloat64InsertHighWord32(Node * node)2181 void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
2182 ArmOperandGenerator g(this);
2183 Node* left = node->InputAt(0);
2184 Node* right = node->InputAt(1);
2185 if (left->opcode() == IrOpcode::kFloat64InsertLowWord32 &&
2186 CanCover(node, left)) {
2187 left = left->InputAt(1);
2188 Emit(kArmVmovF64U32U32, g.DefineAsRegister(node), g.UseRegister(left),
2189 g.UseRegister(right));
2190 return;
2191 }
2192 Emit(kArmVmovHighF64U32, g.DefineSameAsFirst(node), g.UseRegister(left),
2193 g.UseRegister(right));
2194 }
2195
VisitAtomicLoad(Node * node)2196 void InstructionSelector::VisitAtomicLoad(Node* node) {
2197 LoadRepresentation load_rep = LoadRepresentationOf(node->op());
2198 ArmOperandGenerator g(this);
2199 Node* base = node->InputAt(0);
2200 Node* index = node->InputAt(1);
2201 ArchOpcode opcode = kArchNop;
2202 switch (load_rep.representation()) {
2203 case MachineRepresentation::kWord8:
2204 opcode = load_rep.IsSigned() ? kAtomicLoadInt8 : kAtomicLoadUint8;
2205 break;
2206 case MachineRepresentation::kWord16:
2207 opcode = load_rep.IsSigned() ? kAtomicLoadInt16 : kAtomicLoadUint16;
2208 break;
2209 case MachineRepresentation::kWord32:
2210 opcode = kAtomicLoadWord32;
2211 break;
2212 default:
2213 UNREACHABLE();
2214 return;
2215 }
2216 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR),
2217 g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(index));
2218 }
2219
VisitAtomicStore(Node * node)2220 void InstructionSelector::VisitAtomicStore(Node* node) {
2221 MachineRepresentation rep = AtomicStoreRepresentationOf(node->op());
2222 ArmOperandGenerator g(this);
2223 Node* base = node->InputAt(0);
2224 Node* index = node->InputAt(1);
2225 Node* value = node->InputAt(2);
2226 ArchOpcode opcode = kArchNop;
2227 switch (rep) {
2228 case MachineRepresentation::kWord8:
2229 opcode = kAtomicStoreWord8;
2230 break;
2231 case MachineRepresentation::kWord16:
2232 opcode = kAtomicStoreWord16;
2233 break;
2234 case MachineRepresentation::kWord32:
2235 opcode = kAtomicStoreWord32;
2236 break;
2237 default:
2238 UNREACHABLE();
2239 return;
2240 }
2241
2242 AddressingMode addressing_mode = kMode_Offset_RR;
2243 InstructionOperand inputs[4];
2244 size_t input_count = 0;
2245 inputs[input_count++] = g.UseUniqueRegister(base);
2246 inputs[input_count++] = g.UseUniqueRegister(index);
2247 inputs[input_count++] = g.UseUniqueRegister(value);
2248 InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
2249 Emit(code, 0, nullptr, input_count, inputs);
2250 }
2251
2252 // static
2253 MachineOperatorBuilder::Flags
SupportedMachineOperatorFlags()2254 InstructionSelector::SupportedMachineOperatorFlags() {
2255 MachineOperatorBuilder::Flags flags;
2256 if (CpuFeatures::IsSupported(SUDIV)) {
2257 // The sdiv and udiv instructions correctly return 0 if the divisor is 0,
2258 // but the fall-back implementation does not.
2259 flags |= MachineOperatorBuilder::kInt32DivIsSafe |
2260 MachineOperatorBuilder::kUint32DivIsSafe;
2261 }
2262 if (CpuFeatures::IsSupported(ARMv7)) {
2263 flags |= MachineOperatorBuilder::kWord32ReverseBits;
2264 }
2265 if (CpuFeatures::IsSupported(ARMv8)) {
2266 flags |= MachineOperatorBuilder::kFloat32RoundDown |
2267 MachineOperatorBuilder::kFloat64RoundDown |
2268 MachineOperatorBuilder::kFloat32RoundUp |
2269 MachineOperatorBuilder::kFloat64RoundUp |
2270 MachineOperatorBuilder::kFloat32RoundTruncate |
2271 MachineOperatorBuilder::kFloat64RoundTruncate |
2272 MachineOperatorBuilder::kFloat64RoundTiesAway |
2273 MachineOperatorBuilder::kFloat32RoundTiesEven |
2274 MachineOperatorBuilder::kFloat64RoundTiesEven;
2275 }
2276 return flags;
2277 }
2278
2279 // static
2280 MachineOperatorBuilder::AlignmentRequirements
AlignmentRequirements()2281 InstructionSelector::AlignmentRequirements() {
2282 Vector<MachineType> req_aligned = Vector<MachineType>::New(2);
2283 req_aligned[0] = MachineType::Float32();
2284 req_aligned[1] = MachineType::Float64();
2285 return MachineOperatorBuilder::AlignmentRequirements::
2286 SomeUnalignedAccessUnsupported(req_aligned, req_aligned);
2287 }
2288
2289 } // namespace compiler
2290 } // namespace internal
2291 } // namespace v8
2292