blob: e21e63f8d0e261c034c0876f878fc138e2f273a1 [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
Ben Murdoch61f157c2016-09-16 13:49:30 +0100118template <IrOpcode::Value kOpcode, int kImmMin, int kImmMax,
119 AddressingMode kImmMode>
120bool TryMatchShiftImmediate(InstructionSelector* selector,
121 InstructionCode* opcode_return, Node* node,
122 InstructionOperand* value_return,
123 InstructionOperand* shift_return) {
124 ArmOperandGenerator g(selector);
125 if (node->opcode() == kOpcode) {
126 Int32BinopMatcher m(node);
127 if (m.right().IsInRange(kImmMin, kImmMax)) {
128 *opcode_return |= AddressingModeField::encode(kImmMode);
129 *value_return = g.UseRegister(m.left().node());
130 *shift_return = g.UseImmediate(m.right().node());
131 return true;
132 }
133 }
134 return false;
135}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000136
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400137bool TryMatchROR(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::kWord32Ror, 1, 31, kMode_Operand2_R_ROR_I,
141 kMode_Operand2_R_ROR_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 TryMatchASR(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::kWord32Sar, 1, 32, kMode_Operand2_R_ASR_I,
150 kMode_Operand2_R_ASR_R>(selector, opcode_return, node,
151 value_return, shift_return);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000152}
153
154
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400155bool TryMatchLSL(InstructionSelector* selector, InstructionCode* opcode_return,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000156 Node* node, InstructionOperand* value_return,
157 InstructionOperand* shift_return) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400158 return TryMatchShift<IrOpcode::kWord32Shl, 0, 31, kMode_Operand2_R_LSL_I,
159 kMode_Operand2_R_LSL_R>(selector, opcode_return, node,
160 value_return, shift_return);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000161}
162
Ben Murdoch61f157c2016-09-16 13:49:30 +0100163bool TryMatchLSLImmediate(InstructionSelector* selector,
164 InstructionCode* opcode_return, Node* node,
165 InstructionOperand* value_return,
166 InstructionOperand* shift_return) {
167 return TryMatchShiftImmediate<IrOpcode::kWord32Shl, 0, 31,
168 kMode_Operand2_R_LSL_I>(
169 selector, opcode_return, node, value_return, shift_return);
170}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000171
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400172bool TryMatchLSR(InstructionSelector* selector, InstructionCode* opcode_return,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000173 Node* node, InstructionOperand* value_return,
174 InstructionOperand* shift_return) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400175 return TryMatchShift<IrOpcode::kWord32Shr, 1, 32, kMode_Operand2_R_LSR_I,
176 kMode_Operand2_R_LSR_R>(selector, opcode_return, node,
177 value_return, shift_return);
178}
179
180
181bool TryMatchShift(InstructionSelector* selector,
182 InstructionCode* opcode_return, Node* node,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000183 InstructionOperand* value_return,
184 InstructionOperand* shift_return) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000185 return (
186 TryMatchASR(selector, opcode_return, node, value_return, shift_return) ||
187 TryMatchLSL(selector, opcode_return, node, value_return, shift_return) ||
188 TryMatchLSR(selector, opcode_return, node, value_return, shift_return) ||
189 TryMatchROR(selector, opcode_return, node, value_return, shift_return));
190}
191
192
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400193bool TryMatchImmediateOrShift(InstructionSelector* selector,
194 InstructionCode* opcode_return, Node* node,
195 size_t* input_count_return,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000196 InstructionOperand* inputs) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000197 ArmOperandGenerator g(selector);
198 if (g.CanBeImmediate(node, *opcode_return)) {
199 *opcode_return |= AddressingModeField::encode(kMode_Operand2_I);
200 inputs[0] = g.UseImmediate(node);
201 *input_count_return = 1;
202 return true;
203 }
204 if (TryMatchShift(selector, opcode_return, node, &inputs[0], &inputs[1])) {
205 *input_count_return = 2;
206 return true;
207 }
208 return false;
209}
210
211
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400212void VisitBinop(InstructionSelector* selector, Node* node,
213 InstructionCode opcode, InstructionCode reverse_opcode,
214 FlagsContinuation* cont) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000215 ArmOperandGenerator g(selector);
216 Int32BinopMatcher m(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000217 InstructionOperand inputs[5];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000218 size_t input_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000219 InstructionOperand outputs[2];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000220 size_t output_count = 0;
221
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400222 if (m.left().node() == m.right().node()) {
223 // If both inputs refer to the same operand, enforce allocating a register
224 // for both of them to ensure that we don't end up generating code like
225 // this:
226 //
227 // mov r0, r1, asr #16
228 // adds r0, r0, r1, asr #16
229 // bvs label
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000230 InstructionOperand const input = g.UseRegister(m.left().node());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400231 opcode |= AddressingModeField::encode(kMode_Operand2_R);
232 inputs[input_count++] = input;
233 inputs[input_count++] = input;
234 } else if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(),
235 &input_count, &inputs[1])) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000236 inputs[0] = g.UseRegister(m.left().node());
237 input_count++;
238 } else if (TryMatchImmediateOrShift(selector, &reverse_opcode,
239 m.left().node(), &input_count,
240 &inputs[1])) {
241 inputs[0] = g.UseRegister(m.right().node());
242 opcode = reverse_opcode;
243 input_count++;
244 } else {
245 opcode |= AddressingModeField::encode(kMode_Operand2_R);
246 inputs[input_count++] = g.UseRegister(m.left().node());
247 inputs[input_count++] = g.UseRegister(m.right().node());
248 }
249
250 if (cont->IsBranch()) {
251 inputs[input_count++] = g.Label(cont->true_block());
252 inputs[input_count++] = g.Label(cont->false_block());
253 }
254
Ben Murdoch61f157c2016-09-16 13:49:30 +0100255 if (cont->IsDeoptimize()) {
256 // If we can deoptimize as a result of the binop, we need to make sure that
257 // the deopt inputs are not overwritten by the binop result. One way
258 // to achieve that is to declare the output register as same-as-first.
259 outputs[output_count++] = g.DefineSameAsFirst(node);
260 } else {
261 outputs[output_count++] = g.DefineAsRegister(node);
262 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000263 if (cont->IsSet()) {
264 outputs[output_count++] = g.DefineAsRegister(cont->result());
265 }
266
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000267 DCHECK_NE(0u, input_count);
268 DCHECK_NE(0u, output_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000269 DCHECK_GE(arraysize(inputs), input_count);
270 DCHECK_GE(arraysize(outputs), output_count);
271 DCHECK_NE(kMode_None, AddressingModeField::decode(opcode));
272
Ben Murdochda12d292016-06-02 14:46:10 +0100273 opcode = cont->Encode(opcode);
274 if (cont->IsDeoptimize()) {
275 selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
276 cont->frame_state());
277 } else {
278 selector->Emit(opcode, output_count, outputs, input_count, inputs);
279 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000280}
281
282
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400283void VisitBinop(InstructionSelector* selector, Node* node,
284 InstructionCode opcode, InstructionCode reverse_opcode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000285 FlagsContinuation cont;
286 VisitBinop(selector, node, opcode, reverse_opcode, &cont);
287}
288
289
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000290void EmitDiv(InstructionSelector* selector, ArchOpcode div_opcode,
291 ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode,
292 InstructionOperand result_operand, InstructionOperand left_operand,
293 InstructionOperand right_operand) {
294 ArmOperandGenerator g(selector);
295 if (selector->IsSupported(SUDIV)) {
296 selector->Emit(div_opcode, result_operand, left_operand, right_operand);
297 return;
298 }
299 InstructionOperand left_double_operand = g.TempDoubleRegister();
300 InstructionOperand right_double_operand = g.TempDoubleRegister();
301 InstructionOperand result_double_operand = g.TempDoubleRegister();
302 selector->Emit(f64i32_opcode, left_double_operand, left_operand);
303 selector->Emit(f64i32_opcode, right_double_operand, right_operand);
304 selector->Emit(kArmVdivF64, result_double_operand, left_double_operand,
305 right_double_operand);
306 selector->Emit(i32f64_opcode, result_operand, result_double_operand);
307}
308
309
310void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode div_opcode,
311 ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode) {
312 ArmOperandGenerator g(selector);
313 Int32BinopMatcher m(node);
314 EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode,
315 g.DefineAsRegister(node), g.UseRegister(m.left().node()),
316 g.UseRegister(m.right().node()));
317}
318
319
320void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode div_opcode,
321 ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode) {
322 ArmOperandGenerator g(selector);
323 Int32BinopMatcher m(node);
324 InstructionOperand div_operand = g.TempRegister();
325 InstructionOperand result_operand = g.DefineAsRegister(node);
326 InstructionOperand left_operand = g.UseRegister(m.left().node());
327 InstructionOperand right_operand = g.UseRegister(m.right().node());
328 EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode, div_operand,
329 left_operand, right_operand);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100330 if (selector->IsSupported(ARMv7)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000331 selector->Emit(kArmMls, result_operand, div_operand, right_operand,
332 left_operand);
333 } else {
334 InstructionOperand mul_operand = g.TempRegister();
335 selector->Emit(kArmMul, mul_operand, div_operand, right_operand);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100336 selector->Emit(kArmSub | AddressingModeField::encode(kMode_Operand2_R),
337 result_operand, left_operand, mul_operand);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000338 }
339}
340
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400341} // namespace
342
343
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000344void InstructionSelector::VisitLoad(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000345 LoadRepresentation load_rep = LoadRepresentationOf(node->op());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000346 ArmOperandGenerator g(this);
347 Node* base = node->InputAt(0);
348 Node* index = node->InputAt(1);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100349 InstructionOperand inputs[3];
350 size_t input_count = 0;
351 InstructionOperand outputs[1];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000352
Ben Murdoch61f157c2016-09-16 13:49:30 +0100353 InstructionCode opcode = kArchNop;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000354 switch (load_rep.representation()) {
355 case MachineRepresentation::kFloat32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400356 opcode = kArmVldrF32;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000357 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000358 case MachineRepresentation::kFloat64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400359 opcode = kArmVldrF64;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000360 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000361 case MachineRepresentation::kBit: // Fall through.
362 case MachineRepresentation::kWord8:
363 opcode = load_rep.IsUnsigned() ? kArmLdrb : kArmLdrsb;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000364 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000365 case MachineRepresentation::kWord16:
366 opcode = load_rep.IsUnsigned() ? kArmLdrh : kArmLdrsh;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000367 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000368 case MachineRepresentation::kTagged: // Fall through.
369 case MachineRepresentation::kWord32:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000370 opcode = kArmLdr;
371 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100372 case MachineRepresentation::kWord64: // Fall through.
373 case MachineRepresentation::kSimd128: // Fall through.
374 case MachineRepresentation::kNone:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000375 UNREACHABLE();
376 return;
377 }
378
Ben Murdoch61f157c2016-09-16 13:49:30 +0100379 outputs[0] = g.DefineAsRegister(node);
380 inputs[0] = g.UseRegister(base);
381
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000382 if (g.CanBeImmediate(index, opcode)) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100383 input_count = 2;
384 inputs[1] = g.UseImmediate(index);
385 opcode |= AddressingModeField::encode(kMode_Offset_RI);
386 } else if ((opcode == kArmLdr) &&
387 TryMatchLSLImmediate(this, &opcode, index, &inputs[1],
388 &inputs[2])) {
389 input_count = 3;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000390 } else {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100391 input_count = 2;
392 inputs[1] = g.UseRegister(index);
393 opcode |= AddressingModeField::encode(kMode_Offset_RR);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000394 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100395
396 Emit(opcode, arraysize(outputs), outputs, input_count, inputs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000397}
398
399
400void InstructionSelector::VisitStore(Node* node) {
401 ArmOperandGenerator g(this);
402 Node* base = node->InputAt(0);
403 Node* index = node->InputAt(1);
404 Node* value = node->InputAt(2);
405
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000406 StoreRepresentation store_rep = StoreRepresentationOf(node->op());
407 WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind();
408 MachineRepresentation rep = store_rep.representation();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000409
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000410 if (write_barrier_kind != kNoWriteBarrier) {
411 DCHECK_EQ(MachineRepresentation::kTagged, rep);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100412 AddressingMode addressing_mode;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000413 InstructionOperand inputs[3];
414 size_t input_count = 0;
415 inputs[input_count++] = g.UseUniqueRegister(base);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100416 // OutOfLineRecordWrite uses the index in an 'add' instruction as well as
417 // for the store itself, so we must check compatibility with both.
418 if (g.CanBeImmediate(index, kArmAdd) && g.CanBeImmediate(index, kArmStr)) {
419 inputs[input_count++] = g.UseImmediate(index);
420 addressing_mode = kMode_Offset_RI;
421 } else {
422 inputs[input_count++] = g.UseUniqueRegister(index);
423 addressing_mode = kMode_Offset_RR;
424 }
Ben Murdochda12d292016-06-02 14:46:10 +0100425 inputs[input_count++] = g.UseUniqueRegister(value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000426 RecordWriteMode record_write_mode = RecordWriteMode::kValueIsAny;
427 switch (write_barrier_kind) {
428 case kNoWriteBarrier:
429 UNREACHABLE();
430 break;
431 case kMapWriteBarrier:
432 record_write_mode = RecordWriteMode::kValueIsMap;
433 break;
434 case kPointerWriteBarrier:
435 record_write_mode = RecordWriteMode::kValueIsPointer;
436 break;
437 case kFullWriteBarrier:
438 record_write_mode = RecordWriteMode::kValueIsAny;
439 break;
440 }
441 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
442 size_t const temp_count = arraysize(temps);
443 InstructionCode code = kArchStoreWithWriteBarrier;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100444 code |= AddressingModeField::encode(addressing_mode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000445 code |= MiscField::encode(static_cast<int>(record_write_mode));
446 Emit(code, 0, nullptr, input_count, inputs, temp_count, temps);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000447 } else {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100448 InstructionOperand inputs[4];
449 size_t input_count = 0;
450
451 InstructionCode opcode = kArchNop;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000452 switch (rep) {
453 case MachineRepresentation::kFloat32:
454 opcode = kArmVstrF32;
455 break;
456 case MachineRepresentation::kFloat64:
457 opcode = kArmVstrF64;
458 break;
459 case MachineRepresentation::kBit: // Fall through.
460 case MachineRepresentation::kWord8:
461 opcode = kArmStrb;
462 break;
463 case MachineRepresentation::kWord16:
464 opcode = kArmStrh;
465 break;
466 case MachineRepresentation::kTagged: // Fall through.
467 case MachineRepresentation::kWord32:
468 opcode = kArmStr;
469 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100470 case MachineRepresentation::kWord64: // Fall through.
471 case MachineRepresentation::kSimd128: // Fall through.
472 case MachineRepresentation::kNone:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000473 UNREACHABLE();
474 return;
475 }
476
Ben Murdoch61f157c2016-09-16 13:49:30 +0100477 inputs[0] = g.UseRegister(value);
478 inputs[1] = g.UseRegister(base);
479
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000480 if (g.CanBeImmediate(index, opcode)) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100481 input_count = 3;
482 inputs[2] = g.UseImmediate(index);
483 opcode |= AddressingModeField::encode(kMode_Offset_RI);
484 } else if ((opcode == kArmStr) &&
485 TryMatchLSLImmediate(this, &opcode, index, &inputs[2],
486 &inputs[3])) {
487 input_count = 4;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000488 } else {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100489 input_count = 3;
490 inputs[2] = g.UseRegister(index);
491 opcode |= AddressingModeField::encode(kMode_Offset_RR);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000492 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100493 Emit(opcode, 0, nullptr, input_count, inputs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000494 }
495}
496
497
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400498void InstructionSelector::VisitCheckedLoad(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000499 CheckedLoadRepresentation load_rep = CheckedLoadRepresentationOf(node->op());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400500 ArmOperandGenerator g(this);
501 Node* const buffer = node->InputAt(0);
502 Node* const offset = node->InputAt(1);
503 Node* const length = node->InputAt(2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000504 ArchOpcode opcode = kArchNop;
505 switch (load_rep.representation()) {
506 case MachineRepresentation::kWord8:
507 opcode = load_rep.IsSigned() ? kCheckedLoadInt8 : kCheckedLoadUint8;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400508 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000509 case MachineRepresentation::kWord16:
510 opcode = load_rep.IsSigned() ? kCheckedLoadInt16 : kCheckedLoadUint16;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400511 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000512 case MachineRepresentation::kWord32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400513 opcode = kCheckedLoadWord32;
514 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000515 case MachineRepresentation::kFloat32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400516 opcode = kCheckedLoadFloat32;
517 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000518 case MachineRepresentation::kFloat64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400519 opcode = kCheckedLoadFloat64;
520 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100521 case MachineRepresentation::kBit: // Fall through.
522 case MachineRepresentation::kTagged: // Fall through.
523 case MachineRepresentation::kWord64: // Fall through.
524 case MachineRepresentation::kSimd128: // Fall through.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000525 case MachineRepresentation::kNone:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400526 UNREACHABLE();
527 return;
528 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000529 InstructionOperand offset_operand = g.UseRegister(offset);
530 InstructionOperand length_operand = g.CanBeImmediate(length, kArmCmp)
531 ? g.UseImmediate(length)
532 : g.UseRegister(length);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400533 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR),
534 g.DefineAsRegister(node), offset_operand, length_operand,
535 g.UseRegister(buffer), offset_operand);
536}
537
538
539void InstructionSelector::VisitCheckedStore(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000540 MachineRepresentation rep = CheckedStoreRepresentationOf(node->op());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400541 ArmOperandGenerator g(this);
542 Node* const buffer = node->InputAt(0);
543 Node* const offset = node->InputAt(1);
544 Node* const length = node->InputAt(2);
545 Node* const value = node->InputAt(3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000546 ArchOpcode opcode = kArchNop;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400547 switch (rep) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000548 case MachineRepresentation::kWord8:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400549 opcode = kCheckedStoreWord8;
550 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000551 case MachineRepresentation::kWord16:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400552 opcode = kCheckedStoreWord16;
553 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000554 case MachineRepresentation::kWord32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400555 opcode = kCheckedStoreWord32;
556 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000557 case MachineRepresentation::kFloat32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400558 opcode = kCheckedStoreFloat32;
559 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000560 case MachineRepresentation::kFloat64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400561 opcode = kCheckedStoreFloat64;
562 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100563 case MachineRepresentation::kBit: // Fall through.
564 case MachineRepresentation::kTagged: // Fall through.
565 case MachineRepresentation::kWord64: // Fall through.
566 case MachineRepresentation::kSimd128: // Fall through.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000567 case MachineRepresentation::kNone:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400568 UNREACHABLE();
569 return;
570 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000571 InstructionOperand offset_operand = g.UseRegister(offset);
572 InstructionOperand length_operand = g.CanBeImmediate(length, kArmCmp)
573 ? g.UseImmediate(length)
574 : g.UseRegister(length);
575 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), g.NoOutput(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400576 offset_operand, length_operand, g.UseRegister(value),
577 g.UseRegister(buffer), offset_operand);
578}
579
580
581namespace {
582
583void EmitBic(InstructionSelector* selector, Node* node, Node* left,
584 Node* right) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000585 ArmOperandGenerator g(selector);
586 InstructionCode opcode = kArmBic;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000587 InstructionOperand value_operand;
588 InstructionOperand shift_operand;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000589 if (TryMatchShift(selector, &opcode, right, &value_operand, &shift_operand)) {
590 selector->Emit(opcode, g.DefineAsRegister(node), g.UseRegister(left),
591 value_operand, shift_operand);
592 return;
593 }
594 selector->Emit(opcode | AddressingModeField::encode(kMode_Operand2_R),
595 g.DefineAsRegister(node), g.UseRegister(left),
596 g.UseRegister(right));
597}
598
599
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400600void EmitUbfx(InstructionSelector* selector, Node* node, Node* left,
601 uint32_t lsb, uint32_t width) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000602 DCHECK_LE(1u, width);
603 DCHECK_LE(width, 32u - lsb);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400604 ArmOperandGenerator g(selector);
605 selector->Emit(kArmUbfx, g.DefineAsRegister(node), g.UseRegister(left),
606 g.TempImmediate(lsb), g.TempImmediate(width));
607}
608
609} // namespace
610
611
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000612void InstructionSelector::VisitWord32And(Node* node) {
613 ArmOperandGenerator g(this);
614 Int32BinopMatcher m(node);
615 if (m.left().IsWord32Xor() && CanCover(node, m.left().node())) {
616 Int32BinopMatcher mleft(m.left().node());
617 if (mleft.right().Is(-1)) {
618 EmitBic(this, node, m.right().node(), mleft.left().node());
619 return;
620 }
621 }
622 if (m.right().IsWord32Xor() && CanCover(node, m.right().node())) {
623 Int32BinopMatcher mright(m.right().node());
624 if (mright.right().Is(-1)) {
625 EmitBic(this, node, m.left().node(), mright.left().node());
626 return;
627 }
628 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400629 if (m.right().HasValue()) {
630 uint32_t const value = m.right().Value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000631 uint32_t width = base::bits::CountPopulation32(value);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100632 uint32_t leading_zeros = base::bits::CountLeadingZeros32(value);
633
634 // Try to merge SHR operations on the left hand input into this AND.
635 if (m.left().IsWord32Shr()) {
636 Int32BinopMatcher mshr(m.left().node());
637 if (mshr.right().HasValue()) {
638 uint32_t const shift = mshr.right().Value();
639
640 if (((shift == 8) || (shift == 16) || (shift == 24)) &&
641 ((value == 0xff) || (value == 0xffff))) {
642 // Merge SHR into AND by emitting a UXTB or UXTH instruction with a
643 // bytewise rotation.
644 Emit((value == 0xff) ? kArmUxtb : kArmUxth,
645 g.DefineAsRegister(m.node()), g.UseRegister(mshr.left().node()),
646 g.TempImmediate(mshr.right().Value()));
647 return;
648 } else if (IsSupported(ARMv7) && (width != 0) &&
649 ((leading_zeros + width) == 32)) {
650 // Merge Shr into And by emitting a UBFX instruction.
651 DCHECK_EQ(0u, base::bits::CountTrailingZeros32(value));
652 if ((1 <= shift) && (shift <= 31)) {
653 // UBFX cannot extract bits past the register size, however since
654 // shifting the original value would have introduced some zeros we
655 // can still use UBFX with a smaller mask and the remaining bits
656 // will be zeros.
657 EmitUbfx(this, node, mshr.left().node(), shift,
658 std::min(width, 32 - shift));
659 return;
660 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000661 }
662 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100663 } else if (value == 0xffff) {
664 // Emit UXTH for this AND. We don't bother testing for UXTB, as it's no
665 // better than AND 0xff for this operation.
666 Emit(kArmUxth, g.DefineAsRegister(m.node()),
667 g.UseRegister(m.left().node()), g.TempImmediate(0));
668 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400669 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400670 if (g.CanBeImmediate(~value)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100671 // Emit BIC for this AND by inverting the immediate value first.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400672 Emit(kArmBic | AddressingModeField::encode(kMode_Operand2_I),
673 g.DefineAsRegister(node), g.UseRegister(m.left().node()),
674 g.TempImmediate(~value));
675 return;
676 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100677 if (!g.CanBeImmediate(value) && IsSupported(ARMv7)) {
678 // If value has 9 to 23 contiguous set bits, and has the lsb set, we can
679 // replace this AND with UBFX. Other contiguous bit patterns have already
680 // been handled by BIC or will be handled by AND.
681 if ((width != 0) && ((leading_zeros + width) == 32) &&
682 (9 <= leading_zeros) && (leading_zeros <= 23)) {
683 DCHECK_EQ(0u, base::bits::CountTrailingZeros32(value));
684 EmitUbfx(this, node, m.left().node(), 0, width);
685 return;
686 }
687
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400688 width = 32 - width;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100689 leading_zeros = base::bits::CountLeadingZeros32(~value);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400690 uint32_t lsb = base::bits::CountTrailingZeros32(~value);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100691 if ((leading_zeros + width + lsb) == 32) {
692 // This AND can be replaced with BFC.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400693 Emit(kArmBfc, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
694 g.TempImmediate(lsb), g.TempImmediate(width));
695 return;
696 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000697 }
698 }
699 VisitBinop(this, node, kArmAnd, kArmAnd);
700}
701
702
703void InstructionSelector::VisitWord32Or(Node* node) {
704 VisitBinop(this, node, kArmOrr, kArmOrr);
705}
706
707
708void InstructionSelector::VisitWord32Xor(Node* node) {
709 ArmOperandGenerator g(this);
710 Int32BinopMatcher m(node);
711 if (m.right().Is(-1)) {
712 InstructionCode opcode = kArmMvn;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000713 InstructionOperand value_operand;
714 InstructionOperand shift_operand;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000715 if (TryMatchShift(this, &opcode, m.left().node(), &value_operand,
716 &shift_operand)) {
717 Emit(opcode, g.DefineAsRegister(node), value_operand, shift_operand);
718 return;
719 }
720 Emit(opcode | AddressingModeField::encode(kMode_Operand2_R),
721 g.DefineAsRegister(node), g.UseRegister(m.left().node()));
722 return;
723 }
724 VisitBinop(this, node, kArmEor, kArmEor);
725}
726
727
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000728namespace {
729
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000730template <typename TryMatchShift>
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000731void VisitShift(InstructionSelector* selector, Node* node,
732 TryMatchShift try_match_shift, FlagsContinuation* cont) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000733 ArmOperandGenerator g(selector);
734 InstructionCode opcode = kArmMov;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000735 InstructionOperand inputs[4];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000736 size_t input_count = 2;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000737 InstructionOperand outputs[2];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000738 size_t output_count = 0;
739
740 CHECK(try_match_shift(selector, &opcode, node, &inputs[0], &inputs[1]));
741
742 if (cont->IsBranch()) {
743 inputs[input_count++] = g.Label(cont->true_block());
744 inputs[input_count++] = g.Label(cont->false_block());
745 }
746
747 outputs[output_count++] = g.DefineAsRegister(node);
748 if (cont->IsSet()) {
749 outputs[output_count++] = g.DefineAsRegister(cont->result());
750 }
751
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000752 DCHECK_NE(0u, input_count);
753 DCHECK_NE(0u, output_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000754 DCHECK_GE(arraysize(inputs), input_count);
755 DCHECK_GE(arraysize(outputs), output_count);
756 DCHECK_NE(kMode_None, AddressingModeField::decode(opcode));
757
Ben Murdochda12d292016-06-02 14:46:10 +0100758 opcode = cont->Encode(opcode);
759 if (cont->IsDeoptimize()) {
760 selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
761 cont->frame_state());
762 } else {
763 selector->Emit(opcode, output_count, outputs, input_count, inputs);
764 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000765}
766
767
768template <typename TryMatchShift>
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000769void VisitShift(InstructionSelector* selector, Node* node,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000770 TryMatchShift try_match_shift) {
771 FlagsContinuation cont;
772 VisitShift(selector, node, try_match_shift, &cont);
773}
774
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000775} // namespace
776
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000777
778void InstructionSelector::VisitWord32Shl(Node* node) {
779 VisitShift(this, node, TryMatchLSL);
780}
781
782
783void InstructionSelector::VisitWord32Shr(Node* node) {
784 ArmOperandGenerator g(this);
785 Int32BinopMatcher m(node);
786 if (IsSupported(ARMv7) && m.left().IsWord32And() &&
787 m.right().IsInRange(0, 31)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000788 uint32_t lsb = m.right().Value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000789 Int32BinopMatcher mleft(m.left().node());
790 if (mleft.right().HasValue()) {
791 uint32_t value = (mleft.right().Value() >> lsb) << lsb;
792 uint32_t width = base::bits::CountPopulation32(value);
793 uint32_t msb = base::bits::CountLeadingZeros32(value);
794 if (msb + width + lsb == 32) {
795 DCHECK_EQ(lsb, base::bits::CountTrailingZeros32(value));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400796 return EmitUbfx(this, node, mleft.left().node(), lsb, width);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000797 }
798 }
799 }
800 VisitShift(this, node, TryMatchLSR);
801}
802
803
804void InstructionSelector::VisitWord32Sar(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400805 ArmOperandGenerator g(this);
806 Int32BinopMatcher m(node);
807 if (CanCover(m.node(), m.left().node()) && m.left().IsWord32Shl()) {
808 Int32BinopMatcher mleft(m.left().node());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100809 if (m.right().HasValue() && mleft.right().HasValue()) {
810 uint32_t sar = m.right().Value();
811 uint32_t shl = mleft.right().Value();
812 if ((sar == shl) && (sar == 16)) {
813 Emit(kArmSxth, g.DefineAsRegister(node),
814 g.UseRegister(mleft.left().node()), g.TempImmediate(0));
815 return;
816 } else if ((sar == shl) && (sar == 24)) {
817 Emit(kArmSxtb, g.DefineAsRegister(node),
818 g.UseRegister(mleft.left().node()), g.TempImmediate(0));
819 return;
820 } else if (IsSupported(ARMv7) && (sar >= shl)) {
821 Emit(kArmSbfx, g.DefineAsRegister(node),
822 g.UseRegister(mleft.left().node()), g.TempImmediate(sar - shl),
823 g.TempImmediate(32 - sar));
824 return;
825 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400826 }
827 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000828 VisitShift(this, node, TryMatchASR);
829}
830
Ben Murdochda12d292016-06-02 14:46:10 +0100831void InstructionSelector::VisitInt32PairAdd(Node* node) {
832 ArmOperandGenerator g(this);
833
834 // We use UseUniqueRegister here to avoid register sharing with the output
835 // registers.
836 InstructionOperand inputs[] = {
837 g.UseRegister(node->InputAt(0)), g.UseUniqueRegister(node->InputAt(1)),
838 g.UseRegister(node->InputAt(2)), g.UseUniqueRegister(node->InputAt(3))};
839
840 InstructionOperand outputs[] = {
841 g.DefineAsRegister(node),
842 g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
843
844 Emit(kArmAddPair, 2, outputs, 4, inputs);
845}
846
847void InstructionSelector::VisitInt32PairSub(Node* node) {
848 ArmOperandGenerator g(this);
849
850 // We use UseUniqueRegister here to avoid register sharing with the output
851 // register.
852 InstructionOperand inputs[] = {
853 g.UseRegister(node->InputAt(0)), g.UseUniqueRegister(node->InputAt(1)),
854 g.UseRegister(node->InputAt(2)), g.UseUniqueRegister(node->InputAt(3))};
855
856 InstructionOperand outputs[] = {
857 g.DefineAsRegister(node),
858 g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
859
860 Emit(kArmSubPair, 2, outputs, 4, inputs);
861}
862
863void InstructionSelector::VisitInt32PairMul(Node* node) {
864 ArmOperandGenerator g(this);
865 InstructionOperand inputs[] = {g.UseUniqueRegister(node->InputAt(0)),
866 g.UseUniqueRegister(node->InputAt(1)),
867 g.UseUniqueRegister(node->InputAt(2)),
868 g.UseUniqueRegister(node->InputAt(3))};
869
870 InstructionOperand outputs[] = {
871 g.DefineAsRegister(node),
872 g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
873
874 Emit(kArmMulPair, 2, outputs, 4, inputs);
875}
876
877void InstructionSelector::VisitWord32PairShl(Node* node) {
878 ArmOperandGenerator g(this);
879 // We use g.UseUniqueRegister here for InputAt(0) to guarantee that there is
880 // no register aliasing with output registers.
881 Int32Matcher m(node->InputAt(2));
882 InstructionOperand shift_operand;
883 if (m.HasValue()) {
884 shift_operand = g.UseImmediate(m.node());
885 } else {
886 shift_operand = g.UseUniqueRegister(m.node());
887 }
888
889 InstructionOperand inputs[] = {g.UseUniqueRegister(node->InputAt(0)),
890 g.UseRegister(node->InputAt(1)),
891 shift_operand};
892
893 InstructionOperand outputs[] = {
894 g.DefineAsRegister(node),
895 g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
896
897 Emit(kArmLslPair, 2, outputs, 3, inputs);
898}
899
900void InstructionSelector::VisitWord32PairShr(Node* node) {
901 ArmOperandGenerator g(this);
902 // We use g.UseUniqueRegister here for InputAt(1) and InputAt(2) to to
903 // guarantee that there is no register aliasing with output register.
904 Int32Matcher m(node->InputAt(2));
905 InstructionOperand shift_operand;
906 if (m.HasValue()) {
907 shift_operand = g.UseImmediate(m.node());
908 } else {
909 shift_operand = g.UseUniqueRegister(m.node());
910 }
911
912 InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0)),
913 g.UseUniqueRegister(node->InputAt(1)),
914 shift_operand};
915
916 InstructionOperand outputs[] = {
917 g.DefineAsRegister(node),
918 g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
919
920 Emit(kArmLsrPair, 2, outputs, 3, inputs);
921}
922
923void InstructionSelector::VisitWord32PairSar(Node* node) {
924 ArmOperandGenerator g(this);
925 // We use g.UseUniqueRegister here for InputAt(1) and InputAt(2) to to
926 // guarantee that there is no register aliasing with output register.
927 Int32Matcher m(node->InputAt(2));
928 InstructionOperand shift_operand;
929 if (m.HasValue()) {
930 shift_operand = g.UseImmediate(m.node());
931 } else {
932 shift_operand = g.UseUniqueRegister(m.node());
933 }
934
935 InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0)),
936 g.UseUniqueRegister(node->InputAt(1)),
937 shift_operand};
938
939 InstructionOperand outputs[] = {
940 g.DefineAsRegister(node),
941 g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
942
943 Emit(kArmAsrPair, 2, outputs, 3, inputs);
944}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000945
946void InstructionSelector::VisitWord32Ror(Node* node) {
947 VisitShift(this, node, TryMatchROR);
948}
949
950
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000951void InstructionSelector::VisitWord32Clz(Node* node) {
952 VisitRR(this, kArmClz, node);
953}
954
955
956void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); }
957
958
Ben Murdoch097c5b22016-05-18 11:27:45 +0100959void InstructionSelector::VisitWord32ReverseBits(Node* node) {
960 DCHECK(IsSupported(ARMv7));
961 VisitRR(this, kArmRbit, node);
962}
963
964
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000965void InstructionSelector::VisitWord32Popcnt(Node* node) { UNREACHABLE(); }
966
967
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000968void InstructionSelector::VisitInt32Add(Node* node) {
969 ArmOperandGenerator g(this);
970 Int32BinopMatcher m(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400971 if (CanCover(node, m.left().node())) {
972 switch (m.left().opcode()) {
973 case IrOpcode::kInt32Mul: {
974 Int32BinopMatcher mleft(m.left().node());
975 Emit(kArmMla, g.DefineAsRegister(node),
976 g.UseRegister(mleft.left().node()),
977 g.UseRegister(mleft.right().node()),
978 g.UseRegister(m.right().node()));
979 return;
980 }
981 case IrOpcode::kInt32MulHigh: {
982 Int32BinopMatcher mleft(m.left().node());
983 Emit(kArmSmmla, g.DefineAsRegister(node),
984 g.UseRegister(mleft.left().node()),
985 g.UseRegister(mleft.right().node()),
986 g.UseRegister(m.right().node()));
987 return;
988 }
989 case IrOpcode::kWord32And: {
990 Int32BinopMatcher mleft(m.left().node());
991 if (mleft.right().Is(0xff)) {
992 Emit(kArmUxtab, g.DefineAsRegister(node),
993 g.UseRegister(m.right().node()),
994 g.UseRegister(mleft.left().node()), g.TempImmediate(0));
995 return;
996 } else if (mleft.right().Is(0xffff)) {
997 Emit(kArmUxtah, g.DefineAsRegister(node),
998 g.UseRegister(m.right().node()),
999 g.UseRegister(mleft.left().node()), g.TempImmediate(0));
1000 return;
1001 }
1002 }
1003 case IrOpcode::kWord32Sar: {
1004 Int32BinopMatcher mleft(m.left().node());
1005 if (CanCover(mleft.node(), mleft.left().node()) &&
1006 mleft.left().IsWord32Shl()) {
1007 Int32BinopMatcher mleftleft(mleft.left().node());
1008 if (mleft.right().Is(24) && mleftleft.right().Is(24)) {
1009 Emit(kArmSxtab, g.DefineAsRegister(node),
1010 g.UseRegister(m.right().node()),
1011 g.UseRegister(mleftleft.left().node()), g.TempImmediate(0));
1012 return;
1013 } else if (mleft.right().Is(16) && mleftleft.right().Is(16)) {
1014 Emit(kArmSxtah, g.DefineAsRegister(node),
1015 g.UseRegister(m.right().node()),
1016 g.UseRegister(mleftleft.left().node()), g.TempImmediate(0));
1017 return;
1018 }
1019 }
1020 }
1021 default:
1022 break;
1023 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001024 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001025 if (CanCover(node, m.right().node())) {
1026 switch (m.right().opcode()) {
1027 case IrOpcode::kInt32Mul: {
1028 Int32BinopMatcher mright(m.right().node());
1029 Emit(kArmMla, g.DefineAsRegister(node),
1030 g.UseRegister(mright.left().node()),
1031 g.UseRegister(mright.right().node()),
1032 g.UseRegister(m.left().node()));
1033 return;
1034 }
1035 case IrOpcode::kInt32MulHigh: {
1036 Int32BinopMatcher mright(m.right().node());
1037 Emit(kArmSmmla, g.DefineAsRegister(node),
1038 g.UseRegister(mright.left().node()),
1039 g.UseRegister(mright.right().node()),
1040 g.UseRegister(m.left().node()));
1041 return;
1042 }
1043 case IrOpcode::kWord32And: {
1044 Int32BinopMatcher mright(m.right().node());
1045 if (mright.right().Is(0xff)) {
1046 Emit(kArmUxtab, g.DefineAsRegister(node),
1047 g.UseRegister(m.left().node()),
1048 g.UseRegister(mright.left().node()), g.TempImmediate(0));
1049 return;
1050 } else if (mright.right().Is(0xffff)) {
1051 Emit(kArmUxtah, g.DefineAsRegister(node),
1052 g.UseRegister(m.left().node()),
1053 g.UseRegister(mright.left().node()), g.TempImmediate(0));
1054 return;
1055 }
1056 }
1057 case IrOpcode::kWord32Sar: {
1058 Int32BinopMatcher mright(m.right().node());
1059 if (CanCover(mright.node(), mright.left().node()) &&
1060 mright.left().IsWord32Shl()) {
1061 Int32BinopMatcher mrightleft(mright.left().node());
1062 if (mright.right().Is(24) && mrightleft.right().Is(24)) {
1063 Emit(kArmSxtab, g.DefineAsRegister(node),
1064 g.UseRegister(m.left().node()),
1065 g.UseRegister(mrightleft.left().node()), g.TempImmediate(0));
1066 return;
1067 } else if (mright.right().Is(16) && mrightleft.right().Is(16)) {
1068 Emit(kArmSxtah, g.DefineAsRegister(node),
1069 g.UseRegister(m.left().node()),
1070 g.UseRegister(mrightleft.left().node()), g.TempImmediate(0));
1071 return;
1072 }
1073 }
1074 }
1075 default:
1076 break;
1077 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001078 }
1079 VisitBinop(this, node, kArmAdd, kArmAdd);
1080}
1081
1082
1083void InstructionSelector::VisitInt32Sub(Node* node) {
1084 ArmOperandGenerator g(this);
1085 Int32BinopMatcher m(node);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001086 if (IsSupported(ARMv7) && m.right().IsInt32Mul() &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001087 CanCover(node, m.right().node())) {
1088 Int32BinopMatcher mright(m.right().node());
1089 Emit(kArmMls, g.DefineAsRegister(node), g.UseRegister(mright.left().node()),
1090 g.UseRegister(mright.right().node()), g.UseRegister(m.left().node()));
1091 return;
1092 }
1093 VisitBinop(this, node, kArmSub, kArmRsb);
1094}
1095
1096
1097void InstructionSelector::VisitInt32Mul(Node* node) {
1098 ArmOperandGenerator g(this);
1099 Int32BinopMatcher m(node);
1100 if (m.right().HasValue() && m.right().Value() > 0) {
1101 int32_t value = m.right().Value();
1102 if (base::bits::IsPowerOfTwo32(value - 1)) {
1103 Emit(kArmAdd | AddressingModeField::encode(kMode_Operand2_R_LSL_I),
1104 g.DefineAsRegister(node), g.UseRegister(m.left().node()),
1105 g.UseRegister(m.left().node()),
1106 g.TempImmediate(WhichPowerOf2(value - 1)));
1107 return;
1108 }
1109 if (value < kMaxInt && base::bits::IsPowerOfTwo32(value + 1)) {
1110 Emit(kArmRsb | AddressingModeField::encode(kMode_Operand2_R_LSL_I),
1111 g.DefineAsRegister(node), g.UseRegister(m.left().node()),
1112 g.UseRegister(m.left().node()),
1113 g.TempImmediate(WhichPowerOf2(value + 1)));
1114 return;
1115 }
1116 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001117 VisitRRR(this, kArmMul, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001118}
1119
1120
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001121void InstructionSelector::VisitInt32MulHigh(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001122 VisitRRR(this, kArmSmmul, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001123}
1124
1125
1126void InstructionSelector::VisitUint32MulHigh(Node* node) {
1127 ArmOperandGenerator g(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001128 InstructionOperand outputs[] = {g.TempRegister(), g.DefineAsRegister(node)};
1129 InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0)),
1130 g.UseRegister(node->InputAt(1))};
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001131 Emit(kArmUmull, arraysize(outputs), outputs, arraysize(inputs), inputs);
1132}
1133
1134
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001135void InstructionSelector::VisitInt32Div(Node* node) {
1136 VisitDiv(this, node, kArmSdiv, kArmVcvtF64S32, kArmVcvtS32F64);
1137}
1138
1139
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001140void InstructionSelector::VisitUint32Div(Node* node) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001141 VisitDiv(this, node, kArmUdiv, kArmVcvtF64U32, kArmVcvtU32F64);
1142}
1143
1144
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001145void InstructionSelector::VisitInt32Mod(Node* node) {
1146 VisitMod(this, node, kArmSdiv, kArmVcvtF64S32, kArmVcvtS32F64);
1147}
1148
1149
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001150void InstructionSelector::VisitUint32Mod(Node* node) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001151 VisitMod(this, node, kArmUdiv, kArmVcvtF64U32, kArmVcvtU32F64);
1152}
1153
1154
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001155void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001156 VisitRR(this, kArmVcvtF64F32, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001157}
1158
1159
Ben Murdoch097c5b22016-05-18 11:27:45 +01001160void InstructionSelector::VisitRoundInt32ToFloat32(Node* node) {
1161 VisitRR(this, kArmVcvtF32S32, node);
1162}
1163
1164
1165void InstructionSelector::VisitRoundUint32ToFloat32(Node* node) {
1166 VisitRR(this, kArmVcvtF32U32, node);
1167}
1168
1169
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001170void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001171 VisitRR(this, kArmVcvtF64S32, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001172}
1173
1174
1175void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001176 VisitRR(this, kArmVcvtF64U32, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001177}
1178
1179
Ben Murdoch097c5b22016-05-18 11:27:45 +01001180void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) {
1181 VisitRR(this, kArmVcvtS32F32, node);
1182}
1183
1184
1185void InstructionSelector::VisitTruncateFloat32ToUint32(Node* node) {
1186 VisitRR(this, kArmVcvtU32F32, node);
1187}
1188
1189
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001190void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001191 VisitRR(this, kArmVcvtS32F64, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001192}
1193
1194
1195void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001196 VisitRR(this, kArmVcvtU32F64, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001197}
1198
Ben Murdochda12d292016-06-02 14:46:10 +01001199void InstructionSelector::VisitTruncateFloat64ToUint32(Node* node) {
1200 VisitRR(this, kArmVcvtU32F64, node);
1201}
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001202void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001203 VisitRR(this, kArmVcvtF32F64, node);
1204}
1205
Ben Murdochc5610432016-08-08 18:44:38 +01001206void InstructionSelector::VisitTruncateFloat64ToWord32(Node* node) {
1207 VisitRR(this, kArchTruncateDoubleToI, node);
1208}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001209
Ben Murdochc5610432016-08-08 18:44:38 +01001210void InstructionSelector::VisitRoundFloat64ToInt32(Node* node) {
1211 VisitRR(this, kArmVcvtS32F64, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001212}
1213
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001214void InstructionSelector::VisitBitcastFloat32ToInt32(Node* node) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001215 VisitRR(this, kArmVmovU32F32, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001216}
1217
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001218void InstructionSelector::VisitBitcastInt32ToFloat32(Node* node) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001219 VisitRR(this, kArmVmovF32U32, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001220}
1221
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001222void InstructionSelector::VisitFloat32Add(Node* node) {
1223 ArmOperandGenerator g(this);
1224 Float32BinopMatcher m(node);
1225 if (m.left().IsFloat32Mul() && CanCover(node, m.left().node())) {
1226 Float32BinopMatcher mleft(m.left().node());
1227 Emit(kArmVmlaF32, g.DefineSameAsFirst(node),
1228 g.UseRegister(m.right().node()), g.UseRegister(mleft.left().node()),
1229 g.UseRegister(mleft.right().node()));
1230 return;
1231 }
1232 if (m.right().IsFloat32Mul() && CanCover(node, m.right().node())) {
1233 Float32BinopMatcher mright(m.right().node());
1234 Emit(kArmVmlaF32, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
1235 g.UseRegister(mright.left().node()),
1236 g.UseRegister(mright.right().node()));
1237 return;
1238 }
1239 VisitRRR(this, kArmVaddF32, node);
1240}
1241
1242
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001243void InstructionSelector::VisitFloat64Add(Node* node) {
1244 ArmOperandGenerator g(this);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001245 Float64BinopMatcher m(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001246 if (m.left().IsFloat64Mul() && CanCover(node, m.left().node())) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001247 Float64BinopMatcher mleft(m.left().node());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001248 Emit(kArmVmlaF64, g.DefineSameAsFirst(node),
1249 g.UseRegister(m.right().node()), g.UseRegister(mleft.left().node()),
1250 g.UseRegister(mleft.right().node()));
1251 return;
1252 }
1253 if (m.right().IsFloat64Mul() && CanCover(node, m.right().node())) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001254 Float64BinopMatcher mright(m.right().node());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001255 Emit(kArmVmlaF64, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
1256 g.UseRegister(mright.left().node()),
1257 g.UseRegister(mright.right().node()));
1258 return;
1259 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001260 VisitRRR(this, kArmVaddF64, node);
1261}
1262
Ben Murdochc5610432016-08-08 18:44:38 +01001263namespace {
1264void VisitFloat32SubHelper(InstructionSelector* selector, Node* node) {
1265 ArmOperandGenerator g(selector);
1266 Float32BinopMatcher m(node);
1267 if (m.right().IsFloat32Mul() && selector->CanCover(node, m.right().node())) {
1268 Float32BinopMatcher mright(m.right().node());
1269 selector->Emit(kArmVmlsF32, g.DefineSameAsFirst(node),
1270 g.UseRegister(m.left().node()),
1271 g.UseRegister(mright.left().node()),
1272 g.UseRegister(mright.right().node()));
1273 return;
1274 }
1275 VisitRRR(selector, kArmVsubF32, node);
1276}
1277
1278void VisitFloat64SubHelper(InstructionSelector* selector, Node* node) {
1279 ArmOperandGenerator g(selector);
1280 Float64BinopMatcher m(node);
1281 if (m.right().IsFloat64Mul() && selector->CanCover(node, m.right().node())) {
1282 Float64BinopMatcher mright(m.right().node());
1283 selector->Emit(kArmVmlsF64, g.DefineSameAsFirst(node),
1284 g.UseRegister(m.left().node()),
1285 g.UseRegister(mright.left().node()),
1286 g.UseRegister(mright.right().node()));
1287 return;
1288 }
1289 VisitRRR(selector, kArmVsubF64, node);
1290}
1291} // namespace
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001292
1293void InstructionSelector::VisitFloat32Sub(Node* node) {
1294 ArmOperandGenerator g(this);
1295 Float32BinopMatcher m(node);
1296 if (m.left().IsMinusZero()) {
1297 Emit(kArmVnegF32, g.DefineAsRegister(node),
1298 g.UseRegister(m.right().node()));
1299 return;
1300 }
Ben Murdochc5610432016-08-08 18:44:38 +01001301 VisitFloat32SubHelper(this, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001302}
1303
Ben Murdochc5610432016-08-08 18:44:38 +01001304void InstructionSelector::VisitFloat32SubPreserveNan(Node* node) {
1305 VisitFloat32SubHelper(this, node);
1306}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001307
1308void InstructionSelector::VisitFloat64Sub(Node* node) {
1309 ArmOperandGenerator g(this);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001310 Float64BinopMatcher m(node);
1311 if (m.left().IsMinusZero()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001312 if (m.right().IsFloat64RoundDown() &&
1313 CanCover(m.node(), m.right().node())) {
1314 if (m.right().InputAt(0)->opcode() == IrOpcode::kFloat64Sub &&
1315 CanCover(m.right().node(), m.right().InputAt(0))) {
1316 Float64BinopMatcher mright0(m.right().InputAt(0));
1317 if (mright0.left().IsMinusZero()) {
1318 Emit(kArmVrintpF64, g.DefineAsRegister(node),
1319 g.UseRegister(mright0.right().node()));
1320 return;
1321 }
1322 }
1323 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001324 Emit(kArmVnegF64, g.DefineAsRegister(node),
1325 g.UseRegister(m.right().node()));
1326 return;
1327 }
Ben Murdochc5610432016-08-08 18:44:38 +01001328 VisitFloat64SubHelper(this, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001329}
1330
Ben Murdochc5610432016-08-08 18:44:38 +01001331void InstructionSelector::VisitFloat64SubPreserveNan(Node* node) {
1332 VisitFloat64SubHelper(this, node);
1333}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001334
1335void InstructionSelector::VisitFloat32Mul(Node* node) {
1336 VisitRRR(this, kArmVmulF32, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001337}
1338
1339
1340void InstructionSelector::VisitFloat64Mul(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001341 VisitRRR(this, kArmVmulF64, node);
1342}
1343
1344
1345void InstructionSelector::VisitFloat32Div(Node* node) {
1346 VisitRRR(this, kArmVdivF32, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001347}
1348
1349
1350void InstructionSelector::VisitFloat64Div(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001351 VisitRRR(this, kArmVdivF64, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001352}
1353
1354
1355void InstructionSelector::VisitFloat64Mod(Node* node) {
1356 ArmOperandGenerator g(this);
1357 Emit(kArmVmodF64, g.DefineAsFixed(node, d0), g.UseFixed(node->InputAt(0), d0),
1358 g.UseFixed(node->InputAt(1), d1))->MarkAsCall();
1359}
1360
Ben Murdochc5610432016-08-08 18:44:38 +01001361void InstructionSelector::VisitFloat32Max(Node* node) {
1362 DCHECK(IsSupported(ARMv8));
1363 VisitRRR(this, kArmFloat32Max, node);
1364}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001365
Ben Murdochc5610432016-08-08 18:44:38 +01001366void InstructionSelector::VisitFloat64Max(Node* node) {
1367 DCHECK(IsSupported(ARMv8));
1368 VisitRRR(this, kArmFloat64Max, node);
1369}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001370
Ben Murdoch61f157c2016-09-16 13:49:30 +01001371void InstructionSelector::VisitFloat64SilenceNaN(Node* node) {
1372 VisitRR(this, kArmFloat64SilenceNaN, node);
1373}
1374
Ben Murdochc5610432016-08-08 18:44:38 +01001375void InstructionSelector::VisitFloat32Min(Node* node) {
1376 DCHECK(IsSupported(ARMv8));
1377 VisitRRR(this, kArmFloat32Min, node);
1378}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001379
Ben Murdochc5610432016-08-08 18:44:38 +01001380void InstructionSelector::VisitFloat64Min(Node* node) {
1381 DCHECK(IsSupported(ARMv8));
1382 VisitRRR(this, kArmFloat64Min, node);
1383}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001384
1385void InstructionSelector::VisitFloat32Abs(Node* node) {
1386 VisitRR(this, kArmVabsF32, node);
1387}
1388
1389
1390void InstructionSelector::VisitFloat64Abs(Node* node) {
1391 VisitRR(this, kArmVabsF64, node);
1392}
1393
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001394void InstructionSelector::VisitFloat32Sqrt(Node* node) {
1395 VisitRR(this, kArmVsqrtF32, node);
1396}
1397
1398
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001399void InstructionSelector::VisitFloat64Sqrt(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001400 VisitRR(this, kArmVsqrtF64, node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001401}
1402
1403
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001404void InstructionSelector::VisitFloat32RoundDown(Node* node) {
1405 VisitRR(this, kArmVrintmF32, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001406}
1407
1408
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001409void InstructionSelector::VisitFloat64RoundDown(Node* node) {
1410 VisitRR(this, kArmVrintmF64, node);
1411}
1412
1413
1414void InstructionSelector::VisitFloat32RoundUp(Node* node) {
1415 VisitRR(this, kArmVrintpF32, node);
1416}
1417
1418
1419void InstructionSelector::VisitFloat64RoundUp(Node* node) {
1420 VisitRR(this, kArmVrintpF64, node);
1421}
1422
1423
1424void InstructionSelector::VisitFloat32RoundTruncate(Node* node) {
1425 VisitRR(this, kArmVrintzF32, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001426}
1427
1428
1429void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001430 VisitRR(this, kArmVrintzF64, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001431}
1432
1433
1434void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001435 VisitRR(this, kArmVrintaF64, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001436}
1437
1438
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001439void InstructionSelector::VisitFloat32RoundTiesEven(Node* node) {
1440 VisitRR(this, kArmVrintnF32, node);
1441}
1442
1443
1444void InstructionSelector::VisitFloat64RoundTiesEven(Node* node) {
1445 VisitRR(this, kArmVrintnF64, node);
1446}
1447
Ben Murdoch61f157c2016-09-16 13:49:30 +01001448void InstructionSelector::VisitFloat32Neg(Node* node) {
1449 VisitRR(this, kArmVnegF32, node);
1450}
1451
1452void InstructionSelector::VisitFloat64Neg(Node* node) {
1453 VisitRR(this, kArmVnegF64, node);
1454}
1455
1456void InstructionSelector::VisitFloat64Ieee754Binop(Node* node,
1457 InstructionCode opcode) {
1458 ArmOperandGenerator g(this);
1459 Emit(opcode, g.DefineAsFixed(node, d0), g.UseFixed(node->InputAt(0), d0),
1460 g.UseFixed(node->InputAt(1), d1))
1461 ->MarkAsCall();
1462}
1463
1464void InstructionSelector::VisitFloat64Ieee754Unop(Node* node,
1465 InstructionCode opcode) {
1466 ArmOperandGenerator g(this);
1467 Emit(opcode, g.DefineAsFixed(node, d0), g.UseFixed(node->InputAt(0), d0))
1468 ->MarkAsCall();
1469}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001470
1471void InstructionSelector::EmitPrepareArguments(
1472 ZoneVector<PushParameter>* arguments, const CallDescriptor* descriptor,
1473 Node* node) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001474 ArmOperandGenerator g(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001475
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001476 // Prepare for C function call.
1477 if (descriptor->IsCFunctionCall()) {
1478 Emit(kArchPrepareCallCFunction |
1479 MiscField::encode(static_cast<int>(descriptor->CParameterCount())),
1480 0, nullptr, 0, nullptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001481
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001482 // Poke any stack arguments.
1483 for (size_t n = 0; n < arguments->size(); ++n) {
1484 PushParameter input = (*arguments)[n];
1485 if (input.node()) {
1486 int slot = static_cast<int>(n);
1487 Emit(kArmPoke | MiscField::encode(slot), g.NoOutput(),
1488 g.UseRegister(input.node()));
1489 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001490 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001491 } else {
1492 // Push any stack arguments.
1493 for (PushParameter input : base::Reversed(*arguments)) {
1494 // Skip any alignment holes in pushed nodes.
1495 if (input.node() == nullptr) continue;
1496 Emit(kArmPush, g.NoOutput(), g.UseRegister(input.node()));
1497 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001498 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001499}
1500
1501
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001502bool InstructionSelector::IsTailCallAddressImmediate() { return false; }
1503
Ben Murdochda12d292016-06-02 14:46:10 +01001504int InstructionSelector::GetTempsCountForTailCallFromJSFunction() { return 3; }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001505
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001506namespace {
1507
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001508// Shared routine for multiple compare operations.
1509void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
1510 InstructionOperand left, InstructionOperand right,
1511 FlagsContinuation* cont) {
1512 ArmOperandGenerator g(selector);
1513 opcode = cont->Encode(opcode);
1514 if (cont->IsBranch()) {
1515 selector->Emit(opcode, g.NoOutput(), left, right,
1516 g.Label(cont->true_block()), g.Label(cont->false_block()));
Ben Murdochda12d292016-06-02 14:46:10 +01001517 } else if (cont->IsDeoptimize()) {
1518 selector->EmitDeoptimize(opcode, g.NoOutput(), left, right,
1519 cont->frame_state());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001520 } else {
1521 DCHECK(cont->IsSet());
1522 selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
1523 }
1524}
1525
1526
1527// Shared routine for multiple float32 compare operations.
1528void VisitFloat32Compare(InstructionSelector* selector, Node* node,
1529 FlagsContinuation* cont) {
1530 ArmOperandGenerator g(selector);
1531 Float32BinopMatcher m(node);
1532 if (m.right().Is(0.0f)) {
1533 VisitCompare(selector, kArmVcmpF32, g.UseRegister(m.left().node()),
1534 g.UseImmediate(m.right().node()), cont);
1535 } else if (m.left().Is(0.0f)) {
1536 cont->Commute();
1537 VisitCompare(selector, kArmVcmpF32, g.UseRegister(m.right().node()),
1538 g.UseImmediate(m.left().node()), cont);
1539 } else {
1540 VisitCompare(selector, kArmVcmpF32, g.UseRegister(m.left().node()),
1541 g.UseRegister(m.right().node()), cont);
1542 }
1543}
1544
1545
1546// Shared routine for multiple float64 compare operations.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001547void VisitFloat64Compare(InstructionSelector* selector, Node* node,
1548 FlagsContinuation* cont) {
1549 ArmOperandGenerator g(selector);
1550 Float64BinopMatcher m(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001551 if (m.right().Is(0.0)) {
1552 VisitCompare(selector, kArmVcmpF64, g.UseRegister(m.left().node()),
1553 g.UseImmediate(m.right().node()), cont);
1554 } else if (m.left().Is(0.0)) {
1555 cont->Commute();
1556 VisitCompare(selector, kArmVcmpF64, g.UseRegister(m.right().node()),
1557 g.UseImmediate(m.left().node()), cont);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001558 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001559 VisitCompare(selector, kArmVcmpF64, g.UseRegister(m.left().node()),
1560 g.UseRegister(m.right().node()), cont);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001561 }
1562}
1563
1564
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001565// Shared routine for multiple word compare operations.
1566void VisitWordCompare(InstructionSelector* selector, Node* node,
1567 InstructionCode opcode, FlagsContinuation* cont) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001568 ArmOperandGenerator g(selector);
1569 Int32BinopMatcher m(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001570 InstructionOperand inputs[5];
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001571 size_t input_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001572 InstructionOperand outputs[1];
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001573 size_t output_count = 0;
1574
1575 if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(),
1576 &input_count, &inputs[1])) {
1577 inputs[0] = g.UseRegister(m.left().node());
1578 input_count++;
1579 } else if (TryMatchImmediateOrShift(selector, &opcode, m.left().node(),
1580 &input_count, &inputs[1])) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001581 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001582 inputs[0] = g.UseRegister(m.right().node());
1583 input_count++;
1584 } else {
1585 opcode |= AddressingModeField::encode(kMode_Operand2_R);
1586 inputs[input_count++] = g.UseRegister(m.left().node());
1587 inputs[input_count++] = g.UseRegister(m.right().node());
1588 }
1589
1590 if (cont->IsBranch()) {
1591 inputs[input_count++] = g.Label(cont->true_block());
1592 inputs[input_count++] = g.Label(cont->false_block());
Ben Murdochda12d292016-06-02 14:46:10 +01001593 } else if (cont->IsSet()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001594 outputs[output_count++] = g.DefineAsRegister(cont->result());
1595 }
1596
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001597 DCHECK_NE(0u, input_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001598 DCHECK_GE(arraysize(inputs), input_count);
1599 DCHECK_GE(arraysize(outputs), output_count);
1600
Ben Murdochda12d292016-06-02 14:46:10 +01001601 opcode = cont->Encode(opcode);
1602 if (cont->IsDeoptimize()) {
1603 selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
1604 cont->frame_state());
1605 } else {
1606 selector->Emit(opcode, output_count, outputs, input_count, inputs);
1607 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001608}
1609
1610
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001611void VisitWordCompare(InstructionSelector* selector, Node* node,
1612 FlagsContinuation* cont) {
1613 VisitWordCompare(selector, node, kArmCmp, cont);
1614}
1615
1616
1617// Shared routine for word comparisons against zero.
1618void VisitWordCompareZero(InstructionSelector* selector, Node* user,
1619 Node* value, FlagsContinuation* cont) {
1620 while (selector->CanCover(user, value)) {
1621 switch (value->opcode()) {
1622 case IrOpcode::kWord32Equal: {
1623 // Combine with comparisons against 0 by simply inverting the
1624 // continuation.
1625 Int32BinopMatcher m(value);
1626 if (m.right().Is(0)) {
1627 user = value;
1628 value = m.left().node();
1629 cont->Negate();
1630 continue;
1631 }
1632 cont->OverwriteAndNegateIfEqual(kEqual);
1633 return VisitWordCompare(selector, value, cont);
1634 }
1635 case IrOpcode::kInt32LessThan:
1636 cont->OverwriteAndNegateIfEqual(kSignedLessThan);
1637 return VisitWordCompare(selector, value, cont);
1638 case IrOpcode::kInt32LessThanOrEqual:
1639 cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
1640 return VisitWordCompare(selector, value, cont);
1641 case IrOpcode::kUint32LessThan:
1642 cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
1643 return VisitWordCompare(selector, value, cont);
1644 case IrOpcode::kUint32LessThanOrEqual:
1645 cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
1646 return VisitWordCompare(selector, value, cont);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001647 case IrOpcode::kFloat32Equal:
1648 cont->OverwriteAndNegateIfEqual(kEqual);
1649 return VisitFloat32Compare(selector, value, cont);
1650 case IrOpcode::kFloat32LessThan:
1651 cont->OverwriteAndNegateIfEqual(kFloatLessThan);
1652 return VisitFloat32Compare(selector, value, cont);
1653 case IrOpcode::kFloat32LessThanOrEqual:
1654 cont->OverwriteAndNegateIfEqual(kFloatLessThanOrEqual);
1655 return VisitFloat32Compare(selector, value, cont);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001656 case IrOpcode::kFloat64Equal:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001657 cont->OverwriteAndNegateIfEqual(kEqual);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001658 return VisitFloat64Compare(selector, value, cont);
1659 case IrOpcode::kFloat64LessThan:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001660 cont->OverwriteAndNegateIfEqual(kFloatLessThan);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001661 return VisitFloat64Compare(selector, value, cont);
1662 case IrOpcode::kFloat64LessThanOrEqual:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001663 cont->OverwriteAndNegateIfEqual(kFloatLessThanOrEqual);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001664 return VisitFloat64Compare(selector, value, cont);
1665 case IrOpcode::kProjection:
1666 // Check if this is the overflow output projection of an
1667 // <Operation>WithOverflow node.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001668 if (ProjectionIndexOf(value->op()) == 1u) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001669 // We cannot combine the <Operation>WithOverflow with this branch
1670 // unless the 0th projection (the use of the actual value of the
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001671 // <Operation> is either nullptr, which means there's no use of the
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001672 // actual value, or was already defined, which means it is scheduled
1673 // *AFTER* this branch).
1674 Node* const node = value->InputAt(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001675 Node* const result = NodeProperties::FindProjection(node, 0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001676 if (!result || selector->IsDefined(result)) {
1677 switch (node->opcode()) {
1678 case IrOpcode::kInt32AddWithOverflow:
1679 cont->OverwriteAndNegateIfEqual(kOverflow);
1680 return VisitBinop(selector, node, kArmAdd, kArmAdd, cont);
1681 case IrOpcode::kInt32SubWithOverflow:
1682 cont->OverwriteAndNegateIfEqual(kOverflow);
1683 return VisitBinop(selector, node, kArmSub, kArmRsb, cont);
1684 default:
1685 break;
1686 }
1687 }
1688 }
1689 break;
1690 case IrOpcode::kInt32Add:
1691 return VisitWordCompare(selector, value, kArmCmn, cont);
1692 case IrOpcode::kInt32Sub:
1693 return VisitWordCompare(selector, value, kArmCmp, cont);
1694 case IrOpcode::kWord32And:
1695 return VisitWordCompare(selector, value, kArmTst, cont);
1696 case IrOpcode::kWord32Or:
1697 return VisitBinop(selector, value, kArmOrr, kArmOrr, cont);
1698 case IrOpcode::kWord32Xor:
1699 return VisitWordCompare(selector, value, kArmTeq, cont);
1700 case IrOpcode::kWord32Sar:
1701 return VisitShift(selector, value, TryMatchASR, cont);
1702 case IrOpcode::kWord32Shl:
1703 return VisitShift(selector, value, TryMatchLSL, cont);
1704 case IrOpcode::kWord32Shr:
1705 return VisitShift(selector, value, TryMatchLSR, cont);
1706 case IrOpcode::kWord32Ror:
1707 return VisitShift(selector, value, TryMatchROR, cont);
1708 default:
1709 break;
1710 }
1711 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001712 }
1713
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001714 // Continuation could not be combined with a compare, emit compare against 0.
1715 ArmOperandGenerator g(selector);
1716 InstructionCode const opcode =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001717 cont->Encode(kArmTst) | AddressingModeField::encode(kMode_Operand2_R);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001718 InstructionOperand const value_operand = g.UseRegister(value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001719 if (cont->IsBranch()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001720 selector->Emit(opcode, g.NoOutput(), value_operand, value_operand,
1721 g.Label(cont->true_block()), g.Label(cont->false_block()));
Ben Murdochda12d292016-06-02 14:46:10 +01001722 } else if (cont->IsDeoptimize()) {
1723 selector->EmitDeoptimize(opcode, g.NoOutput(), value_operand, value_operand,
1724 cont->frame_state());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001725 } else {
Ben Murdochda12d292016-06-02 14:46:10 +01001726 DCHECK(cont->IsSet());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001727 selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand,
1728 value_operand);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001729 }
1730}
1731
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001732} // namespace
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001733
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001734void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
1735 BasicBlock* fbranch) {
1736 FlagsContinuation cont(kNotEqual, tbranch, fbranch);
1737 VisitWordCompareZero(this, branch, branch->InputAt(0), &cont);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001738}
1739
Ben Murdochda12d292016-06-02 14:46:10 +01001740void InstructionSelector::VisitDeoptimizeIf(Node* node) {
1741 FlagsContinuation cont =
1742 FlagsContinuation::ForDeoptimize(kNotEqual, node->InputAt(1));
1743 VisitWordCompareZero(this, node, node->InputAt(0), &cont);
1744}
1745
1746void InstructionSelector::VisitDeoptimizeUnless(Node* node) {
1747 FlagsContinuation cont =
1748 FlagsContinuation::ForDeoptimize(kEqual, node->InputAt(1));
1749 VisitWordCompareZero(this, node, node->InputAt(0), &cont);
1750}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001751
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001752void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
1753 ArmOperandGenerator g(this);
1754 InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
1755
1756 // Emit either ArchTableSwitch or ArchLookupSwitch.
1757 size_t table_space_cost = 4 + sw.value_range;
1758 size_t table_time_cost = 3;
1759 size_t lookup_space_cost = 3 + 2 * sw.case_count;
1760 size_t lookup_time_cost = sw.case_count;
1761 if (sw.case_count > 0 &&
1762 table_space_cost + 3 * table_time_cost <=
1763 lookup_space_cost + 3 * lookup_time_cost &&
1764 sw.min_value > std::numeric_limits<int32_t>::min()) {
1765 InstructionOperand index_operand = value_operand;
1766 if (sw.min_value) {
1767 index_operand = g.TempRegister();
1768 Emit(kArmSub | AddressingModeField::encode(kMode_Operand2_I),
1769 index_operand, value_operand, g.TempImmediate(sw.min_value));
1770 }
1771 // Generate a table lookup.
1772 return EmitTableSwitch(sw, index_operand);
1773 }
1774
1775 // Generate a sequence of conditional jumps.
1776 return EmitLookupSwitch(sw, value_operand);
1777}
1778
1779
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001780void InstructionSelector::VisitWord32Equal(Node* const node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001781 FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001782 Int32BinopMatcher m(node);
1783 if (m.right().Is(0)) {
1784 return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001785 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001786 VisitWordCompare(this, node, &cont);
1787}
1788
1789
1790void InstructionSelector::VisitInt32LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001791 FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001792 VisitWordCompare(this, node, &cont);
1793}
1794
1795
1796void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001797 FlagsContinuation cont =
1798 FlagsContinuation::ForSet(kSignedLessThanOrEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001799 VisitWordCompare(this, node, &cont);
1800}
1801
1802
1803void InstructionSelector::VisitUint32LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001804 FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001805 VisitWordCompare(this, node, &cont);
1806}
1807
1808
1809void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001810 FlagsContinuation cont =
1811 FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001812 VisitWordCompare(this, node, &cont);
1813}
1814
1815
1816void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001817 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
Ben Murdochda12d292016-06-02 14:46:10 +01001818 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001819 return VisitBinop(this, node, kArmAdd, kArmAdd, &cont);
1820 }
1821 FlagsContinuation cont;
1822 VisitBinop(this, node, kArmAdd, kArmAdd, &cont);
1823}
1824
1825
1826void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001827 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
Ben Murdochda12d292016-06-02 14:46:10 +01001828 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001829 return VisitBinop(this, node, kArmSub, kArmRsb, &cont);
1830 }
1831 FlagsContinuation cont;
1832 VisitBinop(this, node, kArmSub, kArmRsb, &cont);
1833}
1834
1835
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001836void InstructionSelector::VisitFloat32Equal(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001837 FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001838 VisitFloat32Compare(this, node, &cont);
1839}
1840
1841
1842void InstructionSelector::VisitFloat32LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001843 FlagsContinuation cont = FlagsContinuation::ForSet(kFloatLessThan, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001844 VisitFloat32Compare(this, node, &cont);
1845}
1846
1847
1848void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001849 FlagsContinuation cont =
1850 FlagsContinuation::ForSet(kFloatLessThanOrEqual, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001851 VisitFloat32Compare(this, node, &cont);
1852}
1853
1854
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001855void InstructionSelector::VisitFloat64Equal(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001856 FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001857 VisitFloat64Compare(this, node, &cont);
1858}
1859
1860
1861void InstructionSelector::VisitFloat64LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001862 FlagsContinuation cont = FlagsContinuation::ForSet(kFloatLessThan, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001863 VisitFloat64Compare(this, node, &cont);
1864}
1865
1866
1867void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001868 FlagsContinuation cont =
1869 FlagsContinuation::ForSet(kFloatLessThanOrEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001870 VisitFloat64Compare(this, node, &cont);
1871}
1872
1873
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001874void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) {
1875 VisitRR(this, kArmVmovLowU32F64, node);
1876}
1877
1878
1879void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) {
1880 VisitRR(this, kArmVmovHighU32F64, node);
1881}
1882
1883
1884void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) {
1885 ArmOperandGenerator g(this);
1886 Node* left = node->InputAt(0);
1887 Node* right = node->InputAt(1);
1888 if (left->opcode() == IrOpcode::kFloat64InsertHighWord32 &&
1889 CanCover(node, left)) {
1890 left = left->InputAt(1);
1891 Emit(kArmVmovF64U32U32, g.DefineAsRegister(node), g.UseRegister(right),
1892 g.UseRegister(left));
1893 return;
1894 }
1895 Emit(kArmVmovLowF64U32, g.DefineSameAsFirst(node), g.UseRegister(left),
1896 g.UseRegister(right));
1897}
1898
1899
1900void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
1901 ArmOperandGenerator g(this);
1902 Node* left = node->InputAt(0);
1903 Node* right = node->InputAt(1);
1904 if (left->opcode() == IrOpcode::kFloat64InsertLowWord32 &&
1905 CanCover(node, left)) {
1906 left = left->InputAt(1);
1907 Emit(kArmVmovF64U32U32, g.DefineAsRegister(node), g.UseRegister(left),
1908 g.UseRegister(right));
1909 return;
1910 }
1911 Emit(kArmVmovHighF64U32, g.DefineSameAsFirst(node), g.UseRegister(left),
1912 g.UseRegister(right));
1913}
1914
Ben Murdochc5610432016-08-08 18:44:38 +01001915void InstructionSelector::VisitAtomicLoad(Node* node) {
1916 LoadRepresentation load_rep = LoadRepresentationOf(node->op());
1917 ArmOperandGenerator g(this);
1918 Node* base = node->InputAt(0);
1919 Node* index = node->InputAt(1);
1920 ArchOpcode opcode = kArchNop;
1921 switch (load_rep.representation()) {
1922 case MachineRepresentation::kWord8:
1923 opcode = load_rep.IsSigned() ? kAtomicLoadInt8 : kAtomicLoadUint8;
1924 break;
1925 case MachineRepresentation::kWord16:
1926 opcode = load_rep.IsSigned() ? kAtomicLoadInt16 : kAtomicLoadUint16;
1927 break;
1928 case MachineRepresentation::kWord32:
1929 opcode = kAtomicLoadWord32;
1930 break;
1931 default:
1932 UNREACHABLE();
1933 return;
1934 }
1935 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR),
1936 g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(index));
1937}
1938
1939void InstructionSelector::VisitAtomicStore(Node* node) {
1940 MachineRepresentation rep = AtomicStoreRepresentationOf(node->op());
1941 ArmOperandGenerator g(this);
1942 Node* base = node->InputAt(0);
1943 Node* index = node->InputAt(1);
1944 Node* value = node->InputAt(2);
1945 ArchOpcode opcode = kArchNop;
1946 switch (rep) {
1947 case MachineRepresentation::kWord8:
1948 opcode = kAtomicStoreWord8;
1949 break;
1950 case MachineRepresentation::kWord16:
1951 opcode = kAtomicStoreWord16;
1952 break;
1953 case MachineRepresentation::kWord32:
1954 opcode = kAtomicStoreWord32;
1955 break;
1956 default:
1957 UNREACHABLE();
1958 return;
1959 }
1960
1961 AddressingMode addressing_mode = kMode_Offset_RR;
1962 InstructionOperand inputs[4];
1963 size_t input_count = 0;
1964 inputs[input_count++] = g.UseUniqueRegister(base);
1965 inputs[input_count++] = g.UseUniqueRegister(index);
1966 inputs[input_count++] = g.UseUniqueRegister(value);
1967 InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
1968 Emit(code, 0, nullptr, input_count, inputs);
1969}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001970
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001971// static
1972MachineOperatorBuilder::Flags
1973InstructionSelector::SupportedMachineOperatorFlags() {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001974 MachineOperatorBuilder::Flags flags;
1975 if (CpuFeatures::IsSupported(SUDIV)) {
1976 // The sdiv and udiv instructions correctly return 0 if the divisor is 0,
1977 // but the fall-back implementation does not.
1978 flags |= MachineOperatorBuilder::kInt32DivIsSafe |
1979 MachineOperatorBuilder::kUint32DivIsSafe;
1980 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001981 if (CpuFeatures::IsSupported(ARMv7)) {
1982 flags |= MachineOperatorBuilder::kWord32ReverseBits;
1983 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001984 if (CpuFeatures::IsSupported(ARMv8)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001985 flags |= MachineOperatorBuilder::kFloat32RoundDown |
1986 MachineOperatorBuilder::kFloat64RoundDown |
1987 MachineOperatorBuilder::kFloat32RoundUp |
1988 MachineOperatorBuilder::kFloat64RoundUp |
1989 MachineOperatorBuilder::kFloat32RoundTruncate |
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001990 MachineOperatorBuilder::kFloat64RoundTruncate |
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001991 MachineOperatorBuilder::kFloat64RoundTiesAway |
1992 MachineOperatorBuilder::kFloat32RoundTiesEven |
Ben Murdochc5610432016-08-08 18:44:38 +01001993 MachineOperatorBuilder::kFloat64RoundTiesEven |
1994 MachineOperatorBuilder::kFloat32Min |
1995 MachineOperatorBuilder::kFloat32Max |
1996 MachineOperatorBuilder::kFloat64Min |
Ben Murdoch61f157c2016-09-16 13:49:30 +01001997 MachineOperatorBuilder::kFloat64Max |
1998 MachineOperatorBuilder::kFloat32Neg |
1999 MachineOperatorBuilder::kFloat64Neg;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002000 }
2001 return flags;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002002}
2003
Ben Murdoch61f157c2016-09-16 13:49:30 +01002004// static
2005MachineOperatorBuilder::AlignmentRequirements
2006InstructionSelector::AlignmentRequirements() {
2007 return MachineOperatorBuilder::AlignmentRequirements::
2008 FullUnalignedAccessSupport();
2009}
2010
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002011} // namespace compiler
2012} // namespace internal
2013} // namespace v8