blob: f86ffe76439f73b3daa7ac461b276c722bf29e83 [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 MipsOperandGenerator final : public OperandGenerator {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040023 public:
24 explicit MipsOperandGenerator(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 Int32Matcher m(node);
36 if (!m.HasValue()) return false;
37 int32_t value = m.Value();
38 switch (ArchOpcodeField::decode(opcode)) {
39 case kMipsShl:
40 case kMipsSar:
41 case kMipsShr:
42 return is_uint5(value);
43 case kMipsXor:
44 return is_uint16(value);
45 case kMipsLdc1:
46 case kMipsSdc1:
Emily Bernierd0a1eb72015-03-24 16:35:39 -040047 case kCheckedLoadFloat64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -040048 case kCheckedStoreFloat64:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000049 return std::numeric_limits<int16_t>::min() <= (value + kIntSize) &&
50 std::numeric_limits<int16_t>::max() >= (value + kIntSize);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040051 default:
52 return is_int16(value);
53 }
54 }
55
56 private:
57 bool ImmediateFitsAddrMode1Instruction(int32_t imm) const {
58 TRACE_UNIMPL();
59 return false;
60 }
61};
62
63
64static void VisitRRR(InstructionSelector* selector, ArchOpcode opcode,
65 Node* node) {
66 MipsOperandGenerator g(selector);
67 selector->Emit(opcode, g.DefineAsRegister(node),
68 g.UseRegister(node->InputAt(0)),
69 g.UseRegister(node->InputAt(1)));
70}
71
72
73static void VisitRR(InstructionSelector* selector, ArchOpcode opcode,
74 Node* node) {
75 MipsOperandGenerator g(selector);
76 selector->Emit(opcode, g.DefineAsRegister(node),
77 g.UseRegister(node->InputAt(0)));
78}
79
80
81static void VisitRRO(InstructionSelector* selector, ArchOpcode opcode,
82 Node* node) {
83 MipsOperandGenerator g(selector);
84 selector->Emit(opcode, g.DefineAsRegister(node),
85 g.UseRegister(node->InputAt(0)),
86 g.UseOperand(node->InputAt(1), opcode));
87}
88
89
90static void VisitBinop(InstructionSelector* selector, Node* node,
91 InstructionCode opcode, FlagsContinuation* cont) {
92 MipsOperandGenerator g(selector);
93 Int32BinopMatcher m(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000094 InstructionOperand inputs[4];
Emily Bernierd0a1eb72015-03-24 16:35:39 -040095 size_t input_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000096 InstructionOperand outputs[2];
Emily Bernierd0a1eb72015-03-24 16:35:39 -040097 size_t output_count = 0;
98
99 inputs[input_count++] = g.UseRegister(m.left().node());
100 inputs[input_count++] = g.UseOperand(m.right().node(), opcode);
101
102 if (cont->IsBranch()) {
103 inputs[input_count++] = g.Label(cont->true_block());
104 inputs[input_count++] = g.Label(cont->false_block());
105 }
106
107 outputs[output_count++] = g.DefineAsRegister(node);
108 if (cont->IsSet()) {
109 outputs[output_count++] = g.DefineAsRegister(cont->result());
110 }
111
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000112 DCHECK_NE(0u, input_count);
113 DCHECK_NE(0u, output_count);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400114 DCHECK_GE(arraysize(inputs), input_count);
115 DCHECK_GE(arraysize(outputs), output_count);
116
Ben Murdochda12d292016-06-02 14:46:10 +0100117 opcode = cont->Encode(opcode);
118 if (cont->IsDeoptimize()) {
119 selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
120 cont->frame_state());
121 } else {
122 selector->Emit(opcode, output_count, outputs, input_count, inputs);
123 }
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 MipsOperandGenerator 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 = kMipsLwc1;
144 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000145 case MachineRepresentation::kFloat64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400146 opcode = kMipsLdc1;
147 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000148 case MachineRepresentation::kBit: // Fall through.
149 case MachineRepresentation::kWord8:
150 opcode = load_rep.IsUnsigned() ? kMipsLbu : kMipsLb;
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() ? kMipsLhu : kMipsLh;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400154 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000155 case MachineRepresentation::kTagged: // Fall through.
156 case MachineRepresentation::kWord32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400157 opcode = kMipsLw;
158 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100159 case MachineRepresentation::kWord64: // Fall through.
160 case MachineRepresentation::kSimd128: // Fall through.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000161 case MachineRepresentation::kNone:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400162 UNREACHABLE();
163 return;
164 }
165
166 if (g.CanBeImmediate(index, opcode)) {
167 Emit(opcode | AddressingModeField::encode(kMode_MRI),
168 g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index));
169 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000170 InstructionOperand addr_reg = g.TempRegister();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400171 Emit(kMipsAdd | AddressingModeField::encode(kMode_None), addr_reg,
172 g.UseRegister(index), g.UseRegister(base));
173 // Emit desired load opcode, using temp addr_reg.
174 Emit(opcode | AddressingModeField::encode(kMode_MRI),
175 g.DefineAsRegister(node), addr_reg, g.TempImmediate(0));
176 }
177}
178
179
180void InstructionSelector::VisitStore(Node* node) {
181 MipsOperandGenerator g(this);
182 Node* base = node->InputAt(0);
183 Node* index = node->InputAt(1);
184 Node* value = node->InputAt(2);
185
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000186 StoreRepresentation store_rep = StoreRepresentationOf(node->op());
187 WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind();
188 MachineRepresentation rep = store_rep.representation();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400189
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000190 // TODO(mips): I guess this could be done in a better way.
191 if (write_barrier_kind != kNoWriteBarrier) {
192 DCHECK_EQ(MachineRepresentation::kTagged, rep);
193 InstructionOperand inputs[3];
194 size_t input_count = 0;
195 inputs[input_count++] = g.UseUniqueRegister(base);
196 inputs[input_count++] = g.UseUniqueRegister(index);
Ben Murdochda12d292016-06-02 14:46:10 +0100197 inputs[input_count++] = g.UseUniqueRegister(value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000198 RecordWriteMode record_write_mode = RecordWriteMode::kValueIsAny;
199 switch (write_barrier_kind) {
200 case kNoWriteBarrier:
201 UNREACHABLE();
202 break;
203 case kMapWriteBarrier:
204 record_write_mode = RecordWriteMode::kValueIsMap;
205 break;
206 case kPointerWriteBarrier:
207 record_write_mode = RecordWriteMode::kValueIsPointer;
208 break;
209 case kFullWriteBarrier:
210 record_write_mode = RecordWriteMode::kValueIsAny;
211 break;
212 }
213 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
214 size_t const temp_count = arraysize(temps);
215 InstructionCode code = kArchStoreWithWriteBarrier;
216 code |= MiscField::encode(static_cast<int>(record_write_mode));
217 Emit(code, 0, nullptr, input_count, inputs, temp_count, temps);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400218 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000219 ArchOpcode opcode = kArchNop;
220 switch (rep) {
221 case MachineRepresentation::kFloat32:
222 opcode = kMipsSwc1;
223 break;
224 case MachineRepresentation::kFloat64:
225 opcode = kMipsSdc1;
226 break;
227 case MachineRepresentation::kBit: // Fall through.
228 case MachineRepresentation::kWord8:
229 opcode = kMipsSb;
230 break;
231 case MachineRepresentation::kWord16:
232 opcode = kMipsSh;
233 break;
234 case MachineRepresentation::kTagged: // Fall through.
235 case MachineRepresentation::kWord32:
236 opcode = kMipsSw;
237 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100238 case MachineRepresentation::kWord64: // Fall through.
239 case MachineRepresentation::kSimd128: // Fall through.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000240 case MachineRepresentation::kNone:
241 UNREACHABLE();
242 return;
243 }
244
245 if (g.CanBeImmediate(index, opcode)) {
246 Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
247 g.UseRegister(base), g.UseImmediate(index), g.UseRegister(value));
248 } else {
249 InstructionOperand addr_reg = g.TempRegister();
250 Emit(kMipsAdd | AddressingModeField::encode(kMode_None), addr_reg,
251 g.UseRegister(index), g.UseRegister(base));
252 // Emit desired store opcode, using temp addr_reg.
253 Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
254 addr_reg, g.TempImmediate(0), g.UseRegister(value));
255 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400256 }
257}
258
259
260void InstructionSelector::VisitWord32And(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000261 MipsOperandGenerator g(this);
262 Int32BinopMatcher m(node);
263 if (m.left().IsWord32Shr() && CanCover(node, m.left().node()) &&
264 m.right().HasValue()) {
265 uint32_t mask = m.right().Value();
266 uint32_t mask_width = base::bits::CountPopulation32(mask);
267 uint32_t mask_msb = base::bits::CountLeadingZeros32(mask);
268 if ((mask_width != 0) && (mask_msb + mask_width == 32)) {
269 // The mask must be contiguous, and occupy the least-significant bits.
270 DCHECK_EQ(0u, base::bits::CountTrailingZeros32(mask));
271
272 // Select Ext for And(Shr(x, imm), mask) where the mask is in the least
273 // significant bits.
274 Int32BinopMatcher mleft(m.left().node());
275 if (mleft.right().HasValue()) {
276 // Any shift value can match; int32 shifts use `value % 32`.
277 uint32_t lsb = mleft.right().Value() & 0x1f;
278
279 // Ext cannot extract bits past the register size, however since
280 // shifting the original value would have introduced some zeros we can
281 // still use Ext with a smaller mask and the remaining bits will be
282 // zeros.
283 if (lsb + mask_width > 32) mask_width = 32 - lsb;
284
285 Emit(kMipsExt, g.DefineAsRegister(node),
286 g.UseRegister(mleft.left().node()), g.TempImmediate(lsb),
287 g.TempImmediate(mask_width));
288 return;
289 }
290 // Other cases fall through to the normal And operation.
291 }
292 }
293 if (m.right().HasValue()) {
294 uint32_t mask = m.right().Value();
295 uint32_t shift = base::bits::CountPopulation32(~mask);
296 uint32_t msb = base::bits::CountLeadingZeros32(~mask);
297 if (shift != 0 && shift != 32 && msb + shift == 32) {
298 // Insert zeros for (x >> K) << K => x & ~(2^K - 1) expression reduction
299 // and remove constant loading of invereted mask.
300 Emit(kMipsIns, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
301 g.TempImmediate(0), g.TempImmediate(shift));
302 return;
303 }
304 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400305 VisitBinop(this, node, kMipsAnd);
306}
307
308
309void InstructionSelector::VisitWord32Or(Node* node) {
310 VisitBinop(this, node, kMipsOr);
311}
312
313
314void InstructionSelector::VisitWord32Xor(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000315 Int32BinopMatcher m(node);
316 if (m.left().IsWord32Or() && CanCover(node, m.left().node()) &&
317 m.right().Is(-1)) {
318 Int32BinopMatcher mleft(m.left().node());
319 if (!mleft.right().HasValue()) {
320 MipsOperandGenerator g(this);
321 Emit(kMipsNor, g.DefineAsRegister(node),
322 g.UseRegister(mleft.left().node()),
323 g.UseRegister(mleft.right().node()));
324 return;
325 }
326 }
327 if (m.right().Is(-1)) {
328 // Use Nor for bit negation and eliminate constant loading for xori.
329 MipsOperandGenerator g(this);
330 Emit(kMipsNor, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
331 g.TempImmediate(0));
332 return;
333 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400334 VisitBinop(this, node, kMipsXor);
335}
336
337
338void InstructionSelector::VisitWord32Shl(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000339 Int32BinopMatcher m(node);
340 if (m.left().IsWord32And() && CanCover(node, m.left().node()) &&
341 m.right().IsInRange(1, 31)) {
342 MipsOperandGenerator g(this);
343 Int32BinopMatcher mleft(m.left().node());
344 // Match Word32Shl(Word32And(x, mask), imm) to Shl where the mask is
345 // contiguous, and the shift immediate non-zero.
346 if (mleft.right().HasValue()) {
347 uint32_t mask = mleft.right().Value();
348 uint32_t mask_width = base::bits::CountPopulation32(mask);
349 uint32_t mask_msb = base::bits::CountLeadingZeros32(mask);
350 if ((mask_width != 0) && (mask_msb + mask_width == 32)) {
351 uint32_t shift = m.right().Value();
352 DCHECK_EQ(0u, base::bits::CountTrailingZeros32(mask));
353 DCHECK_NE(0u, shift);
354 if ((shift + mask_width) >= 32) {
355 // If the mask is contiguous and reaches or extends beyond the top
356 // bit, only the shift is needed.
357 Emit(kMipsShl, g.DefineAsRegister(node),
358 g.UseRegister(mleft.left().node()),
359 g.UseImmediate(m.right().node()));
360 return;
361 }
362 }
363 }
364 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400365 VisitRRO(this, kMipsShl, node);
366}
367
368
369void InstructionSelector::VisitWord32Shr(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000370 Int32BinopMatcher m(node);
371 if (m.left().IsWord32And() && m.right().HasValue()) {
372 uint32_t lsb = m.right().Value() & 0x1f;
373 Int32BinopMatcher mleft(m.left().node());
374 if (mleft.right().HasValue()) {
375 // Select Ext for Shr(And(x, mask), imm) where the result of the mask is
376 // shifted into the least-significant bits.
377 uint32_t mask = (mleft.right().Value() >> lsb) << lsb;
378 unsigned mask_width = base::bits::CountPopulation32(mask);
379 unsigned mask_msb = base::bits::CountLeadingZeros32(mask);
380 if ((mask_msb + mask_width + lsb) == 32) {
381 MipsOperandGenerator g(this);
382 DCHECK_EQ(lsb, base::bits::CountTrailingZeros32(mask));
383 Emit(kMipsExt, g.DefineAsRegister(node),
384 g.UseRegister(mleft.left().node()), g.TempImmediate(lsb),
385 g.TempImmediate(mask_width));
386 return;
387 }
388 }
389 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400390 VisitRRO(this, kMipsShr, node);
391}
392
393
394void InstructionSelector::VisitWord32Sar(Node* node) {
395 VisitRRO(this, kMipsSar, node);
396}
397
Ben Murdochda12d292016-06-02 14:46:10 +0100398void InstructionSelector::VisitInt32PairAdd(Node* node) { UNIMPLEMENTED(); }
399
400void InstructionSelector::VisitInt32PairSub(Node* node) { UNIMPLEMENTED(); }
401
402void InstructionSelector::VisitInt32PairMul(Node* node) {
403 MipsOperandGenerator g(this);
404 InstructionOperand inputs[] = {g.UseUniqueRegister(node->InputAt(0)),
405 g.UseUniqueRegister(node->InputAt(1)),
406 g.UseUniqueRegister(node->InputAt(2)),
407 g.UseUniqueRegister(node->InputAt(3))};
408 InstructionOperand outputs[] = {
409 g.DefineAsRegister(node),
410 g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
411 Emit(kMipsMulPair, 2, outputs, 4, inputs);
412}
413
414void InstructionSelector::VisitWord32PairShl(Node* node) { UNIMPLEMENTED(); }
415
416void InstructionSelector::VisitWord32PairShr(Node* node) { UNIMPLEMENTED(); }
417
418void InstructionSelector::VisitWord32PairSar(Node* node) { UNIMPLEMENTED(); }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400419
420void InstructionSelector::VisitWord32Ror(Node* node) {
421 VisitRRO(this, kMipsRor, node);
422}
423
424
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000425void InstructionSelector::VisitWord32Clz(Node* node) {
426 VisitRR(this, kMipsClz, node);
427}
428
429
Ben Murdoch097c5b22016-05-18 11:27:45 +0100430void InstructionSelector::VisitWord32ReverseBits(Node* node) { UNREACHABLE(); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000431
432
Ben Murdoch097c5b22016-05-18 11:27:45 +0100433void InstructionSelector::VisitWord32Ctz(Node* node) {
434 MipsOperandGenerator g(this);
435 Emit(kMipsCtz, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
436}
437
438
439void InstructionSelector::VisitWord32Popcnt(Node* node) {
440 MipsOperandGenerator g(this);
441 Emit(kMipsPopcnt, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
442}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000443
444
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400445void InstructionSelector::VisitInt32Add(Node* node) {
446 MipsOperandGenerator g(this);
447
448 // TODO(plind): Consider multiply & add optimization from arm port.
449 VisitBinop(this, node, kMipsAdd);
450}
451
452
453void InstructionSelector::VisitInt32Sub(Node* node) {
454 VisitBinop(this, node, kMipsSub);
455}
456
457
458void InstructionSelector::VisitInt32Mul(Node* node) {
459 MipsOperandGenerator g(this);
460 Int32BinopMatcher m(node);
461 if (m.right().HasValue() && m.right().Value() > 0) {
462 int32_t value = m.right().Value();
463 if (base::bits::IsPowerOfTwo32(value)) {
464 Emit(kMipsShl | AddressingModeField::encode(kMode_None),
465 g.DefineAsRegister(node), g.UseRegister(m.left().node()),
466 g.TempImmediate(WhichPowerOf2(value)));
467 return;
468 }
469 if (base::bits::IsPowerOfTwo32(value - 1)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000470 InstructionOperand temp = g.TempRegister();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400471 Emit(kMipsShl | AddressingModeField::encode(kMode_None), temp,
472 g.UseRegister(m.left().node()),
473 g.TempImmediate(WhichPowerOf2(value - 1)));
474 Emit(kMipsAdd | AddressingModeField::encode(kMode_None),
475 g.DefineAsRegister(node), g.UseRegister(m.left().node()), temp);
476 return;
477 }
478 if (base::bits::IsPowerOfTwo32(value + 1)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000479 InstructionOperand temp = g.TempRegister();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400480 Emit(kMipsShl | AddressingModeField::encode(kMode_None), temp,
481 g.UseRegister(m.left().node()),
482 g.TempImmediate(WhichPowerOf2(value + 1)));
483 Emit(kMipsSub | AddressingModeField::encode(kMode_None),
484 g.DefineAsRegister(node), temp, g.UseRegister(m.left().node()));
485 return;
486 }
487 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000488 VisitRRR(this, kMipsMul, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400489}
490
491
492void InstructionSelector::VisitInt32MulHigh(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000493 VisitRRR(this, kMipsMulHigh, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400494}
495
496
497void InstructionSelector::VisitUint32MulHigh(Node* node) {
498 MipsOperandGenerator g(this);
499 Emit(kMipsMulHighU, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
500 g.UseRegister(node->InputAt(1)));
501}
502
503
504void InstructionSelector::VisitInt32Div(Node* node) {
505 MipsOperandGenerator g(this);
506 Int32BinopMatcher m(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000507 Emit(kMipsDiv, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400508 g.UseRegister(m.right().node()));
509}
510
511
512void InstructionSelector::VisitUint32Div(Node* node) {
513 MipsOperandGenerator g(this);
514 Int32BinopMatcher m(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000515 Emit(kMipsDivU, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400516 g.UseRegister(m.right().node()));
517}
518
519
520void InstructionSelector::VisitInt32Mod(Node* node) {
521 MipsOperandGenerator g(this);
522 Int32BinopMatcher m(node);
523 Emit(kMipsMod, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
524 g.UseRegister(m.right().node()));
525}
526
527
528void InstructionSelector::VisitUint32Mod(Node* node) {
529 MipsOperandGenerator g(this);
530 Int32BinopMatcher m(node);
531 Emit(kMipsModU, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
532 g.UseRegister(m.right().node()));
533}
534
535
536void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000537 VisitRR(this, kMipsCvtDS, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400538}
539
540
Ben Murdoch097c5b22016-05-18 11:27:45 +0100541void InstructionSelector::VisitRoundInt32ToFloat32(Node* node) {
542 VisitRR(this, kMipsCvtSW, node);
543}
544
545
546void InstructionSelector::VisitRoundUint32ToFloat32(Node* node) {
547 VisitRR(this, kMipsCvtSUw, node);
548}
549
550
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400551void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000552 VisitRR(this, kMipsCvtDW, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400553}
554
555
556void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000557 VisitRR(this, kMipsCvtDUw, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400558}
559
560
Ben Murdoch097c5b22016-05-18 11:27:45 +0100561void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) {
562 VisitRR(this, kMipsTruncWS, node);
563}
564
565
566void InstructionSelector::VisitTruncateFloat32ToUint32(Node* node) {
567 VisitRR(this, kMipsTruncUwS, node);
568}
569
570
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400571void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
572 MipsOperandGenerator g(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000573 Node* value = node->InputAt(0);
574 // Match ChangeFloat64ToInt32(Float64Round##OP) to corresponding instruction
575 // which does rounding and conversion to integer format.
576 if (CanCover(node, value)) {
577 switch (value->opcode()) {
578 case IrOpcode::kFloat64RoundDown:
579 Emit(kMipsFloorWD, g.DefineAsRegister(node),
580 g.UseRegister(value->InputAt(0)));
581 return;
582 case IrOpcode::kFloat64RoundUp:
583 Emit(kMipsCeilWD, g.DefineAsRegister(node),
584 g.UseRegister(value->InputAt(0)));
585 return;
586 case IrOpcode::kFloat64RoundTiesEven:
587 Emit(kMipsRoundWD, g.DefineAsRegister(node),
588 g.UseRegister(value->InputAt(0)));
589 return;
590 case IrOpcode::kFloat64RoundTruncate:
591 Emit(kMipsTruncWD, g.DefineAsRegister(node),
592 g.UseRegister(value->InputAt(0)));
593 return;
594 default:
595 break;
596 }
597 if (value->opcode() == IrOpcode::kChangeFloat32ToFloat64) {
598 Node* next = value->InputAt(0);
599 if (CanCover(value, next)) {
600 // Match ChangeFloat64ToInt32(ChangeFloat32ToFloat64(Float64Round##OP))
601 switch (next->opcode()) {
602 case IrOpcode::kFloat32RoundDown:
603 Emit(kMipsFloorWS, g.DefineAsRegister(node),
604 g.UseRegister(next->InputAt(0)));
605 return;
606 case IrOpcode::kFloat32RoundUp:
607 Emit(kMipsCeilWS, g.DefineAsRegister(node),
608 g.UseRegister(next->InputAt(0)));
609 return;
610 case IrOpcode::kFloat32RoundTiesEven:
611 Emit(kMipsRoundWS, g.DefineAsRegister(node),
612 g.UseRegister(next->InputAt(0)));
613 return;
614 case IrOpcode::kFloat32RoundTruncate:
615 Emit(kMipsTruncWS, g.DefineAsRegister(node),
616 g.UseRegister(next->InputAt(0)));
617 return;
618 default:
619 Emit(kMipsTruncWS, g.DefineAsRegister(node),
620 g.UseRegister(value->InputAt(0)));
621 return;
622 }
623 } else {
624 // Match float32 -> float64 -> int32 representation change path.
625 Emit(kMipsTruncWS, g.DefineAsRegister(node),
626 g.UseRegister(value->InputAt(0)));
627 return;
628 }
629 }
630 }
631 VisitRR(this, kMipsTruncWD, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400632}
633
634
635void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000636 VisitRR(this, kMipsTruncUwD, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400637}
638
Ben Murdochda12d292016-06-02 14:46:10 +0100639void InstructionSelector::VisitTruncateFloat64ToUint32(Node* node) {
640 VisitRR(this, kMipsTruncUwD, node);
641}
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400642
643void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
644 MipsOperandGenerator g(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000645 Node* value = node->InputAt(0);
646 // Match TruncateFloat64ToFloat32(ChangeInt32ToFloat64) to corresponding
647 // instruction.
648 if (CanCover(node, value) &&
649 value->opcode() == IrOpcode::kChangeInt32ToFloat64) {
650 Emit(kMipsCvtSW, g.DefineAsRegister(node),
651 g.UseRegister(value->InputAt(0)));
652 return;
653 }
654 VisitRR(this, kMipsCvtSD, node);
655}
656
657
658void InstructionSelector::VisitTruncateFloat64ToInt32(Node* node) {
659 switch (TruncationModeOf(node->op())) {
660 case TruncationMode::kJavaScript:
661 return VisitRR(this, kArchTruncateDoubleToI, node);
662 case TruncationMode::kRoundToZero:
663 return VisitRR(this, kMipsTruncWD, node);
664 }
665 UNREACHABLE();
666}
667
668
669void InstructionSelector::VisitBitcastFloat32ToInt32(Node* node) {
670 VisitRR(this, kMipsFloat64ExtractLowWord32, node);
671}
672
673
674void InstructionSelector::VisitBitcastInt32ToFloat32(Node* node) {
675 MipsOperandGenerator g(this);
676 Emit(kMipsFloat64InsertLowWord32, g.DefineAsRegister(node),
677 ImmediateOperand(ImmediateOperand::INLINE, 0),
678 g.UseRegister(node->InputAt(0)));
679}
680
681
682void InstructionSelector::VisitFloat32Add(Node* node) {
683 VisitRRR(this, kMipsAddS, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400684}
685
686
687void InstructionSelector::VisitFloat64Add(Node* node) {
688 VisitRRR(this, kMipsAddD, node);
689}
690
691
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000692void InstructionSelector::VisitFloat32Sub(Node* node) {
693 VisitRRR(this, kMipsSubS, node);
694}
695
696
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400697void InstructionSelector::VisitFloat64Sub(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000698 MipsOperandGenerator g(this);
699 Float64BinopMatcher m(node);
700 if (m.left().IsMinusZero() && m.right().IsFloat64RoundDown() &&
701 CanCover(m.node(), m.right().node())) {
702 if (m.right().InputAt(0)->opcode() == IrOpcode::kFloat64Sub &&
703 CanCover(m.right().node(), m.right().InputAt(0))) {
704 Float64BinopMatcher mright0(m.right().InputAt(0));
705 if (mright0.left().IsMinusZero()) {
706 Emit(kMipsFloat64RoundUp, g.DefineAsRegister(node),
707 g.UseRegister(mright0.right().node()));
708 return;
709 }
710 }
711 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400712 VisitRRR(this, kMipsSubD, node);
713}
714
715
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000716void InstructionSelector::VisitFloat32Mul(Node* node) {
717 VisitRRR(this, kMipsMulS, node);
718}
719
720
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400721void InstructionSelector::VisitFloat64Mul(Node* node) {
722 VisitRRR(this, kMipsMulD, node);
723}
724
725
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000726void InstructionSelector::VisitFloat32Div(Node* node) {
727 VisitRRR(this, kMipsDivS, node);
728}
729
730
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400731void InstructionSelector::VisitFloat64Div(Node* node) {
732 VisitRRR(this, kMipsDivD, node);
733}
734
735
736void InstructionSelector::VisitFloat64Mod(Node* node) {
737 MipsOperandGenerator g(this);
738 Emit(kMipsModD, g.DefineAsFixed(node, f0), g.UseFixed(node->InputAt(0), f12),
739 g.UseFixed(node->InputAt(1), f14))->MarkAsCall();
740}
741
742
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000743void InstructionSelector::VisitFloat32Max(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400744 MipsOperandGenerator g(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000745 if (IsMipsArchVariant(kMips32r6)) {
746 Emit(kMipsFloat32Max, g.DefineAsRegister(node),
747 g.UseUniqueRegister(node->InputAt(0)),
748 g.UseUniqueRegister(node->InputAt(1)));
749
750 } else {
751 // Reverse operands, and use same reg. for result and right operand.
752 Emit(kMipsFloat32Max, g.DefineSameAsFirst(node),
753 g.UseRegister(node->InputAt(1)), g.UseRegister(node->InputAt(0)));
754 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400755}
756
757
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000758void InstructionSelector::VisitFloat64Max(Node* node) {
759 MipsOperandGenerator g(this);
760 if (IsMipsArchVariant(kMips32r6)) {
761 Emit(kMipsFloat64Max, g.DefineAsRegister(node),
762 g.UseUniqueRegister(node->InputAt(0)),
763 g.UseUniqueRegister(node->InputAt(1)));
764
765 } else {
766 // Reverse operands, and use same reg. for result and right operand.
767 Emit(kMipsFloat64Max, g.DefineSameAsFirst(node),
768 g.UseRegister(node->InputAt(1)), g.UseRegister(node->InputAt(0)));
769 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400770}
771
772
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000773void InstructionSelector::VisitFloat32Min(Node* node) {
774 MipsOperandGenerator g(this);
775 if (IsMipsArchVariant(kMips32r6)) {
776 Emit(kMipsFloat32Min, g.DefineAsRegister(node),
777 g.UseUniqueRegister(node->InputAt(0)),
778 g.UseUniqueRegister(node->InputAt(1)));
779
780 } else {
781 // Reverse operands, and use same reg. for result and right operand.
782 Emit(kMipsFloat32Min, g.DefineSameAsFirst(node),
783 g.UseRegister(node->InputAt(1)), g.UseRegister(node->InputAt(0)));
784 }
785}
786
787
788void InstructionSelector::VisitFloat64Min(Node* node) {
789 MipsOperandGenerator g(this);
790 if (IsMipsArchVariant(kMips32r6)) {
791 Emit(kMipsFloat64Min, g.DefineAsRegister(node),
792 g.UseUniqueRegister(node->InputAt(0)),
793 g.UseUniqueRegister(node->InputAt(1)));
794
795 } else {
796 // Reverse operands, and use same reg. for result and right operand.
797 Emit(kMipsFloat64Min, g.DefineSameAsFirst(node),
798 g.UseRegister(node->InputAt(1)), g.UseRegister(node->InputAt(0)));
799 }
800}
801
802
803void InstructionSelector::VisitFloat32Abs(Node* node) {
804 VisitRR(this, kMipsAbsS, node);
805}
806
807
808void InstructionSelector::VisitFloat64Abs(Node* node) {
809 VisitRR(this, kMipsAbsD, node);
810}
811
812
813void InstructionSelector::VisitFloat32Sqrt(Node* node) {
814 VisitRR(this, kMipsSqrtS, node);
815}
816
817
818void InstructionSelector::VisitFloat64Sqrt(Node* node) {
819 VisitRR(this, kMipsSqrtD, node);
820}
821
822
823void InstructionSelector::VisitFloat32RoundDown(Node* node) {
824 VisitRR(this, kMipsFloat32RoundDown, node);
825}
826
827
828void InstructionSelector::VisitFloat64RoundDown(Node* node) {
829 VisitRR(this, kMipsFloat64RoundDown, node);
830}
831
832
833void InstructionSelector::VisitFloat32RoundUp(Node* node) {
834 VisitRR(this, kMipsFloat32RoundUp, node);
835}
836
837
838void InstructionSelector::VisitFloat64RoundUp(Node* node) {
839 VisitRR(this, kMipsFloat64RoundUp, node);
840}
841
842
843void InstructionSelector::VisitFloat32RoundTruncate(Node* node) {
844 VisitRR(this, kMipsFloat32RoundTruncate, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400845}
846
847
848void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
849 VisitRR(this, kMipsFloat64RoundTruncate, node);
850}
851
852
853void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
854 UNREACHABLE();
855}
856
857
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000858void InstructionSelector::VisitFloat32RoundTiesEven(Node* node) {
859 VisitRR(this, kMipsFloat32RoundTiesEven, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400860}
861
862
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000863void InstructionSelector::VisitFloat64RoundTiesEven(Node* node) {
864 VisitRR(this, kMipsFloat64RoundTiesEven, node);
865}
866
867
868void InstructionSelector::EmitPrepareArguments(
869 ZoneVector<PushParameter>* arguments, const CallDescriptor* descriptor,
870 Node* node) {
871 MipsOperandGenerator g(this);
872
873 // Prepare for C function call.
874 if (descriptor->IsCFunctionCall()) {
875 Emit(kArchPrepareCallCFunction |
876 MiscField::encode(static_cast<int>(descriptor->CParameterCount())),
877 0, nullptr, 0, nullptr);
878
879 // Poke any stack arguments.
880 int slot = kCArgSlotCount;
881 for (PushParameter input : (*arguments)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100882 if (input.node()) {
883 Emit(kMipsStoreToStackSlot, g.NoOutput(), g.UseRegister(input.node()),
884 g.TempImmediate(slot << kPointerSizeLog2));
885 ++slot;
886 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000887 }
888 } else {
889 // Possibly align stack here for functions.
890 int push_count = static_cast<int>(descriptor->StackParameterCount());
891 if (push_count > 0) {
892 Emit(kMipsStackClaim, g.NoOutput(),
893 g.TempImmediate(push_count << kPointerSizeLog2));
894 }
895 for (size_t n = 0; n < arguments->size(); ++n) {
896 PushParameter input = (*arguments)[n];
897 if (input.node()) {
898 Emit(kMipsStoreToStackSlot, g.NoOutput(), g.UseRegister(input.node()),
899 g.TempImmediate(n << kPointerSizeLog2));
900 }
901 }
902 }
903}
904
905
906bool InstructionSelector::IsTailCallAddressImmediate() { return false; }
907
Ben Murdochda12d292016-06-02 14:46:10 +0100908int InstructionSelector::GetTempsCountForTailCallFromJSFunction() { return 3; }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000909
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400910void InstructionSelector::VisitCheckedLoad(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000911 CheckedLoadRepresentation load_rep = CheckedLoadRepresentationOf(node->op());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400912 MipsOperandGenerator g(this);
913 Node* const buffer = node->InputAt(0);
914 Node* const offset = node->InputAt(1);
915 Node* const length = node->InputAt(2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000916 ArchOpcode opcode = kArchNop;
917 switch (load_rep.representation()) {
918 case MachineRepresentation::kWord8:
919 opcode = load_rep.IsSigned() ? kCheckedLoadInt8 : kCheckedLoadUint8;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400920 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000921 case MachineRepresentation::kWord16:
922 opcode = load_rep.IsSigned() ? kCheckedLoadInt16 : kCheckedLoadUint16;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400923 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000924 case MachineRepresentation::kWord32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400925 opcode = kCheckedLoadWord32;
926 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000927 case MachineRepresentation::kFloat32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400928 opcode = kCheckedLoadFloat32;
929 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000930 case MachineRepresentation::kFloat64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400931 opcode = kCheckedLoadFloat64;
932 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100933 case MachineRepresentation::kBit: // Fall through.
934 case MachineRepresentation::kTagged: // Fall through.
935 case MachineRepresentation::kWord64: // Fall through.
936 case MachineRepresentation::kSimd128: // Fall through.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000937 case MachineRepresentation::kNone:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400938 UNREACHABLE();
939 return;
940 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000941 InstructionOperand offset_operand = g.CanBeImmediate(offset, opcode)
942 ? g.UseImmediate(offset)
943 : g.UseRegister(offset);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400944
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000945 InstructionOperand length_operand = (!g.CanBeImmediate(offset, opcode))
946 ? g.CanBeImmediate(length, opcode)
947 ? g.UseImmediate(length)
948 : g.UseRegister(length)
949 : g.UseRegister(length);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400950
951 Emit(opcode | AddressingModeField::encode(kMode_MRI),
952 g.DefineAsRegister(node), offset_operand, length_operand,
953 g.UseRegister(buffer));
954}
955
956
957void InstructionSelector::VisitCheckedStore(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000958 MachineRepresentation rep = CheckedStoreRepresentationOf(node->op());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400959 MipsOperandGenerator g(this);
960 Node* const buffer = node->InputAt(0);
961 Node* const offset = node->InputAt(1);
962 Node* const length = node->InputAt(2);
963 Node* const value = node->InputAt(3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000964 ArchOpcode opcode = kArchNop;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400965 switch (rep) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000966 case MachineRepresentation::kWord8:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400967 opcode = kCheckedStoreWord8;
968 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000969 case MachineRepresentation::kWord16:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400970 opcode = kCheckedStoreWord16;
971 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000972 case MachineRepresentation::kWord32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400973 opcode = kCheckedStoreWord32;
974 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000975 case MachineRepresentation::kFloat32:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400976 opcode = kCheckedStoreFloat32;
977 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000978 case MachineRepresentation::kFloat64:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400979 opcode = kCheckedStoreFloat64;
980 break;
981 default:
982 UNREACHABLE();
983 return;
984 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000985 InstructionOperand offset_operand = g.CanBeImmediate(offset, opcode)
986 ? g.UseImmediate(offset)
987 : g.UseRegister(offset);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400988
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000989 InstructionOperand length_operand = (!g.CanBeImmediate(offset, opcode))
990 ? g.CanBeImmediate(length, opcode)
991 ? g.UseImmediate(length)
992 : g.UseRegister(length)
993 : g.UseRegister(length);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400994
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000995 Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
996 offset_operand, length_operand, g.UseRegister(value),
997 g.UseRegister(buffer));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400998}
999
1000
1001namespace {
1002
1003// Shared routine for multiple compare operations.
1004static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001005 InstructionOperand left, InstructionOperand right,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001006 FlagsContinuation* cont) {
1007 MipsOperandGenerator g(selector);
1008 opcode = cont->Encode(opcode);
1009 if (cont->IsBranch()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001010 selector->Emit(opcode, g.NoOutput(), left, right,
1011 g.Label(cont->true_block()), g.Label(cont->false_block()));
Ben Murdochda12d292016-06-02 14:46:10 +01001012 } else if (cont->IsDeoptimize()) {
1013 selector->EmitDeoptimize(opcode, g.NoOutput(), left, right,
1014 cont->frame_state());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001015 } else {
1016 DCHECK(cont->IsSet());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001017 selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
1018 }
1019}
1020
1021
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001022// Shared routine for multiple float32 compare operations.
1023void VisitFloat32Compare(InstructionSelector* selector, Node* node,
1024 FlagsContinuation* cont) {
1025 MipsOperandGenerator g(selector);
1026 Float32BinopMatcher m(node);
1027 InstructionOperand lhs, rhs;
1028
1029 lhs = m.left().IsZero() ? g.UseImmediate(m.left().node())
1030 : g.UseRegister(m.left().node());
1031 rhs = m.right().IsZero() ? g.UseImmediate(m.right().node())
1032 : g.UseRegister(m.right().node());
1033 VisitCompare(selector, kMipsCmpS, lhs, rhs, cont);
1034}
1035
1036
1037// Shared routine for multiple float64 compare operations.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001038void VisitFloat64Compare(InstructionSelector* selector, Node* node,
1039 FlagsContinuation* cont) {
1040 MipsOperandGenerator g(selector);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001041 Float64BinopMatcher m(node);
1042 InstructionOperand lhs, rhs;
1043
1044 lhs = m.left().IsZero() ? g.UseImmediate(m.left().node())
1045 : g.UseRegister(m.left().node());
1046 rhs = m.right().IsZero() ? g.UseImmediate(m.right().node())
1047 : g.UseRegister(m.right().node());
1048 VisitCompare(selector, kMipsCmpD, lhs, rhs, cont);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001049}
1050
1051
1052// Shared routine for multiple word compare operations.
1053void VisitWordCompare(InstructionSelector* selector, Node* node,
1054 InstructionCode opcode, FlagsContinuation* cont,
1055 bool commutative) {
1056 MipsOperandGenerator g(selector);
1057 Node* left = node->InputAt(0);
1058 Node* right = node->InputAt(1);
1059
1060 // Match immediates on left or right side of comparison.
1061 if (g.CanBeImmediate(right, opcode)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001062 switch (cont->condition()) {
1063 case kEqual:
1064 case kNotEqual:
1065 if (cont->IsSet()) {
1066 VisitCompare(selector, opcode, g.UseRegister(left),
1067 g.UseImmediate(right), cont);
1068 } else {
1069 VisitCompare(selector, opcode, g.UseRegister(left),
1070 g.UseRegister(right), cont);
1071 }
1072 break;
1073 case kSignedLessThan:
1074 case kSignedGreaterThanOrEqual:
1075 case kUnsignedLessThan:
1076 case kUnsignedGreaterThanOrEqual:
1077 VisitCompare(selector, opcode, g.UseRegister(left),
1078 g.UseImmediate(right), cont);
1079 break;
1080 default:
1081 VisitCompare(selector, opcode, g.UseRegister(left),
1082 g.UseRegister(right), cont);
1083 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001084 } else if (g.CanBeImmediate(left, opcode)) {
1085 if (!commutative) cont->Commute();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001086 switch (cont->condition()) {
1087 case kEqual:
1088 case kNotEqual:
1089 if (cont->IsSet()) {
1090 VisitCompare(selector, opcode, g.UseRegister(right),
1091 g.UseImmediate(left), cont);
1092 } else {
1093 VisitCompare(selector, opcode, g.UseRegister(right),
1094 g.UseRegister(left), cont);
1095 }
1096 break;
1097 case kSignedLessThan:
1098 case kSignedGreaterThanOrEqual:
1099 case kUnsignedLessThan:
1100 case kUnsignedGreaterThanOrEqual:
1101 VisitCompare(selector, opcode, g.UseRegister(right),
1102 g.UseImmediate(left), cont);
1103 break;
1104 default:
1105 VisitCompare(selector, opcode, g.UseRegister(right),
1106 g.UseRegister(left), cont);
1107 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001108 } else {
1109 VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right),
1110 cont);
1111 }
1112}
1113
1114
1115void VisitWordCompare(InstructionSelector* selector, Node* node,
1116 FlagsContinuation* cont) {
1117 VisitWordCompare(selector, node, kMipsCmp, cont, false);
1118}
1119
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001120// Shared routine for word comparisons against zero.
1121void VisitWordCompareZero(InstructionSelector* selector, Node* user,
1122 Node* value, FlagsContinuation* cont) {
1123 while (selector->CanCover(user, value)) {
1124 switch (value->opcode()) {
1125 case IrOpcode::kWord32Equal: {
1126 // Combine with comparisons against 0 by simply inverting the
1127 // continuation.
1128 Int32BinopMatcher m(value);
1129 if (m.right().Is(0)) {
1130 user = value;
1131 value = m.left().node();
1132 cont->Negate();
1133 continue;
1134 }
1135 cont->OverwriteAndNegateIfEqual(kEqual);
1136 return VisitWordCompare(selector, value, cont);
1137 }
1138 case IrOpcode::kInt32LessThan:
1139 cont->OverwriteAndNegateIfEqual(kSignedLessThan);
1140 return VisitWordCompare(selector, value, cont);
1141 case IrOpcode::kInt32LessThanOrEqual:
1142 cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
1143 return VisitWordCompare(selector, value, cont);
1144 case IrOpcode::kUint32LessThan:
1145 cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
1146 return VisitWordCompare(selector, value, cont);
1147 case IrOpcode::kUint32LessThanOrEqual:
1148 cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
1149 return VisitWordCompare(selector, value, cont);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001150 case IrOpcode::kFloat32Equal:
1151 cont->OverwriteAndNegateIfEqual(kEqual);
1152 return VisitFloat32Compare(selector, value, cont);
1153 case IrOpcode::kFloat32LessThan:
1154 cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
1155 return VisitFloat32Compare(selector, value, cont);
1156 case IrOpcode::kFloat32LessThanOrEqual:
1157 cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
1158 return VisitFloat32Compare(selector, value, cont);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001159 case IrOpcode::kFloat64Equal:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001160 cont->OverwriteAndNegateIfEqual(kEqual);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001161 return VisitFloat64Compare(selector, value, cont);
1162 case IrOpcode::kFloat64LessThan:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001163 cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001164 return VisitFloat64Compare(selector, value, cont);
1165 case IrOpcode::kFloat64LessThanOrEqual:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001166 cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001167 return VisitFloat64Compare(selector, value, cont);
1168 case IrOpcode::kProjection:
1169 // Check if this is the overflow output projection of an
1170 // <Operation>WithOverflow node.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001171 if (ProjectionIndexOf(value->op()) == 1u) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001172 // We cannot combine the <Operation>WithOverflow with this branch
1173 // unless the 0th projection (the use of the actual value of the
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001174 // <Operation> is either nullptr, which means there's no use of the
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001175 // actual value, or was already defined, which means it is scheduled
1176 // *AFTER* this branch).
1177 Node* const node = value->InputAt(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001178 Node* const result = NodeProperties::FindProjection(node, 0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001179 if (!result || selector->IsDefined(result)) {
1180 switch (node->opcode()) {
1181 case IrOpcode::kInt32AddWithOverflow:
1182 cont->OverwriteAndNegateIfEqual(kOverflow);
1183 return VisitBinop(selector, node, kMipsAddOvf, cont);
1184 case IrOpcode::kInt32SubWithOverflow:
1185 cont->OverwriteAndNegateIfEqual(kOverflow);
1186 return VisitBinop(selector, node, kMipsSubOvf, cont);
1187 default:
1188 break;
1189 }
1190 }
1191 }
1192 break;
1193 case IrOpcode::kWord32And:
1194 return VisitWordCompare(selector, value, kMipsTst, cont, true);
1195 default:
1196 break;
1197 }
1198 break;
1199 }
1200
1201 // Continuation could not be combined with a compare, emit compare against 0.
1202 MipsOperandGenerator g(selector);
1203 InstructionCode const opcode = cont->Encode(kMipsCmp);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001204 InstructionOperand const value_operand = g.UseRegister(value);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001205 if (cont->IsBranch()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001206 selector->Emit(opcode, g.NoOutput(), value_operand, g.TempImmediate(0),
1207 g.Label(cont->true_block()), g.Label(cont->false_block()));
Ben Murdochda12d292016-06-02 14:46:10 +01001208 } else if (cont->IsDeoptimize()) {
1209 selector->EmitDeoptimize(opcode, g.NoOutput(), value_operand,
1210 g.TempImmediate(0), cont->frame_state());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001211 } else {
Ben Murdochda12d292016-06-02 14:46:10 +01001212 DCHECK(cont->IsSet());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001213 selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand,
1214 g.TempImmediate(0));
1215 }
1216}
1217
Ben Murdochda12d292016-06-02 14:46:10 +01001218} // namespace
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001219
1220void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
1221 BasicBlock* fbranch) {
1222 FlagsContinuation cont(kNotEqual, tbranch, fbranch);
1223 VisitWordCompareZero(this, branch, branch->InputAt(0), &cont);
1224}
1225
Ben Murdochda12d292016-06-02 14:46:10 +01001226void InstructionSelector::VisitDeoptimizeIf(Node* node) {
1227 FlagsContinuation cont =
1228 FlagsContinuation::ForDeoptimize(kNotEqual, node->InputAt(1));
1229 VisitWordCompareZero(this, node, node->InputAt(0), &cont);
1230}
1231
1232void InstructionSelector::VisitDeoptimizeUnless(Node* node) {
1233 FlagsContinuation cont =
1234 FlagsContinuation::ForDeoptimize(kEqual, node->InputAt(1));
1235 VisitWordCompareZero(this, node, node->InputAt(0), &cont);
1236}
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001237
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001238void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
1239 MipsOperandGenerator g(this);
1240 InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
1241
1242 // Emit either ArchTableSwitch or ArchLookupSwitch.
1243 size_t table_space_cost = 9 + sw.value_range;
1244 size_t table_time_cost = 3;
1245 size_t lookup_space_cost = 2 + 2 * sw.case_count;
1246 size_t lookup_time_cost = sw.case_count;
1247 if (sw.case_count > 0 &&
1248 table_space_cost + 3 * table_time_cost <=
1249 lookup_space_cost + 3 * lookup_time_cost &&
1250 sw.min_value > std::numeric_limits<int32_t>::min()) {
1251 InstructionOperand index_operand = value_operand;
1252 if (sw.min_value) {
1253 index_operand = g.TempRegister();
1254 Emit(kMipsSub, index_operand, value_operand,
1255 g.TempImmediate(sw.min_value));
1256 }
1257 // Generate a table lookup.
1258 return EmitTableSwitch(sw, index_operand);
1259 }
1260
1261 // Generate a sequence of conditional jumps.
1262 return EmitLookupSwitch(sw, value_operand);
1263}
1264
1265
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001266void InstructionSelector::VisitWord32Equal(Node* const node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001267 FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001268 Int32BinopMatcher m(node);
1269 if (m.right().Is(0)) {
1270 return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
1271 }
1272 VisitWordCompare(this, node, &cont);
1273}
1274
1275
1276void InstructionSelector::VisitInt32LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001277 FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001278 VisitWordCompare(this, node, &cont);
1279}
1280
1281
1282void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001283 FlagsContinuation cont =
1284 FlagsContinuation::ForSet(kSignedLessThanOrEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001285 VisitWordCompare(this, node, &cont);
1286}
1287
1288
1289void InstructionSelector::VisitUint32LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001290 FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001291 VisitWordCompare(this, node, &cont);
1292}
1293
1294
1295void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001296 FlagsContinuation cont =
1297 FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001298 VisitWordCompare(this, node, &cont);
1299}
1300
1301
1302void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001303 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
Ben Murdochda12d292016-06-02 14:46:10 +01001304 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001305 return VisitBinop(this, node, kMipsAddOvf, &cont);
1306 }
1307 FlagsContinuation cont;
1308 VisitBinop(this, node, kMipsAddOvf, &cont);
1309}
1310
1311
1312void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001313 if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
Ben Murdochda12d292016-06-02 14:46:10 +01001314 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001315 return VisitBinop(this, node, kMipsSubOvf, &cont);
1316 }
1317 FlagsContinuation cont;
1318 VisitBinop(this, node, kMipsSubOvf, &cont);
1319}
1320
1321
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001322void InstructionSelector::VisitFloat32Equal(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001323 FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001324 VisitFloat32Compare(this, node, &cont);
1325}
1326
1327
1328void InstructionSelector::VisitFloat32LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001329 FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001330 VisitFloat32Compare(this, node, &cont);
1331}
1332
1333
1334void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001335 FlagsContinuation cont =
1336 FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001337 VisitFloat32Compare(this, node, &cont);
1338}
1339
1340
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001341void InstructionSelector::VisitFloat64Equal(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001342 FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001343 VisitFloat64Compare(this, node, &cont);
1344}
1345
1346
1347void InstructionSelector::VisitFloat64LessThan(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001348 FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001349 VisitFloat64Compare(this, node, &cont);
1350}
1351
1352
1353void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001354 FlagsContinuation cont =
1355 FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001356 VisitFloat64Compare(this, node, &cont);
1357}
1358
1359
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001360void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) {
1361 MipsOperandGenerator g(this);
1362 Emit(kMipsFloat64ExtractLowWord32, g.DefineAsRegister(node),
1363 g.UseRegister(node->InputAt(0)));
1364}
1365
1366
1367void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) {
1368 MipsOperandGenerator g(this);
1369 Emit(kMipsFloat64ExtractHighWord32, g.DefineAsRegister(node),
1370 g.UseRegister(node->InputAt(0)));
1371}
1372
1373
1374void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) {
1375 MipsOperandGenerator g(this);
1376 Node* left = node->InputAt(0);
1377 Node* right = node->InputAt(1);
1378 Emit(kMipsFloat64InsertLowWord32, g.DefineSameAsFirst(node),
1379 g.UseRegister(left), g.UseRegister(right));
1380}
1381
1382
1383void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
1384 MipsOperandGenerator g(this);
1385 Node* left = node->InputAt(0);
1386 Node* right = node->InputAt(1);
1387 Emit(kMipsFloat64InsertHighWord32, g.DefineSameAsFirst(node),
1388 g.UseRegister(left), g.UseRegister(right));
1389}
1390
1391
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001392// static
1393MachineOperatorBuilder::Flags
1394InstructionSelector::SupportedMachineOperatorFlags() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001395 MachineOperatorBuilder::Flags flags = MachineOperatorBuilder::kNoFlags;
1396 if ((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
1397 IsFp64Mode()) {
1398 flags |= MachineOperatorBuilder::kFloat64RoundDown |
1399 MachineOperatorBuilder::kFloat64RoundUp |
1400 MachineOperatorBuilder::kFloat64RoundTruncate |
1401 MachineOperatorBuilder::kFloat64RoundTiesEven;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001402 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001403 return flags | MachineOperatorBuilder::kWord32Ctz |
1404 MachineOperatorBuilder::kWord32Popcnt |
1405 MachineOperatorBuilder::kInt32DivIsSafe |
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001406 MachineOperatorBuilder::kUint32DivIsSafe |
1407 MachineOperatorBuilder::kWord32ShiftIsSafe |
1408 MachineOperatorBuilder::kFloat64Min |
1409 MachineOperatorBuilder::kFloat64Max |
1410 MachineOperatorBuilder::kFloat32Min |
1411 MachineOperatorBuilder::kFloat32Max |
1412 MachineOperatorBuilder::kFloat32RoundDown |
1413 MachineOperatorBuilder::kFloat32RoundUp |
1414 MachineOperatorBuilder::kFloat32RoundTruncate |
1415 MachineOperatorBuilder::kFloat32RoundTiesEven;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001416}
1417
1418} // namespace compiler
1419} // namespace internal
1420} // namespace v8