blob: 44a5470aca12dc22bbe189510022c4cc71719d35 [file] [log] [blame]
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001// 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"
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006#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"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010
11namespace v8 {
12namespace internal {
13namespace compiler {
14
15#define TRACE_UNIMPL() \
16 PrintF("UNIMPLEMENTED instr_sel: %s at line %d\n", __FUNCTION__, __LINE__)
17
18#define TRACE() PrintF("instr_sel: %s at line %d\n", __FUNCTION__, __LINE__)
19
20
21// Adds Mips-specific methods for generating InstructionOperands.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000022class Mips64OperandGenerator final : public OperandGenerator {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040023 public:
24 explicit Mips64OperandGenerator(InstructionSelector* selector)
25 : OperandGenerator(selector) {}
26
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000027 InstructionOperand UseOperand(Node* node, InstructionCode opcode) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040028 if (CanBeImmediate(node, opcode)) {
29 return UseImmediate(node);
30 }
31 return UseRegister(node);
32 }
33
34 bool CanBeImmediate(Node* node, InstructionCode opcode) {
35 int64_t value;
36 if (node->opcode() == IrOpcode::kInt32Constant)
37 value = OpParameter<int32_t>(node);
38 else if (node->opcode() == IrOpcode::kInt64Constant)
39 value = OpParameter<int64_t>(node);
40 else
41 return false;
42 switch (ArchOpcodeField::decode(opcode)) {
43 case kMips64Shl:
44 case kMips64Sar:
45 case kMips64Shr:
46 return is_uint5(value);
47 case kMips64Dshl:
48 case kMips64Dsar:
49 case kMips64Dshr:
50 return is_uint6(value);
51 case kMips64Xor:
52 return is_uint16(value);
53 case kMips64Ldc1:
54 case kMips64Sdc1:
55 return is_int16(value + kIntSize);
56 default:
57 return is_int16(value);
58 }
59 }
60
Emily Bernierd0a1eb72015-03-24 16:35:39 -040061 private:
62 bool ImmediateFitsAddrMode1Instruction(int32_t imm) const {
63 TRACE_UNIMPL();
64 return false;
65 }
66};
67
68
69static void VisitRR(InstructionSelector* selector, ArchOpcode opcode,
70 Node* node) {
71 Mips64OperandGenerator g(selector);
72 selector->Emit(opcode, g.DefineAsRegister(node),
73 g.UseRegister(node->InputAt(0)));
74}
75
76
77static void VisitRRR(InstructionSelector* selector, ArchOpcode opcode,
78 Node* node) {
79 Mips64OperandGenerator g(selector);
80 selector->Emit(opcode, g.DefineAsRegister(node),
81 g.UseRegister(node->InputAt(0)),
82 g.UseRegister(node->InputAt(1)));
83}
84
85
86static void VisitRRO(InstructionSelector* selector, ArchOpcode opcode,
87 Node* node) {
88 Mips64OperandGenerator g(selector);
89 selector->Emit(opcode, g.DefineAsRegister(node),
90 g.UseRegister(node->InputAt(0)),
91 g.UseOperand(node->InputAt(1), opcode));
92}
93
94
95static void VisitBinop(InstructionSelector* selector, Node* node,
96 InstructionCode opcode, FlagsContinuation* cont) {
97 Mips64OperandGenerator g(selector);
98 Int32BinopMatcher m(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000099 InstructionOperand inputs[4];
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400100 size_t input_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000101 InstructionOperand outputs[2];
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400102 size_t output_count = 0;
103
104 inputs[input_count++] = g.UseRegister(m.left().node());
105 inputs[input_count++] = g.UseOperand(m.right().node(), opcode);
106
107 if (cont->IsBranch()) {
108 inputs[input_count++] = g.Label(cont->true_block());
109 inputs[input_count++] = g.Label(cont->false_block());
110 }
111
112 outputs[output_count++] = g.DefineAsRegister(node);
113 if (cont->IsSet()) {
114 outputs[output_count++] = g.DefineAsRegister(cont->result());
115 }
116
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000117 DCHECK_NE(0u, input_count);
118 DCHECK_NE(0u, output_count);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400119 DCHECK_GE(arraysize(inputs), input_count);
120 DCHECK_GE(arraysize(outputs), output_count);
121
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000122 selector->Emit(cont->Encode(opcode), output_count, outputs, input_count,
123 inputs);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400124}
125
126
127static void VisitBinop(InstructionSelector* selector, Node* node,
128 InstructionCode opcode) {
129 FlagsContinuation cont;
130 VisitBinop(selector, node, opcode, &cont);
131}
132
133
134void InstructionSelector::VisitLoad(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000135 LoadRepresentation load_rep = LoadRepresentationOf(node->op());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400136 Mips64OperandGenerator g(this);
137 Node* base = node->InputAt(0);
138 Node* index = node->InputAt(1);
139
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000140 ArchOpcode opcode = kArchNop;
141 switch (load_rep.representation()) {
142 case MachineRepresentation::kFloat32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400143 opcode = kMips64Lwc1;
144 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000145 case MachineRepresentation::kFloat64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400146 opcode = kMips64Ldc1;
147 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000148 case MachineRepresentation::kBit: // Fall through.
149 case MachineRepresentation::kWord8:
150 opcode = load_rep.IsUnsigned() ? kMips64Lbu : kMips64Lb;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400151 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000152 case MachineRepresentation::kWord16:
153 opcode = load_rep.IsUnsigned() ? kMips64Lhu : kMips64Lh;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400154 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000155 case MachineRepresentation::kWord32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400156 opcode = kMips64Lw;
157 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000158 case MachineRepresentation::kTagged: // Fall through.
159 case MachineRepresentation::kWord64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400160 opcode = kMips64Ld;
161 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100162 case MachineRepresentation::kSimd128: // Fall through.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000163 case MachineRepresentation::kNone:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400164 UNREACHABLE();
165 return;
166 }
167
168 if (g.CanBeImmediate(index, opcode)) {
169 Emit(opcode | AddressingModeField::encode(kMode_MRI),
170 g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index));
171 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000172 InstructionOperand addr_reg = g.TempRegister();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400173 Emit(kMips64Dadd | AddressingModeField::encode(kMode_None), addr_reg,
174 g.UseRegister(index), g.UseRegister(base));
175 // Emit desired load opcode, using temp addr_reg.
176 Emit(opcode | AddressingModeField::encode(kMode_MRI),
177 g.DefineAsRegister(node), addr_reg, g.TempImmediate(0));
178 }
179}
180
181
182void InstructionSelector::VisitStore(Node* node) {
183 Mips64OperandGenerator g(this);
184 Node* base = node->InputAt(0);
185 Node* index = node->InputAt(1);
186 Node* value = node->InputAt(2);
187
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000188 StoreRepresentation store_rep = StoreRepresentationOf(node->op());
189 WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind();
190 MachineRepresentation rep = store_rep.representation();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400191
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000192 // TODO(mips): I guess this could be done in a better way.
193 if (write_barrier_kind != kNoWriteBarrier) {
194 DCHECK_EQ(MachineRepresentation::kTagged, rep);
195 InstructionOperand inputs[3];
196 size_t input_count = 0;
197 inputs[input_count++] = g.UseUniqueRegister(base);
198 inputs[input_count++] = g.UseUniqueRegister(index);
199 inputs[input_count++] = (write_barrier_kind == kMapWriteBarrier)
200 ? g.UseRegister(value)
201 : g.UseUniqueRegister(value);
202 RecordWriteMode record_write_mode = RecordWriteMode::kValueIsAny;
203 switch (write_barrier_kind) {
204 case kNoWriteBarrier:
205 UNREACHABLE();
206 break;
207 case kMapWriteBarrier:
208 record_write_mode = RecordWriteMode::kValueIsMap;
209 break;
210 case kPointerWriteBarrier:
211 record_write_mode = RecordWriteMode::kValueIsPointer;
212 break;
213 case kFullWriteBarrier:
214 record_write_mode = RecordWriteMode::kValueIsAny;
215 break;
216 }
217 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
218 size_t const temp_count = arraysize(temps);
219 InstructionCode code = kArchStoreWithWriteBarrier;
220 code |= MiscField::encode(static_cast<int>(record_write_mode));
221 Emit(code, 0, nullptr, input_count, inputs, temp_count, temps);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400222 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000223 ArchOpcode opcode = kArchNop;
224 switch (rep) {
225 case MachineRepresentation::kFloat32:
226 opcode = kMips64Swc1;
227 break;
228 case MachineRepresentation::kFloat64:
229 opcode = kMips64Sdc1;
230 break;
231 case MachineRepresentation::kBit: // Fall through.
232 case MachineRepresentation::kWord8:
233 opcode = kMips64Sb;
234 break;
235 case MachineRepresentation::kWord16:
236 opcode = kMips64Sh;
237 break;
238 case MachineRepresentation::kWord32:
239 opcode = kMips64Sw;
240 break;
241 case MachineRepresentation::kTagged: // Fall through.
242 case MachineRepresentation::kWord64:
243 opcode = kMips64Sd;
244 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100245 case MachineRepresentation::kSimd128: // Fall through.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000246 case MachineRepresentation::kNone:
247 UNREACHABLE();
248 return;
249 }
250
251 if (g.CanBeImmediate(index, opcode)) {
252 Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
253 g.UseRegister(base), g.UseImmediate(index), g.UseRegister(value));
254 } else {
255 InstructionOperand addr_reg = g.TempRegister();
256 Emit(kMips64Dadd | AddressingModeField::encode(kMode_None), addr_reg,
257 g.UseRegister(index), g.UseRegister(base));
258 // Emit desired store opcode, using temp addr_reg.
259 Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
260 addr_reg, g.TempImmediate(0), g.UseRegister(value));
261 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400262 }
263}
264
265
266void InstructionSelector::VisitWord32And(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000267 Mips64OperandGenerator g(this);
268 Int32BinopMatcher m(node);
269 if (m.left().IsWord32Shr() && CanCover(node, m.left().node()) &&
270 m.right().HasValue()) {
271 uint32_t mask = m.right().Value();
272 uint32_t mask_width = base::bits::CountPopulation32(mask);
273 uint32_t mask_msb = base::bits::CountLeadingZeros32(mask);
274 if ((mask_width != 0) && (mask_msb + mask_width == 32)) {
275 // The mask must be contiguous, and occupy the least-significant bits.
276 DCHECK_EQ(0u, base::bits::CountTrailingZeros32(mask));
277
278 // Select Ext for And(Shr(x, imm), mask) where the mask is in the least
279 // significant bits.
280 Int32BinopMatcher mleft(m.left().node());
281 if (mleft.right().HasValue()) {
282 // Any shift value can match; int32 shifts use `value % 32`.
283 uint32_t lsb = mleft.right().Value() & 0x1f;
284
285 // Ext cannot extract bits past the register size, however since
286 // shifting the original value would have introduced some zeros we can
287 // still use Ext with a smaller mask and the remaining bits will be
288 // zeros.
289 if (lsb + mask_width > 32) mask_width = 32 - lsb;
290
291 Emit(kMips64Ext, g.DefineAsRegister(node),
292 g.UseRegister(mleft.left().node()), g.TempImmediate(lsb),
293 g.TempImmediate(mask_width));
294 return;
295 }
296 // Other cases fall through to the normal And operation.
297 }
298 }
299 if (m.right().HasValue()) {
300 uint32_t mask = m.right().Value();
301 uint32_t shift = base::bits::CountPopulation32(~mask);
302 uint32_t msb = base::bits::CountLeadingZeros32(~mask);
303 if (shift != 0 && shift != 32 && msb + shift == 32) {
304 // Insert zeros for (x >> K) << K => x & ~(2^K - 1) expression reduction
305 // and remove constant loading of inverted mask.
306 Emit(kMips64Ins, g.DefineSameAsFirst(node),
307 g.UseRegister(m.left().node()), g.TempImmediate(0),
308 g.TempImmediate(shift));
309 return;
310 }
311 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400312 VisitBinop(this, node, kMips64And);
313}
314
315
316void InstructionSelector::VisitWord64And(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000317 Mips64OperandGenerator g(this);
318 Int64BinopMatcher m(node);
319 if (m.left().IsWord64Shr() && CanCover(node, m.left().node()) &&
320 m.right().HasValue()) {
321 uint64_t mask = m.right().Value();
322 uint32_t mask_width = base::bits::CountPopulation64(mask);
323 uint32_t mask_msb = base::bits::CountLeadingZeros64(mask);
324 if ((mask_width != 0) && (mask_msb + mask_width == 64)) {
325 // The mask must be contiguous, and occupy the least-significant bits.
326 DCHECK_EQ(0u, base::bits::CountTrailingZeros64(mask));
327
328 // Select Dext for And(Shr(x, imm), mask) where the mask is in the least
329 // significant bits.
330 Int64BinopMatcher mleft(m.left().node());
331 if (mleft.right().HasValue()) {
332 // Any shift value can match; int64 shifts use `value % 64`.
333 uint32_t lsb = static_cast<uint32_t>(mleft.right().Value() & 0x3f);
334
335 // Dext cannot extract bits past the register size, however since
336 // shifting the original value would have introduced some zeros we can
337 // still use Dext with a smaller mask and the remaining bits will be
338 // zeros.
339 if (lsb + mask_width > 64) mask_width = 64 - lsb;
340
341 Emit(kMips64Dext, g.DefineAsRegister(node),
342 g.UseRegister(mleft.left().node()), g.TempImmediate(lsb),
343 g.TempImmediate(static_cast<int32_t>(mask_width)));
344 return;
345 }
346 // Other cases fall through to the normal And operation.
347 }
348 }
349 if (m.right().HasValue()) {
350 uint64_t mask = m.right().Value();
351 uint32_t shift = base::bits::CountPopulation64(~mask);
352 uint32_t msb = base::bits::CountLeadingZeros64(~mask);
353 if (shift != 0 && shift < 32 && msb + shift == 64) {
354 // Insert zeros for (x >> K) << K => x & ~(2^K - 1) expression reduction
355 // and remove constant loading of inverted mask. Dins cannot insert bits
356 // past word size, so shifts smaller than 32 are covered.
357 Emit(kMips64Dins, g.DefineSameAsFirst(node),
358 g.UseRegister(m.left().node()), g.TempImmediate(0),
359 g.TempImmediate(shift));
360 return;
361 }
362 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400363 VisitBinop(this, node, kMips64And);
364}
365
366
367void InstructionSelector::VisitWord32Or(Node* node) {
368 VisitBinop(this, node, kMips64Or);
369}
370
371
372void InstructionSelector::VisitWord64Or(Node* node) {
373 VisitBinop(this, node, kMips64Or);
374}
375
376
377void InstructionSelector::VisitWord32Xor(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000378 Int32BinopMatcher m(node);
379 if (m.left().IsWord32Or() && CanCover(node, m.left().node()) &&
380 m.right().Is(-1)) {
381 Int32BinopMatcher mleft(m.left().node());
382 if (!mleft.right().HasValue()) {
383 Mips64OperandGenerator g(this);
384 Emit(kMips64Nor, g.DefineAsRegister(node),
385 g.UseRegister(mleft.left().node()),
386 g.UseRegister(mleft.right().node()));
387 return;
388 }
389 }
390 if (m.right().Is(-1)) {
391 // Use Nor for bit negation and eliminate constant loading for xori.
392 Mips64OperandGenerator g(this);
393 Emit(kMips64Nor, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
394 g.TempImmediate(0));
395 return;
396 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400397 VisitBinop(this, node, kMips64Xor);
398}
399
400
401void InstructionSelector::VisitWord64Xor(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000402 Int64BinopMatcher m(node);
403 if (m.left().IsWord64Or() && CanCover(node, m.left().node()) &&
404 m.right().Is(-1)) {
405 Int64BinopMatcher mleft(m.left().node());
406 if (!mleft.right().HasValue()) {
407 Mips64OperandGenerator g(this);
408 Emit(kMips64Nor, g.DefineAsRegister(node),
409 g.UseRegister(mleft.left().node()),
410 g.UseRegister(mleft.right().node()));
411 return;
412 }
413 }
414 if (m.right().Is(-1)) {
415 // Use Nor for bit negation and eliminate constant loading for xori.
416 Mips64OperandGenerator g(this);
417 Emit(kMips64Nor, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
418 g.TempImmediate(0));
419 return;
420 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400421 VisitBinop(this, node, kMips64Xor);
422}
423
424
425void InstructionSelector::VisitWord32Shl(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000426 Int32BinopMatcher m(node);
427 if (m.left().IsWord32And() && CanCover(node, m.left().node()) &&
428 m.right().IsInRange(1, 31)) {
429 Mips64OperandGenerator g(this);
430 Int32BinopMatcher mleft(m.left().node());
431 // Match Word32Shl(Word32And(x, mask), imm) to Shl where the mask is
432 // contiguous, and the shift immediate non-zero.
433 if (mleft.right().HasValue()) {
434 uint32_t mask = mleft.right().Value();
435 uint32_t mask_width = base::bits::CountPopulation32(mask);
436 uint32_t mask_msb = base::bits::CountLeadingZeros32(mask);
437 if ((mask_width != 0) && (mask_msb + mask_width == 32)) {
438 uint32_t shift = m.right().Value();
439 DCHECK_EQ(0u, base::bits::CountTrailingZeros32(mask));
440 DCHECK_NE(0u, shift);
441 if ((shift + mask_width) >= 32) {
442 // If the mask is contiguous and reaches or extends beyond the top
443 // bit, only the shift is needed.
444 Emit(kMips64Shl, g.DefineAsRegister(node),
445 g.UseRegister(mleft.left().node()),
446 g.UseImmediate(m.right().node()));
447 return;
448 }
449 }
450 }
451 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400452 VisitRRO(this, kMips64Shl, node);
453}
454
455
456void InstructionSelector::VisitWord32Shr(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000457 Int32BinopMatcher m(node);
458 if (m.left().IsWord32And() && m.right().HasValue()) {
459 uint32_t lsb = m.right().Value() & 0x1f;
460 Int32BinopMatcher mleft(m.left().node());
461 if (mleft.right().HasValue()) {
462 // Select Ext for Shr(And(x, mask), imm) where the result of the mask is
463 // shifted into the least-significant bits.
464 uint32_t mask = (mleft.right().Value() >> lsb) << lsb;
465 unsigned mask_width = base::bits::CountPopulation32(mask);
466 unsigned mask_msb = base::bits::CountLeadingZeros32(mask);
467 if ((mask_msb + mask_width + lsb) == 32) {
468 Mips64OperandGenerator g(this);
469 DCHECK_EQ(lsb, base::bits::CountTrailingZeros32(mask));
470 Emit(kMips64Ext, g.DefineAsRegister(node),
471 g.UseRegister(mleft.left().node()), g.TempImmediate(lsb),
472 g.TempImmediate(mask_width));
473 return;
474 }
475 }
476 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400477 VisitRRO(this, kMips64Shr, node);
478}
479
480
481void InstructionSelector::VisitWord32Sar(Node* node) {
482 VisitRRO(this, kMips64Sar, node);
483}
484
485
486void InstructionSelector::VisitWord64Shl(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000487 Mips64OperandGenerator g(this);
488 Int64BinopMatcher m(node);
489 if ((m.left().IsChangeInt32ToInt64() || m.left().IsChangeUint32ToUint64()) &&
490 m.right().IsInRange(32, 63)) {
491 // There's no need to sign/zero-extend to 64-bit if we shift out the upper
492 // 32 bits anyway.
493 Emit(kMips64Dshl, g.DefineSameAsFirst(node),
494 g.UseRegister(m.left().node()->InputAt(0)),
495 g.UseImmediate(m.right().node()));
496 return;
497 }
498 if (m.left().IsWord64And() && CanCover(node, m.left().node()) &&
499 m.right().IsInRange(1, 63)) {
500 // Match Word64Shl(Word64And(x, mask), imm) to Dshl where the mask is
501 // contiguous, and the shift immediate non-zero.
502 Int64BinopMatcher mleft(m.left().node());
503 if (mleft.right().HasValue()) {
504 uint64_t mask = mleft.right().Value();
505 uint32_t mask_width = base::bits::CountPopulation64(mask);
506 uint32_t mask_msb = base::bits::CountLeadingZeros64(mask);
507 if ((mask_width != 0) && (mask_msb + mask_width == 64)) {
508 uint64_t shift = m.right().Value();
509 DCHECK_EQ(0u, base::bits::CountTrailingZeros64(mask));
510 DCHECK_NE(0u, shift);
511
512 if ((shift + mask_width) >= 64) {
513 // If the mask is contiguous and reaches or extends beyond the top
514 // bit, only the shift is needed.
515 Emit(kMips64Dshl, g.DefineAsRegister(node),
516 g.UseRegister(mleft.left().node()),
517 g.UseImmediate(m.right().node()));
518 return;
519 }
520 }
521 }
522 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400523 VisitRRO(this, kMips64Dshl, node);
524}
525
526
527void InstructionSelector::VisitWord64Shr(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000528 Int64BinopMatcher m(node);
529 if (m.left().IsWord64And() && m.right().HasValue()) {
530 uint32_t lsb = m.right().Value() & 0x3f;
531 Int64BinopMatcher mleft(m.left().node());
532 if (mleft.right().HasValue()) {
533 // Select Dext for Shr(And(x, mask), imm) where the result of the mask is
534 // shifted into the least-significant bits.
535 uint64_t mask = (mleft.right().Value() >> lsb) << lsb;
536 unsigned mask_width = base::bits::CountPopulation64(mask);
537 unsigned mask_msb = base::bits::CountLeadingZeros64(mask);
538 if ((mask_msb + mask_width + lsb) == 64) {
539 Mips64OperandGenerator g(this);
540 DCHECK_EQ(lsb, base::bits::CountTrailingZeros64(mask));
541 Emit(kMips64Dext, g.DefineAsRegister(node),
542 g.UseRegister(mleft.left().node()), g.TempImmediate(lsb),
543 g.TempImmediate(mask_width));
544 return;
545 }
546 }
547 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400548 VisitRRO(this, kMips64Dshr, node);
549}
550
551
552void InstructionSelector::VisitWord64Sar(Node* node) {
553 VisitRRO(this, kMips64Dsar, node);
554}
555
556
557void InstructionSelector::VisitWord32Ror(Node* node) {
558 VisitRRO(this, kMips64Ror, node);
559}
560
561
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000562void InstructionSelector::VisitWord32Clz(Node* node) {
563 VisitRR(this, kMips64Clz, node);
564}
565
566
Ben Murdoch097c5b22016-05-18 11:27:45 +0100567void InstructionSelector::VisitWord32ReverseBits(Node* node) { UNREACHABLE(); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000568
569
Ben Murdoch097c5b22016-05-18 11:27:45 +0100570void InstructionSelector::VisitWord64ReverseBits(Node* node) { UNREACHABLE(); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000571
572
Ben Murdoch097c5b22016-05-18 11:27:45 +0100573void InstructionSelector::VisitWord32Ctz(Node* node) {
574 Mips64OperandGenerator g(this);
575 Emit(kMips64Ctz, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
576}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000577
578
Ben Murdoch097c5b22016-05-18 11:27:45 +0100579void InstructionSelector::VisitWord64Ctz(Node* node) {
580 Mips64OperandGenerator g(this);
581 Emit(kMips64Dctz, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
582}
583
584
585void InstructionSelector::VisitWord32Popcnt(Node* node) {
586 Mips64OperandGenerator g(this);
587 Emit(kMips64Popcnt, g.DefineAsRegister(node),
588 g.UseRegister(node->InputAt(0)));
589}
590
591
592void InstructionSelector::VisitWord64Popcnt(Node* node) {
593 Mips64OperandGenerator g(this);
594 Emit(kMips64Dpopcnt, g.DefineAsRegister(node),
595 g.UseRegister(node->InputAt(0)));
596}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000597
598
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400599void InstructionSelector::VisitWord64Ror(Node* node) {
600 VisitRRO(this, kMips64Dror, node);
601}
602
603
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000604void InstructionSelector::VisitWord64Clz(Node* node) {
605 VisitRR(this, kMips64Dclz, node);
606}
607
608
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400609void InstructionSelector::VisitInt32Add(Node* node) {
610 Mips64OperandGenerator g(this);
611 // TODO(plind): Consider multiply & add optimization from arm port.
612 VisitBinop(this, node, kMips64Add);
613}
614
615
616void InstructionSelector::VisitInt64Add(Node* node) {
617 Mips64OperandGenerator g(this);
618 // TODO(plind): Consider multiply & add optimization from arm port.
619 VisitBinop(this, node, kMips64Dadd);
620}
621
622
623void InstructionSelector::VisitInt32Sub(Node* node) {
624 VisitBinop(this, node, kMips64Sub);
625}
626
627
628void InstructionSelector::VisitInt64Sub(Node* node) {
629 VisitBinop(this, node, kMips64Dsub);
630}
631
632
633void InstructionSelector::VisitInt32Mul(Node* node) {
634 Mips64OperandGenerator g(this);
635 Int32BinopMatcher m(node);
636 if (m.right().HasValue() && m.right().Value() > 0) {
637 int32_t value = m.right().Value();
638 if (base::bits::IsPowerOfTwo32(value)) {
639 Emit(kMips64Shl | AddressingModeField::encode(kMode_None),
640 g.DefineAsRegister(node), g.UseRegister(m.left().node()),
641 g.TempImmediate(WhichPowerOf2(value)));
642 return;
643 }
644 if (base::bits::IsPowerOfTwo32(value - 1)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000645 InstructionOperand temp = g.TempRegister();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400646 Emit(kMips64Shl | AddressingModeField::encode(kMode_None), temp,
647 g.UseRegister(m.left().node()),
648 g.TempImmediate(WhichPowerOf2(value - 1)));
649 Emit(kMips64Add | AddressingModeField::encode(kMode_None),
650 g.DefineAsRegister(node), g.UseRegister(m.left().node()), temp);
651 return;
652 }
653 if (base::bits::IsPowerOfTwo32(value + 1)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000654 InstructionOperand temp = g.TempRegister();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400655 Emit(kMips64Shl | AddressingModeField::encode(kMode_None), temp,
656 g.UseRegister(m.left().node()),
657 g.TempImmediate(WhichPowerOf2(value + 1)));
658 Emit(kMips64Sub | AddressingModeField::encode(kMode_None),
659 g.DefineAsRegister(node), temp, g.UseRegister(m.left().node()));
660 return;
661 }
662 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000663 Node* left = node->InputAt(0);
664 Node* right = node->InputAt(1);
665 if (CanCover(node, left) && CanCover(node, right)) {
666 if (left->opcode() == IrOpcode::kWord64Sar &&
667 right->opcode() == IrOpcode::kWord64Sar) {
668 Int64BinopMatcher leftInput(left), rightInput(right);
669 if (leftInput.right().Is(32) && rightInput.right().Is(32)) {
670 // Combine untagging shifts with Dmul high.
671 Emit(kMips64DMulHigh, g.DefineSameAsFirst(node),
672 g.UseRegister(leftInput.left().node()),
673 g.UseRegister(rightInput.left().node()));
674 return;
675 }
676 }
677 }
678 VisitRRR(this, kMips64Mul, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400679}
680
681
682void InstructionSelector::VisitInt32MulHigh(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000683 VisitRRR(this, kMips64MulHigh, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400684}
685
686
687void InstructionSelector::VisitUint32MulHigh(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000688 VisitRRR(this, kMips64MulHighU, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400689}
690
691
692void InstructionSelector::VisitInt64Mul(Node* node) {
693 Mips64OperandGenerator g(this);
694 Int64BinopMatcher m(node);
695 // TODO(dusmil): Add optimization for shifts larger than 32.
696 if (m.right().HasValue() && m.right().Value() > 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000697 int32_t value = static_cast<int32_t>(m.right().Value());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400698 if (base::bits::IsPowerOfTwo32(value)) {
699 Emit(kMips64Dshl | AddressingModeField::encode(kMode_None),
700 g.DefineAsRegister(node), g.UseRegister(m.left().node()),
701 g.TempImmediate(WhichPowerOf2(value)));
702 return;
703 }
704 if (base::bits::IsPowerOfTwo32(value - 1)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000705 InstructionOperand temp = g.TempRegister();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400706 Emit(kMips64Dshl | AddressingModeField::encode(kMode_None), temp,
707 g.UseRegister(m.left().node()),
708 g.TempImmediate(WhichPowerOf2(value - 1)));
709 Emit(kMips64Dadd | AddressingModeField::encode(kMode_None),
710 g.DefineAsRegister(node), g.UseRegister(m.left().node()), temp);
711 return;
712 }
713 if (base::bits::IsPowerOfTwo32(value + 1)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000714 InstructionOperand temp = g.TempRegister();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400715 Emit(kMips64Dshl | AddressingModeField::encode(kMode_None), temp,
716 g.UseRegister(m.left().node()),
717 g.TempImmediate(WhichPowerOf2(value + 1)));
718 Emit(kMips64Dsub | AddressingModeField::encode(kMode_None),
719 g.DefineAsRegister(node), temp, g.UseRegister(m.left().node()));
720 return;
721 }
722 }
723 Emit(kMips64Dmul, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
724 g.UseRegister(m.right().node()));
725}
726
727
728void InstructionSelector::VisitInt32Div(Node* node) {
729 Mips64OperandGenerator g(this);
730 Int32BinopMatcher m(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000731 Node* left = node->InputAt(0);
732 Node* right = node->InputAt(1);
733 if (CanCover(node, left) && CanCover(node, right)) {
734 if (left->opcode() == IrOpcode::kWord64Sar &&
735 right->opcode() == IrOpcode::kWord64Sar) {
736 Int64BinopMatcher rightInput(right), leftInput(left);
737 if (rightInput.right().Is(32) && leftInput.right().Is(32)) {
738 // Combine both shifted operands with Ddiv.
739 Emit(kMips64Ddiv, g.DefineSameAsFirst(node),
740 g.UseRegister(leftInput.left().node()),
741 g.UseRegister(rightInput.left().node()));
742 return;
743 }
744 }
745 }
746 Emit(kMips64Div, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400747 g.UseRegister(m.right().node()));
748}
749
750
751void InstructionSelector::VisitUint32Div(Node* node) {
752 Mips64OperandGenerator g(this);
753 Int32BinopMatcher m(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000754 Emit(kMips64DivU, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400755 g.UseRegister(m.right().node()));
756}
757
758
759void InstructionSelector::VisitInt32Mod(Node* node) {
760 Mips64OperandGenerator g(this);
761 Int32BinopMatcher m(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000762 Node* left = node->InputAt(0);
763 Node* right = node->InputAt(1);
764 if (CanCover(node, left) && CanCover(node, right)) {
765 if (left->opcode() == IrOpcode::kWord64Sar &&
766 right->opcode() == IrOpcode::kWord64Sar) {
767 Int64BinopMatcher rightInput(right), leftInput(left);
768 if (rightInput.right().Is(32) && leftInput.right().Is(32)) {
769 // Combine both shifted operands with Dmod.
770 Emit(kMips64Dmod, g.DefineSameAsFirst(node),
771 g.UseRegister(leftInput.left().node()),
772 g.UseRegister(rightInput.left().node()));
773 return;
774 }
775 }
776 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400777 Emit(kMips64Mod, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
778 g.UseRegister(m.right().node()));
779}
780
781
782void InstructionSelector::VisitUint32Mod(Node* node) {
783 Mips64OperandGenerator g(this);
784 Int32BinopMatcher m(node);
785 Emit(kMips64ModU, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
786 g.UseRegister(m.right().node()));
787}
788
789
790void InstructionSelector::VisitInt64Div(Node* node) {
791 Mips64OperandGenerator g(this);
792 Int64BinopMatcher m(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000793 Emit(kMips64Ddiv, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400794 g.UseRegister(m.right().node()));
795}
796
797
798void InstructionSelector::VisitUint64Div(Node* node) {
799 Mips64OperandGenerator g(this);
800 Int64BinopMatcher m(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000801 Emit(kMips64DdivU, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400802 g.UseRegister(m.right().node()));
803}
804
805
806void InstructionSelector::VisitInt64Mod(Node* node) {
807 Mips64OperandGenerator g(this);
808 Int64BinopMatcher m(node);
809 Emit(kMips64Dmod, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
810 g.UseRegister(m.right().node()));
811}
812
813
814void InstructionSelector::VisitUint64Mod(Node* node) {
815 Mips64OperandGenerator g(this);
816 Int64BinopMatcher m(node);
817 Emit(kMips64DmodU, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
818 g.UseRegister(m.right().node()));
819}
820
821
822void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000823 VisitRR(this, kMips64CvtDS, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400824}
825
826
Ben Murdoch097c5b22016-05-18 11:27:45 +0100827void InstructionSelector::VisitRoundInt32ToFloat32(Node* node) {
828 VisitRR(this, kMips64CvtSW, node);
829}
830
831
832void InstructionSelector::VisitRoundUint32ToFloat32(Node* node) {
833 VisitRR(this, kMips64CvtSUw, node);
834}
835
836
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400837void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000838 VisitRR(this, kMips64CvtDW, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400839}
840
841
842void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000843 VisitRR(this, kMips64CvtDUw, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400844}
845
846
Ben Murdoch097c5b22016-05-18 11:27:45 +0100847void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) {
848 VisitRR(this, kMips64TruncWS, node);
849}
850
851
852void InstructionSelector::VisitTruncateFloat32ToUint32(Node* node) {
853 VisitRR(this, kMips64TruncUwS, node);
854}
855
856
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400857void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
858 Mips64OperandGenerator g(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000859 Node* value = node->InputAt(0);
860 // Match ChangeFloat64ToInt32(Float64Round##OP) to corresponding instruction
861 // which does rounding and conversion to integer format.
862 if (CanCover(node, value)) {
863 switch (value->opcode()) {
864 case IrOpcode::kFloat64RoundDown:
865 Emit(kMips64FloorWD, g.DefineAsRegister(node),
866 g.UseRegister(value->InputAt(0)));
867 return;
868 case IrOpcode::kFloat64RoundUp:
869 Emit(kMips64CeilWD, g.DefineAsRegister(node),
870 g.UseRegister(value->InputAt(0)));
871 return;
872 case IrOpcode::kFloat64RoundTiesEven:
873 Emit(kMips64RoundWD, g.DefineAsRegister(node),
874 g.UseRegister(value->InputAt(0)));
875 return;
876 case IrOpcode::kFloat64RoundTruncate:
877 Emit(kMips64TruncWD, g.DefineAsRegister(node),
878 g.UseRegister(value->InputAt(0)));
879 return;
880 default:
881 break;
882 }
883 if (value->opcode() == IrOpcode::kChangeFloat32ToFloat64) {
884 Node* next = value->InputAt(0);
885 if (CanCover(value, next)) {
886 // Match ChangeFloat64ToInt32(ChangeFloat32ToFloat64(Float64Round##OP))
887 switch (next->opcode()) {
888 case IrOpcode::kFloat32RoundDown:
889 Emit(kMips64FloorWS, g.DefineAsRegister(node),
890 g.UseRegister(next->InputAt(0)));
891 return;
892 case IrOpcode::kFloat32RoundUp:
893 Emit(kMips64CeilWS, g.DefineAsRegister(node),
894 g.UseRegister(next->InputAt(0)));
895 return;
896 case IrOpcode::kFloat32RoundTiesEven:
897 Emit(kMips64RoundWS, g.DefineAsRegister(node),
898 g.UseRegister(next->InputAt(0)));
899 return;
900 case IrOpcode::kFloat32RoundTruncate:
901 Emit(kMips64TruncWS, g.DefineAsRegister(node),
902 g.UseRegister(next->InputAt(0)));
903 return;
904 default:
905 Emit(kMips64TruncWS, g.DefineAsRegister(node),
906 g.UseRegister(value->InputAt(0)));
907 return;
908 }
909 } else {
910 // Match float32 -> float64 -> int32 representation change path.
911 Emit(kMips64TruncWS, g.DefineAsRegister(node),
912 g.UseRegister(value->InputAt(0)));
913 return;
914 }
915 }
916 }
917 VisitRR(this, kMips64TruncWD, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400918}
919
920
921void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000922 VisitRR(this, kMips64TruncUwD, node);
923}
924
925
926void InstructionSelector::VisitTryTruncateFloat32ToInt64(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400927 Mips64OperandGenerator g(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000928 InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0))};
929 InstructionOperand outputs[2];
930 size_t output_count = 0;
931 outputs[output_count++] = g.DefineAsRegister(node);
932
933 Node* success_output = NodeProperties::FindProjection(node, 1);
934 if (success_output) {
935 outputs[output_count++] = g.DefineAsRegister(success_output);
936 }
937
938 this->Emit(kMips64TruncLS, output_count, outputs, 1, inputs);
939}
940
941
942void InstructionSelector::VisitTryTruncateFloat64ToInt64(Node* node) {
943 Mips64OperandGenerator g(this);
944 InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0))};
945 InstructionOperand outputs[2];
946 size_t output_count = 0;
947 outputs[output_count++] = g.DefineAsRegister(node);
948
949 Node* success_output = NodeProperties::FindProjection(node, 1);
950 if (success_output) {
951 outputs[output_count++] = g.DefineAsRegister(success_output);
952 }
953
954 Emit(kMips64TruncLD, output_count, outputs, 1, inputs);
955}
956
957
958void InstructionSelector::VisitTryTruncateFloat32ToUint64(Node* node) {
959 Mips64OperandGenerator g(this);
960 InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0))};
961 InstructionOperand outputs[2];
962 size_t output_count = 0;
963 outputs[output_count++] = g.DefineAsRegister(node);
964
965 Node* success_output = NodeProperties::FindProjection(node, 1);
966 if (success_output) {
967 outputs[output_count++] = g.DefineAsRegister(success_output);
968 }
969
970 Emit(kMips64TruncUlS, output_count, outputs, 1, inputs);
971}
972
973
974void InstructionSelector::VisitTryTruncateFloat64ToUint64(Node* node) {
975 Mips64OperandGenerator g(this);
976
977 InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0))};
978 InstructionOperand outputs[2];
979 size_t output_count = 0;
980 outputs[output_count++] = g.DefineAsRegister(node);
981
982 Node* success_output = NodeProperties::FindProjection(node, 1);
983 if (success_output) {
984 outputs[output_count++] = g.DefineAsRegister(success_output);
985 }
986
987 Emit(kMips64TruncUlD, output_count, outputs, 1, inputs);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400988}
989
990
991void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
992 Mips64OperandGenerator g(this);
993 Emit(kMips64Shl, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
994 g.TempImmediate(0));
995}
996
997
998void InstructionSelector::VisitChangeUint32ToUint64(Node* node) {
999 Mips64OperandGenerator g(this);
1000 Emit(kMips64Dext, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
1001 g.TempImmediate(0), g.TempImmediate(32));
1002}
1003
1004
1005void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) {
1006 Mips64OperandGenerator g(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001007 Node* value = node->InputAt(0);
1008 if (CanCover(node, value)) {
1009 switch (value->opcode()) {
1010 case IrOpcode::kWord64Sar: {
1011 Int64BinopMatcher m(value);
1012 if (m.right().IsInRange(32, 63)) {
1013 // After smi untagging no need for truncate. Combine sequence.
1014 Emit(kMips64Dsar, g.DefineSameAsFirst(node),
1015 g.UseRegister(m.left().node()),
1016 g.UseImmediate(m.right().node()));
1017 return;
1018 }
1019 break;
1020 }
1021 default:
1022 break;
1023 }
1024 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001025 Emit(kMips64Ext, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
1026 g.TempImmediate(0), g.TempImmediate(32));
1027}
1028
1029
1030void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
1031 Mips64OperandGenerator g(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001032 Node* value = node->InputAt(0);
1033 // Match TruncateFloat64ToFloat32(ChangeInt32ToFloat64) to corresponding
1034 // instruction.
1035 if (CanCover(node, value) &&
1036 value->opcode() == IrOpcode::kChangeInt32ToFloat64) {
1037 Emit(kMips64CvtSW, g.DefineAsRegister(node),
1038 g.UseRegister(value->InputAt(0)));
1039 return;
1040 }
1041 VisitRR(this, kMips64CvtSD, node);
1042}
1043
1044
1045void InstructionSelector::VisitTruncateFloat64ToInt32(Node* node) {
1046 switch (TruncationModeOf(node->op())) {
1047 case TruncationMode::kJavaScript:
1048 return VisitRR(this, kArchTruncateDoubleToI, node);
1049 case TruncationMode::kRoundToZero:
1050 return VisitRR(this, kMips64TruncWD, node);
1051 }
1052 UNREACHABLE();
1053}
1054
1055
1056void InstructionSelector::VisitRoundInt64ToFloat32(Node* node) {
1057 VisitRR(this, kMips64CvtSL, node);
1058}
1059
1060
1061void InstructionSelector::VisitRoundInt64ToFloat64(Node* node) {
1062 VisitRR(this, kMips64CvtDL, node);
1063}
1064
1065
1066void InstructionSelector::VisitRoundUint64ToFloat32(Node* node) {
1067 VisitRR(this, kMips64CvtSUl, node);
1068}
1069
1070
1071void InstructionSelector::VisitRoundUint64ToFloat64(Node* node) {
1072 VisitRR(this, kMips64CvtDUl, node);
1073}
1074
1075
1076void InstructionSelector::VisitBitcastFloat32ToInt32(Node* node) {
1077 VisitRR(this, kMips64Float64ExtractLowWord32, node);
1078}
1079
1080
1081void InstructionSelector::VisitBitcastFloat64ToInt64(Node* node) {
1082 VisitRR(this, kMips64BitcastDL, node);
1083}
1084
1085
1086void InstructionSelector::VisitBitcastInt32ToFloat32(Node* node) {
1087 Mips64OperandGenerator g(this);
1088 Emit(kMips64Float64InsertLowWord32, g.DefineAsRegister(node),
1089 ImmediateOperand(ImmediateOperand::INLINE, 0),
1090 g.UseRegister(node->InputAt(0)));
1091}
1092
1093
1094void InstructionSelector::VisitBitcastInt64ToFloat64(Node* node) {
1095 VisitRR(this, kMips64BitcastLD, node);
1096}
1097
1098
1099void InstructionSelector::VisitFloat32Add(Node* node) {
1100 VisitRRR(this, kMips64AddS, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001101}
1102
1103
1104void InstructionSelector::VisitFloat64Add(Node* node) {
1105 VisitRRR(this, kMips64AddD, node);
1106}
1107
1108
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001109void InstructionSelector::VisitFloat32Sub(Node* node) {
1110 VisitRRR(this, kMips64SubS, node);
1111}
1112
1113
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001114void InstructionSelector::VisitFloat64Sub(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001115 Mips64OperandGenerator g(this);
1116 Float64BinopMatcher m(node);
1117 if (m.left().IsMinusZero() && m.right().IsFloat64RoundDown() &&
1118 CanCover(m.node(), m.right().node())) {
1119 if (m.right().InputAt(0)->opcode() == IrOpcode::kFloat64Sub &&
1120 CanCover(m.right().node(), m.right().InputAt(0))) {
1121 Float64BinopMatcher mright0(m.right().InputAt(0));
1122 if (mright0.left().IsMinusZero()) {
1123 Emit(kMips64Float64RoundUp, g.DefineAsRegister(node),
1124 g.UseRegister(mright0.right().node()));
1125 return;
1126 }
1127 }
1128 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001129 VisitRRR(this, kMips64SubD, node);
1130}
1131
1132
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001133void InstructionSelector::VisitFloat32Mul(Node* node) {
1134 VisitRRR(this, kMips64MulS, node);
1135}
1136
1137
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001138void InstructionSelector::VisitFloat64Mul(Node* node) {
1139 VisitRRR(this, kMips64MulD, node);
1140}
1141
1142
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001143void InstructionSelector::VisitFloat32Div(Node* node) {
1144 VisitRRR(this, kMips64DivS, node);
1145}
1146
1147
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001148void InstructionSelector::VisitFloat64Div(Node* node) {
1149 VisitRRR(this, kMips64DivD, node);
1150}
1151
1152
1153void InstructionSelector::VisitFloat64Mod(Node* node) {
1154 Mips64OperandGenerator g(this);
1155 Emit(kMips64ModD, g.DefineAsFixed(node, f0),
1156 g.UseFixed(node->InputAt(0), f12),
1157 g.UseFixed(node->InputAt(1), f14))->MarkAsCall();
1158}
1159
1160
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001161void InstructionSelector::VisitFloat32Max(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001162 Mips64OperandGenerator g(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001163 if (kArchVariant == kMips64r6) {
1164 Emit(kMips64Float32Max, g.DefineAsRegister(node),
1165 g.UseUniqueRegister(node->InputAt(0)),
1166 g.UseUniqueRegister(node->InputAt(1)));
1167
1168 } else {
1169 // Reverse operands, and use same reg. for result and right operand.
1170 Emit(kMips64Float32Max, g.DefineSameAsFirst(node),
1171 g.UseRegister(node->InputAt(1)), g.UseRegister(node->InputAt(0)));
1172 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001173}
1174
1175
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001176void InstructionSelector::VisitFloat64Max(Node* node) {
1177 Mips64OperandGenerator g(this);
1178 if (kArchVariant == kMips64r6) {
1179 Emit(kMips64Float64Max, g.DefineAsRegister(node),
1180 g.UseUniqueRegister(node->InputAt(0)),
1181 g.UseUniqueRegister(node->InputAt(1)));
1182
1183 } else {
1184 // Reverse operands, and use same reg. for result and right operand.
1185 Emit(kMips64Float64Max, g.DefineSameAsFirst(node),
1186 g.UseRegister(node->InputAt(1)), g.UseRegister(node->InputAt(0)));
1187 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001188}
1189
1190
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001191void InstructionSelector::VisitFloat32Min(Node* node) {
1192 Mips64OperandGenerator g(this);
1193 if (kArchVariant == kMips64r6) {
1194 Emit(kMips64Float32Min, g.DefineAsRegister(node),
1195 g.UseUniqueRegister(node->InputAt(0)),
1196 g.UseUniqueRegister(node->InputAt(1)));
1197
1198 } else {
1199 // Reverse operands, and use same reg. for result and right operand.
1200 Emit(kMips64Float32Min, g.DefineSameAsFirst(node),
1201 g.UseRegister(node->InputAt(1)), g.UseRegister(node->InputAt(0)));
1202 }
1203}
1204
1205
1206void InstructionSelector::VisitFloat64Min(Node* node) {
1207 Mips64OperandGenerator g(this);
1208 if (kArchVariant == kMips64r6) {
1209 Emit(kMips64Float64Min, g.DefineAsRegister(node),
1210 g.UseUniqueRegister(node->InputAt(0)),
1211 g.UseUniqueRegister(node->InputAt(1)));
1212
1213 } else {
1214 // Reverse operands, and use same reg. for result and right operand.
1215 Emit(kMips64Float64Min, g.DefineSameAsFirst(node),
1216 g.UseRegister(node->InputAt(1)), g.UseRegister(node->InputAt(0)));
1217 }
1218}
1219
1220
1221void InstructionSelector::VisitFloat32Abs(Node* node) {
1222 VisitRR(this, kMips64AbsS, node);
1223}
1224
1225
1226void InstructionSelector::VisitFloat64Abs(Node* node) {
1227 VisitRR(this, kMips64AbsD, node);
1228}
1229
1230
1231void InstructionSelector::VisitFloat32Sqrt(Node* node) {
1232 VisitRR(this, kMips64SqrtS, node);
1233}
1234
1235
1236void InstructionSelector::VisitFloat64Sqrt(Node* node) {
1237 VisitRR(this, kMips64SqrtD, node);
1238}
1239
1240
1241void InstructionSelector::VisitFloat32RoundDown(Node* node) {
1242 VisitRR(this, kMips64Float32RoundDown, node);
1243}
1244
1245
1246void InstructionSelector::VisitFloat64RoundDown(Node* node) {
1247 VisitRR(this, kMips64Float64RoundDown, node);
1248}
1249
1250
1251void InstructionSelector::VisitFloat32RoundUp(Node* node) {
1252 VisitRR(this, kMips64Float32RoundUp, node);
1253}
1254
1255
1256void InstructionSelector::VisitFloat64RoundUp(Node* node) {
1257 VisitRR(this, kMips64Float64RoundUp, node);
1258}
1259
1260
1261void InstructionSelector::VisitFloat32RoundTruncate(Node* node) {
1262 VisitRR(this, kMips64Float32RoundTruncate, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001263}
1264
1265
1266void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
1267 VisitRR(this, kMips64Float64RoundTruncate, node);
1268}
1269
1270
1271void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
1272 UNREACHABLE();
1273}
1274
1275
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001276void InstructionSelector::VisitFloat32RoundTiesEven(Node* node) {
1277 VisitRR(this, kMips64Float32RoundTiesEven, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001278}
1279
1280
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001281void InstructionSelector::VisitFloat64RoundTiesEven(Node* node) {
1282 VisitRR(this, kMips64Float64RoundTiesEven, node);
1283}
1284
1285
1286void InstructionSelector::EmitPrepareArguments(
1287 ZoneVector<PushParameter>* arguments, const CallDescriptor* descriptor,
1288 Node* node) {
1289 Mips64OperandGenerator g(this);
1290
1291 // Prepare for C function call.
1292 if (descriptor->IsCFunctionCall()) {
1293 Emit(kArchPrepareCallCFunction |
1294 MiscField::encode(static_cast<int>(descriptor->CParameterCount())),
1295 0, nullptr, 0, nullptr);
1296
1297 // Poke any stack arguments.
1298 int slot = kCArgSlotCount;
1299 for (PushParameter input : (*arguments)) {
1300 Emit(kMips64StoreToStackSlot, g.NoOutput(), g.UseRegister(input.node()),
1301 g.TempImmediate(slot << kPointerSizeLog2));
1302 ++slot;
1303 }
1304 } else {
1305 int push_count = static_cast<int>(descriptor->StackParameterCount());
1306 if (push_count > 0) {
1307 Emit(kMips64StackClaim, g.NoOutput(),
1308 g.TempImmediate(push_count << kPointerSizeLog2));
1309 }
1310 for (size_t n = 0; n < arguments->size(); ++n) {
1311 PushParameter input = (*arguments)[n];
1312 if (input.node()) {
1313 Emit(kMips64StoreToStackSlot, g.NoOutput(), g.UseRegister(input.node()),
1314 g.TempImmediate(static_cast<int>(n << kPointerSizeLog2)));
1315 }
1316 }
1317 }
1318}
1319
1320
1321bool InstructionSelector::IsTailCallAddressImmediate() { return false; }
1322
1323
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001324void InstructionSelector::VisitCheckedLoad(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001325 CheckedLoadRepresentation load_rep = CheckedLoadRepresentationOf(node->op());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001326 Mips64OperandGenerator g(this);
1327 Node* const buffer = node->InputAt(0);
1328 Node* const offset = node->InputAt(1);
1329 Node* const length = node->InputAt(2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001330 ArchOpcode opcode = kArchNop;
1331 switch (load_rep.representation()) {
1332 case MachineRepresentation::kWord8:
1333 opcode = load_rep.IsSigned() ? kCheckedLoadInt8 : kCheckedLoadUint8;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001334 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001335 case MachineRepresentation::kWord16:
1336 opcode = load_rep.IsSigned() ? kCheckedLoadInt16 : kCheckedLoadUint16;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001337 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001338 case MachineRepresentation::kWord32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001339 opcode = kCheckedLoadWord32;
1340 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001341 case MachineRepresentation::kWord64:
1342 opcode = kCheckedLoadWord64;
1343 break;
1344 case MachineRepresentation::kFloat32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001345 opcode = kCheckedLoadFloat32;
1346 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001347 case MachineRepresentation::kFloat64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001348 opcode = kCheckedLoadFloat64;
1349 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001350 case MachineRepresentation::kBit:
1351 case MachineRepresentation::kTagged:
Ben Murdoch097c5b22016-05-18 11:27:45 +01001352 case MachineRepresentation::kSimd128:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001353 case MachineRepresentation::kNone:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001354 UNREACHABLE();
1355 return;
1356 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001357 InstructionOperand offset_operand = g.CanBeImmediate(offset, opcode)
1358 ? g.UseImmediate(offset)
1359 : g.UseRegister(offset);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001360
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001361 InstructionOperand length_operand = (!g.CanBeImmediate(offset, opcode))
1362 ? g.CanBeImmediate(length, opcode)
1363 ? g.UseImmediate(length)
1364 : g.UseRegister(length)
1365 : g.UseRegister(length);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001366
1367 Emit(opcode | AddressingModeField::encode(kMode_MRI),
1368 g.DefineAsRegister(node), offset_operand, length_operand,
1369 g.UseRegister(buffer));
1370}
1371
1372
1373void InstructionSelector::VisitCheckedStore(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001374 MachineRepresentation rep = CheckedStoreRepresentationOf(node->op());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001375 Mips64OperandGenerator g(this);
1376 Node* const buffer = node->InputAt(0);
1377 Node* const offset = node->InputAt(1);
1378 Node* const length = node->InputAt(2);
1379 Node* const value = node->InputAt(3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001380 ArchOpcode opcode = kArchNop;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001381 switch (rep) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001382 case MachineRepresentation::kWord8:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001383 opcode = kCheckedStoreWord8;
1384 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001385 case MachineRepresentation::kWord16:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001386 opcode = kCheckedStoreWord16;
1387 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001388 case MachineRepresentation::kWord32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001389 opcode = kCheckedStoreWord32;
1390 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001391 case MachineRepresentation::kWord64:
1392 opcode = kCheckedStoreWord64;
1393 break;
1394 case MachineRepresentation::kFloat32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001395 opcode = kCheckedStoreFloat32;
1396 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001397 case MachineRepresentation::kFloat64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001398 opcode = kCheckedStoreFloat64;
1399 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001400 case MachineRepresentation::kBit:
1401 case MachineRepresentation::kTagged:
Ben Murdoch097c5b22016-05-18 11:27:45 +01001402 case MachineRepresentation::kSimd128:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001403 case MachineRepresentation::kNone:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001404 UNREACHABLE();
1405 return;
1406 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001407 InstructionOperand offset_operand = g.CanBeImmediate(offset, opcode)
1408 ? g.UseImmediate(offset)
1409 : g.UseRegister(offset);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001410
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001411 InstructionOperand length_operand = (!g.CanBeImmediate(offset, opcode))
1412 ? g.CanBeImmediate(length, opcode)
1413 ? g.UseImmediate(length)
1414 : g.UseRegister(length)
1415 : g.UseRegister(length);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001416
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001417 Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
1418 offset_operand, length_operand, g.UseRegister(value),
1419 g.UseRegister(buffer));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001420}
1421
1422
1423namespace {
1424
1425// Shared routine for multiple compare operations.
1426static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001427 InstructionOperand left, InstructionOperand right,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001428 FlagsContinuation* cont) {
1429 Mips64OperandGenerator g(selector);
1430 opcode = cont->Encode(opcode);
1431 if (cont->IsBranch()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001432 selector->Emit(opcode, g.NoOutput(), left, right,
1433 g.Label(cont->true_block()), g.Label(cont->false_block()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001434 } else {
1435 DCHECK(cont->IsSet());
1436 selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
1437 }
1438}
1439
1440
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001441// Shared routine for multiple float32 compare operations.
1442void VisitFloat32Compare(InstructionSelector* selector, Node* node,
1443 FlagsContinuation* cont) {
1444 Mips64OperandGenerator g(selector);
1445 Float32BinopMatcher m(node);
1446 InstructionOperand lhs, rhs;
1447
1448 lhs = m.left().IsZero() ? g.UseImmediate(m.left().node())
1449 : g.UseRegister(m.left().node());
1450 rhs = m.right().IsZero() ? g.UseImmediate(m.right().node())
1451 : g.UseRegister(m.right().node());
1452 VisitCompare(selector, kMips64CmpS, lhs, rhs, cont);
1453}
1454
1455
1456// Shared routine for multiple float64 compare operations.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001457void VisitFloat64Compare(InstructionSelector* selector, Node* node,
1458 FlagsContinuation* cont) {
1459 Mips64OperandGenerator g(selector);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001460 Float64BinopMatcher m(node);
1461 InstructionOperand lhs, rhs;
1462
1463 lhs = m.left().IsZero() ? g.UseImmediate(m.left().node())
1464 : g.UseRegister(m.left().node());
1465 rhs = m.right().IsZero() ? g.UseImmediate(m.right().node())
1466 : g.UseRegister(m.right().node());
1467 VisitCompare(selector, kMips64CmpD, lhs, rhs, cont);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001468}
1469
1470
1471// Shared routine for multiple word compare operations.
1472void VisitWordCompare(InstructionSelector* selector, Node* node,
1473 InstructionCode opcode, FlagsContinuation* cont,
1474 bool commutative) {
1475 Mips64OperandGenerator g(selector);
1476 Node* left = node->InputAt(0);
1477 Node* right = node->InputAt(1);
1478
1479 // Match immediates on left or right side of comparison.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001480 if (g.CanBeImmediate(right, opcode)) {
1481 switch (cont->condition()) {
1482 case kEqual:
1483 case kNotEqual:
1484 if (cont->IsSet()) {
1485 VisitCompare(selector, opcode, g.UseRegister(left),
1486 g.UseImmediate(right), cont);
1487 } else {
1488 VisitCompare(selector, opcode, g.UseRegister(left),
1489 g.UseRegister(right), cont);
1490 }
1491 break;
1492 case kSignedLessThan:
1493 case kSignedGreaterThanOrEqual:
1494 case kUnsignedLessThan:
1495 case kUnsignedGreaterThanOrEqual:
1496 VisitCompare(selector, opcode, g.UseRegister(left),
1497 g.UseImmediate(right), cont);
1498 break;
1499 default:
1500 VisitCompare(selector, opcode, g.UseRegister(left),
1501 g.UseRegister(right), cont);
1502 }
1503 } else if (g.CanBeImmediate(left, opcode)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001504 if (!commutative) cont->Commute();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001505 switch (cont->condition()) {
1506 case kEqual:
1507 case kNotEqual:
1508 if (cont->IsSet()) {
1509 VisitCompare(selector, opcode, g.UseRegister(right),
1510 g.UseImmediate(left), cont);
1511 } else {
1512 VisitCompare(selector, opcode, g.UseRegister(right),
1513 g.UseRegister(left), cont);
1514 }
1515 break;
1516 case kSignedLessThan:
1517 case kSignedGreaterThanOrEqual:
1518 case kUnsignedLessThan:
1519 case kUnsignedGreaterThanOrEqual:
1520 VisitCompare(selector, opcode, g.UseRegister(right),
1521 g.UseImmediate(left), cont);
1522 break;
1523 default:
1524 VisitCompare(selector, opcode, g.UseRegister(right),
1525 g.UseRegister(left), cont);
1526 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001527 } else {
1528 VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right),
1529 cont);
1530 }
1531}
1532
1533
1534void VisitWord32Compare(InstructionSelector* selector, Node* node,
1535 FlagsContinuation* cont) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001536 VisitWordCompare(selector, node, kMips64Cmp, cont, false);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001537}
1538
1539
1540void VisitWord64Compare(InstructionSelector* selector, Node* node,
1541 FlagsContinuation* cont) {
1542 VisitWordCompare(selector, node, kMips64Cmp, cont, false);
1543}
1544
1545} // namespace
1546
1547
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001548void EmitWordCompareZero(InstructionSelector* selector, Node* value,
1549 FlagsContinuation* cont) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001550 Mips64OperandGenerator g(selector);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001551 InstructionCode opcode = cont->Encode(kMips64Cmp);
1552 InstructionOperand const value_operand = g.UseRegister(value);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001553 if (cont->IsBranch()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001554 selector->Emit(opcode, g.NoOutput(), value_operand, g.TempImmediate(0),
1555 g.Label(cont->true_block()), g.Label(cont->false_block()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001556 } else {
1557 selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand,
1558 g.TempImmediate(0));
1559 }
1560}
1561
1562
1563// Shared routine for word comparisons against zero.
1564void VisitWordCompareZero(InstructionSelector* selector, Node* user,
1565 Node* value, FlagsContinuation* cont) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001566 while (selector->CanCover(user, value)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001567 switch (value->opcode()) {
1568 case IrOpcode::kWord32Equal: {
1569 // Combine with comparisons against 0 by simply inverting the
1570 // continuation.
1571 Int32BinopMatcher m(value);
1572 if (m.right().Is(0)) {
1573 user = value;
1574 value = m.left().node();
1575 cont->Negate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001576 continue;
1577 }
1578 cont->OverwriteAndNegateIfEqual(kEqual);
1579 return VisitWord32Compare(selector, value, cont);
1580 }
1581 case IrOpcode::kInt32LessThan:
1582 cont->OverwriteAndNegateIfEqual(kSignedLessThan);
1583 return VisitWord32Compare(selector, value, cont);
1584 case IrOpcode::kInt32LessThanOrEqual:
1585 cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
1586 return VisitWord32Compare(selector, value, cont);
1587 case IrOpcode::kUint32LessThan:
1588 cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
1589 return VisitWord32Compare(selector, value, cont);
1590 case IrOpcode::kUint32LessThanOrEqual:
1591 cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
1592 return VisitWord32Compare(selector, value, cont);
1593 case IrOpcode::kWord64Equal: {
1594 // Combine with comparisons against 0 by simply inverting the
1595 // continuation.
1596 Int64BinopMatcher m(value);
1597 if (m.right().Is(0)) {
1598 user = value;
1599 value = m.left().node();
1600 cont->Negate();
1601 continue;
1602 }
1603 cont->OverwriteAndNegateIfEqual(kEqual);
1604 return VisitWord64Compare(selector, value, cont);
1605 }
1606 case IrOpcode::kInt64LessThan:
1607 cont->OverwriteAndNegateIfEqual(kSignedLessThan);
1608 return VisitWord64Compare(selector, value, cont);
1609 case IrOpcode::kInt64LessThanOrEqual:
1610 cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
1611 return VisitWord64Compare(selector, value, cont);
1612 case IrOpcode::kUint64LessThan:
1613 cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
1614 return VisitWord64Compare(selector, value, cont);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001615 case IrOpcode::kUint64LessThanOrEqual:
1616 cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
1617 return VisitWord64Compare(selector, value, cont);
1618 case IrOpcode::kFloat32Equal:
1619 cont->OverwriteAndNegateIfEqual(kEqual);
1620 return VisitFloat32Compare(selector, value, cont);
1621 case IrOpcode::kFloat32LessThan:
1622 cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
1623 return VisitFloat32Compare(selector, value, cont);
1624 case IrOpcode::kFloat32LessThanOrEqual:
1625 cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
1626 return VisitFloat32Compare(selector, value, cont);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001627 case IrOpcode::kFloat64Equal:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001628 cont->OverwriteAndNegateIfEqual(kEqual);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001629 return VisitFloat64Compare(selector, value, cont);
1630 case IrOpcode::kFloat64LessThan:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001631 cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001632 return VisitFloat64Compare(selector, value, cont);
1633 case IrOpcode::kFloat64LessThanOrEqual:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001634 cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001635 return VisitFloat64Compare(selector, value, cont);
1636 case IrOpcode::kProjection:
1637 // Check if this is the overflow output projection of an
1638 // <Operation>WithOverflow node.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001639 if (ProjectionIndexOf(value->op()) == 1u) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001640 // We cannot combine the <Operation>WithOverflow with this branch
1641 // unless the 0th projection (the use of the actual value of the
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001642 // <Operation> is either nullptr, which means there's no use of the
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001643 // actual value, or was already defined, which means it is scheduled
1644 // *AFTER* this branch).
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001645 Node* const node = value->InputAt(0);
1646 Node* const result = NodeProperties::FindProjection(node, 0);
1647 if (result == nullptr || selector->IsDefined(result)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001648 switch (node->opcode()) {
1649 case IrOpcode::kInt32AddWithOverflow:
1650 cont->OverwriteAndNegateIfEqual(kOverflow);
1651 return VisitBinop(selector, node, kMips64Dadd, cont);
1652 case IrOpcode::kInt32SubWithOverflow:
1653 cont->OverwriteAndNegateIfEqual(kOverflow);
1654 return VisitBinop(selector, node, kMips64Dsub, cont);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001655 case IrOpcode::kInt64AddWithOverflow:
1656 cont->OverwriteAndNegateIfEqual(kOverflow);
1657 return VisitBinop(selector, node, kMips64DaddOvf, cont);
1658 case IrOpcode::kInt64SubWithOverflow:
1659 cont->OverwriteAndNegateIfEqual(kOverflow);
1660 return VisitBinop(selector, node, kMips64DsubOvf, cont);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001661 default:
1662 break;
1663 }
1664 }
1665 }
1666 break;
1667 case IrOpcode::kWord32And:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001668 case IrOpcode::kWord64And:
1669 return VisitWordCompare(selector, value, kMips64Tst, cont, true);
1670 default:
1671 break;
1672 }
1673 break;
1674 }
1675
1676 // Continuation could not be combined with a compare, emit compare against 0.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001677 EmitWordCompareZero(selector, value, cont);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001678}
1679
1680
1681void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
1682 BasicBlock* fbranch) {
1683 FlagsContinuation cont(kNotEqual, tbranch, fbranch);
1684 VisitWordCompareZero(this, branch, branch->InputAt(0), &cont);
1685}
1686
1687
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001688void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
1689 Mips64OperandGenerator g(this);
1690 InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
1691
1692 // Emit either ArchTableSwitch or ArchLookupSwitch.
1693 size_t table_space_cost = 10 + 2 * sw.value_range;
1694 size_t table_time_cost = 3;
1695 size_t lookup_space_cost = 2 + 2 * sw.case_count;
1696 size_t lookup_time_cost = sw.case_count;
1697 if (sw.case_count > 0 &&
1698 table_space_cost + 3 * table_time_cost <=
1699 lookup_space_cost + 3 * lookup_time_cost &&
1700 sw.min_value > std::numeric_limits<int32_t>::min()) {
1701 InstructionOperand index_operand = value_operand;
1702 if (sw.min_value) {
1703 index_operand = g.TempRegister();
1704 Emit(kMips64Sub, index_operand, value_operand,
1705 g.TempImmediate(sw.min_value));
1706 }
1707 // Generate a table lookup.
1708 return EmitTableSwitch(sw, index_operand);
1709 }
1710
1711 // Generate a sequence of conditional jumps.
1712 return EmitLookupSwitch(sw, value_operand);
1713}
1714
1715
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001716void InstructionSelector::VisitWord32Equal(Node* const node) {
1717 FlagsContinuation cont(kEqual, node);
1718 Int32BinopMatcher m(node);
1719 if (m.right().Is(0)) {
1720 return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
1721 }
1722
1723 VisitWord32Compare(this, node, &cont);
1724}
1725
1726
1727void InstructionSelector::VisitInt32LessThan(Node* node) {
1728 FlagsContinuation cont(kSignedLessThan, node);
1729 VisitWord32Compare(this, node, &cont);
1730}
1731
1732
1733void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
1734 FlagsContinuation cont(kSignedLessThanOrEqual, node);
1735 VisitWord32Compare(this, node, &cont);
1736}
1737
1738
1739void InstructionSelector::VisitUint32LessThan(Node* node) {
1740 FlagsContinuation cont(kUnsignedLessThan, node);
1741 VisitWord32Compare(this, node, &cont);
1742}
1743
1744
1745void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
1746 FlagsContinuation cont(kUnsignedLessThanOrEqual, node);
1747 VisitWord32Compare(this, node, &cont);
1748}
1749
1750
1751void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001752 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001753 FlagsContinuation cont(kOverflow, ovf);
1754 return VisitBinop(this, node, kMips64Dadd, &cont);
1755 }
1756 FlagsContinuation cont;
1757 VisitBinop(this, node, kMips64Dadd, &cont);
1758}
1759
1760
1761void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001762 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001763 FlagsContinuation cont(kOverflow, ovf);
1764 return VisitBinop(this, node, kMips64Dsub, &cont);
1765 }
1766 FlagsContinuation cont;
1767 VisitBinop(this, node, kMips64Dsub, &cont);
1768}
1769
1770
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001771void InstructionSelector::VisitInt64AddWithOverflow(Node* node) {
1772 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
1773 FlagsContinuation cont(kOverflow, ovf);
1774 return VisitBinop(this, node, kMips64DaddOvf, &cont);
1775 }
1776 FlagsContinuation cont;
1777 VisitBinop(this, node, kMips64DaddOvf, &cont);
1778}
1779
1780
1781void InstructionSelector::VisitInt64SubWithOverflow(Node* node) {
1782 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
1783 FlagsContinuation cont(kOverflow, ovf);
1784 return VisitBinop(this, node, kMips64DsubOvf, &cont);
1785 }
1786 FlagsContinuation cont;
1787 VisitBinop(this, node, kMips64DsubOvf, &cont);
1788}
1789
1790
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001791void InstructionSelector::VisitWord64Equal(Node* const node) {
1792 FlagsContinuation cont(kEqual, node);
1793 Int64BinopMatcher m(node);
1794 if (m.right().Is(0)) {
1795 return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
1796 }
1797
1798 VisitWord64Compare(this, node, &cont);
1799}
1800
1801
1802void InstructionSelector::VisitInt64LessThan(Node* node) {
1803 FlagsContinuation cont(kSignedLessThan, node);
1804 VisitWord64Compare(this, node, &cont);
1805}
1806
1807
1808void InstructionSelector::VisitInt64LessThanOrEqual(Node* node) {
1809 FlagsContinuation cont(kSignedLessThanOrEqual, node);
1810 VisitWord64Compare(this, node, &cont);
1811}
1812
1813
1814void InstructionSelector::VisitUint64LessThan(Node* node) {
1815 FlagsContinuation cont(kUnsignedLessThan, node);
1816 VisitWord64Compare(this, node, &cont);
1817}
1818
1819
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001820void InstructionSelector::VisitUint64LessThanOrEqual(Node* node) {
1821 FlagsContinuation cont(kUnsignedLessThanOrEqual, node);
1822 VisitWord64Compare(this, node, &cont);
1823}
1824
1825
1826void InstructionSelector::VisitFloat32Equal(Node* node) {
1827 FlagsContinuation cont(kEqual, node);
1828 VisitFloat32Compare(this, node, &cont);
1829}
1830
1831
1832void InstructionSelector::VisitFloat32LessThan(Node* node) {
1833 FlagsContinuation cont(kUnsignedLessThan, node);
1834 VisitFloat32Compare(this, node, &cont);
1835}
1836
1837
1838void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) {
1839 FlagsContinuation cont(kUnsignedLessThanOrEqual, node);
1840 VisitFloat32Compare(this, node, &cont);
1841}
1842
1843
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001844void InstructionSelector::VisitFloat64Equal(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001845 FlagsContinuation cont(kEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001846 VisitFloat64Compare(this, node, &cont);
1847}
1848
1849
1850void InstructionSelector::VisitFloat64LessThan(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001851 FlagsContinuation cont(kUnsignedLessThan, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001852 VisitFloat64Compare(this, node, &cont);
1853}
1854
1855
1856void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001857 FlagsContinuation cont(kUnsignedLessThanOrEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001858 VisitFloat64Compare(this, node, &cont);
1859}
1860
1861
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001862void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) {
1863 VisitRR(this, kMips64Float64ExtractLowWord32, node);
1864}
1865
1866
1867void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) {
1868 VisitRR(this, kMips64Float64ExtractHighWord32, node);
1869}
1870
1871
1872void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) {
1873 Mips64OperandGenerator g(this);
1874 Node* left = node->InputAt(0);
1875 Node* right = node->InputAt(1);
1876 Emit(kMips64Float64InsertLowWord32, g.DefineSameAsFirst(node),
1877 g.UseRegister(left), g.UseRegister(right));
1878}
1879
1880
1881void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
1882 Mips64OperandGenerator g(this);
1883 Node* left = node->InputAt(0);
1884 Node* right = node->InputAt(1);
1885 Emit(kMips64Float64InsertHighWord32, g.DefineSameAsFirst(node),
1886 g.UseRegister(left), g.UseRegister(right));
1887}
1888
1889
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001890// static
1891MachineOperatorBuilder::Flags
1892InstructionSelector::SupportedMachineOperatorFlags() {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001893 return MachineOperatorBuilder::kWord32Ctz |
1894 MachineOperatorBuilder::kWord64Ctz |
1895 MachineOperatorBuilder::kWord32Popcnt |
1896 MachineOperatorBuilder::kWord64Popcnt |
1897 MachineOperatorBuilder::kWord32ShiftIsSafe |
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001898 MachineOperatorBuilder::kInt32DivIsSafe |
1899 MachineOperatorBuilder::kUint32DivIsSafe |
1900 MachineOperatorBuilder::kFloat64Min |
1901 MachineOperatorBuilder::kFloat64Max |
1902 MachineOperatorBuilder::kFloat32Min |
1903 MachineOperatorBuilder::kFloat32Max |
1904 MachineOperatorBuilder::kFloat64RoundDown |
1905 MachineOperatorBuilder::kFloat32RoundDown |
1906 MachineOperatorBuilder::kFloat64RoundUp |
1907 MachineOperatorBuilder::kFloat32RoundUp |
1908 MachineOperatorBuilder::kFloat64RoundTruncate |
1909 MachineOperatorBuilder::kFloat32RoundTruncate |
1910 MachineOperatorBuilder::kFloat64RoundTiesEven |
1911 MachineOperatorBuilder::kFloat32RoundTiesEven;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001912}
1913
1914} // namespace compiler
1915} // namespace internal
1916} // namespace v8