blob: 14b30b1af08dbdfc0c0d6d52a8da8aecf1eccef0 [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 Murdoch4a90d5f2016-03-22 12:00:34 +0000240 selector->Emit(cont->Encode(opcode), output_count, outputs, input_count,
241 inputs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000242}
243
244
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400245void VisitBinop(InstructionSelector* selector, Node* node,
246 InstructionCode opcode, InstructionCode reverse_opcode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000247 FlagsContinuation cont;
248 VisitBinop(selector, node, opcode, reverse_opcode, &cont);
249}
250
251
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000252void EmitDiv(InstructionSelector* selector, ArchOpcode div_opcode,
253 ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode,
254 InstructionOperand result_operand, InstructionOperand left_operand,
255 InstructionOperand right_operand) {
256 ArmOperandGenerator g(selector);
257 if (selector->IsSupported(SUDIV)) {
258 selector->Emit(div_opcode, result_operand, left_operand, right_operand);
259 return;
260 }
261 InstructionOperand left_double_operand = g.TempDoubleRegister();
262 InstructionOperand right_double_operand = g.TempDoubleRegister();
263 InstructionOperand result_double_operand = g.TempDoubleRegister();
264 selector->Emit(f64i32_opcode, left_double_operand, left_operand);
265 selector->Emit(f64i32_opcode, right_double_operand, right_operand);
266 selector->Emit(kArmVdivF64, result_double_operand, left_double_operand,
267 right_double_operand);
268 selector->Emit(i32f64_opcode, result_operand, result_double_operand);
269}
270
271
272void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode div_opcode,
273 ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode) {
274 ArmOperandGenerator g(selector);
275 Int32BinopMatcher m(node);
276 EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode,
277 g.DefineAsRegister(node), g.UseRegister(m.left().node()),
278 g.UseRegister(m.right().node()));
279}
280
281
282void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode div_opcode,
283 ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode) {
284 ArmOperandGenerator g(selector);
285 Int32BinopMatcher m(node);
286 InstructionOperand div_operand = g.TempRegister();
287 InstructionOperand result_operand = g.DefineAsRegister(node);
288 InstructionOperand left_operand = g.UseRegister(m.left().node());
289 InstructionOperand right_operand = g.UseRegister(m.right().node());
290 EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode, div_operand,
291 left_operand, right_operand);
292 if (selector->IsSupported(MLS)) {
293 selector->Emit(kArmMls, result_operand, div_operand, right_operand,
294 left_operand);
295 } else {
296 InstructionOperand mul_operand = g.TempRegister();
297 selector->Emit(kArmMul, mul_operand, div_operand, right_operand);
298 selector->Emit(kArmSub, result_operand, left_operand, mul_operand);
299 }
300}
301
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400302} // namespace
303
304
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000305void InstructionSelector::VisitLoad(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000306 LoadRepresentation load_rep = LoadRepresentationOf(node->op());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000307 ArmOperandGenerator g(this);
308 Node* base = node->InputAt(0);
309 Node* index = node->InputAt(1);
310
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000311 ArchOpcode opcode = kArchNop;
312 switch (load_rep.representation()) {
313 case MachineRepresentation::kFloat32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400314 opcode = kArmVldrF32;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000315 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000316 case MachineRepresentation::kFloat64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400317 opcode = kArmVldrF64;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000318 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000319 case MachineRepresentation::kBit: // Fall through.
320 case MachineRepresentation::kWord8:
321 opcode = load_rep.IsUnsigned() ? kArmLdrb : kArmLdrsb;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000322 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000323 case MachineRepresentation::kWord16:
324 opcode = load_rep.IsUnsigned() ? kArmLdrh : kArmLdrsh;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000325 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000326 case MachineRepresentation::kTagged: // Fall through.
327 case MachineRepresentation::kWord32:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000328 opcode = kArmLdr;
329 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100330 case MachineRepresentation::kWord64: // Fall through.
331 case MachineRepresentation::kSimd128: // Fall through.
332 case MachineRepresentation::kNone:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000333 UNREACHABLE();
334 return;
335 }
336
337 if (g.CanBeImmediate(index, opcode)) {
338 Emit(opcode | AddressingModeField::encode(kMode_Offset_RI),
339 g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index));
340 } else {
341 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR),
342 g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(index));
343 }
344}
345
346
347void InstructionSelector::VisitStore(Node* node) {
348 ArmOperandGenerator g(this);
349 Node* base = node->InputAt(0);
350 Node* index = node->InputAt(1);
351 Node* value = node->InputAt(2);
352
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000353 StoreRepresentation store_rep = StoreRepresentationOf(node->op());
354 WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind();
355 MachineRepresentation rep = store_rep.representation();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000356
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000357 if (write_barrier_kind != kNoWriteBarrier) {
358 DCHECK_EQ(MachineRepresentation::kTagged, rep);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100359 AddressingMode addressing_mode;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000360 InstructionOperand inputs[3];
361 size_t input_count = 0;
362 inputs[input_count++] = g.UseUniqueRegister(base);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100363 // OutOfLineRecordWrite uses the index in an 'add' instruction as well as
364 // for the store itself, so we must check compatibility with both.
365 if (g.CanBeImmediate(index, kArmAdd) && g.CanBeImmediate(index, kArmStr)) {
366 inputs[input_count++] = g.UseImmediate(index);
367 addressing_mode = kMode_Offset_RI;
368 } else {
369 inputs[input_count++] = g.UseUniqueRegister(index);
370 addressing_mode = kMode_Offset_RR;
371 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000372 inputs[input_count++] = (write_barrier_kind == kMapWriteBarrier)
373 ? g.UseRegister(value)
374 : g.UseUniqueRegister(value);
375 RecordWriteMode record_write_mode = RecordWriteMode::kValueIsAny;
376 switch (write_barrier_kind) {
377 case kNoWriteBarrier:
378 UNREACHABLE();
379 break;
380 case kMapWriteBarrier:
381 record_write_mode = RecordWriteMode::kValueIsMap;
382 break;
383 case kPointerWriteBarrier:
384 record_write_mode = RecordWriteMode::kValueIsPointer;
385 break;
386 case kFullWriteBarrier:
387 record_write_mode = RecordWriteMode::kValueIsAny;
388 break;
389 }
390 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
391 size_t const temp_count = arraysize(temps);
392 InstructionCode code = kArchStoreWithWriteBarrier;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100393 code |= AddressingModeField::encode(addressing_mode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000394 code |= MiscField::encode(static_cast<int>(record_write_mode));
395 Emit(code, 0, nullptr, input_count, inputs, temp_count, temps);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000396 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000397 ArchOpcode opcode = kArchNop;
398 switch (rep) {
399 case MachineRepresentation::kFloat32:
400 opcode = kArmVstrF32;
401 break;
402 case MachineRepresentation::kFloat64:
403 opcode = kArmVstrF64;
404 break;
405 case MachineRepresentation::kBit: // Fall through.
406 case MachineRepresentation::kWord8:
407 opcode = kArmStrb;
408 break;
409 case MachineRepresentation::kWord16:
410 opcode = kArmStrh;
411 break;
412 case MachineRepresentation::kTagged: // Fall through.
413 case MachineRepresentation::kWord32:
414 opcode = kArmStr;
415 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100416 case MachineRepresentation::kWord64: // Fall through.
417 case MachineRepresentation::kSimd128: // Fall through.
418 case MachineRepresentation::kNone:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000419 UNREACHABLE();
420 return;
421 }
422
423 if (g.CanBeImmediate(index, opcode)) {
424 Emit(opcode | AddressingModeField::encode(kMode_Offset_RI), g.NoOutput(),
425 g.UseRegister(base), g.UseImmediate(index), g.UseRegister(value));
426 } else {
427 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), g.NoOutput(),
428 g.UseRegister(base), g.UseRegister(index), g.UseRegister(value));
429 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000430 }
431}
432
433
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400434void InstructionSelector::VisitCheckedLoad(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000435 CheckedLoadRepresentation load_rep = CheckedLoadRepresentationOf(node->op());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400436 ArmOperandGenerator g(this);
437 Node* const buffer = node->InputAt(0);
438 Node* const offset = node->InputAt(1);
439 Node* const length = node->InputAt(2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000440 ArchOpcode opcode = kArchNop;
441 switch (load_rep.representation()) {
442 case MachineRepresentation::kWord8:
443 opcode = load_rep.IsSigned() ? kCheckedLoadInt8 : kCheckedLoadUint8;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400444 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000445 case MachineRepresentation::kWord16:
446 opcode = load_rep.IsSigned() ? kCheckedLoadInt16 : kCheckedLoadUint16;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400447 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000448 case MachineRepresentation::kWord32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400449 opcode = kCheckedLoadWord32;
450 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000451 case MachineRepresentation::kFloat32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400452 opcode = kCheckedLoadFloat32;
453 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000454 case MachineRepresentation::kFloat64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400455 opcode = kCheckedLoadFloat64;
456 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100457 case MachineRepresentation::kBit: // Fall through.
458 case MachineRepresentation::kTagged: // Fall through.
459 case MachineRepresentation::kWord64: // Fall through.
460 case MachineRepresentation::kSimd128: // Fall through.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000461 case MachineRepresentation::kNone:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400462 UNREACHABLE();
463 return;
464 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000465 InstructionOperand offset_operand = g.UseRegister(offset);
466 InstructionOperand length_operand = g.CanBeImmediate(length, kArmCmp)
467 ? g.UseImmediate(length)
468 : g.UseRegister(length);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400469 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR),
470 g.DefineAsRegister(node), offset_operand, length_operand,
471 g.UseRegister(buffer), offset_operand);
472}
473
474
475void InstructionSelector::VisitCheckedStore(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000476 MachineRepresentation rep = CheckedStoreRepresentationOf(node->op());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400477 ArmOperandGenerator g(this);
478 Node* const buffer = node->InputAt(0);
479 Node* const offset = node->InputAt(1);
480 Node* const length = node->InputAt(2);
481 Node* const value = node->InputAt(3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000482 ArchOpcode opcode = kArchNop;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400483 switch (rep) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000484 case MachineRepresentation::kWord8:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400485 opcode = kCheckedStoreWord8;
486 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000487 case MachineRepresentation::kWord16:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400488 opcode = kCheckedStoreWord16;
489 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000490 case MachineRepresentation::kWord32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400491 opcode = kCheckedStoreWord32;
492 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000493 case MachineRepresentation::kFloat32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400494 opcode = kCheckedStoreFloat32;
495 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000496 case MachineRepresentation::kFloat64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400497 opcode = kCheckedStoreFloat64;
498 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100499 case MachineRepresentation::kBit: // Fall through.
500 case MachineRepresentation::kTagged: // Fall through.
501 case MachineRepresentation::kWord64: // Fall through.
502 case MachineRepresentation::kSimd128: // Fall through.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000503 case MachineRepresentation::kNone:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400504 UNREACHABLE();
505 return;
506 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000507 InstructionOperand offset_operand = g.UseRegister(offset);
508 InstructionOperand length_operand = g.CanBeImmediate(length, kArmCmp)
509 ? g.UseImmediate(length)
510 : g.UseRegister(length);
511 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), g.NoOutput(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400512 offset_operand, length_operand, g.UseRegister(value),
513 g.UseRegister(buffer), offset_operand);
514}
515
516
517namespace {
518
519void EmitBic(InstructionSelector* selector, Node* node, Node* left,
520 Node* right) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000521 ArmOperandGenerator g(selector);
522 InstructionCode opcode = kArmBic;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000523 InstructionOperand value_operand;
524 InstructionOperand shift_operand;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000525 if (TryMatchShift(selector, &opcode, right, &value_operand, &shift_operand)) {
526 selector->Emit(opcode, g.DefineAsRegister(node), g.UseRegister(left),
527 value_operand, shift_operand);
528 return;
529 }
530 selector->Emit(opcode | AddressingModeField::encode(kMode_Operand2_R),
531 g.DefineAsRegister(node), g.UseRegister(left),
532 g.UseRegister(right));
533}
534
535
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400536void EmitUbfx(InstructionSelector* selector, Node* node, Node* left,
537 uint32_t lsb, uint32_t width) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000538 DCHECK_LE(1u, width);
539 DCHECK_LE(width, 32u - lsb);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400540 ArmOperandGenerator g(selector);
541 selector->Emit(kArmUbfx, g.DefineAsRegister(node), g.UseRegister(left),
542 g.TempImmediate(lsb), g.TempImmediate(width));
543}
544
545} // namespace
546
547
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000548void InstructionSelector::VisitWord32And(Node* node) {
549 ArmOperandGenerator g(this);
550 Int32BinopMatcher m(node);
551 if (m.left().IsWord32Xor() && CanCover(node, m.left().node())) {
552 Int32BinopMatcher mleft(m.left().node());
553 if (mleft.right().Is(-1)) {
554 EmitBic(this, node, m.right().node(), mleft.left().node());
555 return;
556 }
557 }
558 if (m.right().IsWord32Xor() && CanCover(node, m.right().node())) {
559 Int32BinopMatcher mright(m.right().node());
560 if (mright.right().Is(-1)) {
561 EmitBic(this, node, m.left().node(), mright.left().node());
562 return;
563 }
564 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400565 if (m.right().HasValue()) {
566 uint32_t const value = m.right().Value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000567 uint32_t width = base::bits::CountPopulation32(value);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100568 uint32_t leading_zeros = base::bits::CountLeadingZeros32(value);
569
570 // Try to merge SHR operations on the left hand input into this AND.
571 if (m.left().IsWord32Shr()) {
572 Int32BinopMatcher mshr(m.left().node());
573 if (mshr.right().HasValue()) {
574 uint32_t const shift = mshr.right().Value();
575
576 if (((shift == 8) || (shift == 16) || (shift == 24)) &&
577 ((value == 0xff) || (value == 0xffff))) {
578 // Merge SHR into AND by emitting a UXTB or UXTH instruction with a
579 // bytewise rotation.
580 Emit((value == 0xff) ? kArmUxtb : kArmUxth,
581 g.DefineAsRegister(m.node()), g.UseRegister(mshr.left().node()),
582 g.TempImmediate(mshr.right().Value()));
583 return;
584 } else if (IsSupported(ARMv7) && (width != 0) &&
585 ((leading_zeros + width) == 32)) {
586 // Merge Shr into And by emitting a UBFX instruction.
587 DCHECK_EQ(0u, base::bits::CountTrailingZeros32(value));
588 if ((1 <= shift) && (shift <= 31)) {
589 // UBFX cannot extract bits past the register size, however since
590 // shifting the original value would have introduced some zeros we
591 // can still use UBFX with a smaller mask and the remaining bits
592 // will be zeros.
593 EmitUbfx(this, node, mshr.left().node(), shift,
594 std::min(width, 32 - shift));
595 return;
596 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000597 }
598 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100599 } else if (value == 0xffff) {
600 // Emit UXTH for this AND. We don't bother testing for UXTB, as it's no
601 // better than AND 0xff for this operation.
602 Emit(kArmUxth, g.DefineAsRegister(m.node()),
603 g.UseRegister(m.left().node()), g.TempImmediate(0));
604 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400605 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400606 if (g.CanBeImmediate(~value)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100607 // Emit BIC for this AND by inverting the immediate value first.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400608 Emit(kArmBic | AddressingModeField::encode(kMode_Operand2_I),
609 g.DefineAsRegister(node), g.UseRegister(m.left().node()),
610 g.TempImmediate(~value));
611 return;
612 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100613 if (!g.CanBeImmediate(value) && IsSupported(ARMv7)) {
614 // If value has 9 to 23 contiguous set bits, and has the lsb set, we can
615 // replace this AND with UBFX. Other contiguous bit patterns have already
616 // been handled by BIC or will be handled by AND.
617 if ((width != 0) && ((leading_zeros + width) == 32) &&
618 (9 <= leading_zeros) && (leading_zeros <= 23)) {
619 DCHECK_EQ(0u, base::bits::CountTrailingZeros32(value));
620 EmitUbfx(this, node, m.left().node(), 0, width);
621 return;
622 }
623
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400624 width = 32 - width;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100625 leading_zeros = base::bits::CountLeadingZeros32(~value);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400626 uint32_t lsb = base::bits::CountTrailingZeros32(~value);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100627 if ((leading_zeros + width + lsb) == 32) {
628 // This AND can be replaced with BFC.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400629 Emit(kArmBfc, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
630 g.TempImmediate(lsb), g.TempImmediate(width));
631 return;
632 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000633 }
634 }
635 VisitBinop(this, node, kArmAnd, kArmAnd);
636}
637
638
639void InstructionSelector::VisitWord32Or(Node* node) {
640 VisitBinop(this, node, kArmOrr, kArmOrr);
641}
642
643
644void InstructionSelector::VisitWord32Xor(Node* node) {
645 ArmOperandGenerator g(this);
646 Int32BinopMatcher m(node);
647 if (m.right().Is(-1)) {
648 InstructionCode opcode = kArmMvn;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000649 InstructionOperand value_operand;
650 InstructionOperand shift_operand;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000651 if (TryMatchShift(this, &opcode, m.left().node(), &value_operand,
652 &shift_operand)) {
653 Emit(opcode, g.DefineAsRegister(node), value_operand, shift_operand);
654 return;
655 }
656 Emit(opcode | AddressingModeField::encode(kMode_Operand2_R),
657 g.DefineAsRegister(node), g.UseRegister(m.left().node()));
658 return;
659 }
660 VisitBinop(this, node, kArmEor, kArmEor);
661}
662
663
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000664namespace {
665
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000666template <typename TryMatchShift>
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000667void VisitShift(InstructionSelector* selector, Node* node,
668 TryMatchShift try_match_shift, FlagsContinuation* cont) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000669 ArmOperandGenerator g(selector);
670 InstructionCode opcode = kArmMov;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000671 InstructionOperand inputs[4];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000672 size_t input_count = 2;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000673 InstructionOperand outputs[2];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000674 size_t output_count = 0;
675
676 CHECK(try_match_shift(selector, &opcode, node, &inputs[0], &inputs[1]));
677
678 if (cont->IsBranch()) {
679 inputs[input_count++] = g.Label(cont->true_block());
680 inputs[input_count++] = g.Label(cont->false_block());
681 }
682
683 outputs[output_count++] = g.DefineAsRegister(node);
684 if (cont->IsSet()) {
685 outputs[output_count++] = g.DefineAsRegister(cont->result());
686 }
687
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000688 DCHECK_NE(0u, input_count);
689 DCHECK_NE(0u, output_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000690 DCHECK_GE(arraysize(inputs), input_count);
691 DCHECK_GE(arraysize(outputs), output_count);
692 DCHECK_NE(kMode_None, AddressingModeField::decode(opcode));
693
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000694 selector->Emit(cont->Encode(opcode), output_count, outputs, input_count,
695 inputs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000696}
697
698
699template <typename TryMatchShift>
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000700void VisitShift(InstructionSelector* selector, Node* node,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000701 TryMatchShift try_match_shift) {
702 FlagsContinuation cont;
703 VisitShift(selector, node, try_match_shift, &cont);
704}
705
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000706} // namespace
707
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000708
709void InstructionSelector::VisitWord32Shl(Node* node) {
710 VisitShift(this, node, TryMatchLSL);
711}
712
713
714void InstructionSelector::VisitWord32Shr(Node* node) {
715 ArmOperandGenerator g(this);
716 Int32BinopMatcher m(node);
717 if (IsSupported(ARMv7) && m.left().IsWord32And() &&
718 m.right().IsInRange(0, 31)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000719 uint32_t lsb = m.right().Value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000720 Int32BinopMatcher mleft(m.left().node());
721 if (mleft.right().HasValue()) {
722 uint32_t value = (mleft.right().Value() >> lsb) << lsb;
723 uint32_t width = base::bits::CountPopulation32(value);
724 uint32_t msb = base::bits::CountLeadingZeros32(value);
725 if (msb + width + lsb == 32) {
726 DCHECK_EQ(lsb, base::bits::CountTrailingZeros32(value));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400727 return EmitUbfx(this, node, mleft.left().node(), lsb, width);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000728 }
729 }
730 }
731 VisitShift(this, node, TryMatchLSR);
732}
733
734
735void InstructionSelector::VisitWord32Sar(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400736 ArmOperandGenerator g(this);
737 Int32BinopMatcher m(node);
738 if (CanCover(m.node(), m.left().node()) && m.left().IsWord32Shl()) {
739 Int32BinopMatcher mleft(m.left().node());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100740 if (m.right().HasValue() && mleft.right().HasValue()) {
741 uint32_t sar = m.right().Value();
742 uint32_t shl = mleft.right().Value();
743 if ((sar == shl) && (sar == 16)) {
744 Emit(kArmSxth, g.DefineAsRegister(node),
745 g.UseRegister(mleft.left().node()), g.TempImmediate(0));
746 return;
747 } else if ((sar == shl) && (sar == 24)) {
748 Emit(kArmSxtb, g.DefineAsRegister(node),
749 g.UseRegister(mleft.left().node()), g.TempImmediate(0));
750 return;
751 } else if (IsSupported(ARMv7) && (sar >= shl)) {
752 Emit(kArmSbfx, g.DefineAsRegister(node),
753 g.UseRegister(mleft.left().node()), g.TempImmediate(sar - shl),
754 g.TempImmediate(32 - sar));
755 return;
756 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400757 }
758 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000759 VisitShift(this, node, TryMatchASR);
760}
761
762
763void InstructionSelector::VisitWord32Ror(Node* node) {
764 VisitShift(this, node, TryMatchROR);
765}
766
767
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000768void InstructionSelector::VisitWord32Clz(Node* node) {
769 VisitRR(this, kArmClz, node);
770}
771
772
773void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); }
774
775
Ben Murdoch097c5b22016-05-18 11:27:45 +0100776void InstructionSelector::VisitWord32ReverseBits(Node* node) {
777 DCHECK(IsSupported(ARMv7));
778 VisitRR(this, kArmRbit, node);
779}
780
781
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000782void InstructionSelector::VisitWord32Popcnt(Node* node) { UNREACHABLE(); }
783
784
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000785void InstructionSelector::VisitInt32Add(Node* node) {
786 ArmOperandGenerator g(this);
787 Int32BinopMatcher m(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400788 if (CanCover(node, m.left().node())) {
789 switch (m.left().opcode()) {
790 case IrOpcode::kInt32Mul: {
791 Int32BinopMatcher mleft(m.left().node());
792 Emit(kArmMla, g.DefineAsRegister(node),
793 g.UseRegister(mleft.left().node()),
794 g.UseRegister(mleft.right().node()),
795 g.UseRegister(m.right().node()));
796 return;
797 }
798 case IrOpcode::kInt32MulHigh: {
799 Int32BinopMatcher mleft(m.left().node());
800 Emit(kArmSmmla, g.DefineAsRegister(node),
801 g.UseRegister(mleft.left().node()),
802 g.UseRegister(mleft.right().node()),
803 g.UseRegister(m.right().node()));
804 return;
805 }
806 case IrOpcode::kWord32And: {
807 Int32BinopMatcher mleft(m.left().node());
808 if (mleft.right().Is(0xff)) {
809 Emit(kArmUxtab, g.DefineAsRegister(node),
810 g.UseRegister(m.right().node()),
811 g.UseRegister(mleft.left().node()), g.TempImmediate(0));
812 return;
813 } else if (mleft.right().Is(0xffff)) {
814 Emit(kArmUxtah, g.DefineAsRegister(node),
815 g.UseRegister(m.right().node()),
816 g.UseRegister(mleft.left().node()), g.TempImmediate(0));
817 return;
818 }
819 }
820 case IrOpcode::kWord32Sar: {
821 Int32BinopMatcher mleft(m.left().node());
822 if (CanCover(mleft.node(), mleft.left().node()) &&
823 mleft.left().IsWord32Shl()) {
824 Int32BinopMatcher mleftleft(mleft.left().node());
825 if (mleft.right().Is(24) && mleftleft.right().Is(24)) {
826 Emit(kArmSxtab, g.DefineAsRegister(node),
827 g.UseRegister(m.right().node()),
828 g.UseRegister(mleftleft.left().node()), g.TempImmediate(0));
829 return;
830 } else if (mleft.right().Is(16) && mleftleft.right().Is(16)) {
831 Emit(kArmSxtah, g.DefineAsRegister(node),
832 g.UseRegister(m.right().node()),
833 g.UseRegister(mleftleft.left().node()), g.TempImmediate(0));
834 return;
835 }
836 }
837 }
838 default:
839 break;
840 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000841 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400842 if (CanCover(node, m.right().node())) {
843 switch (m.right().opcode()) {
844 case IrOpcode::kInt32Mul: {
845 Int32BinopMatcher mright(m.right().node());
846 Emit(kArmMla, g.DefineAsRegister(node),
847 g.UseRegister(mright.left().node()),
848 g.UseRegister(mright.right().node()),
849 g.UseRegister(m.left().node()));
850 return;
851 }
852 case IrOpcode::kInt32MulHigh: {
853 Int32BinopMatcher mright(m.right().node());
854 Emit(kArmSmmla, g.DefineAsRegister(node),
855 g.UseRegister(mright.left().node()),
856 g.UseRegister(mright.right().node()),
857 g.UseRegister(m.left().node()));
858 return;
859 }
860 case IrOpcode::kWord32And: {
861 Int32BinopMatcher mright(m.right().node());
862 if (mright.right().Is(0xff)) {
863 Emit(kArmUxtab, g.DefineAsRegister(node),
864 g.UseRegister(m.left().node()),
865 g.UseRegister(mright.left().node()), g.TempImmediate(0));
866 return;
867 } else if (mright.right().Is(0xffff)) {
868 Emit(kArmUxtah, g.DefineAsRegister(node),
869 g.UseRegister(m.left().node()),
870 g.UseRegister(mright.left().node()), g.TempImmediate(0));
871 return;
872 }
873 }
874 case IrOpcode::kWord32Sar: {
875 Int32BinopMatcher mright(m.right().node());
876 if (CanCover(mright.node(), mright.left().node()) &&
877 mright.left().IsWord32Shl()) {
878 Int32BinopMatcher mrightleft(mright.left().node());
879 if (mright.right().Is(24) && mrightleft.right().Is(24)) {
880 Emit(kArmSxtab, g.DefineAsRegister(node),
881 g.UseRegister(m.left().node()),
882 g.UseRegister(mrightleft.left().node()), g.TempImmediate(0));
883 return;
884 } else if (mright.right().Is(16) && mrightleft.right().Is(16)) {
885 Emit(kArmSxtah, g.DefineAsRegister(node),
886 g.UseRegister(m.left().node()),
887 g.UseRegister(mrightleft.left().node()), g.TempImmediate(0));
888 return;
889 }
890 }
891 }
892 default:
893 break;
894 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000895 }
896 VisitBinop(this, node, kArmAdd, kArmAdd);
897}
898
899
900void InstructionSelector::VisitInt32Sub(Node* node) {
901 ArmOperandGenerator g(this);
902 Int32BinopMatcher m(node);
903 if (IsSupported(MLS) && m.right().IsInt32Mul() &&
904 CanCover(node, m.right().node())) {
905 Int32BinopMatcher mright(m.right().node());
906 Emit(kArmMls, g.DefineAsRegister(node), g.UseRegister(mright.left().node()),
907 g.UseRegister(mright.right().node()), g.UseRegister(m.left().node()));
908 return;
909 }
910 VisitBinop(this, node, kArmSub, kArmRsb);
911}
912
913
914void InstructionSelector::VisitInt32Mul(Node* node) {
915 ArmOperandGenerator g(this);
916 Int32BinopMatcher m(node);
917 if (m.right().HasValue() && m.right().Value() > 0) {
918 int32_t value = m.right().Value();
919 if (base::bits::IsPowerOfTwo32(value - 1)) {
920 Emit(kArmAdd | AddressingModeField::encode(kMode_Operand2_R_LSL_I),
921 g.DefineAsRegister(node), g.UseRegister(m.left().node()),
922 g.UseRegister(m.left().node()),
923 g.TempImmediate(WhichPowerOf2(value - 1)));
924 return;
925 }
926 if (value < kMaxInt && base::bits::IsPowerOfTwo32(value + 1)) {
927 Emit(kArmRsb | AddressingModeField::encode(kMode_Operand2_R_LSL_I),
928 g.DefineAsRegister(node), g.UseRegister(m.left().node()),
929 g.UseRegister(m.left().node()),
930 g.TempImmediate(WhichPowerOf2(value + 1)));
931 return;
932 }
933 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000934 VisitRRR(this, kArmMul, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000935}
936
937
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400938void InstructionSelector::VisitInt32MulHigh(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000939 VisitRRR(this, kArmSmmul, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400940}
941
942
943void InstructionSelector::VisitUint32MulHigh(Node* node) {
944 ArmOperandGenerator g(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000945 InstructionOperand outputs[] = {g.TempRegister(), g.DefineAsRegister(node)};
946 InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0)),
947 g.UseRegister(node->InputAt(1))};
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400948 Emit(kArmUmull, arraysize(outputs), outputs, arraysize(inputs), inputs);
949}
950
951
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000952void InstructionSelector::VisitInt32Div(Node* node) {
953 VisitDiv(this, node, kArmSdiv, kArmVcvtF64S32, kArmVcvtS32F64);
954}
955
956
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400957void InstructionSelector::VisitUint32Div(Node* node) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000958 VisitDiv(this, node, kArmUdiv, kArmVcvtF64U32, kArmVcvtU32F64);
959}
960
961
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000962void InstructionSelector::VisitInt32Mod(Node* node) {
963 VisitMod(this, node, kArmSdiv, kArmVcvtF64S32, kArmVcvtS32F64);
964}
965
966
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400967void InstructionSelector::VisitUint32Mod(Node* node) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000968 VisitMod(this, node, kArmUdiv, kArmVcvtF64U32, kArmVcvtU32F64);
969}
970
971
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400972void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000973 VisitRR(this, kArmVcvtF64F32, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400974}
975
976
Ben Murdoch097c5b22016-05-18 11:27:45 +0100977void InstructionSelector::VisitRoundInt32ToFloat32(Node* node) {
978 VisitRR(this, kArmVcvtF32S32, node);
979}
980
981
982void InstructionSelector::VisitRoundUint32ToFloat32(Node* node) {
983 VisitRR(this, kArmVcvtF32U32, node);
984}
985
986
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000987void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000988 VisitRR(this, kArmVcvtF64S32, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000989}
990
991
992void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000993 VisitRR(this, kArmVcvtF64U32, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000994}
995
996
Ben Murdoch097c5b22016-05-18 11:27:45 +0100997void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) {
998 VisitRR(this, kArmVcvtS32F32, node);
999}
1000
1001
1002void InstructionSelector::VisitTruncateFloat32ToUint32(Node* node) {
1003 VisitRR(this, kArmVcvtU32F32, node);
1004}
1005
1006
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001007void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001008 VisitRR(this, kArmVcvtS32F64, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001009}
1010
1011
1012void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001013 VisitRR(this, kArmVcvtU32F64, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001014}
1015
1016
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001017void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001018 VisitRR(this, kArmVcvtF32F64, node);
1019}
1020
1021
1022void InstructionSelector::VisitTruncateFloat64ToInt32(Node* node) {
1023 switch (TruncationModeOf(node->op())) {
1024 case TruncationMode::kJavaScript:
1025 return VisitRR(this, kArchTruncateDoubleToI, node);
1026 case TruncationMode::kRoundToZero:
1027 return VisitRR(this, kArmVcvtS32F64, node);
1028 }
1029 UNREACHABLE();
1030}
1031
1032
1033void InstructionSelector::VisitBitcastFloat32ToInt32(Node* node) {
1034 VisitRR(this, kArmVmovLowU32F64, node);
1035}
1036
1037
1038void InstructionSelector::VisitBitcastInt32ToFloat32(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001039 ArmOperandGenerator g(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001040 Emit(kArmVmovLowF64U32, g.DefineAsRegister(node),
1041 ImmediateOperand(ImmediateOperand::INLINE, 0),
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001042 g.UseRegister(node->InputAt(0)));
1043}
1044
1045
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001046void InstructionSelector::VisitFloat32Add(Node* node) {
1047 ArmOperandGenerator g(this);
1048 Float32BinopMatcher m(node);
1049 if (m.left().IsFloat32Mul() && CanCover(node, m.left().node())) {
1050 Float32BinopMatcher mleft(m.left().node());
1051 Emit(kArmVmlaF32, g.DefineSameAsFirst(node),
1052 g.UseRegister(m.right().node()), g.UseRegister(mleft.left().node()),
1053 g.UseRegister(mleft.right().node()));
1054 return;
1055 }
1056 if (m.right().IsFloat32Mul() && CanCover(node, m.right().node())) {
1057 Float32BinopMatcher mright(m.right().node());
1058 Emit(kArmVmlaF32, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
1059 g.UseRegister(mright.left().node()),
1060 g.UseRegister(mright.right().node()));
1061 return;
1062 }
1063 VisitRRR(this, kArmVaddF32, node);
1064}
1065
1066
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001067void InstructionSelector::VisitFloat64Add(Node* node) {
1068 ArmOperandGenerator g(this);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001069 Float64BinopMatcher m(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001070 if (m.left().IsFloat64Mul() && CanCover(node, m.left().node())) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001071 Float64BinopMatcher mleft(m.left().node());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001072 Emit(kArmVmlaF64, g.DefineSameAsFirst(node),
1073 g.UseRegister(m.right().node()), g.UseRegister(mleft.left().node()),
1074 g.UseRegister(mleft.right().node()));
1075 return;
1076 }
1077 if (m.right().IsFloat64Mul() && CanCover(node, m.right().node())) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001078 Float64BinopMatcher mright(m.right().node());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001079 Emit(kArmVmlaF64, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
1080 g.UseRegister(mright.left().node()),
1081 g.UseRegister(mright.right().node()));
1082 return;
1083 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001084 VisitRRR(this, kArmVaddF64, node);
1085}
1086
1087
1088void InstructionSelector::VisitFloat32Sub(Node* node) {
1089 ArmOperandGenerator g(this);
1090 Float32BinopMatcher m(node);
1091 if (m.left().IsMinusZero()) {
1092 Emit(kArmVnegF32, g.DefineAsRegister(node),
1093 g.UseRegister(m.right().node()));
1094 return;
1095 }
1096 if (m.right().IsFloat32Mul() && CanCover(node, m.right().node())) {
1097 Float32BinopMatcher mright(m.right().node());
1098 Emit(kArmVmlsF32, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
1099 g.UseRegister(mright.left().node()),
1100 g.UseRegister(mright.right().node()));
1101 return;
1102 }
1103 VisitRRR(this, kArmVsubF32, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001104}
1105
1106
1107void InstructionSelector::VisitFloat64Sub(Node* node) {
1108 ArmOperandGenerator g(this);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001109 Float64BinopMatcher m(node);
1110 if (m.left().IsMinusZero()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001111 if (m.right().IsFloat64RoundDown() &&
1112 CanCover(m.node(), m.right().node())) {
1113 if (m.right().InputAt(0)->opcode() == IrOpcode::kFloat64Sub &&
1114 CanCover(m.right().node(), m.right().InputAt(0))) {
1115 Float64BinopMatcher mright0(m.right().InputAt(0));
1116 if (mright0.left().IsMinusZero()) {
1117 Emit(kArmVrintpF64, g.DefineAsRegister(node),
1118 g.UseRegister(mright0.right().node()));
1119 return;
1120 }
1121 }
1122 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001123 Emit(kArmVnegF64, g.DefineAsRegister(node),
1124 g.UseRegister(m.right().node()));
1125 return;
1126 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001127 if (m.right().IsFloat64Mul() && CanCover(node, m.right().node())) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001128 Float64BinopMatcher mright(m.right().node());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001129 Emit(kArmVmlsF64, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
1130 g.UseRegister(mright.left().node()),
1131 g.UseRegister(mright.right().node()));
1132 return;
1133 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001134 VisitRRR(this, kArmVsubF64, node);
1135}
1136
1137
1138void InstructionSelector::VisitFloat32Mul(Node* node) {
1139 VisitRRR(this, kArmVmulF32, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001140}
1141
1142
1143void InstructionSelector::VisitFloat64Mul(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001144 VisitRRR(this, kArmVmulF64, node);
1145}
1146
1147
1148void InstructionSelector::VisitFloat32Div(Node* node) {
1149 VisitRRR(this, kArmVdivF32, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001150}
1151
1152
1153void InstructionSelector::VisitFloat64Div(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001154 VisitRRR(this, kArmVdivF64, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001155}
1156
1157
1158void InstructionSelector::VisitFloat64Mod(Node* node) {
1159 ArmOperandGenerator g(this);
1160 Emit(kArmVmodF64, g.DefineAsFixed(node, d0), g.UseFixed(node->InputAt(0), d0),
1161 g.UseFixed(node->InputAt(1), d1))->MarkAsCall();
1162}
1163
1164
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001165void InstructionSelector::VisitFloat32Max(Node* node) { UNREACHABLE(); }
1166
1167
1168void InstructionSelector::VisitFloat64Max(Node* node) { UNREACHABLE(); }
1169
1170
1171void InstructionSelector::VisitFloat32Min(Node* node) { UNREACHABLE(); }
1172
1173
1174void InstructionSelector::VisitFloat64Min(Node* node) { UNREACHABLE(); }
1175
1176
1177void InstructionSelector::VisitFloat32Abs(Node* node) {
1178 VisitRR(this, kArmVabsF32, node);
1179}
1180
1181
1182void InstructionSelector::VisitFloat64Abs(Node* node) {
1183 VisitRR(this, kArmVabsF64, node);
1184}
1185
1186
1187void InstructionSelector::VisitFloat32Sqrt(Node* node) {
1188 VisitRR(this, kArmVsqrtF32, node);
1189}
1190
1191
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001192void InstructionSelector::VisitFloat64Sqrt(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001193 VisitRR(this, kArmVsqrtF64, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001194}
1195
1196
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001197void InstructionSelector::VisitFloat32RoundDown(Node* node) {
1198 VisitRR(this, kArmVrintmF32, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001199}
1200
1201
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001202void InstructionSelector::VisitFloat64RoundDown(Node* node) {
1203 VisitRR(this, kArmVrintmF64, node);
1204}
1205
1206
1207void InstructionSelector::VisitFloat32RoundUp(Node* node) {
1208 VisitRR(this, kArmVrintpF32, node);
1209}
1210
1211
1212void InstructionSelector::VisitFloat64RoundUp(Node* node) {
1213 VisitRR(this, kArmVrintpF64, node);
1214}
1215
1216
1217void InstructionSelector::VisitFloat32RoundTruncate(Node* node) {
1218 VisitRR(this, kArmVrintzF32, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001219}
1220
1221
1222void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001223 VisitRR(this, kArmVrintzF64, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001224}
1225
1226
1227void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001228 VisitRR(this, kArmVrintaF64, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001229}
1230
1231
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001232void InstructionSelector::VisitFloat32RoundTiesEven(Node* node) {
1233 VisitRR(this, kArmVrintnF32, node);
1234}
1235
1236
1237void InstructionSelector::VisitFloat64RoundTiesEven(Node* node) {
1238 VisitRR(this, kArmVrintnF64, node);
1239}
1240
1241
1242void InstructionSelector::EmitPrepareArguments(
1243 ZoneVector<PushParameter>* arguments, const CallDescriptor* descriptor,
1244 Node* node) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001245 ArmOperandGenerator g(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001246
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001247 // Prepare for C function call.
1248 if (descriptor->IsCFunctionCall()) {
1249 Emit(kArchPrepareCallCFunction |
1250 MiscField::encode(static_cast<int>(descriptor->CParameterCount())),
1251 0, nullptr, 0, nullptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001252
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001253 // Poke any stack arguments.
1254 for (size_t n = 0; n < arguments->size(); ++n) {
1255 PushParameter input = (*arguments)[n];
1256 if (input.node()) {
1257 int slot = static_cast<int>(n);
1258 Emit(kArmPoke | MiscField::encode(slot), g.NoOutput(),
1259 g.UseRegister(input.node()));
1260 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001261 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001262 } else {
1263 // Push any stack arguments.
1264 for (PushParameter input : base::Reversed(*arguments)) {
1265 // Skip any alignment holes in pushed nodes.
1266 if (input.node() == nullptr) continue;
1267 Emit(kArmPush, g.NoOutput(), g.UseRegister(input.node()));
1268 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001269 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001270}
1271
1272
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001273bool InstructionSelector::IsTailCallAddressImmediate() { return false; }
1274
1275
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001276namespace {
1277
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001278// Shared routine for multiple compare operations.
1279void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
1280 InstructionOperand left, InstructionOperand right,
1281 FlagsContinuation* cont) {
1282 ArmOperandGenerator g(selector);
1283 opcode = cont->Encode(opcode);
1284 if (cont->IsBranch()) {
1285 selector->Emit(opcode, g.NoOutput(), left, right,
1286 g.Label(cont->true_block()), g.Label(cont->false_block()));
1287 } else {
1288 DCHECK(cont->IsSet());
1289 selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
1290 }
1291}
1292
1293
1294// Shared routine for multiple float32 compare operations.
1295void VisitFloat32Compare(InstructionSelector* selector, Node* node,
1296 FlagsContinuation* cont) {
1297 ArmOperandGenerator g(selector);
1298 Float32BinopMatcher m(node);
1299 if (m.right().Is(0.0f)) {
1300 VisitCompare(selector, kArmVcmpF32, g.UseRegister(m.left().node()),
1301 g.UseImmediate(m.right().node()), cont);
1302 } else if (m.left().Is(0.0f)) {
1303 cont->Commute();
1304 VisitCompare(selector, kArmVcmpF32, g.UseRegister(m.right().node()),
1305 g.UseImmediate(m.left().node()), cont);
1306 } else {
1307 VisitCompare(selector, kArmVcmpF32, g.UseRegister(m.left().node()),
1308 g.UseRegister(m.right().node()), cont);
1309 }
1310}
1311
1312
1313// Shared routine for multiple float64 compare operations.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001314void VisitFloat64Compare(InstructionSelector* selector, Node* node,
1315 FlagsContinuation* cont) {
1316 ArmOperandGenerator g(selector);
1317 Float64BinopMatcher m(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001318 if (m.right().Is(0.0)) {
1319 VisitCompare(selector, kArmVcmpF64, g.UseRegister(m.left().node()),
1320 g.UseImmediate(m.right().node()), cont);
1321 } else if (m.left().Is(0.0)) {
1322 cont->Commute();
1323 VisitCompare(selector, kArmVcmpF64, g.UseRegister(m.right().node()),
1324 g.UseImmediate(m.left().node()), cont);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001325 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001326 VisitCompare(selector, kArmVcmpF64, g.UseRegister(m.left().node()),
1327 g.UseRegister(m.right().node()), cont);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001328 }
1329}
1330
1331
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001332// Shared routine for multiple word compare operations.
1333void VisitWordCompare(InstructionSelector* selector, Node* node,
1334 InstructionCode opcode, FlagsContinuation* cont) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001335 ArmOperandGenerator g(selector);
1336 Int32BinopMatcher m(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001337 InstructionOperand inputs[5];
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001338 size_t input_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001339 InstructionOperand outputs[1];
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001340 size_t output_count = 0;
1341
1342 if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(),
1343 &input_count, &inputs[1])) {
1344 inputs[0] = g.UseRegister(m.left().node());
1345 input_count++;
1346 } else if (TryMatchImmediateOrShift(selector, &opcode, m.left().node(),
1347 &input_count, &inputs[1])) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001348 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001349 inputs[0] = g.UseRegister(m.right().node());
1350 input_count++;
1351 } else {
1352 opcode |= AddressingModeField::encode(kMode_Operand2_R);
1353 inputs[input_count++] = g.UseRegister(m.left().node());
1354 inputs[input_count++] = g.UseRegister(m.right().node());
1355 }
1356
1357 if (cont->IsBranch()) {
1358 inputs[input_count++] = g.Label(cont->true_block());
1359 inputs[input_count++] = g.Label(cont->false_block());
1360 } else {
1361 DCHECK(cont->IsSet());
1362 outputs[output_count++] = g.DefineAsRegister(cont->result());
1363 }
1364
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001365 DCHECK_NE(0u, input_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001366 DCHECK_GE(arraysize(inputs), input_count);
1367 DCHECK_GE(arraysize(outputs), output_count);
1368
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001369 selector->Emit(cont->Encode(opcode), output_count, outputs, input_count,
1370 inputs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001371}
1372
1373
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001374void VisitWordCompare(InstructionSelector* selector, Node* node,
1375 FlagsContinuation* cont) {
1376 VisitWordCompare(selector, node, kArmCmp, cont);
1377}
1378
1379
1380// Shared routine for word comparisons against zero.
1381void VisitWordCompareZero(InstructionSelector* selector, Node* user,
1382 Node* value, FlagsContinuation* cont) {
1383 while (selector->CanCover(user, value)) {
1384 switch (value->opcode()) {
1385 case IrOpcode::kWord32Equal: {
1386 // Combine with comparisons against 0 by simply inverting the
1387 // continuation.
1388 Int32BinopMatcher m(value);
1389 if (m.right().Is(0)) {
1390 user = value;
1391 value = m.left().node();
1392 cont->Negate();
1393 continue;
1394 }
1395 cont->OverwriteAndNegateIfEqual(kEqual);
1396 return VisitWordCompare(selector, value, cont);
1397 }
1398 case IrOpcode::kInt32LessThan:
1399 cont->OverwriteAndNegateIfEqual(kSignedLessThan);
1400 return VisitWordCompare(selector, value, cont);
1401 case IrOpcode::kInt32LessThanOrEqual:
1402 cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
1403 return VisitWordCompare(selector, value, cont);
1404 case IrOpcode::kUint32LessThan:
1405 cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
1406 return VisitWordCompare(selector, value, cont);
1407 case IrOpcode::kUint32LessThanOrEqual:
1408 cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
1409 return VisitWordCompare(selector, value, cont);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001410 case IrOpcode::kFloat32Equal:
1411 cont->OverwriteAndNegateIfEqual(kEqual);
1412 return VisitFloat32Compare(selector, value, cont);
1413 case IrOpcode::kFloat32LessThan:
1414 cont->OverwriteAndNegateIfEqual(kFloatLessThan);
1415 return VisitFloat32Compare(selector, value, cont);
1416 case IrOpcode::kFloat32LessThanOrEqual:
1417 cont->OverwriteAndNegateIfEqual(kFloatLessThanOrEqual);
1418 return VisitFloat32Compare(selector, value, cont);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001419 case IrOpcode::kFloat64Equal:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001420 cont->OverwriteAndNegateIfEqual(kEqual);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001421 return VisitFloat64Compare(selector, value, cont);
1422 case IrOpcode::kFloat64LessThan:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001423 cont->OverwriteAndNegateIfEqual(kFloatLessThan);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001424 return VisitFloat64Compare(selector, value, cont);
1425 case IrOpcode::kFloat64LessThanOrEqual:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001426 cont->OverwriteAndNegateIfEqual(kFloatLessThanOrEqual);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001427 return VisitFloat64Compare(selector, value, cont);
1428 case IrOpcode::kProjection:
1429 // Check if this is the overflow output projection of an
1430 // <Operation>WithOverflow node.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001431 if (ProjectionIndexOf(value->op()) == 1u) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001432 // We cannot combine the <Operation>WithOverflow with this branch
1433 // unless the 0th projection (the use of the actual value of the
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001434 // <Operation> is either nullptr, which means there's no use of the
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001435 // actual value, or was already defined, which means it is scheduled
1436 // *AFTER* this branch).
1437 Node* const node = value->InputAt(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001438 Node* const result = NodeProperties::FindProjection(node, 0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001439 if (!result || selector->IsDefined(result)) {
1440 switch (node->opcode()) {
1441 case IrOpcode::kInt32AddWithOverflow:
1442 cont->OverwriteAndNegateIfEqual(kOverflow);
1443 return VisitBinop(selector, node, kArmAdd, kArmAdd, cont);
1444 case IrOpcode::kInt32SubWithOverflow:
1445 cont->OverwriteAndNegateIfEqual(kOverflow);
1446 return VisitBinop(selector, node, kArmSub, kArmRsb, cont);
1447 default:
1448 break;
1449 }
1450 }
1451 }
1452 break;
1453 case IrOpcode::kInt32Add:
1454 return VisitWordCompare(selector, value, kArmCmn, cont);
1455 case IrOpcode::kInt32Sub:
1456 return VisitWordCompare(selector, value, kArmCmp, cont);
1457 case IrOpcode::kWord32And:
1458 return VisitWordCompare(selector, value, kArmTst, cont);
1459 case IrOpcode::kWord32Or:
1460 return VisitBinop(selector, value, kArmOrr, kArmOrr, cont);
1461 case IrOpcode::kWord32Xor:
1462 return VisitWordCompare(selector, value, kArmTeq, cont);
1463 case IrOpcode::kWord32Sar:
1464 return VisitShift(selector, value, TryMatchASR, cont);
1465 case IrOpcode::kWord32Shl:
1466 return VisitShift(selector, value, TryMatchLSL, cont);
1467 case IrOpcode::kWord32Shr:
1468 return VisitShift(selector, value, TryMatchLSR, cont);
1469 case IrOpcode::kWord32Ror:
1470 return VisitShift(selector, value, TryMatchROR, cont);
1471 default:
1472 break;
1473 }
1474 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001475 }
1476
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001477 // Continuation could not be combined with a compare, emit compare against 0.
1478 ArmOperandGenerator g(selector);
1479 InstructionCode const opcode =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001480 cont->Encode(kArmTst) | AddressingModeField::encode(kMode_Operand2_R);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001481 InstructionOperand const value_operand = g.UseRegister(value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001482 if (cont->IsBranch()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001483 selector->Emit(opcode, g.NoOutput(), value_operand, value_operand,
1484 g.Label(cont->true_block()), g.Label(cont->false_block()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001485 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001486 selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand,
1487 value_operand);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001488 }
1489}
1490
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001491} // namespace
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001492
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001493
1494void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
1495 BasicBlock* fbranch) {
1496 FlagsContinuation cont(kNotEqual, tbranch, fbranch);
1497 VisitWordCompareZero(this, branch, branch->InputAt(0), &cont);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001498}
1499
1500
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001501void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
1502 ArmOperandGenerator g(this);
1503 InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
1504
1505 // Emit either ArchTableSwitch or ArchLookupSwitch.
1506 size_t table_space_cost = 4 + sw.value_range;
1507 size_t table_time_cost = 3;
1508 size_t lookup_space_cost = 3 + 2 * sw.case_count;
1509 size_t lookup_time_cost = sw.case_count;
1510 if (sw.case_count > 0 &&
1511 table_space_cost + 3 * table_time_cost <=
1512 lookup_space_cost + 3 * lookup_time_cost &&
1513 sw.min_value > std::numeric_limits<int32_t>::min()) {
1514 InstructionOperand index_operand = value_operand;
1515 if (sw.min_value) {
1516 index_operand = g.TempRegister();
1517 Emit(kArmSub | AddressingModeField::encode(kMode_Operand2_I),
1518 index_operand, value_operand, g.TempImmediate(sw.min_value));
1519 }
1520 // Generate a table lookup.
1521 return EmitTableSwitch(sw, index_operand);
1522 }
1523
1524 // Generate a sequence of conditional jumps.
1525 return EmitLookupSwitch(sw, value_operand);
1526}
1527
1528
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001529void InstructionSelector::VisitWord32Equal(Node* const node) {
1530 FlagsContinuation cont(kEqual, node);
1531 Int32BinopMatcher m(node);
1532 if (m.right().Is(0)) {
1533 return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001534 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001535 VisitWordCompare(this, node, &cont);
1536}
1537
1538
1539void InstructionSelector::VisitInt32LessThan(Node* node) {
1540 FlagsContinuation cont(kSignedLessThan, node);
1541 VisitWordCompare(this, node, &cont);
1542}
1543
1544
1545void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
1546 FlagsContinuation cont(kSignedLessThanOrEqual, node);
1547 VisitWordCompare(this, node, &cont);
1548}
1549
1550
1551void InstructionSelector::VisitUint32LessThan(Node* node) {
1552 FlagsContinuation cont(kUnsignedLessThan, node);
1553 VisitWordCompare(this, node, &cont);
1554}
1555
1556
1557void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
1558 FlagsContinuation cont(kUnsignedLessThanOrEqual, node);
1559 VisitWordCompare(this, node, &cont);
1560}
1561
1562
1563void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001564 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001565 FlagsContinuation cont(kOverflow, ovf);
1566 return VisitBinop(this, node, kArmAdd, kArmAdd, &cont);
1567 }
1568 FlagsContinuation cont;
1569 VisitBinop(this, node, kArmAdd, kArmAdd, &cont);
1570}
1571
1572
1573void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001574 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001575 FlagsContinuation cont(kOverflow, ovf);
1576 return VisitBinop(this, node, kArmSub, kArmRsb, &cont);
1577 }
1578 FlagsContinuation cont;
1579 VisitBinop(this, node, kArmSub, kArmRsb, &cont);
1580}
1581
1582
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001583void InstructionSelector::VisitFloat32Equal(Node* node) {
1584 FlagsContinuation cont(kEqual, node);
1585 VisitFloat32Compare(this, node, &cont);
1586}
1587
1588
1589void InstructionSelector::VisitFloat32LessThan(Node* node) {
1590 FlagsContinuation cont(kFloatLessThan, node);
1591 VisitFloat32Compare(this, node, &cont);
1592}
1593
1594
1595void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) {
1596 FlagsContinuation cont(kFloatLessThanOrEqual, node);
1597 VisitFloat32Compare(this, node, &cont);
1598}
1599
1600
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001601void InstructionSelector::VisitFloat64Equal(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001602 FlagsContinuation cont(kEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001603 VisitFloat64Compare(this, node, &cont);
1604}
1605
1606
1607void InstructionSelector::VisitFloat64LessThan(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001608 FlagsContinuation cont(kFloatLessThan, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001609 VisitFloat64Compare(this, node, &cont);
1610}
1611
1612
1613void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001614 FlagsContinuation cont(kFloatLessThanOrEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001615 VisitFloat64Compare(this, node, &cont);
1616}
1617
1618
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001619void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) {
1620 VisitRR(this, kArmVmovLowU32F64, node);
1621}
1622
1623
1624void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) {
1625 VisitRR(this, kArmVmovHighU32F64, node);
1626}
1627
1628
1629void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) {
1630 ArmOperandGenerator g(this);
1631 Node* left = node->InputAt(0);
1632 Node* right = node->InputAt(1);
1633 if (left->opcode() == IrOpcode::kFloat64InsertHighWord32 &&
1634 CanCover(node, left)) {
1635 left = left->InputAt(1);
1636 Emit(kArmVmovF64U32U32, g.DefineAsRegister(node), g.UseRegister(right),
1637 g.UseRegister(left));
1638 return;
1639 }
1640 Emit(kArmVmovLowF64U32, g.DefineSameAsFirst(node), g.UseRegister(left),
1641 g.UseRegister(right));
1642}
1643
1644
1645void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
1646 ArmOperandGenerator g(this);
1647 Node* left = node->InputAt(0);
1648 Node* right = node->InputAt(1);
1649 if (left->opcode() == IrOpcode::kFloat64InsertLowWord32 &&
1650 CanCover(node, left)) {
1651 left = left->InputAt(1);
1652 Emit(kArmVmovF64U32U32, g.DefineAsRegister(node), g.UseRegister(left),
1653 g.UseRegister(right));
1654 return;
1655 }
1656 Emit(kArmVmovHighF64U32, g.DefineSameAsFirst(node), g.UseRegister(left),
1657 g.UseRegister(right));
1658}
1659
1660
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001661// static
1662MachineOperatorBuilder::Flags
1663InstructionSelector::SupportedMachineOperatorFlags() {
1664 MachineOperatorBuilder::Flags flags =
1665 MachineOperatorBuilder::kInt32DivIsSafe |
1666 MachineOperatorBuilder::kUint32DivIsSafe;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001667 if (CpuFeatures::IsSupported(ARMv7)) {
1668 flags |= MachineOperatorBuilder::kWord32ReverseBits;
1669 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001670 if (CpuFeatures::IsSupported(ARMv8)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001671 flags |= MachineOperatorBuilder::kFloat32RoundDown |
1672 MachineOperatorBuilder::kFloat64RoundDown |
1673 MachineOperatorBuilder::kFloat32RoundUp |
1674 MachineOperatorBuilder::kFloat64RoundUp |
1675 MachineOperatorBuilder::kFloat32RoundTruncate |
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001676 MachineOperatorBuilder::kFloat64RoundTruncate |
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001677 MachineOperatorBuilder::kFloat64RoundTiesAway |
1678 MachineOperatorBuilder::kFloat32RoundTiesEven |
1679 MachineOperatorBuilder::kFloat64RoundTiesEven;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001680 }
1681 return flags;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001682}
1683
1684} // namespace compiler
1685} // namespace internal
1686} // namespace v8