blob: 76d9e3c66dd5bda81be114043dd5d3081662d856 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005#include "src/base/adapters.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006#include "src/base/bits.h"
7#include "src/compiler/instruction-selector-impl.h"
8#include "src/compiler/node-matchers.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009#include "src/compiler/node-properties.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010
11namespace v8 {
12namespace internal {
13namespace compiler {
14
15// Adds Arm-specific methods for generating InstructionOperands.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016class ArmOperandGenerator : public OperandGenerator {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017 public:
18 explicit ArmOperandGenerator(InstructionSelector* selector)
19 : OperandGenerator(selector) {}
20
Emily Bernierd0a1eb72015-03-24 16:35:39 -040021 bool CanBeImmediate(int32_t value) const {
22 return Assembler::ImmediateFitsAddrMode1Instruction(value);
23 }
24
25 bool CanBeImmediate(uint32_t value) const {
26 return CanBeImmediate(bit_cast<int32_t>(value));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000027 }
28
29 bool CanBeImmediate(Node* node, InstructionCode opcode) {
30 Int32Matcher m(node);
31 if (!m.HasValue()) return false;
32 int32_t value = m.Value();
33 switch (ArchOpcodeField::decode(opcode)) {
34 case kArmAnd:
35 case kArmMov:
36 case kArmMvn:
37 case kArmBic:
Emily Bernierd0a1eb72015-03-24 16:35:39 -040038 return CanBeImmediate(value) || CanBeImmediate(~value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000039
40 case kArmAdd:
41 case kArmSub:
42 case kArmCmp:
43 case kArmCmn:
Emily Bernierd0a1eb72015-03-24 16:35:39 -040044 return CanBeImmediate(value) || CanBeImmediate(-value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000045
46 case kArmTst:
47 case kArmTeq:
48 case kArmOrr:
49 case kArmEor:
50 case kArmRsb:
Emily Bernierd0a1eb72015-03-24 16:35:39 -040051 return CanBeImmediate(value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000052
Emily Bernierd0a1eb72015-03-24 16:35:39 -040053 case kArmVldrF32:
54 case kArmVstrF32:
55 case kArmVldrF64:
56 case kArmVstrF64:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000057 return value >= -1020 && value <= 1020 && (value % 4) == 0;
58
59 case kArmLdrb:
60 case kArmLdrsb:
61 case kArmStrb:
62 case kArmLdr:
63 case kArmStr:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000064 return value >= -4095 && value <= 4095;
65
66 case kArmLdrh:
67 case kArmLdrsh:
68 case kArmStrh:
69 return value >= -255 && value <= 255;
70
Emily Bernierd0a1eb72015-03-24 16:35:39 -040071 default:
72 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000073 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000074 return false;
75 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000076};
77
78
Emily Bernierd0a1eb72015-03-24 16:35:39 -040079namespace {
80
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000081void VisitRR(InstructionSelector* selector, ArchOpcode opcode, Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040082 ArmOperandGenerator g(selector);
83 selector->Emit(opcode, g.DefineAsRegister(node),
84 g.UseRegister(node->InputAt(0)));
85}
86
87
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000088void VisitRRR(InstructionSelector* selector, ArchOpcode opcode, Node* node) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000089 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
Emily Bernierd0a1eb72015-03-24 16:35:39 -040096template <IrOpcode::Value kOpcode, int kImmMin, int kImmMax,
97 AddressingMode kImmMode, AddressingMode kRegMode>
98bool TryMatchShift(InstructionSelector* selector,
99 InstructionCode* opcode_return, Node* node,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000100 InstructionOperand* value_return,
101 InstructionOperand* shift_return) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000102 ArmOperandGenerator g(selector);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400103 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;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000114 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400115 return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000116}
117
118
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400119bool TryMatchROR(InstructionSelector* selector, InstructionCode* opcode_return,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000120 Node* node, InstructionOperand* value_return,
121 InstructionOperand* shift_return) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400122 return TryMatchShift<IrOpcode::kWord32Ror, 1, 31, kMode_Operand2_R_ROR_I,
123 kMode_Operand2_R_ROR_R>(selector, opcode_return, node,
124 value_return, shift_return);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000125}
126
127
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400128bool TryMatchASR(InstructionSelector* selector, InstructionCode* opcode_return,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000129 Node* node, InstructionOperand* value_return,
130 InstructionOperand* shift_return) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400131 return TryMatchShift<IrOpcode::kWord32Sar, 1, 32, kMode_Operand2_R_ASR_I,
132 kMode_Operand2_R_ASR_R>(selector, opcode_return, node,
133 value_return, shift_return);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000134}
135
136
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400137bool TryMatchLSL(InstructionSelector* selector, InstructionCode* opcode_return,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000138 Node* node, InstructionOperand* value_return,
139 InstructionOperand* shift_return) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400140 return TryMatchShift<IrOpcode::kWord32Shl, 0, 31, kMode_Operand2_R_LSL_I,
141 kMode_Operand2_R_LSL_R>(selector, opcode_return, node,
142 value_return, shift_return);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000143}
144
145
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400146bool TryMatchLSR(InstructionSelector* selector, InstructionCode* opcode_return,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000147 Node* node, InstructionOperand* value_return,
148 InstructionOperand* shift_return) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400149 return TryMatchShift<IrOpcode::kWord32Shr, 1, 32, kMode_Operand2_R_LSR_I,
150 kMode_Operand2_R_LSR_R>(selector, opcode_return, node,
151 value_return, shift_return);
152}
153
154
155bool TryMatchShift(InstructionSelector* selector,
156 InstructionCode* opcode_return, Node* node,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000157 InstructionOperand* value_return,
158 InstructionOperand* shift_return) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000159 return (
160 TryMatchASR(selector, opcode_return, node, value_return, shift_return) ||
161 TryMatchLSL(selector, opcode_return, node, value_return, shift_return) ||
162 TryMatchLSR(selector, opcode_return, node, value_return, shift_return) ||
163 TryMatchROR(selector, opcode_return, node, value_return, shift_return));
164}
165
166
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400167bool TryMatchImmediateOrShift(InstructionSelector* selector,
168 InstructionCode* opcode_return, Node* node,
169 size_t* input_count_return,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000170 InstructionOperand* inputs) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000171 ArmOperandGenerator g(selector);
172 if (g.CanBeImmediate(node, *opcode_return)) {
173 *opcode_return |= AddressingModeField::encode(kMode_Operand2_I);
174 inputs[0] = g.UseImmediate(node);
175 *input_count_return = 1;
176 return true;
177 }
178 if (TryMatchShift(selector, opcode_return, node, &inputs[0], &inputs[1])) {
179 *input_count_return = 2;
180 return true;
181 }
182 return false;
183}
184
185
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400186void VisitBinop(InstructionSelector* selector, Node* node,
187 InstructionCode opcode, InstructionCode reverse_opcode,
188 FlagsContinuation* cont) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000189 ArmOperandGenerator g(selector);
190 Int32BinopMatcher m(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000191 InstructionOperand inputs[5];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000192 size_t input_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000193 InstructionOperand outputs[2];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000194 size_t output_count = 0;
195
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400196 if (m.left().node() == m.right().node()) {
197 // If both inputs refer to the same operand, enforce allocating a register
198 // for both of them to ensure that we don't end up generating code like
199 // this:
200 //
201 // mov r0, r1, asr #16
202 // adds r0, r0, r1, asr #16
203 // bvs label
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000204 InstructionOperand const input = g.UseRegister(m.left().node());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400205 opcode |= AddressingModeField::encode(kMode_Operand2_R);
206 inputs[input_count++] = input;
207 inputs[input_count++] = input;
208 } else if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(),
209 &input_count, &inputs[1])) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000210 inputs[0] = g.UseRegister(m.left().node());
211 input_count++;
212 } else if (TryMatchImmediateOrShift(selector, &reverse_opcode,
213 m.left().node(), &input_count,
214 &inputs[1])) {
215 inputs[0] = g.UseRegister(m.right().node());
216 opcode = reverse_opcode;
217 input_count++;
218 } else {
219 opcode |= AddressingModeField::encode(kMode_Operand2_R);
220 inputs[input_count++] = g.UseRegister(m.left().node());
221 inputs[input_count++] = g.UseRegister(m.right().node());
222 }
223
224 if (cont->IsBranch()) {
225 inputs[input_count++] = g.Label(cont->true_block());
226 inputs[input_count++] = g.Label(cont->false_block());
227 }
228
229 outputs[output_count++] = g.DefineAsRegister(node);
230 if (cont->IsSet()) {
231 outputs[output_count++] = g.DefineAsRegister(cont->result());
232 }
233
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000234 DCHECK_NE(0u, input_count);
235 DCHECK_NE(0u, output_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000236 DCHECK_GE(arraysize(inputs), input_count);
237 DCHECK_GE(arraysize(outputs), output_count);
238 DCHECK_NE(kMode_None, AddressingModeField::decode(opcode));
239
Ben Murdochda12d292016-06-02 14:46:10 +0100240 opcode = cont->Encode(opcode);
241 if (cont->IsDeoptimize()) {
242 selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
243 cont->frame_state());
244 } else {
245 selector->Emit(opcode, output_count, outputs, input_count, inputs);
246 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000247}
248
249
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400250void VisitBinop(InstructionSelector* selector, Node* node,
251 InstructionCode opcode, InstructionCode reverse_opcode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000252 FlagsContinuation cont;
253 VisitBinop(selector, node, opcode, reverse_opcode, &cont);
254}
255
256
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000257void EmitDiv(InstructionSelector* selector, ArchOpcode div_opcode,
258 ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode,
259 InstructionOperand result_operand, InstructionOperand left_operand,
260 InstructionOperand right_operand) {
261 ArmOperandGenerator g(selector);
262 if (selector->IsSupported(SUDIV)) {
263 selector->Emit(div_opcode, result_operand, left_operand, right_operand);
264 return;
265 }
266 InstructionOperand left_double_operand = g.TempDoubleRegister();
267 InstructionOperand right_double_operand = g.TempDoubleRegister();
268 InstructionOperand result_double_operand = g.TempDoubleRegister();
269 selector->Emit(f64i32_opcode, left_double_operand, left_operand);
270 selector->Emit(f64i32_opcode, right_double_operand, right_operand);
271 selector->Emit(kArmVdivF64, result_double_operand, left_double_operand,
272 right_double_operand);
273 selector->Emit(i32f64_opcode, result_operand, result_double_operand);
274}
275
276
277void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode div_opcode,
278 ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode) {
279 ArmOperandGenerator g(selector);
280 Int32BinopMatcher m(node);
281 EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode,
282 g.DefineAsRegister(node), g.UseRegister(m.left().node()),
283 g.UseRegister(m.right().node()));
284}
285
286
287void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode div_opcode,
288 ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode) {
289 ArmOperandGenerator g(selector);
290 Int32BinopMatcher m(node);
291 InstructionOperand div_operand = g.TempRegister();
292 InstructionOperand result_operand = g.DefineAsRegister(node);
293 InstructionOperand left_operand = g.UseRegister(m.left().node());
294 InstructionOperand right_operand = g.UseRegister(m.right().node());
295 EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode, div_operand,
296 left_operand, right_operand);
297 if (selector->IsSupported(MLS)) {
298 selector->Emit(kArmMls, result_operand, div_operand, right_operand,
299 left_operand);
300 } else {
301 InstructionOperand mul_operand = g.TempRegister();
302 selector->Emit(kArmMul, mul_operand, div_operand, right_operand);
303 selector->Emit(kArmSub, result_operand, left_operand, mul_operand);
304 }
305}
306
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400307} // namespace
308
309
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000310void InstructionSelector::VisitLoad(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000311 LoadRepresentation load_rep = LoadRepresentationOf(node->op());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000312 ArmOperandGenerator g(this);
313 Node* base = node->InputAt(0);
314 Node* index = node->InputAt(1);
315
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000316 ArchOpcode opcode = kArchNop;
317 switch (load_rep.representation()) {
318 case MachineRepresentation::kFloat32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400319 opcode = kArmVldrF32;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000320 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000321 case MachineRepresentation::kFloat64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400322 opcode = kArmVldrF64;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000323 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000324 case MachineRepresentation::kBit: // Fall through.
325 case MachineRepresentation::kWord8:
326 opcode = load_rep.IsUnsigned() ? kArmLdrb : kArmLdrsb;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000327 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000328 case MachineRepresentation::kWord16:
329 opcode = load_rep.IsUnsigned() ? kArmLdrh : kArmLdrsh;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000330 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000331 case MachineRepresentation::kTagged: // Fall through.
332 case MachineRepresentation::kWord32:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000333 opcode = kArmLdr;
334 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100335 case MachineRepresentation::kWord64: // Fall through.
336 case MachineRepresentation::kSimd128: // Fall through.
337 case MachineRepresentation::kNone:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000338 UNREACHABLE();
339 return;
340 }
341
342 if (g.CanBeImmediate(index, opcode)) {
343 Emit(opcode | AddressingModeField::encode(kMode_Offset_RI),
344 g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index));
345 } else {
346 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR),
347 g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(index));
348 }
349}
350
351
352void InstructionSelector::VisitStore(Node* node) {
353 ArmOperandGenerator g(this);
354 Node* base = node->InputAt(0);
355 Node* index = node->InputAt(1);
356 Node* value = node->InputAt(2);
357
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000358 StoreRepresentation store_rep = StoreRepresentationOf(node->op());
359 WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind();
360 MachineRepresentation rep = store_rep.representation();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000361
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000362 if (write_barrier_kind != kNoWriteBarrier) {
363 DCHECK_EQ(MachineRepresentation::kTagged, rep);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100364 AddressingMode addressing_mode;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000365 InstructionOperand inputs[3];
366 size_t input_count = 0;
367 inputs[input_count++] = g.UseUniqueRegister(base);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100368 // OutOfLineRecordWrite uses the index in an 'add' instruction as well as
369 // for the store itself, so we must check compatibility with both.
370 if (g.CanBeImmediate(index, kArmAdd) && g.CanBeImmediate(index, kArmStr)) {
371 inputs[input_count++] = g.UseImmediate(index);
372 addressing_mode = kMode_Offset_RI;
373 } else {
374 inputs[input_count++] = g.UseUniqueRegister(index);
375 addressing_mode = kMode_Offset_RR;
376 }
Ben Murdochda12d292016-06-02 14:46:10 +0100377 inputs[input_count++] = g.UseUniqueRegister(value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000378 RecordWriteMode record_write_mode = RecordWriteMode::kValueIsAny;
379 switch (write_barrier_kind) {
380 case kNoWriteBarrier:
381 UNREACHABLE();
382 break;
383 case kMapWriteBarrier:
384 record_write_mode = RecordWriteMode::kValueIsMap;
385 break;
386 case kPointerWriteBarrier:
387 record_write_mode = RecordWriteMode::kValueIsPointer;
388 break;
389 case kFullWriteBarrier:
390 record_write_mode = RecordWriteMode::kValueIsAny;
391 break;
392 }
393 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
394 size_t const temp_count = arraysize(temps);
395 InstructionCode code = kArchStoreWithWriteBarrier;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100396 code |= AddressingModeField::encode(addressing_mode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000397 code |= MiscField::encode(static_cast<int>(record_write_mode));
398 Emit(code, 0, nullptr, input_count, inputs, temp_count, temps);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000399 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000400 ArchOpcode opcode = kArchNop;
401 switch (rep) {
402 case MachineRepresentation::kFloat32:
403 opcode = kArmVstrF32;
404 break;
405 case MachineRepresentation::kFloat64:
406 opcode = kArmVstrF64;
407 break;
408 case MachineRepresentation::kBit: // Fall through.
409 case MachineRepresentation::kWord8:
410 opcode = kArmStrb;
411 break;
412 case MachineRepresentation::kWord16:
413 opcode = kArmStrh;
414 break;
415 case MachineRepresentation::kTagged: // Fall through.
416 case MachineRepresentation::kWord32:
417 opcode = kArmStr;
418 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100419 case MachineRepresentation::kWord64: // Fall through.
420 case MachineRepresentation::kSimd128: // Fall through.
421 case MachineRepresentation::kNone:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000422 UNREACHABLE();
423 return;
424 }
425
426 if (g.CanBeImmediate(index, opcode)) {
427 Emit(opcode | AddressingModeField::encode(kMode_Offset_RI), g.NoOutput(),
428 g.UseRegister(base), g.UseImmediate(index), g.UseRegister(value));
429 } else {
430 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), g.NoOutput(),
431 g.UseRegister(base), g.UseRegister(index), g.UseRegister(value));
432 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000433 }
434}
435
436
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400437void InstructionSelector::VisitCheckedLoad(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000438 CheckedLoadRepresentation load_rep = CheckedLoadRepresentationOf(node->op());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400439 ArmOperandGenerator g(this);
440 Node* const buffer = node->InputAt(0);
441 Node* const offset = node->InputAt(1);
442 Node* const length = node->InputAt(2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000443 ArchOpcode opcode = kArchNop;
444 switch (load_rep.representation()) {
445 case MachineRepresentation::kWord8:
446 opcode = load_rep.IsSigned() ? kCheckedLoadInt8 : kCheckedLoadUint8;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400447 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000448 case MachineRepresentation::kWord16:
449 opcode = load_rep.IsSigned() ? kCheckedLoadInt16 : kCheckedLoadUint16;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400450 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000451 case MachineRepresentation::kWord32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400452 opcode = kCheckedLoadWord32;
453 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000454 case MachineRepresentation::kFloat32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400455 opcode = kCheckedLoadFloat32;
456 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000457 case MachineRepresentation::kFloat64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400458 opcode = kCheckedLoadFloat64;
459 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100460 case MachineRepresentation::kBit: // Fall through.
461 case MachineRepresentation::kTagged: // Fall through.
462 case MachineRepresentation::kWord64: // Fall through.
463 case MachineRepresentation::kSimd128: // Fall through.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000464 case MachineRepresentation::kNone:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400465 UNREACHABLE();
466 return;
467 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000468 InstructionOperand offset_operand = g.UseRegister(offset);
469 InstructionOperand length_operand = g.CanBeImmediate(length, kArmCmp)
470 ? g.UseImmediate(length)
471 : g.UseRegister(length);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400472 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR),
473 g.DefineAsRegister(node), offset_operand, length_operand,
474 g.UseRegister(buffer), offset_operand);
475}
476
477
478void InstructionSelector::VisitCheckedStore(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000479 MachineRepresentation rep = CheckedStoreRepresentationOf(node->op());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400480 ArmOperandGenerator g(this);
481 Node* const buffer = node->InputAt(0);
482 Node* const offset = node->InputAt(1);
483 Node* const length = node->InputAt(2);
484 Node* const value = node->InputAt(3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000485 ArchOpcode opcode = kArchNop;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400486 switch (rep) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000487 case MachineRepresentation::kWord8:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400488 opcode = kCheckedStoreWord8;
489 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000490 case MachineRepresentation::kWord16:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400491 opcode = kCheckedStoreWord16;
492 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000493 case MachineRepresentation::kWord32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400494 opcode = kCheckedStoreWord32;
495 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000496 case MachineRepresentation::kFloat32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400497 opcode = kCheckedStoreFloat32;
498 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000499 case MachineRepresentation::kFloat64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400500 opcode = kCheckedStoreFloat64;
501 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100502 case MachineRepresentation::kBit: // Fall through.
503 case MachineRepresentation::kTagged: // Fall through.
504 case MachineRepresentation::kWord64: // Fall through.
505 case MachineRepresentation::kSimd128: // Fall through.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000506 case MachineRepresentation::kNone:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400507 UNREACHABLE();
508 return;
509 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000510 InstructionOperand offset_operand = g.UseRegister(offset);
511 InstructionOperand length_operand = g.CanBeImmediate(length, kArmCmp)
512 ? g.UseImmediate(length)
513 : g.UseRegister(length);
514 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), g.NoOutput(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400515 offset_operand, length_operand, g.UseRegister(value),
516 g.UseRegister(buffer), offset_operand);
517}
518
519
520namespace {
521
522void EmitBic(InstructionSelector* selector, Node* node, Node* left,
523 Node* right) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000524 ArmOperandGenerator g(selector);
525 InstructionCode opcode = kArmBic;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000526 InstructionOperand value_operand;
527 InstructionOperand shift_operand;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000528 if (TryMatchShift(selector, &opcode, right, &value_operand, &shift_operand)) {
529 selector->Emit(opcode, g.DefineAsRegister(node), g.UseRegister(left),
530 value_operand, shift_operand);
531 return;
532 }
533 selector->Emit(opcode | AddressingModeField::encode(kMode_Operand2_R),
534 g.DefineAsRegister(node), g.UseRegister(left),
535 g.UseRegister(right));
536}
537
538
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400539void EmitUbfx(InstructionSelector* selector, Node* node, Node* left,
540 uint32_t lsb, uint32_t width) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000541 DCHECK_LE(1u, width);
542 DCHECK_LE(width, 32u - lsb);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400543 ArmOperandGenerator g(selector);
544 selector->Emit(kArmUbfx, g.DefineAsRegister(node), g.UseRegister(left),
545 g.TempImmediate(lsb), g.TempImmediate(width));
546}
547
548} // namespace
549
550
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000551void InstructionSelector::VisitWord32And(Node* node) {
552 ArmOperandGenerator g(this);
553 Int32BinopMatcher m(node);
554 if (m.left().IsWord32Xor() && CanCover(node, m.left().node())) {
555 Int32BinopMatcher mleft(m.left().node());
556 if (mleft.right().Is(-1)) {
557 EmitBic(this, node, m.right().node(), mleft.left().node());
558 return;
559 }
560 }
561 if (m.right().IsWord32Xor() && CanCover(node, m.right().node())) {
562 Int32BinopMatcher mright(m.right().node());
563 if (mright.right().Is(-1)) {
564 EmitBic(this, node, m.left().node(), mright.left().node());
565 return;
566 }
567 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400568 if (m.right().HasValue()) {
569 uint32_t const value = m.right().Value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000570 uint32_t width = base::bits::CountPopulation32(value);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100571 uint32_t leading_zeros = base::bits::CountLeadingZeros32(value);
572
573 // Try to merge SHR operations on the left hand input into this AND.
574 if (m.left().IsWord32Shr()) {
575 Int32BinopMatcher mshr(m.left().node());
576 if (mshr.right().HasValue()) {
577 uint32_t const shift = mshr.right().Value();
578
579 if (((shift == 8) || (shift == 16) || (shift == 24)) &&
580 ((value == 0xff) || (value == 0xffff))) {
581 // Merge SHR into AND by emitting a UXTB or UXTH instruction with a
582 // bytewise rotation.
583 Emit((value == 0xff) ? kArmUxtb : kArmUxth,
584 g.DefineAsRegister(m.node()), g.UseRegister(mshr.left().node()),
585 g.TempImmediate(mshr.right().Value()));
586 return;
587 } else if (IsSupported(ARMv7) && (width != 0) &&
588 ((leading_zeros + width) == 32)) {
589 // Merge Shr into And by emitting a UBFX instruction.
590 DCHECK_EQ(0u, base::bits::CountTrailingZeros32(value));
591 if ((1 <= shift) && (shift <= 31)) {
592 // UBFX cannot extract bits past the register size, however since
593 // shifting the original value would have introduced some zeros we
594 // can still use UBFX with a smaller mask and the remaining bits
595 // will be zeros.
596 EmitUbfx(this, node, mshr.left().node(), shift,
597 std::min(width, 32 - shift));
598 return;
599 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000600 }
601 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100602 } else if (value == 0xffff) {
603 // Emit UXTH for this AND. We don't bother testing for UXTB, as it's no
604 // better than AND 0xff for this operation.
605 Emit(kArmUxth, g.DefineAsRegister(m.node()),
606 g.UseRegister(m.left().node()), g.TempImmediate(0));
607 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400608 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400609 if (g.CanBeImmediate(~value)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100610 // Emit BIC for this AND by inverting the immediate value first.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400611 Emit(kArmBic | AddressingModeField::encode(kMode_Operand2_I),
612 g.DefineAsRegister(node), g.UseRegister(m.left().node()),
613 g.TempImmediate(~value));
614 return;
615 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100616 if (!g.CanBeImmediate(value) && IsSupported(ARMv7)) {
617 // If value has 9 to 23 contiguous set bits, and has the lsb set, we can
618 // replace this AND with UBFX. Other contiguous bit patterns have already
619 // been handled by BIC or will be handled by AND.
620 if ((width != 0) && ((leading_zeros + width) == 32) &&
621 (9 <= leading_zeros) && (leading_zeros <= 23)) {
622 DCHECK_EQ(0u, base::bits::CountTrailingZeros32(value));
623 EmitUbfx(this, node, m.left().node(), 0, width);
624 return;
625 }
626
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400627 width = 32 - width;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100628 leading_zeros = base::bits::CountLeadingZeros32(~value);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400629 uint32_t lsb = base::bits::CountTrailingZeros32(~value);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100630 if ((leading_zeros + width + lsb) == 32) {
631 // This AND can be replaced with BFC.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400632 Emit(kArmBfc, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
633 g.TempImmediate(lsb), g.TempImmediate(width));
634 return;
635 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000636 }
637 }
638 VisitBinop(this, node, kArmAnd, kArmAnd);
639}
640
641
642void InstructionSelector::VisitWord32Or(Node* node) {
643 VisitBinop(this, node, kArmOrr, kArmOrr);
644}
645
646
647void InstructionSelector::VisitWord32Xor(Node* node) {
648 ArmOperandGenerator g(this);
649 Int32BinopMatcher m(node);
650 if (m.right().Is(-1)) {
651 InstructionCode opcode = kArmMvn;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000652 InstructionOperand value_operand;
653 InstructionOperand shift_operand;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000654 if (TryMatchShift(this, &opcode, m.left().node(), &value_operand,
655 &shift_operand)) {
656 Emit(opcode, g.DefineAsRegister(node), value_operand, shift_operand);
657 return;
658 }
659 Emit(opcode | AddressingModeField::encode(kMode_Operand2_R),
660 g.DefineAsRegister(node), g.UseRegister(m.left().node()));
661 return;
662 }
663 VisitBinop(this, node, kArmEor, kArmEor);
664}
665
666
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000667namespace {
668
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000669template <typename TryMatchShift>
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000670void VisitShift(InstructionSelector* selector, Node* node,
671 TryMatchShift try_match_shift, FlagsContinuation* cont) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000672 ArmOperandGenerator g(selector);
673 InstructionCode opcode = kArmMov;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000674 InstructionOperand inputs[4];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000675 size_t input_count = 2;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000676 InstructionOperand outputs[2];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000677 size_t output_count = 0;
678
679 CHECK(try_match_shift(selector, &opcode, node, &inputs[0], &inputs[1]));
680
681 if (cont->IsBranch()) {
682 inputs[input_count++] = g.Label(cont->true_block());
683 inputs[input_count++] = g.Label(cont->false_block());
684 }
685
686 outputs[output_count++] = g.DefineAsRegister(node);
687 if (cont->IsSet()) {
688 outputs[output_count++] = g.DefineAsRegister(cont->result());
689 }
690
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000691 DCHECK_NE(0u, input_count);
692 DCHECK_NE(0u, output_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000693 DCHECK_GE(arraysize(inputs), input_count);
694 DCHECK_GE(arraysize(outputs), output_count);
695 DCHECK_NE(kMode_None, AddressingModeField::decode(opcode));
696
Ben Murdochda12d292016-06-02 14:46:10 +0100697 opcode = cont->Encode(opcode);
698 if (cont->IsDeoptimize()) {
699 selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
700 cont->frame_state());
701 } else {
702 selector->Emit(opcode, output_count, outputs, input_count, inputs);
703 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000704}
705
706
707template <typename TryMatchShift>
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000708void VisitShift(InstructionSelector* selector, Node* node,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000709 TryMatchShift try_match_shift) {
710 FlagsContinuation cont;
711 VisitShift(selector, node, try_match_shift, &cont);
712}
713
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000714} // namespace
715
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000716
717void InstructionSelector::VisitWord32Shl(Node* node) {
718 VisitShift(this, node, TryMatchLSL);
719}
720
721
722void InstructionSelector::VisitWord32Shr(Node* node) {
723 ArmOperandGenerator g(this);
724 Int32BinopMatcher m(node);
725 if (IsSupported(ARMv7) && m.left().IsWord32And() &&
726 m.right().IsInRange(0, 31)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000727 uint32_t lsb = m.right().Value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000728 Int32BinopMatcher mleft(m.left().node());
729 if (mleft.right().HasValue()) {
730 uint32_t value = (mleft.right().Value() >> lsb) << lsb;
731 uint32_t width = base::bits::CountPopulation32(value);
732 uint32_t msb = base::bits::CountLeadingZeros32(value);
733 if (msb + width + lsb == 32) {
734 DCHECK_EQ(lsb, base::bits::CountTrailingZeros32(value));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400735 return EmitUbfx(this, node, mleft.left().node(), lsb, width);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000736 }
737 }
738 }
739 VisitShift(this, node, TryMatchLSR);
740}
741
742
743void InstructionSelector::VisitWord32Sar(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400744 ArmOperandGenerator g(this);
745 Int32BinopMatcher m(node);
746 if (CanCover(m.node(), m.left().node()) && m.left().IsWord32Shl()) {
747 Int32BinopMatcher mleft(m.left().node());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100748 if (m.right().HasValue() && mleft.right().HasValue()) {
749 uint32_t sar = m.right().Value();
750 uint32_t shl = mleft.right().Value();
751 if ((sar == shl) && (sar == 16)) {
752 Emit(kArmSxth, g.DefineAsRegister(node),
753 g.UseRegister(mleft.left().node()), g.TempImmediate(0));
754 return;
755 } else if ((sar == shl) && (sar == 24)) {
756 Emit(kArmSxtb, g.DefineAsRegister(node),
757 g.UseRegister(mleft.left().node()), g.TempImmediate(0));
758 return;
759 } else if (IsSupported(ARMv7) && (sar >= shl)) {
760 Emit(kArmSbfx, g.DefineAsRegister(node),
761 g.UseRegister(mleft.left().node()), g.TempImmediate(sar - shl),
762 g.TempImmediate(32 - sar));
763 return;
764 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400765 }
766 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000767 VisitShift(this, node, TryMatchASR);
768}
769
Ben Murdochda12d292016-06-02 14:46:10 +0100770void InstructionSelector::VisitInt32PairAdd(Node* node) {
771 ArmOperandGenerator g(this);
772
773 // We use UseUniqueRegister here to avoid register sharing with the output
774 // registers.
775 InstructionOperand inputs[] = {
776 g.UseRegister(node->InputAt(0)), g.UseUniqueRegister(node->InputAt(1)),
777 g.UseRegister(node->InputAt(2)), g.UseUniqueRegister(node->InputAt(3))};
778
779 InstructionOperand outputs[] = {
780 g.DefineAsRegister(node),
781 g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
782
783 Emit(kArmAddPair, 2, outputs, 4, inputs);
784}
785
786void InstructionSelector::VisitInt32PairSub(Node* node) {
787 ArmOperandGenerator g(this);
788
789 // We use UseUniqueRegister here to avoid register sharing with the output
790 // register.
791 InstructionOperand inputs[] = {
792 g.UseRegister(node->InputAt(0)), g.UseUniqueRegister(node->InputAt(1)),
793 g.UseRegister(node->InputAt(2)), g.UseUniqueRegister(node->InputAt(3))};
794
795 InstructionOperand outputs[] = {
796 g.DefineAsRegister(node),
797 g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
798
799 Emit(kArmSubPair, 2, outputs, 4, inputs);
800}
801
802void InstructionSelector::VisitInt32PairMul(Node* node) {
803 ArmOperandGenerator g(this);
804 InstructionOperand inputs[] = {g.UseUniqueRegister(node->InputAt(0)),
805 g.UseUniqueRegister(node->InputAt(1)),
806 g.UseUniqueRegister(node->InputAt(2)),
807 g.UseUniqueRegister(node->InputAt(3))};
808
809 InstructionOperand outputs[] = {
810 g.DefineAsRegister(node),
811 g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
812
813 Emit(kArmMulPair, 2, outputs, 4, inputs);
814}
815
816void InstructionSelector::VisitWord32PairShl(Node* node) {
817 ArmOperandGenerator g(this);
818 // We use g.UseUniqueRegister here for InputAt(0) to guarantee that there is
819 // no register aliasing with output registers.
820 Int32Matcher m(node->InputAt(2));
821 InstructionOperand shift_operand;
822 if (m.HasValue()) {
823 shift_operand = g.UseImmediate(m.node());
824 } else {
825 shift_operand = g.UseUniqueRegister(m.node());
826 }
827
828 InstructionOperand inputs[] = {g.UseUniqueRegister(node->InputAt(0)),
829 g.UseRegister(node->InputAt(1)),
830 shift_operand};
831
832 InstructionOperand outputs[] = {
833 g.DefineAsRegister(node),
834 g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
835
836 Emit(kArmLslPair, 2, outputs, 3, inputs);
837}
838
839void InstructionSelector::VisitWord32PairShr(Node* node) {
840 ArmOperandGenerator g(this);
841 // We use g.UseUniqueRegister here for InputAt(1) and InputAt(2) to to
842 // guarantee that there is no register aliasing with output register.
843 Int32Matcher m(node->InputAt(2));
844 InstructionOperand shift_operand;
845 if (m.HasValue()) {
846 shift_operand = g.UseImmediate(m.node());
847 } else {
848 shift_operand = g.UseUniqueRegister(m.node());
849 }
850
851 InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0)),
852 g.UseUniqueRegister(node->InputAt(1)),
853 shift_operand};
854
855 InstructionOperand outputs[] = {
856 g.DefineAsRegister(node),
857 g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
858
859 Emit(kArmLsrPair, 2, outputs, 3, inputs);
860}
861
862void InstructionSelector::VisitWord32PairSar(Node* node) {
863 ArmOperandGenerator g(this);
864 // We use g.UseUniqueRegister here for InputAt(1) and InputAt(2) to to
865 // guarantee that there is no register aliasing with output register.
866 Int32Matcher m(node->InputAt(2));
867 InstructionOperand shift_operand;
868 if (m.HasValue()) {
869 shift_operand = g.UseImmediate(m.node());
870 } else {
871 shift_operand = g.UseUniqueRegister(m.node());
872 }
873
874 InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0)),
875 g.UseUniqueRegister(node->InputAt(1)),
876 shift_operand};
877
878 InstructionOperand outputs[] = {
879 g.DefineAsRegister(node),
880 g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
881
882 Emit(kArmAsrPair, 2, outputs, 3, inputs);
883}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000884
885void InstructionSelector::VisitWord32Ror(Node* node) {
886 VisitShift(this, node, TryMatchROR);
887}
888
889
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000890void InstructionSelector::VisitWord32Clz(Node* node) {
891 VisitRR(this, kArmClz, node);
892}
893
894
895void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); }
896
897
Ben Murdoch097c5b22016-05-18 11:27:45 +0100898void InstructionSelector::VisitWord32ReverseBits(Node* node) {
899 DCHECK(IsSupported(ARMv7));
900 VisitRR(this, kArmRbit, node);
901}
902
903
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000904void InstructionSelector::VisitWord32Popcnt(Node* node) { UNREACHABLE(); }
905
906
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000907void InstructionSelector::VisitInt32Add(Node* node) {
908 ArmOperandGenerator g(this);
909 Int32BinopMatcher m(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400910 if (CanCover(node, m.left().node())) {
911 switch (m.left().opcode()) {
912 case IrOpcode::kInt32Mul: {
913 Int32BinopMatcher mleft(m.left().node());
914 Emit(kArmMla, g.DefineAsRegister(node),
915 g.UseRegister(mleft.left().node()),
916 g.UseRegister(mleft.right().node()),
917 g.UseRegister(m.right().node()));
918 return;
919 }
920 case IrOpcode::kInt32MulHigh: {
921 Int32BinopMatcher mleft(m.left().node());
922 Emit(kArmSmmla, g.DefineAsRegister(node),
923 g.UseRegister(mleft.left().node()),
924 g.UseRegister(mleft.right().node()),
925 g.UseRegister(m.right().node()));
926 return;
927 }
928 case IrOpcode::kWord32And: {
929 Int32BinopMatcher mleft(m.left().node());
930 if (mleft.right().Is(0xff)) {
931 Emit(kArmUxtab, g.DefineAsRegister(node),
932 g.UseRegister(m.right().node()),
933 g.UseRegister(mleft.left().node()), g.TempImmediate(0));
934 return;
935 } else if (mleft.right().Is(0xffff)) {
936 Emit(kArmUxtah, g.DefineAsRegister(node),
937 g.UseRegister(m.right().node()),
938 g.UseRegister(mleft.left().node()), g.TempImmediate(0));
939 return;
940 }
941 }
942 case IrOpcode::kWord32Sar: {
943 Int32BinopMatcher mleft(m.left().node());
944 if (CanCover(mleft.node(), mleft.left().node()) &&
945 mleft.left().IsWord32Shl()) {
946 Int32BinopMatcher mleftleft(mleft.left().node());
947 if (mleft.right().Is(24) && mleftleft.right().Is(24)) {
948 Emit(kArmSxtab, g.DefineAsRegister(node),
949 g.UseRegister(m.right().node()),
950 g.UseRegister(mleftleft.left().node()), g.TempImmediate(0));
951 return;
952 } else if (mleft.right().Is(16) && mleftleft.right().Is(16)) {
953 Emit(kArmSxtah, g.DefineAsRegister(node),
954 g.UseRegister(m.right().node()),
955 g.UseRegister(mleftleft.left().node()), g.TempImmediate(0));
956 return;
957 }
958 }
959 }
960 default:
961 break;
962 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000963 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400964 if (CanCover(node, m.right().node())) {
965 switch (m.right().opcode()) {
966 case IrOpcode::kInt32Mul: {
967 Int32BinopMatcher mright(m.right().node());
968 Emit(kArmMla, g.DefineAsRegister(node),
969 g.UseRegister(mright.left().node()),
970 g.UseRegister(mright.right().node()),
971 g.UseRegister(m.left().node()));
972 return;
973 }
974 case IrOpcode::kInt32MulHigh: {
975 Int32BinopMatcher mright(m.right().node());
976 Emit(kArmSmmla, g.DefineAsRegister(node),
977 g.UseRegister(mright.left().node()),
978 g.UseRegister(mright.right().node()),
979 g.UseRegister(m.left().node()));
980 return;
981 }
982 case IrOpcode::kWord32And: {
983 Int32BinopMatcher mright(m.right().node());
984 if (mright.right().Is(0xff)) {
985 Emit(kArmUxtab, g.DefineAsRegister(node),
986 g.UseRegister(m.left().node()),
987 g.UseRegister(mright.left().node()), g.TempImmediate(0));
988 return;
989 } else if (mright.right().Is(0xffff)) {
990 Emit(kArmUxtah, g.DefineAsRegister(node),
991 g.UseRegister(m.left().node()),
992 g.UseRegister(mright.left().node()), g.TempImmediate(0));
993 return;
994 }
995 }
996 case IrOpcode::kWord32Sar: {
997 Int32BinopMatcher mright(m.right().node());
998 if (CanCover(mright.node(), mright.left().node()) &&
999 mright.left().IsWord32Shl()) {
1000 Int32BinopMatcher mrightleft(mright.left().node());
1001 if (mright.right().Is(24) && mrightleft.right().Is(24)) {
1002 Emit(kArmSxtab, g.DefineAsRegister(node),
1003 g.UseRegister(m.left().node()),
1004 g.UseRegister(mrightleft.left().node()), g.TempImmediate(0));
1005 return;
1006 } else if (mright.right().Is(16) && mrightleft.right().Is(16)) {
1007 Emit(kArmSxtah, g.DefineAsRegister(node),
1008 g.UseRegister(m.left().node()),
1009 g.UseRegister(mrightleft.left().node()), g.TempImmediate(0));
1010 return;
1011 }
1012 }
1013 }
1014 default:
1015 break;
1016 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001017 }
1018 VisitBinop(this, node, kArmAdd, kArmAdd);
1019}
1020
1021
1022void InstructionSelector::VisitInt32Sub(Node* node) {
1023 ArmOperandGenerator g(this);
1024 Int32BinopMatcher m(node);
1025 if (IsSupported(MLS) && m.right().IsInt32Mul() &&
1026 CanCover(node, m.right().node())) {
1027 Int32BinopMatcher mright(m.right().node());
1028 Emit(kArmMls, g.DefineAsRegister(node), g.UseRegister(mright.left().node()),
1029 g.UseRegister(mright.right().node()), g.UseRegister(m.left().node()));
1030 return;
1031 }
1032 VisitBinop(this, node, kArmSub, kArmRsb);
1033}
1034
1035
1036void InstructionSelector::VisitInt32Mul(Node* node) {
1037 ArmOperandGenerator g(this);
1038 Int32BinopMatcher m(node);
1039 if (m.right().HasValue() && m.right().Value() > 0) {
1040 int32_t value = m.right().Value();
1041 if (base::bits::IsPowerOfTwo32(value - 1)) {
1042 Emit(kArmAdd | AddressingModeField::encode(kMode_Operand2_R_LSL_I),
1043 g.DefineAsRegister(node), g.UseRegister(m.left().node()),
1044 g.UseRegister(m.left().node()),
1045 g.TempImmediate(WhichPowerOf2(value - 1)));
1046 return;
1047 }
1048 if (value < kMaxInt && base::bits::IsPowerOfTwo32(value + 1)) {
1049 Emit(kArmRsb | AddressingModeField::encode(kMode_Operand2_R_LSL_I),
1050 g.DefineAsRegister(node), g.UseRegister(m.left().node()),
1051 g.UseRegister(m.left().node()),
1052 g.TempImmediate(WhichPowerOf2(value + 1)));
1053 return;
1054 }
1055 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001056 VisitRRR(this, kArmMul, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001057}
1058
1059
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001060void InstructionSelector::VisitInt32MulHigh(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001061 VisitRRR(this, kArmSmmul, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001062}
1063
1064
1065void InstructionSelector::VisitUint32MulHigh(Node* node) {
1066 ArmOperandGenerator g(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001067 InstructionOperand outputs[] = {g.TempRegister(), g.DefineAsRegister(node)};
1068 InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0)),
1069 g.UseRegister(node->InputAt(1))};
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001070 Emit(kArmUmull, arraysize(outputs), outputs, arraysize(inputs), inputs);
1071}
1072
1073
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001074void InstructionSelector::VisitInt32Div(Node* node) {
1075 VisitDiv(this, node, kArmSdiv, kArmVcvtF64S32, kArmVcvtS32F64);
1076}
1077
1078
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001079void InstructionSelector::VisitUint32Div(Node* node) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001080 VisitDiv(this, node, kArmUdiv, kArmVcvtF64U32, kArmVcvtU32F64);
1081}
1082
1083
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001084void InstructionSelector::VisitInt32Mod(Node* node) {
1085 VisitMod(this, node, kArmSdiv, kArmVcvtF64S32, kArmVcvtS32F64);
1086}
1087
1088
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001089void InstructionSelector::VisitUint32Mod(Node* node) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001090 VisitMod(this, node, kArmUdiv, kArmVcvtF64U32, kArmVcvtU32F64);
1091}
1092
1093
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001094void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001095 VisitRR(this, kArmVcvtF64F32, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001096}
1097
1098
Ben Murdoch097c5b22016-05-18 11:27:45 +01001099void InstructionSelector::VisitRoundInt32ToFloat32(Node* node) {
1100 VisitRR(this, kArmVcvtF32S32, node);
1101}
1102
1103
1104void InstructionSelector::VisitRoundUint32ToFloat32(Node* node) {
1105 VisitRR(this, kArmVcvtF32U32, node);
1106}
1107
1108
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001109void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001110 VisitRR(this, kArmVcvtF64S32, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001111}
1112
1113
1114void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001115 VisitRR(this, kArmVcvtF64U32, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001116}
1117
1118
Ben Murdoch097c5b22016-05-18 11:27:45 +01001119void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) {
1120 VisitRR(this, kArmVcvtS32F32, node);
1121}
1122
1123
1124void InstructionSelector::VisitTruncateFloat32ToUint32(Node* node) {
1125 VisitRR(this, kArmVcvtU32F32, node);
1126}
1127
1128
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001129void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001130 VisitRR(this, kArmVcvtS32F64, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001131}
1132
1133
1134void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001135 VisitRR(this, kArmVcvtU32F64, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001136}
1137
Ben Murdochda12d292016-06-02 14:46:10 +01001138void InstructionSelector::VisitTruncateFloat64ToUint32(Node* node) {
1139 VisitRR(this, kArmVcvtU32F64, node);
1140}
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001141void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001142 VisitRR(this, kArmVcvtF32F64, node);
1143}
1144
1145
1146void InstructionSelector::VisitTruncateFloat64ToInt32(Node* node) {
1147 switch (TruncationModeOf(node->op())) {
1148 case TruncationMode::kJavaScript:
1149 return VisitRR(this, kArchTruncateDoubleToI, node);
1150 case TruncationMode::kRoundToZero:
1151 return VisitRR(this, kArmVcvtS32F64, node);
1152 }
1153 UNREACHABLE();
1154}
1155
1156
1157void InstructionSelector::VisitBitcastFloat32ToInt32(Node* node) {
1158 VisitRR(this, kArmVmovLowU32F64, node);
1159}
1160
1161
1162void InstructionSelector::VisitBitcastInt32ToFloat32(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001163 ArmOperandGenerator g(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001164 Emit(kArmVmovLowF64U32, g.DefineAsRegister(node),
1165 ImmediateOperand(ImmediateOperand::INLINE, 0),
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001166 g.UseRegister(node->InputAt(0)));
1167}
1168
1169
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001170void InstructionSelector::VisitFloat32Add(Node* node) {
1171 ArmOperandGenerator g(this);
1172 Float32BinopMatcher m(node);
1173 if (m.left().IsFloat32Mul() && CanCover(node, m.left().node())) {
1174 Float32BinopMatcher mleft(m.left().node());
1175 Emit(kArmVmlaF32, g.DefineSameAsFirst(node),
1176 g.UseRegister(m.right().node()), g.UseRegister(mleft.left().node()),
1177 g.UseRegister(mleft.right().node()));
1178 return;
1179 }
1180 if (m.right().IsFloat32Mul() && CanCover(node, m.right().node())) {
1181 Float32BinopMatcher mright(m.right().node());
1182 Emit(kArmVmlaF32, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
1183 g.UseRegister(mright.left().node()),
1184 g.UseRegister(mright.right().node()));
1185 return;
1186 }
1187 VisitRRR(this, kArmVaddF32, node);
1188}
1189
1190
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001191void InstructionSelector::VisitFloat64Add(Node* node) {
1192 ArmOperandGenerator g(this);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001193 Float64BinopMatcher m(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001194 if (m.left().IsFloat64Mul() && CanCover(node, m.left().node())) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001195 Float64BinopMatcher mleft(m.left().node());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001196 Emit(kArmVmlaF64, g.DefineSameAsFirst(node),
1197 g.UseRegister(m.right().node()), g.UseRegister(mleft.left().node()),
1198 g.UseRegister(mleft.right().node()));
1199 return;
1200 }
1201 if (m.right().IsFloat64Mul() && CanCover(node, m.right().node())) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001202 Float64BinopMatcher mright(m.right().node());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001203 Emit(kArmVmlaF64, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
1204 g.UseRegister(mright.left().node()),
1205 g.UseRegister(mright.right().node()));
1206 return;
1207 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001208 VisitRRR(this, kArmVaddF64, node);
1209}
1210
1211
1212void InstructionSelector::VisitFloat32Sub(Node* node) {
1213 ArmOperandGenerator g(this);
1214 Float32BinopMatcher m(node);
1215 if (m.left().IsMinusZero()) {
1216 Emit(kArmVnegF32, g.DefineAsRegister(node),
1217 g.UseRegister(m.right().node()));
1218 return;
1219 }
1220 if (m.right().IsFloat32Mul() && CanCover(node, m.right().node())) {
1221 Float32BinopMatcher mright(m.right().node());
1222 Emit(kArmVmlsF32, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
1223 g.UseRegister(mright.left().node()),
1224 g.UseRegister(mright.right().node()));
1225 return;
1226 }
1227 VisitRRR(this, kArmVsubF32, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001228}
1229
1230
1231void InstructionSelector::VisitFloat64Sub(Node* node) {
1232 ArmOperandGenerator g(this);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001233 Float64BinopMatcher m(node);
1234 if (m.left().IsMinusZero()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001235 if (m.right().IsFloat64RoundDown() &&
1236 CanCover(m.node(), m.right().node())) {
1237 if (m.right().InputAt(0)->opcode() == IrOpcode::kFloat64Sub &&
1238 CanCover(m.right().node(), m.right().InputAt(0))) {
1239 Float64BinopMatcher mright0(m.right().InputAt(0));
1240 if (mright0.left().IsMinusZero()) {
1241 Emit(kArmVrintpF64, g.DefineAsRegister(node),
1242 g.UseRegister(mright0.right().node()));
1243 return;
1244 }
1245 }
1246 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001247 Emit(kArmVnegF64, g.DefineAsRegister(node),
1248 g.UseRegister(m.right().node()));
1249 return;
1250 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001251 if (m.right().IsFloat64Mul() && CanCover(node, m.right().node())) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001252 Float64BinopMatcher mright(m.right().node());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001253 Emit(kArmVmlsF64, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
1254 g.UseRegister(mright.left().node()),
1255 g.UseRegister(mright.right().node()));
1256 return;
1257 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001258 VisitRRR(this, kArmVsubF64, node);
1259}
1260
1261
1262void InstructionSelector::VisitFloat32Mul(Node* node) {
1263 VisitRRR(this, kArmVmulF32, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001264}
1265
1266
1267void InstructionSelector::VisitFloat64Mul(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001268 VisitRRR(this, kArmVmulF64, node);
1269}
1270
1271
1272void InstructionSelector::VisitFloat32Div(Node* node) {
1273 VisitRRR(this, kArmVdivF32, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001274}
1275
1276
1277void InstructionSelector::VisitFloat64Div(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001278 VisitRRR(this, kArmVdivF64, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001279}
1280
1281
1282void InstructionSelector::VisitFloat64Mod(Node* node) {
1283 ArmOperandGenerator g(this);
1284 Emit(kArmVmodF64, g.DefineAsFixed(node, d0), g.UseFixed(node->InputAt(0), d0),
1285 g.UseFixed(node->InputAt(1), d1))->MarkAsCall();
1286}
1287
1288
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001289void InstructionSelector::VisitFloat32Max(Node* node) { UNREACHABLE(); }
1290
1291
1292void InstructionSelector::VisitFloat64Max(Node* node) { UNREACHABLE(); }
1293
1294
1295void InstructionSelector::VisitFloat32Min(Node* node) { UNREACHABLE(); }
1296
1297
1298void InstructionSelector::VisitFloat64Min(Node* node) { UNREACHABLE(); }
1299
1300
1301void InstructionSelector::VisitFloat32Abs(Node* node) {
1302 VisitRR(this, kArmVabsF32, node);
1303}
1304
1305
1306void InstructionSelector::VisitFloat64Abs(Node* node) {
1307 VisitRR(this, kArmVabsF64, node);
1308}
1309
1310
1311void InstructionSelector::VisitFloat32Sqrt(Node* node) {
1312 VisitRR(this, kArmVsqrtF32, node);
1313}
1314
1315
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001316void InstructionSelector::VisitFloat64Sqrt(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001317 VisitRR(this, kArmVsqrtF64, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001318}
1319
1320
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001321void InstructionSelector::VisitFloat32RoundDown(Node* node) {
1322 VisitRR(this, kArmVrintmF32, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001323}
1324
1325
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001326void InstructionSelector::VisitFloat64RoundDown(Node* node) {
1327 VisitRR(this, kArmVrintmF64, node);
1328}
1329
1330
1331void InstructionSelector::VisitFloat32RoundUp(Node* node) {
1332 VisitRR(this, kArmVrintpF32, node);
1333}
1334
1335
1336void InstructionSelector::VisitFloat64RoundUp(Node* node) {
1337 VisitRR(this, kArmVrintpF64, node);
1338}
1339
1340
1341void InstructionSelector::VisitFloat32RoundTruncate(Node* node) {
1342 VisitRR(this, kArmVrintzF32, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001343}
1344
1345
1346void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001347 VisitRR(this, kArmVrintzF64, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001348}
1349
1350
1351void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001352 VisitRR(this, kArmVrintaF64, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001353}
1354
1355
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001356void InstructionSelector::VisitFloat32RoundTiesEven(Node* node) {
1357 VisitRR(this, kArmVrintnF32, node);
1358}
1359
1360
1361void InstructionSelector::VisitFloat64RoundTiesEven(Node* node) {
1362 VisitRR(this, kArmVrintnF64, node);
1363}
1364
1365
1366void InstructionSelector::EmitPrepareArguments(
1367 ZoneVector<PushParameter>* arguments, const CallDescriptor* descriptor,
1368 Node* node) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001369 ArmOperandGenerator g(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001370
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001371 // Prepare for C function call.
1372 if (descriptor->IsCFunctionCall()) {
1373 Emit(kArchPrepareCallCFunction |
1374 MiscField::encode(static_cast<int>(descriptor->CParameterCount())),
1375 0, nullptr, 0, nullptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001376
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001377 // Poke any stack arguments.
1378 for (size_t n = 0; n < arguments->size(); ++n) {
1379 PushParameter input = (*arguments)[n];
1380 if (input.node()) {
1381 int slot = static_cast<int>(n);
1382 Emit(kArmPoke | MiscField::encode(slot), g.NoOutput(),
1383 g.UseRegister(input.node()));
1384 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001385 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001386 } else {
1387 // Push any stack arguments.
1388 for (PushParameter input : base::Reversed(*arguments)) {
1389 // Skip any alignment holes in pushed nodes.
1390 if (input.node() == nullptr) continue;
1391 Emit(kArmPush, g.NoOutput(), g.UseRegister(input.node()));
1392 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001393 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001394}
1395
1396
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001397bool InstructionSelector::IsTailCallAddressImmediate() { return false; }
1398
Ben Murdochda12d292016-06-02 14:46:10 +01001399int InstructionSelector::GetTempsCountForTailCallFromJSFunction() { return 3; }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001400
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001401namespace {
1402
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001403// Shared routine for multiple compare operations.
1404void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
1405 InstructionOperand left, InstructionOperand right,
1406 FlagsContinuation* cont) {
1407 ArmOperandGenerator g(selector);
1408 opcode = cont->Encode(opcode);
1409 if (cont->IsBranch()) {
1410 selector->Emit(opcode, g.NoOutput(), left, right,
1411 g.Label(cont->true_block()), g.Label(cont->false_block()));
Ben Murdochda12d292016-06-02 14:46:10 +01001412 } else if (cont->IsDeoptimize()) {
1413 selector->EmitDeoptimize(opcode, g.NoOutput(), left, right,
1414 cont->frame_state());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001415 } else {
1416 DCHECK(cont->IsSet());
1417 selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
1418 }
1419}
1420
1421
1422// Shared routine for multiple float32 compare operations.
1423void VisitFloat32Compare(InstructionSelector* selector, Node* node,
1424 FlagsContinuation* cont) {
1425 ArmOperandGenerator g(selector);
1426 Float32BinopMatcher m(node);
1427 if (m.right().Is(0.0f)) {
1428 VisitCompare(selector, kArmVcmpF32, g.UseRegister(m.left().node()),
1429 g.UseImmediate(m.right().node()), cont);
1430 } else if (m.left().Is(0.0f)) {
1431 cont->Commute();
1432 VisitCompare(selector, kArmVcmpF32, g.UseRegister(m.right().node()),
1433 g.UseImmediate(m.left().node()), cont);
1434 } else {
1435 VisitCompare(selector, kArmVcmpF32, g.UseRegister(m.left().node()),
1436 g.UseRegister(m.right().node()), cont);
1437 }
1438}
1439
1440
1441// Shared routine for multiple float64 compare operations.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001442void VisitFloat64Compare(InstructionSelector* selector, Node* node,
1443 FlagsContinuation* cont) {
1444 ArmOperandGenerator g(selector);
1445 Float64BinopMatcher m(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001446 if (m.right().Is(0.0)) {
1447 VisitCompare(selector, kArmVcmpF64, g.UseRegister(m.left().node()),
1448 g.UseImmediate(m.right().node()), cont);
1449 } else if (m.left().Is(0.0)) {
1450 cont->Commute();
1451 VisitCompare(selector, kArmVcmpF64, g.UseRegister(m.right().node()),
1452 g.UseImmediate(m.left().node()), cont);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001453 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001454 VisitCompare(selector, kArmVcmpF64, g.UseRegister(m.left().node()),
1455 g.UseRegister(m.right().node()), cont);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001456 }
1457}
1458
1459
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001460// Shared routine for multiple word compare operations.
1461void VisitWordCompare(InstructionSelector* selector, Node* node,
1462 InstructionCode opcode, FlagsContinuation* cont) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001463 ArmOperandGenerator g(selector);
1464 Int32BinopMatcher m(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001465 InstructionOperand inputs[5];
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001466 size_t input_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001467 InstructionOperand outputs[1];
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001468 size_t output_count = 0;
1469
1470 if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(),
1471 &input_count, &inputs[1])) {
1472 inputs[0] = g.UseRegister(m.left().node());
1473 input_count++;
1474 } else if (TryMatchImmediateOrShift(selector, &opcode, m.left().node(),
1475 &input_count, &inputs[1])) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001476 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001477 inputs[0] = g.UseRegister(m.right().node());
1478 input_count++;
1479 } else {
1480 opcode |= AddressingModeField::encode(kMode_Operand2_R);
1481 inputs[input_count++] = g.UseRegister(m.left().node());
1482 inputs[input_count++] = g.UseRegister(m.right().node());
1483 }
1484
1485 if (cont->IsBranch()) {
1486 inputs[input_count++] = g.Label(cont->true_block());
1487 inputs[input_count++] = g.Label(cont->false_block());
Ben Murdochda12d292016-06-02 14:46:10 +01001488 } else if (cont->IsSet()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001489 outputs[output_count++] = g.DefineAsRegister(cont->result());
1490 }
1491
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001492 DCHECK_NE(0u, input_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001493 DCHECK_GE(arraysize(inputs), input_count);
1494 DCHECK_GE(arraysize(outputs), output_count);
1495
Ben Murdochda12d292016-06-02 14:46:10 +01001496 opcode = cont->Encode(opcode);
1497 if (cont->IsDeoptimize()) {
1498 selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
1499 cont->frame_state());
1500 } else {
1501 selector->Emit(opcode, output_count, outputs, input_count, inputs);
1502 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001503}
1504
1505
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001506void VisitWordCompare(InstructionSelector* selector, Node* node,
1507 FlagsContinuation* cont) {
1508 VisitWordCompare(selector, node, kArmCmp, cont);
1509}
1510
1511
1512// Shared routine for word comparisons against zero.
1513void VisitWordCompareZero(InstructionSelector* selector, Node* user,
1514 Node* value, FlagsContinuation* cont) {
1515 while (selector->CanCover(user, value)) {
1516 switch (value->opcode()) {
1517 case IrOpcode::kWord32Equal: {
1518 // Combine with comparisons against 0 by simply inverting the
1519 // continuation.
1520 Int32BinopMatcher m(value);
1521 if (m.right().Is(0)) {
1522 user = value;
1523 value = m.left().node();
1524 cont->Negate();
1525 continue;
1526 }
1527 cont->OverwriteAndNegateIfEqual(kEqual);
1528 return VisitWordCompare(selector, value, cont);
1529 }
1530 case IrOpcode::kInt32LessThan:
1531 cont->OverwriteAndNegateIfEqual(kSignedLessThan);
1532 return VisitWordCompare(selector, value, cont);
1533 case IrOpcode::kInt32LessThanOrEqual:
1534 cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
1535 return VisitWordCompare(selector, value, cont);
1536 case IrOpcode::kUint32LessThan:
1537 cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
1538 return VisitWordCompare(selector, value, cont);
1539 case IrOpcode::kUint32LessThanOrEqual:
1540 cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
1541 return VisitWordCompare(selector, value, cont);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001542 case IrOpcode::kFloat32Equal:
1543 cont->OverwriteAndNegateIfEqual(kEqual);
1544 return VisitFloat32Compare(selector, value, cont);
1545 case IrOpcode::kFloat32LessThan:
1546 cont->OverwriteAndNegateIfEqual(kFloatLessThan);
1547 return VisitFloat32Compare(selector, value, cont);
1548 case IrOpcode::kFloat32LessThanOrEqual:
1549 cont->OverwriteAndNegateIfEqual(kFloatLessThanOrEqual);
1550 return VisitFloat32Compare(selector, value, cont);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001551 case IrOpcode::kFloat64Equal:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001552 cont->OverwriteAndNegateIfEqual(kEqual);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001553 return VisitFloat64Compare(selector, value, cont);
1554 case IrOpcode::kFloat64LessThan:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001555 cont->OverwriteAndNegateIfEqual(kFloatLessThan);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001556 return VisitFloat64Compare(selector, value, cont);
1557 case IrOpcode::kFloat64LessThanOrEqual:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001558 cont->OverwriteAndNegateIfEqual(kFloatLessThanOrEqual);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001559 return VisitFloat64Compare(selector, value, cont);
1560 case IrOpcode::kProjection:
1561 // Check if this is the overflow output projection of an
1562 // <Operation>WithOverflow node.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001563 if (ProjectionIndexOf(value->op()) == 1u) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001564 // We cannot combine the <Operation>WithOverflow with this branch
1565 // unless the 0th projection (the use of the actual value of the
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001566 // <Operation> is either nullptr, which means there's no use of the
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001567 // actual value, or was already defined, which means it is scheduled
1568 // *AFTER* this branch).
1569 Node* const node = value->InputAt(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001570 Node* const result = NodeProperties::FindProjection(node, 0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001571 if (!result || selector->IsDefined(result)) {
1572 switch (node->opcode()) {
1573 case IrOpcode::kInt32AddWithOverflow:
1574 cont->OverwriteAndNegateIfEqual(kOverflow);
1575 return VisitBinop(selector, node, kArmAdd, kArmAdd, cont);
1576 case IrOpcode::kInt32SubWithOverflow:
1577 cont->OverwriteAndNegateIfEqual(kOverflow);
1578 return VisitBinop(selector, node, kArmSub, kArmRsb, cont);
1579 default:
1580 break;
1581 }
1582 }
1583 }
1584 break;
1585 case IrOpcode::kInt32Add:
1586 return VisitWordCompare(selector, value, kArmCmn, cont);
1587 case IrOpcode::kInt32Sub:
1588 return VisitWordCompare(selector, value, kArmCmp, cont);
1589 case IrOpcode::kWord32And:
1590 return VisitWordCompare(selector, value, kArmTst, cont);
1591 case IrOpcode::kWord32Or:
1592 return VisitBinop(selector, value, kArmOrr, kArmOrr, cont);
1593 case IrOpcode::kWord32Xor:
1594 return VisitWordCompare(selector, value, kArmTeq, cont);
1595 case IrOpcode::kWord32Sar:
1596 return VisitShift(selector, value, TryMatchASR, cont);
1597 case IrOpcode::kWord32Shl:
1598 return VisitShift(selector, value, TryMatchLSL, cont);
1599 case IrOpcode::kWord32Shr:
1600 return VisitShift(selector, value, TryMatchLSR, cont);
1601 case IrOpcode::kWord32Ror:
1602 return VisitShift(selector, value, TryMatchROR, cont);
1603 default:
1604 break;
1605 }
1606 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001607 }
1608
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001609 // Continuation could not be combined with a compare, emit compare against 0.
1610 ArmOperandGenerator g(selector);
1611 InstructionCode const opcode =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001612 cont->Encode(kArmTst) | AddressingModeField::encode(kMode_Operand2_R);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001613 InstructionOperand const value_operand = g.UseRegister(value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001614 if (cont->IsBranch()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001615 selector->Emit(opcode, g.NoOutput(), value_operand, value_operand,
1616 g.Label(cont->true_block()), g.Label(cont->false_block()));
Ben Murdochda12d292016-06-02 14:46:10 +01001617 } else if (cont->IsDeoptimize()) {
1618 selector->EmitDeoptimize(opcode, g.NoOutput(), value_operand, value_operand,
1619 cont->frame_state());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001620 } else {
Ben Murdochda12d292016-06-02 14:46:10 +01001621 DCHECK(cont->IsSet());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001622 selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand,
1623 value_operand);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001624 }
1625}
1626
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001627} // namespace
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001628
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001629void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
1630 BasicBlock* fbranch) {
1631 FlagsContinuation cont(kNotEqual, tbranch, fbranch);
1632 VisitWordCompareZero(this, branch, branch->InputAt(0), &cont);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001633}
1634
Ben Murdochda12d292016-06-02 14:46:10 +01001635void InstructionSelector::VisitDeoptimizeIf(Node* node) {
1636 FlagsContinuation cont =
1637 FlagsContinuation::ForDeoptimize(kNotEqual, node->InputAt(1));
1638 VisitWordCompareZero(this, node, node->InputAt(0), &cont);
1639}
1640
1641void InstructionSelector::VisitDeoptimizeUnless(Node* node) {
1642 FlagsContinuation cont =
1643 FlagsContinuation::ForDeoptimize(kEqual, node->InputAt(1));
1644 VisitWordCompareZero(this, node, node->InputAt(0), &cont);
1645}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001646
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001647void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
1648 ArmOperandGenerator g(this);
1649 InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
1650
1651 // Emit either ArchTableSwitch or ArchLookupSwitch.
1652 size_t table_space_cost = 4 + sw.value_range;
1653 size_t table_time_cost = 3;
1654 size_t lookup_space_cost = 3 + 2 * sw.case_count;
1655 size_t lookup_time_cost = sw.case_count;
1656 if (sw.case_count > 0 &&
1657 table_space_cost + 3 * table_time_cost <=
1658 lookup_space_cost + 3 * lookup_time_cost &&
1659 sw.min_value > std::numeric_limits<int32_t>::min()) {
1660 InstructionOperand index_operand = value_operand;
1661 if (sw.min_value) {
1662 index_operand = g.TempRegister();
1663 Emit(kArmSub | AddressingModeField::encode(kMode_Operand2_I),
1664 index_operand, value_operand, g.TempImmediate(sw.min_value));
1665 }
1666 // Generate a table lookup.
1667 return EmitTableSwitch(sw, index_operand);
1668 }
1669
1670 // Generate a sequence of conditional jumps.
1671 return EmitLookupSwitch(sw, value_operand);
1672}
1673
1674
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001675void InstructionSelector::VisitWord32Equal(Node* const node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001676 FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001677 Int32BinopMatcher m(node);
1678 if (m.right().Is(0)) {
1679 return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001680 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001681 VisitWordCompare(this, node, &cont);
1682}
1683
1684
1685void InstructionSelector::VisitInt32LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001686 FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001687 VisitWordCompare(this, node, &cont);
1688}
1689
1690
1691void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001692 FlagsContinuation cont =
1693 FlagsContinuation::ForSet(kSignedLessThanOrEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001694 VisitWordCompare(this, node, &cont);
1695}
1696
1697
1698void InstructionSelector::VisitUint32LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001699 FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001700 VisitWordCompare(this, node, &cont);
1701}
1702
1703
1704void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001705 FlagsContinuation cont =
1706 FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001707 VisitWordCompare(this, node, &cont);
1708}
1709
1710
1711void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001712 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
Ben Murdochda12d292016-06-02 14:46:10 +01001713 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001714 return VisitBinop(this, node, kArmAdd, kArmAdd, &cont);
1715 }
1716 FlagsContinuation cont;
1717 VisitBinop(this, node, kArmAdd, kArmAdd, &cont);
1718}
1719
1720
1721void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001722 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
Ben Murdochda12d292016-06-02 14:46:10 +01001723 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001724 return VisitBinop(this, node, kArmSub, kArmRsb, &cont);
1725 }
1726 FlagsContinuation cont;
1727 VisitBinop(this, node, kArmSub, kArmRsb, &cont);
1728}
1729
1730
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001731void InstructionSelector::VisitFloat32Equal(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001732 FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001733 VisitFloat32Compare(this, node, &cont);
1734}
1735
1736
1737void InstructionSelector::VisitFloat32LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001738 FlagsContinuation cont = FlagsContinuation::ForSet(kFloatLessThan, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001739 VisitFloat32Compare(this, node, &cont);
1740}
1741
1742
1743void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001744 FlagsContinuation cont =
1745 FlagsContinuation::ForSet(kFloatLessThanOrEqual, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001746 VisitFloat32Compare(this, node, &cont);
1747}
1748
1749
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001750void InstructionSelector::VisitFloat64Equal(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001751 FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001752 VisitFloat64Compare(this, node, &cont);
1753}
1754
1755
1756void InstructionSelector::VisitFloat64LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001757 FlagsContinuation cont = FlagsContinuation::ForSet(kFloatLessThan, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001758 VisitFloat64Compare(this, node, &cont);
1759}
1760
1761
1762void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001763 FlagsContinuation cont =
1764 FlagsContinuation::ForSet(kFloatLessThanOrEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001765 VisitFloat64Compare(this, node, &cont);
1766}
1767
1768
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001769void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) {
1770 VisitRR(this, kArmVmovLowU32F64, node);
1771}
1772
1773
1774void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) {
1775 VisitRR(this, kArmVmovHighU32F64, node);
1776}
1777
1778
1779void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) {
1780 ArmOperandGenerator g(this);
1781 Node* left = node->InputAt(0);
1782 Node* right = node->InputAt(1);
1783 if (left->opcode() == IrOpcode::kFloat64InsertHighWord32 &&
1784 CanCover(node, left)) {
1785 left = left->InputAt(1);
1786 Emit(kArmVmovF64U32U32, g.DefineAsRegister(node), g.UseRegister(right),
1787 g.UseRegister(left));
1788 return;
1789 }
1790 Emit(kArmVmovLowF64U32, g.DefineSameAsFirst(node), g.UseRegister(left),
1791 g.UseRegister(right));
1792}
1793
1794
1795void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
1796 ArmOperandGenerator g(this);
1797 Node* left = node->InputAt(0);
1798 Node* right = node->InputAt(1);
1799 if (left->opcode() == IrOpcode::kFloat64InsertLowWord32 &&
1800 CanCover(node, left)) {
1801 left = left->InputAt(1);
1802 Emit(kArmVmovF64U32U32, g.DefineAsRegister(node), g.UseRegister(left),
1803 g.UseRegister(right));
1804 return;
1805 }
1806 Emit(kArmVmovHighF64U32, g.DefineSameAsFirst(node), g.UseRegister(left),
1807 g.UseRegister(right));
1808}
1809
1810
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001811// static
1812MachineOperatorBuilder::Flags
1813InstructionSelector::SupportedMachineOperatorFlags() {
1814 MachineOperatorBuilder::Flags flags =
1815 MachineOperatorBuilder::kInt32DivIsSafe |
1816 MachineOperatorBuilder::kUint32DivIsSafe;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001817 if (CpuFeatures::IsSupported(ARMv7)) {
1818 flags |= MachineOperatorBuilder::kWord32ReverseBits;
1819 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001820 if (CpuFeatures::IsSupported(ARMv8)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001821 flags |= MachineOperatorBuilder::kFloat32RoundDown |
1822 MachineOperatorBuilder::kFloat64RoundDown |
1823 MachineOperatorBuilder::kFloat32RoundUp |
1824 MachineOperatorBuilder::kFloat64RoundUp |
1825 MachineOperatorBuilder::kFloat32RoundTruncate |
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001826 MachineOperatorBuilder::kFloat64RoundTruncate |
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001827 MachineOperatorBuilder::kFloat64RoundTiesAway |
1828 MachineOperatorBuilder::kFloat32RoundTiesEven |
1829 MachineOperatorBuilder::kFloat64RoundTiesEven;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001830 }
1831 return flags;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001832}
1833
1834} // namespace compiler
1835} // namespace internal
1836} // namespace v8