blob: b2b1a7049d1e5bb2fc7237f3316dd648d5260352 [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
Ben Murdochc5610432016-08-08 18:44:38 +01001145void InstructionSelector::VisitTruncateFloat64ToWord32(Node* node) {
1146 VisitRR(this, kArchTruncateDoubleToI, node);
1147}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001148
Ben Murdochc5610432016-08-08 18:44:38 +01001149void InstructionSelector::VisitRoundFloat64ToInt32(Node* node) {
1150 VisitRR(this, kArmVcvtS32F64, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001151}
1152
1153
1154void InstructionSelector::VisitBitcastFloat32ToInt32(Node* node) {
1155 VisitRR(this, kArmVmovLowU32F64, node);
1156}
1157
1158
1159void InstructionSelector::VisitBitcastInt32ToFloat32(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001160 ArmOperandGenerator g(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001161 Emit(kArmVmovLowF64U32, g.DefineAsRegister(node),
1162 ImmediateOperand(ImmediateOperand::INLINE, 0),
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001163 g.UseRegister(node->InputAt(0)));
1164}
1165
1166
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001167void InstructionSelector::VisitFloat32Add(Node* node) {
1168 ArmOperandGenerator g(this);
1169 Float32BinopMatcher m(node);
1170 if (m.left().IsFloat32Mul() && CanCover(node, m.left().node())) {
1171 Float32BinopMatcher mleft(m.left().node());
1172 Emit(kArmVmlaF32, g.DefineSameAsFirst(node),
1173 g.UseRegister(m.right().node()), g.UseRegister(mleft.left().node()),
1174 g.UseRegister(mleft.right().node()));
1175 return;
1176 }
1177 if (m.right().IsFloat32Mul() && CanCover(node, m.right().node())) {
1178 Float32BinopMatcher mright(m.right().node());
1179 Emit(kArmVmlaF32, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
1180 g.UseRegister(mright.left().node()),
1181 g.UseRegister(mright.right().node()));
1182 return;
1183 }
1184 VisitRRR(this, kArmVaddF32, node);
1185}
1186
1187
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001188void InstructionSelector::VisitFloat64Add(Node* node) {
1189 ArmOperandGenerator g(this);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001190 Float64BinopMatcher m(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001191 if (m.left().IsFloat64Mul() && CanCover(node, m.left().node())) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001192 Float64BinopMatcher mleft(m.left().node());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001193 Emit(kArmVmlaF64, g.DefineSameAsFirst(node),
1194 g.UseRegister(m.right().node()), g.UseRegister(mleft.left().node()),
1195 g.UseRegister(mleft.right().node()));
1196 return;
1197 }
1198 if (m.right().IsFloat64Mul() && CanCover(node, m.right().node())) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001199 Float64BinopMatcher mright(m.right().node());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001200 Emit(kArmVmlaF64, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
1201 g.UseRegister(mright.left().node()),
1202 g.UseRegister(mright.right().node()));
1203 return;
1204 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001205 VisitRRR(this, kArmVaddF64, node);
1206}
1207
Ben Murdochc5610432016-08-08 18:44:38 +01001208namespace {
1209void VisitFloat32SubHelper(InstructionSelector* selector, Node* node) {
1210 ArmOperandGenerator g(selector);
1211 Float32BinopMatcher m(node);
1212 if (m.right().IsFloat32Mul() && selector->CanCover(node, m.right().node())) {
1213 Float32BinopMatcher mright(m.right().node());
1214 selector->Emit(kArmVmlsF32, g.DefineSameAsFirst(node),
1215 g.UseRegister(m.left().node()),
1216 g.UseRegister(mright.left().node()),
1217 g.UseRegister(mright.right().node()));
1218 return;
1219 }
1220 VisitRRR(selector, kArmVsubF32, node);
1221}
1222
1223void VisitFloat64SubHelper(InstructionSelector* selector, Node* node) {
1224 ArmOperandGenerator g(selector);
1225 Float64BinopMatcher m(node);
1226 if (m.right().IsFloat64Mul() && selector->CanCover(node, m.right().node())) {
1227 Float64BinopMatcher mright(m.right().node());
1228 selector->Emit(kArmVmlsF64, g.DefineSameAsFirst(node),
1229 g.UseRegister(m.left().node()),
1230 g.UseRegister(mright.left().node()),
1231 g.UseRegister(mright.right().node()));
1232 return;
1233 }
1234 VisitRRR(selector, kArmVsubF64, node);
1235}
1236} // namespace
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001237
1238void InstructionSelector::VisitFloat32Sub(Node* node) {
1239 ArmOperandGenerator g(this);
1240 Float32BinopMatcher m(node);
1241 if (m.left().IsMinusZero()) {
1242 Emit(kArmVnegF32, g.DefineAsRegister(node),
1243 g.UseRegister(m.right().node()));
1244 return;
1245 }
Ben Murdochc5610432016-08-08 18:44:38 +01001246 VisitFloat32SubHelper(this, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001247}
1248
Ben Murdochc5610432016-08-08 18:44:38 +01001249void InstructionSelector::VisitFloat32SubPreserveNan(Node* node) {
1250 VisitFloat32SubHelper(this, node);
1251}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001252
1253void InstructionSelector::VisitFloat64Sub(Node* node) {
1254 ArmOperandGenerator g(this);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001255 Float64BinopMatcher m(node);
1256 if (m.left().IsMinusZero()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001257 if (m.right().IsFloat64RoundDown() &&
1258 CanCover(m.node(), m.right().node())) {
1259 if (m.right().InputAt(0)->opcode() == IrOpcode::kFloat64Sub &&
1260 CanCover(m.right().node(), m.right().InputAt(0))) {
1261 Float64BinopMatcher mright0(m.right().InputAt(0));
1262 if (mright0.left().IsMinusZero()) {
1263 Emit(kArmVrintpF64, g.DefineAsRegister(node),
1264 g.UseRegister(mright0.right().node()));
1265 return;
1266 }
1267 }
1268 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001269 Emit(kArmVnegF64, g.DefineAsRegister(node),
1270 g.UseRegister(m.right().node()));
1271 return;
1272 }
Ben Murdochc5610432016-08-08 18:44:38 +01001273 VisitFloat64SubHelper(this, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001274}
1275
Ben Murdochc5610432016-08-08 18:44:38 +01001276void InstructionSelector::VisitFloat64SubPreserveNan(Node* node) {
1277 VisitFloat64SubHelper(this, node);
1278}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001279
1280void InstructionSelector::VisitFloat32Mul(Node* node) {
1281 VisitRRR(this, kArmVmulF32, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001282}
1283
1284
1285void InstructionSelector::VisitFloat64Mul(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001286 VisitRRR(this, kArmVmulF64, node);
1287}
1288
1289
1290void InstructionSelector::VisitFloat32Div(Node* node) {
1291 VisitRRR(this, kArmVdivF32, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001292}
1293
1294
1295void InstructionSelector::VisitFloat64Div(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001296 VisitRRR(this, kArmVdivF64, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001297}
1298
1299
1300void InstructionSelector::VisitFloat64Mod(Node* node) {
1301 ArmOperandGenerator g(this);
1302 Emit(kArmVmodF64, g.DefineAsFixed(node, d0), g.UseFixed(node->InputAt(0), d0),
1303 g.UseFixed(node->InputAt(1), d1))->MarkAsCall();
1304}
1305
Ben Murdochc5610432016-08-08 18:44:38 +01001306void InstructionSelector::VisitFloat32Max(Node* node) {
1307 DCHECK(IsSupported(ARMv8));
1308 VisitRRR(this, kArmFloat32Max, node);
1309}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001310
Ben Murdochc5610432016-08-08 18:44:38 +01001311void InstructionSelector::VisitFloat64Max(Node* node) {
1312 DCHECK(IsSupported(ARMv8));
1313 VisitRRR(this, kArmFloat64Max, node);
1314}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001315
Ben Murdochc5610432016-08-08 18:44:38 +01001316void InstructionSelector::VisitFloat32Min(Node* node) {
1317 DCHECK(IsSupported(ARMv8));
1318 VisitRRR(this, kArmFloat32Min, node);
1319}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001320
Ben Murdochc5610432016-08-08 18:44:38 +01001321void InstructionSelector::VisitFloat64Min(Node* node) {
1322 DCHECK(IsSupported(ARMv8));
1323 VisitRRR(this, kArmFloat64Min, node);
1324}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001325
1326void InstructionSelector::VisitFloat32Abs(Node* node) {
1327 VisitRR(this, kArmVabsF32, node);
1328}
1329
1330
1331void InstructionSelector::VisitFloat64Abs(Node* node) {
1332 VisitRR(this, kArmVabsF64, node);
1333}
1334
1335
1336void InstructionSelector::VisitFloat32Sqrt(Node* node) {
1337 VisitRR(this, kArmVsqrtF32, node);
1338}
1339
1340
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001341void InstructionSelector::VisitFloat64Sqrt(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001342 VisitRR(this, kArmVsqrtF64, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001343}
1344
1345
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001346void InstructionSelector::VisitFloat32RoundDown(Node* node) {
1347 VisitRR(this, kArmVrintmF32, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001348}
1349
1350
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001351void InstructionSelector::VisitFloat64RoundDown(Node* node) {
1352 VisitRR(this, kArmVrintmF64, node);
1353}
1354
1355
1356void InstructionSelector::VisitFloat32RoundUp(Node* node) {
1357 VisitRR(this, kArmVrintpF32, node);
1358}
1359
1360
1361void InstructionSelector::VisitFloat64RoundUp(Node* node) {
1362 VisitRR(this, kArmVrintpF64, node);
1363}
1364
1365
1366void InstructionSelector::VisitFloat32RoundTruncate(Node* node) {
1367 VisitRR(this, kArmVrintzF32, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001368}
1369
1370
1371void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001372 VisitRR(this, kArmVrintzF64, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001373}
1374
1375
1376void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001377 VisitRR(this, kArmVrintaF64, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001378}
1379
1380
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001381void InstructionSelector::VisitFloat32RoundTiesEven(Node* node) {
1382 VisitRR(this, kArmVrintnF32, node);
1383}
1384
1385
1386void InstructionSelector::VisitFloat64RoundTiesEven(Node* node) {
1387 VisitRR(this, kArmVrintnF64, node);
1388}
1389
1390
1391void InstructionSelector::EmitPrepareArguments(
1392 ZoneVector<PushParameter>* arguments, const CallDescriptor* descriptor,
1393 Node* node) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001394 ArmOperandGenerator g(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001395
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001396 // Prepare for C function call.
1397 if (descriptor->IsCFunctionCall()) {
1398 Emit(kArchPrepareCallCFunction |
1399 MiscField::encode(static_cast<int>(descriptor->CParameterCount())),
1400 0, nullptr, 0, nullptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001401
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001402 // Poke any stack arguments.
1403 for (size_t n = 0; n < arguments->size(); ++n) {
1404 PushParameter input = (*arguments)[n];
1405 if (input.node()) {
1406 int slot = static_cast<int>(n);
1407 Emit(kArmPoke | MiscField::encode(slot), g.NoOutput(),
1408 g.UseRegister(input.node()));
1409 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001410 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001411 } else {
1412 // Push any stack arguments.
1413 for (PushParameter input : base::Reversed(*arguments)) {
1414 // Skip any alignment holes in pushed nodes.
1415 if (input.node() == nullptr) continue;
1416 Emit(kArmPush, g.NoOutput(), g.UseRegister(input.node()));
1417 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001418 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001419}
1420
1421
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001422bool InstructionSelector::IsTailCallAddressImmediate() { return false; }
1423
Ben Murdochda12d292016-06-02 14:46:10 +01001424int InstructionSelector::GetTempsCountForTailCallFromJSFunction() { return 3; }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001425
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001426namespace {
1427
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001428// Shared routine for multiple compare operations.
1429void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
1430 InstructionOperand left, InstructionOperand right,
1431 FlagsContinuation* cont) {
1432 ArmOperandGenerator g(selector);
1433 opcode = cont->Encode(opcode);
1434 if (cont->IsBranch()) {
1435 selector->Emit(opcode, g.NoOutput(), left, right,
1436 g.Label(cont->true_block()), g.Label(cont->false_block()));
Ben Murdochda12d292016-06-02 14:46:10 +01001437 } else if (cont->IsDeoptimize()) {
1438 selector->EmitDeoptimize(opcode, g.NoOutput(), left, right,
1439 cont->frame_state());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001440 } else {
1441 DCHECK(cont->IsSet());
1442 selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
1443 }
1444}
1445
1446
1447// Shared routine for multiple float32 compare operations.
1448void VisitFloat32Compare(InstructionSelector* selector, Node* node,
1449 FlagsContinuation* cont) {
1450 ArmOperandGenerator g(selector);
1451 Float32BinopMatcher m(node);
1452 if (m.right().Is(0.0f)) {
1453 VisitCompare(selector, kArmVcmpF32, g.UseRegister(m.left().node()),
1454 g.UseImmediate(m.right().node()), cont);
1455 } else if (m.left().Is(0.0f)) {
1456 cont->Commute();
1457 VisitCompare(selector, kArmVcmpF32, g.UseRegister(m.right().node()),
1458 g.UseImmediate(m.left().node()), cont);
1459 } else {
1460 VisitCompare(selector, kArmVcmpF32, g.UseRegister(m.left().node()),
1461 g.UseRegister(m.right().node()), cont);
1462 }
1463}
1464
1465
1466// Shared routine for multiple float64 compare operations.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001467void VisitFloat64Compare(InstructionSelector* selector, Node* node,
1468 FlagsContinuation* cont) {
1469 ArmOperandGenerator g(selector);
1470 Float64BinopMatcher m(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001471 if (m.right().Is(0.0)) {
1472 VisitCompare(selector, kArmVcmpF64, g.UseRegister(m.left().node()),
1473 g.UseImmediate(m.right().node()), cont);
1474 } else if (m.left().Is(0.0)) {
1475 cont->Commute();
1476 VisitCompare(selector, kArmVcmpF64, g.UseRegister(m.right().node()),
1477 g.UseImmediate(m.left().node()), cont);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001478 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001479 VisitCompare(selector, kArmVcmpF64, g.UseRegister(m.left().node()),
1480 g.UseRegister(m.right().node()), cont);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001481 }
1482}
1483
1484
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001485// Shared routine for multiple word compare operations.
1486void VisitWordCompare(InstructionSelector* selector, Node* node,
1487 InstructionCode opcode, FlagsContinuation* cont) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001488 ArmOperandGenerator g(selector);
1489 Int32BinopMatcher m(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001490 InstructionOperand inputs[5];
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001491 size_t input_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001492 InstructionOperand outputs[1];
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001493 size_t output_count = 0;
1494
1495 if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(),
1496 &input_count, &inputs[1])) {
1497 inputs[0] = g.UseRegister(m.left().node());
1498 input_count++;
1499 } else if (TryMatchImmediateOrShift(selector, &opcode, m.left().node(),
1500 &input_count, &inputs[1])) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001501 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001502 inputs[0] = g.UseRegister(m.right().node());
1503 input_count++;
1504 } else {
1505 opcode |= AddressingModeField::encode(kMode_Operand2_R);
1506 inputs[input_count++] = g.UseRegister(m.left().node());
1507 inputs[input_count++] = g.UseRegister(m.right().node());
1508 }
1509
1510 if (cont->IsBranch()) {
1511 inputs[input_count++] = g.Label(cont->true_block());
1512 inputs[input_count++] = g.Label(cont->false_block());
Ben Murdochda12d292016-06-02 14:46:10 +01001513 } else if (cont->IsSet()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001514 outputs[output_count++] = g.DefineAsRegister(cont->result());
1515 }
1516
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001517 DCHECK_NE(0u, input_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001518 DCHECK_GE(arraysize(inputs), input_count);
1519 DCHECK_GE(arraysize(outputs), output_count);
1520
Ben Murdochda12d292016-06-02 14:46:10 +01001521 opcode = cont->Encode(opcode);
1522 if (cont->IsDeoptimize()) {
1523 selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
1524 cont->frame_state());
1525 } else {
1526 selector->Emit(opcode, output_count, outputs, input_count, inputs);
1527 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001528}
1529
1530
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001531void VisitWordCompare(InstructionSelector* selector, Node* node,
1532 FlagsContinuation* cont) {
1533 VisitWordCompare(selector, node, kArmCmp, cont);
1534}
1535
1536
1537// Shared routine for word comparisons against zero.
1538void VisitWordCompareZero(InstructionSelector* selector, Node* user,
1539 Node* value, FlagsContinuation* cont) {
1540 while (selector->CanCover(user, value)) {
1541 switch (value->opcode()) {
1542 case IrOpcode::kWord32Equal: {
1543 // Combine with comparisons against 0 by simply inverting the
1544 // continuation.
1545 Int32BinopMatcher m(value);
1546 if (m.right().Is(0)) {
1547 user = value;
1548 value = m.left().node();
1549 cont->Negate();
1550 continue;
1551 }
1552 cont->OverwriteAndNegateIfEqual(kEqual);
1553 return VisitWordCompare(selector, value, cont);
1554 }
1555 case IrOpcode::kInt32LessThan:
1556 cont->OverwriteAndNegateIfEqual(kSignedLessThan);
1557 return VisitWordCompare(selector, value, cont);
1558 case IrOpcode::kInt32LessThanOrEqual:
1559 cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
1560 return VisitWordCompare(selector, value, cont);
1561 case IrOpcode::kUint32LessThan:
1562 cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
1563 return VisitWordCompare(selector, value, cont);
1564 case IrOpcode::kUint32LessThanOrEqual:
1565 cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
1566 return VisitWordCompare(selector, value, cont);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001567 case IrOpcode::kFloat32Equal:
1568 cont->OverwriteAndNegateIfEqual(kEqual);
1569 return VisitFloat32Compare(selector, value, cont);
1570 case IrOpcode::kFloat32LessThan:
1571 cont->OverwriteAndNegateIfEqual(kFloatLessThan);
1572 return VisitFloat32Compare(selector, value, cont);
1573 case IrOpcode::kFloat32LessThanOrEqual:
1574 cont->OverwriteAndNegateIfEqual(kFloatLessThanOrEqual);
1575 return VisitFloat32Compare(selector, value, cont);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001576 case IrOpcode::kFloat64Equal:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001577 cont->OverwriteAndNegateIfEqual(kEqual);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001578 return VisitFloat64Compare(selector, value, cont);
1579 case IrOpcode::kFloat64LessThan:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001580 cont->OverwriteAndNegateIfEqual(kFloatLessThan);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001581 return VisitFloat64Compare(selector, value, cont);
1582 case IrOpcode::kFloat64LessThanOrEqual:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001583 cont->OverwriteAndNegateIfEqual(kFloatLessThanOrEqual);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001584 return VisitFloat64Compare(selector, value, cont);
1585 case IrOpcode::kProjection:
1586 // Check if this is the overflow output projection of an
1587 // <Operation>WithOverflow node.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001588 if (ProjectionIndexOf(value->op()) == 1u) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001589 // We cannot combine the <Operation>WithOverflow with this branch
1590 // unless the 0th projection (the use of the actual value of the
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001591 // <Operation> is either nullptr, which means there's no use of the
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001592 // actual value, or was already defined, which means it is scheduled
1593 // *AFTER* this branch).
1594 Node* const node = value->InputAt(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001595 Node* const result = NodeProperties::FindProjection(node, 0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001596 if (!result || selector->IsDefined(result)) {
1597 switch (node->opcode()) {
1598 case IrOpcode::kInt32AddWithOverflow:
1599 cont->OverwriteAndNegateIfEqual(kOverflow);
1600 return VisitBinop(selector, node, kArmAdd, kArmAdd, cont);
1601 case IrOpcode::kInt32SubWithOverflow:
1602 cont->OverwriteAndNegateIfEqual(kOverflow);
1603 return VisitBinop(selector, node, kArmSub, kArmRsb, cont);
1604 default:
1605 break;
1606 }
1607 }
1608 }
1609 break;
1610 case IrOpcode::kInt32Add:
1611 return VisitWordCompare(selector, value, kArmCmn, cont);
1612 case IrOpcode::kInt32Sub:
1613 return VisitWordCompare(selector, value, kArmCmp, cont);
1614 case IrOpcode::kWord32And:
1615 return VisitWordCompare(selector, value, kArmTst, cont);
1616 case IrOpcode::kWord32Or:
1617 return VisitBinop(selector, value, kArmOrr, kArmOrr, cont);
1618 case IrOpcode::kWord32Xor:
1619 return VisitWordCompare(selector, value, kArmTeq, cont);
1620 case IrOpcode::kWord32Sar:
1621 return VisitShift(selector, value, TryMatchASR, cont);
1622 case IrOpcode::kWord32Shl:
1623 return VisitShift(selector, value, TryMatchLSL, cont);
1624 case IrOpcode::kWord32Shr:
1625 return VisitShift(selector, value, TryMatchLSR, cont);
1626 case IrOpcode::kWord32Ror:
1627 return VisitShift(selector, value, TryMatchROR, cont);
1628 default:
1629 break;
1630 }
1631 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001632 }
1633
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001634 // Continuation could not be combined with a compare, emit compare against 0.
1635 ArmOperandGenerator g(selector);
1636 InstructionCode const opcode =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001637 cont->Encode(kArmTst) | AddressingModeField::encode(kMode_Operand2_R);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001638 InstructionOperand const value_operand = g.UseRegister(value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001639 if (cont->IsBranch()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001640 selector->Emit(opcode, g.NoOutput(), value_operand, value_operand,
1641 g.Label(cont->true_block()), g.Label(cont->false_block()));
Ben Murdochda12d292016-06-02 14:46:10 +01001642 } else if (cont->IsDeoptimize()) {
1643 selector->EmitDeoptimize(opcode, g.NoOutput(), value_operand, value_operand,
1644 cont->frame_state());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001645 } else {
Ben Murdochda12d292016-06-02 14:46:10 +01001646 DCHECK(cont->IsSet());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001647 selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand,
1648 value_operand);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001649 }
1650}
1651
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001652} // namespace
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001653
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001654void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
1655 BasicBlock* fbranch) {
1656 FlagsContinuation cont(kNotEqual, tbranch, fbranch);
1657 VisitWordCompareZero(this, branch, branch->InputAt(0), &cont);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001658}
1659
Ben Murdochda12d292016-06-02 14:46:10 +01001660void InstructionSelector::VisitDeoptimizeIf(Node* node) {
1661 FlagsContinuation cont =
1662 FlagsContinuation::ForDeoptimize(kNotEqual, node->InputAt(1));
1663 VisitWordCompareZero(this, node, node->InputAt(0), &cont);
1664}
1665
1666void InstructionSelector::VisitDeoptimizeUnless(Node* node) {
1667 FlagsContinuation cont =
1668 FlagsContinuation::ForDeoptimize(kEqual, node->InputAt(1));
1669 VisitWordCompareZero(this, node, node->InputAt(0), &cont);
1670}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001671
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001672void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
1673 ArmOperandGenerator g(this);
1674 InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
1675
1676 // Emit either ArchTableSwitch or ArchLookupSwitch.
1677 size_t table_space_cost = 4 + sw.value_range;
1678 size_t table_time_cost = 3;
1679 size_t lookup_space_cost = 3 + 2 * sw.case_count;
1680 size_t lookup_time_cost = sw.case_count;
1681 if (sw.case_count > 0 &&
1682 table_space_cost + 3 * table_time_cost <=
1683 lookup_space_cost + 3 * lookup_time_cost &&
1684 sw.min_value > std::numeric_limits<int32_t>::min()) {
1685 InstructionOperand index_operand = value_operand;
1686 if (sw.min_value) {
1687 index_operand = g.TempRegister();
1688 Emit(kArmSub | AddressingModeField::encode(kMode_Operand2_I),
1689 index_operand, value_operand, g.TempImmediate(sw.min_value));
1690 }
1691 // Generate a table lookup.
1692 return EmitTableSwitch(sw, index_operand);
1693 }
1694
1695 // Generate a sequence of conditional jumps.
1696 return EmitLookupSwitch(sw, value_operand);
1697}
1698
1699
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001700void InstructionSelector::VisitWord32Equal(Node* const node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001701 FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001702 Int32BinopMatcher m(node);
1703 if (m.right().Is(0)) {
1704 return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001705 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001706 VisitWordCompare(this, node, &cont);
1707}
1708
1709
1710void InstructionSelector::VisitInt32LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001711 FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001712 VisitWordCompare(this, node, &cont);
1713}
1714
1715
1716void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001717 FlagsContinuation cont =
1718 FlagsContinuation::ForSet(kSignedLessThanOrEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001719 VisitWordCompare(this, node, &cont);
1720}
1721
1722
1723void InstructionSelector::VisitUint32LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001724 FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001725 VisitWordCompare(this, node, &cont);
1726}
1727
1728
1729void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001730 FlagsContinuation cont =
1731 FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001732 VisitWordCompare(this, node, &cont);
1733}
1734
1735
1736void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001737 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
Ben Murdochda12d292016-06-02 14:46:10 +01001738 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001739 return VisitBinop(this, node, kArmAdd, kArmAdd, &cont);
1740 }
1741 FlagsContinuation cont;
1742 VisitBinop(this, node, kArmAdd, kArmAdd, &cont);
1743}
1744
1745
1746void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001747 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
Ben Murdochda12d292016-06-02 14:46:10 +01001748 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001749 return VisitBinop(this, node, kArmSub, kArmRsb, &cont);
1750 }
1751 FlagsContinuation cont;
1752 VisitBinop(this, node, kArmSub, kArmRsb, &cont);
1753}
1754
1755
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001756void InstructionSelector::VisitFloat32Equal(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001757 FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001758 VisitFloat32Compare(this, node, &cont);
1759}
1760
1761
1762void InstructionSelector::VisitFloat32LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001763 FlagsContinuation cont = FlagsContinuation::ForSet(kFloatLessThan, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001764 VisitFloat32Compare(this, node, &cont);
1765}
1766
1767
1768void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001769 FlagsContinuation cont =
1770 FlagsContinuation::ForSet(kFloatLessThanOrEqual, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001771 VisitFloat32Compare(this, node, &cont);
1772}
1773
1774
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001775void InstructionSelector::VisitFloat64Equal(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001776 FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001777 VisitFloat64Compare(this, node, &cont);
1778}
1779
1780
1781void InstructionSelector::VisitFloat64LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001782 FlagsContinuation cont = FlagsContinuation::ForSet(kFloatLessThan, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001783 VisitFloat64Compare(this, node, &cont);
1784}
1785
1786
1787void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001788 FlagsContinuation cont =
1789 FlagsContinuation::ForSet(kFloatLessThanOrEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001790 VisitFloat64Compare(this, node, &cont);
1791}
1792
1793
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001794void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) {
1795 VisitRR(this, kArmVmovLowU32F64, node);
1796}
1797
1798
1799void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) {
1800 VisitRR(this, kArmVmovHighU32F64, node);
1801}
1802
1803
1804void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) {
1805 ArmOperandGenerator g(this);
1806 Node* left = node->InputAt(0);
1807 Node* right = node->InputAt(1);
1808 if (left->opcode() == IrOpcode::kFloat64InsertHighWord32 &&
1809 CanCover(node, left)) {
1810 left = left->InputAt(1);
1811 Emit(kArmVmovF64U32U32, g.DefineAsRegister(node), g.UseRegister(right),
1812 g.UseRegister(left));
1813 return;
1814 }
1815 Emit(kArmVmovLowF64U32, g.DefineSameAsFirst(node), g.UseRegister(left),
1816 g.UseRegister(right));
1817}
1818
1819
1820void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
1821 ArmOperandGenerator g(this);
1822 Node* left = node->InputAt(0);
1823 Node* right = node->InputAt(1);
1824 if (left->opcode() == IrOpcode::kFloat64InsertLowWord32 &&
1825 CanCover(node, left)) {
1826 left = left->InputAt(1);
1827 Emit(kArmVmovF64U32U32, g.DefineAsRegister(node), g.UseRegister(left),
1828 g.UseRegister(right));
1829 return;
1830 }
1831 Emit(kArmVmovHighF64U32, g.DefineSameAsFirst(node), g.UseRegister(left),
1832 g.UseRegister(right));
1833}
1834
Ben Murdochc5610432016-08-08 18:44:38 +01001835void InstructionSelector::VisitAtomicLoad(Node* node) {
1836 LoadRepresentation load_rep = LoadRepresentationOf(node->op());
1837 ArmOperandGenerator g(this);
1838 Node* base = node->InputAt(0);
1839 Node* index = node->InputAt(1);
1840 ArchOpcode opcode = kArchNop;
1841 switch (load_rep.representation()) {
1842 case MachineRepresentation::kWord8:
1843 opcode = load_rep.IsSigned() ? kAtomicLoadInt8 : kAtomicLoadUint8;
1844 break;
1845 case MachineRepresentation::kWord16:
1846 opcode = load_rep.IsSigned() ? kAtomicLoadInt16 : kAtomicLoadUint16;
1847 break;
1848 case MachineRepresentation::kWord32:
1849 opcode = kAtomicLoadWord32;
1850 break;
1851 default:
1852 UNREACHABLE();
1853 return;
1854 }
1855 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR),
1856 g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(index));
1857}
1858
1859void InstructionSelector::VisitAtomicStore(Node* node) {
1860 MachineRepresentation rep = AtomicStoreRepresentationOf(node->op());
1861 ArmOperandGenerator g(this);
1862 Node* base = node->InputAt(0);
1863 Node* index = node->InputAt(1);
1864 Node* value = node->InputAt(2);
1865 ArchOpcode opcode = kArchNop;
1866 switch (rep) {
1867 case MachineRepresentation::kWord8:
1868 opcode = kAtomicStoreWord8;
1869 break;
1870 case MachineRepresentation::kWord16:
1871 opcode = kAtomicStoreWord16;
1872 break;
1873 case MachineRepresentation::kWord32:
1874 opcode = kAtomicStoreWord32;
1875 break;
1876 default:
1877 UNREACHABLE();
1878 return;
1879 }
1880
1881 AddressingMode addressing_mode = kMode_Offset_RR;
1882 InstructionOperand inputs[4];
1883 size_t input_count = 0;
1884 inputs[input_count++] = g.UseUniqueRegister(base);
1885 inputs[input_count++] = g.UseUniqueRegister(index);
1886 inputs[input_count++] = g.UseUniqueRegister(value);
1887 InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
1888 Emit(code, 0, nullptr, input_count, inputs);
1889}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001890
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001891// static
1892MachineOperatorBuilder::Flags
1893InstructionSelector::SupportedMachineOperatorFlags() {
1894 MachineOperatorBuilder::Flags flags =
1895 MachineOperatorBuilder::kInt32DivIsSafe |
1896 MachineOperatorBuilder::kUint32DivIsSafe;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001897 if (CpuFeatures::IsSupported(ARMv7)) {
1898 flags |= MachineOperatorBuilder::kWord32ReverseBits;
1899 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001900 if (CpuFeatures::IsSupported(ARMv8)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001901 flags |= MachineOperatorBuilder::kFloat32RoundDown |
1902 MachineOperatorBuilder::kFloat64RoundDown |
1903 MachineOperatorBuilder::kFloat32RoundUp |
1904 MachineOperatorBuilder::kFloat64RoundUp |
1905 MachineOperatorBuilder::kFloat32RoundTruncate |
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001906 MachineOperatorBuilder::kFloat64RoundTruncate |
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001907 MachineOperatorBuilder::kFloat64RoundTiesAway |
1908 MachineOperatorBuilder::kFloat32RoundTiesEven |
Ben Murdochc5610432016-08-08 18:44:38 +01001909 MachineOperatorBuilder::kFloat64RoundTiesEven |
1910 MachineOperatorBuilder::kFloat32Min |
1911 MachineOperatorBuilder::kFloat32Max |
1912 MachineOperatorBuilder::kFloat64Min |
1913 MachineOperatorBuilder::kFloat64Max;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001914 }
1915 return flags;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001916}
1917
1918} // namespace compiler
1919} // namespace internal
1920} // namespace v8