Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(881)

Side by Side Diff: src/compiler/mips/instruction-selector-mips.cc

Issue 601723002: MIPS: Add turbofan support for mips32. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: rebased 1-Oct, port r24319, r24350, r24356, r24367. Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/compiler/mips/instruction-codes-mips.h ('k') | src/compiler/mips/linkage-mips.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // 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
5 #include "src/base/bits.h"
6 #include "src/compiler/instruction-selector-impl.h"
7 #include "src/compiler/node-matchers.h"
8
9 namespace v8 {
10 namespace internal {
11 namespace compiler {
12
13 #define TRACE_UNIMPL() \
14 PrintF("UNIMPLEMENTED instr_sel: %s at line %d\n", __FUNCTION__, __LINE__)
15
16 #define TRACE() PrintF("instr_sel: %s at line %d\n", __FUNCTION__, __LINE__)
17
18
19 // Adds Mips-specific methods for generating InstructionOperands.
20 class MipsOperandGenerator FINAL : public OperandGenerator {
21 public:
22 explicit MipsOperandGenerator(InstructionSelector* selector)
23 : OperandGenerator(selector) {}
24
25 InstructionOperand* UseOperand(Node* node, InstructionCode opcode) {
26 if (CanBeImmediate(node, opcode)) {
27 return UseImmediate(node);
28 }
29 return UseRegister(node);
30 }
31
32 bool CanBeImmediate(Node* node, InstructionCode opcode) {
33 Int32Matcher m(node);
34 if (!m.HasValue()) return false;
35 int32_t value = m.Value();
36 switch (ArchOpcodeField::decode(opcode)) {
37 case kMipsShl:
38 case kMipsSar:
39 case kMipsShr:
40 return is_uint5(value);
41 case kMipsXor:
42 return is_uint16(value);
43 case kMipsLdc1:
44 case kMipsSdc1:
45 return is_int16(value + kIntSize);
46 default:
47 return is_int16(value);
48 }
49 }
50
51 private:
52 bool ImmediateFitsAddrMode1Instruction(int32_t imm) const {
53 TRACE_UNIMPL();
54 return false;
55 }
56 };
57
58
59 static void VisitRRR(InstructionSelector* selector, ArchOpcode opcode,
60 Node* node) {
61 MipsOperandGenerator g(selector);
62 selector->Emit(opcode, g.DefineAsRegister(node),
63 g.UseRegister(node->InputAt(0)),
64 g.UseRegister(node->InputAt(1)));
65 }
66
67
68 static void VisitRRO(InstructionSelector* selector, ArchOpcode opcode,
69 Node* node) {
70 MipsOperandGenerator g(selector);
71 selector->Emit(opcode, g.DefineAsRegister(node),
72 g.UseRegister(node->InputAt(0)),
73 g.UseOperand(node->InputAt(1), opcode));
74 }
75
76
77 static void VisitBinop(InstructionSelector* selector, Node* node,
78 InstructionCode opcode, FlagsContinuation* cont) {
79 MipsOperandGenerator g(selector);
80 Int32BinopMatcher m(node);
81 InstructionOperand* inputs[4];
82 size_t input_count = 0;
83 InstructionOperand* outputs[2];
84 size_t output_count = 0;
85
86 inputs[input_count++] = g.UseRegister(m.left().node());
87 inputs[input_count++] = g.UseOperand(m.right().node(), opcode);
88
89 if (cont->IsBranch()) {
90 inputs[input_count++] = g.Label(cont->true_block());
91 inputs[input_count++] = g.Label(cont->false_block());
92 }
93
94 outputs[output_count++] = g.DefineAsRegister(node);
95 if (cont->IsSet()) {
96 outputs[output_count++] = g.DefineAsRegister(cont->result());
97 }
98
99 DCHECK_NE(0, input_count);
100 DCHECK_NE(0, output_count);
101 DCHECK_GE(arraysize(inputs), input_count);
102 DCHECK_GE(arraysize(outputs), output_count);
103
104 Instruction* instr = selector->Emit(cont->Encode(opcode), output_count,
105 outputs, input_count, inputs);
106 if (cont->IsBranch()) instr->MarkAsControl();
107 }
108
109
110 static void VisitBinop(InstructionSelector* selector, Node* node,
111 InstructionCode opcode) {
112 FlagsContinuation cont;
113 VisitBinop(selector, node, opcode, &cont);
114 }
115
116
117 void InstructionSelector::VisitLoad(Node* node) {
118 MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node));
119 MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node));
120 MipsOperandGenerator g(this);
121 Node* base = node->InputAt(0);
122 Node* index = node->InputAt(1);
123
124 ArchOpcode opcode;
125 switch (rep) {
126 case kRepFloat32:
127 opcode = kMipsLwc1;
128 break;
129 case kRepFloat64:
130 opcode = kMipsLdc1;
131 break;
132 case kRepBit: // Fall through.
133 case kRepWord8:
134 opcode = typ == kTypeUint32 ? kMipsLbu : kMipsLb;
135 break;
136 case kRepWord16:
137 opcode = typ == kTypeUint32 ? kMipsLhu : kMipsLh;
138 break;
139 case kRepTagged: // Fall through.
140 case kRepWord32:
141 opcode = kMipsLw;
142 break;
143 default:
144 UNREACHABLE();
145 return;
146 }
147
148 if (g.CanBeImmediate(index, opcode)) {
149 Emit(opcode | AddressingModeField::encode(kMode_MRI),
150 g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index));
151 } else {
152 InstructionOperand* addr_reg = g.TempRegister();
153 Emit(kMipsAdd | AddressingModeField::encode(kMode_None), addr_reg,
154 g.UseRegister(index), g.UseRegister(base));
155 // Emit desired load opcode, using temp addr_reg.
156 Emit(opcode | AddressingModeField::encode(kMode_MRI),
157 g.DefineAsRegister(node), addr_reg, g.TempImmediate(0));
158 }
159 }
160
161
162 void InstructionSelector::VisitStore(Node* node) {
163 MipsOperandGenerator g(this);
164 Node* base = node->InputAt(0);
165 Node* index = node->InputAt(1);
166 Node* value = node->InputAt(2);
167
168 StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node);
169 MachineType rep = RepresentationOf(store_rep.machine_type());
170 if (store_rep.write_barrier_kind() == kFullWriteBarrier) {
171 DCHECK(rep == kRepTagged);
172 // TODO(dcarney): refactor RecordWrite function to take temp registers
173 // and pass them here instead of using fixed regs
174 // TODO(dcarney): handle immediate indices.
175 InstructionOperand* temps[] = {g.TempRegister(t1), g.TempRegister(t2)};
176 Emit(kMipsStoreWriteBarrier, NULL, g.UseFixed(base, t0),
177 g.UseFixed(index, t1), g.UseFixed(value, t2), arraysize(temps), temps);
178 return;
179 }
180 DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind());
181
182 ArchOpcode opcode;
183 switch (rep) {
184 case kRepFloat32:
185 opcode = kMipsSwc1;
186 break;
187 case kRepFloat64:
188 opcode = kMipsSdc1;
189 break;
190 case kRepBit: // Fall through.
191 case kRepWord8:
192 opcode = kMipsSb;
193 break;
194 case kRepWord16:
195 opcode = kMipsSh;
196 break;
197 case kRepTagged: // Fall through.
198 case kRepWord32:
199 opcode = kMipsSw;
200 break;
201 default:
202 UNREACHABLE();
203 return;
204 }
205
206 if (g.CanBeImmediate(index, opcode)) {
207 Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL,
208 g.UseRegister(base), g.UseImmediate(index), g.UseRegister(value));
209 } else {
210 InstructionOperand* addr_reg = g.TempRegister();
211 Emit(kMipsAdd | AddressingModeField::encode(kMode_None), addr_reg,
212 g.UseRegister(index), g.UseRegister(base));
213 // Emit desired store opcode, using temp addr_reg.
214 Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL, addr_reg,
215 g.TempImmediate(0), g.UseRegister(value));
216 }
217 }
218
219
220 void InstructionSelector::VisitWord32And(Node* node) {
221 VisitBinop(this, node, kMipsAnd);
222 }
223
224
225 void InstructionSelector::VisitWord32Or(Node* node) {
226 VisitBinop(this, node, kMipsOr);
227 }
228
229
230 void InstructionSelector::VisitWord32Xor(Node* node) {
231 VisitBinop(this, node, kMipsXor);
232 }
233
234
235 void InstructionSelector::VisitWord32Shl(Node* node) {
236 VisitRRO(this, kMipsShl, node);
237 }
238
239
240 void InstructionSelector::VisitWord32Shr(Node* node) {
241 VisitRRO(this, kMipsShr, node);
242 }
243
244
245 void InstructionSelector::VisitWord32Sar(Node* node) {
246 VisitRRO(this, kMipsSar, node);
247 }
248
249
250 void InstructionSelector::VisitWord32Ror(Node* node) {
251 VisitRRO(this, kMipsRor, node);
252 }
253
254
255 void InstructionSelector::VisitInt32Add(Node* node) {
256 MipsOperandGenerator g(this);
257
258 // TODO(plind): Consider multiply & add optimization from arm port.
259 VisitBinop(this, node, kMipsAdd);
260 }
261
262
263 void InstructionSelector::VisitInt32Sub(Node* node) {
264 VisitBinop(this, node, kMipsSub);
265 }
266
267
268 void InstructionSelector::VisitInt32Mul(Node* node) {
269 MipsOperandGenerator g(this);
270 Int32BinopMatcher m(node);
271 if (m.right().HasValue() && m.right().Value() > 0) {
272 int32_t value = m.right().Value();
273 if (base::bits::IsPowerOfTwo32(value)) {
274 Emit(kMipsShl | AddressingModeField::encode(kMode_None),
275 g.DefineAsRegister(node), g.UseRegister(m.left().node()),
276 g.TempImmediate(WhichPowerOf2(value)));
277 return;
278 }
279 if (base::bits::IsPowerOfTwo32(value - 1)) {
280 InstructionOperand* temp = g.TempRegister();
281 Emit(kMipsShl | AddressingModeField::encode(kMode_None), temp,
282 g.UseRegister(m.left().node()),
283 g.TempImmediate(WhichPowerOf2(value - 1)));
284 Emit(kMipsAdd | AddressingModeField::encode(kMode_None),
285 g.DefineAsRegister(node), g.UseRegister(m.left().node()), temp);
286 return;
287 }
288 if (base::bits::IsPowerOfTwo32(value + 1)) {
289 InstructionOperand* temp = g.TempRegister();
290 Emit(kMipsShl | AddressingModeField::encode(kMode_None), temp,
291 g.UseRegister(m.left().node()),
292 g.TempImmediate(WhichPowerOf2(value + 1)));
293 Emit(kMipsSub | AddressingModeField::encode(kMode_None),
294 g.DefineAsRegister(node), temp, g.UseRegister(m.left().node()));
295 return;
296 }
297 }
298 Emit(kMipsMul, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
299 g.UseRegister(m.right().node()));
300 }
301
302
303 void InstructionSelector::VisitInt32Div(Node* node) {
304 MipsOperandGenerator g(this);
305 Int32BinopMatcher m(node);
306 Emit(kMipsDiv, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
307 g.UseRegister(m.right().node()));
308 }
309
310
311 void InstructionSelector::VisitUint32Div(Node* node) {
312 MipsOperandGenerator g(this);
313 Int32BinopMatcher m(node);
314 Emit(kMipsDivU, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
315 g.UseRegister(m.right().node()));
316 }
317
318
319 void InstructionSelector::VisitInt32Mod(Node* node) {
320 MipsOperandGenerator g(this);
321 Int32BinopMatcher m(node);
322 Emit(kMipsMod, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
323 g.UseRegister(m.right().node()));
324 }
325
326
327 void InstructionSelector::VisitUint32Mod(Node* node) {
328 MipsOperandGenerator g(this);
329 Int32BinopMatcher m(node);
330 Emit(kMipsModU, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
331 g.UseRegister(m.right().node()));
332 }
333
334
335 void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
336 MipsOperandGenerator g(this);
337 Emit(kMipsCvtDS, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
338 }
339
340
341 void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
342 MipsOperandGenerator g(this);
343 Emit(kMipsCvtDW, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
344 }
345
346
347 void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
348 MipsOperandGenerator g(this);
349 Emit(kMipsCvtDUw, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
350 }
351
352
353 void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
354 MipsOperandGenerator g(this);
355 Emit(kMipsTruncWD, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
356 }
357
358
359 void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
360 MipsOperandGenerator g(this);
361 Emit(kMipsTruncUwD, g.DefineAsRegister(node),
362 g.UseRegister(node->InputAt(0)));
363 }
364
365
366 void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
367 MipsOperandGenerator g(this);
368 Emit(kMipsCvtSD, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
369 }
370
371
372 void InstructionSelector::VisitFloat64Add(Node* node) {
373 VisitRRR(this, kMipsAddD, node);
374 }
375
376
377 void InstructionSelector::VisitFloat64Sub(Node* node) {
378 VisitRRR(this, kMipsSubD, node);
379 }
380
381
382 void InstructionSelector::VisitFloat64Mul(Node* node) {
383 VisitRRR(this, kMipsMulD, node);
384 }
385
386
387 void InstructionSelector::VisitFloat64Div(Node* node) {
388 VisitRRR(this, kMipsDivD, node);
389 }
390
391
392 void InstructionSelector::VisitFloat64Mod(Node* node) {
393 MipsOperandGenerator g(this);
394 Emit(kMipsModD, g.DefineAsFixed(node, f0), g.UseFixed(node->InputAt(0), f12),
395 g.UseFixed(node->InputAt(1), f14))->MarkAsCall();
396 }
397
398
399 void InstructionSelector::VisitFloat64Sqrt(Node* node) {
400 MipsOperandGenerator g(this);
401 Emit(kMipsSqrtD, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
402 }
403
404 void InstructionSelector::VisitCall(Node* call, BasicBlock* continuation,
405 BasicBlock* deoptimization) {
406 MipsOperandGenerator g(this);
407 CallDescriptor* descriptor = OpParameter<CallDescriptor*>(call);
408
409 FrameStateDescriptor* frame_state_descriptor = NULL;
410 if (descriptor->NeedsFrameState()) {
411 frame_state_descriptor =
412 GetFrameStateDescriptor(call->InputAt(descriptor->InputCount()));
413 }
414
415 CallBuffer buffer(zone(), descriptor, frame_state_descriptor);
416
417 // Compute InstructionOperands for inputs and outputs.
418 InitializeCallBuffer(call, &buffer, true, false);
419
420 // TODO(dcarney): might be possible to use claim/poke instead
421 // Push any stack arguments.
422 for (NodeVectorRIter input = buffer.pushed_nodes.rbegin();
423 input != buffer.pushed_nodes.rend(); input++) {
424 // TODO(plind): inefficient for MIPS, use MultiPush here.
425 // - Also need to align the stack. See arm64.
426 // - Maybe combine with arg slot stuff in DirectCEntry stub.
427 Emit(kMipsPush, NULL, g.UseRegister(*input));
428 }
429
430 // Select the appropriate opcode based on the call type.
431 InstructionCode opcode;
432 switch (descriptor->kind()) {
433 case CallDescriptor::kCallCodeObject: {
434 opcode = kArchCallCodeObject;
435 break;
436 }
437 case CallDescriptor::kCallJSFunction:
438 opcode = kArchCallJSFunction;
439 break;
440 default:
441 UNREACHABLE();
442 return;
443 }
444 opcode |= MiscField::encode(descriptor->flags());
445
446 // Emit the call instruction.
447 Instruction* call_instr =
448 Emit(opcode, buffer.outputs.size(), &buffer.outputs.front(),
449 buffer.instruction_args.size(), &buffer.instruction_args.front());
450
451 call_instr->MarkAsCall();
452 if (deoptimization != NULL) {
453 DCHECK(continuation != NULL);
454 call_instr->MarkAsControl();
455 }
456 }
457
458
459 void InstructionSelector::VisitInt32AddWithOverflow(Node* node,
460 FlagsContinuation* cont) {
461 VisitBinop(this, node, kMipsAddOvf, cont);
462 }
463
464
465 void InstructionSelector::VisitInt32SubWithOverflow(Node* node,
466 FlagsContinuation* cont) {
467 VisitBinop(this, node, kMipsSubOvf, cont);
468 }
469
470
471 // Shared routine for multiple compare operations.
472 static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
473 InstructionOperand* left, InstructionOperand* right,
474 FlagsContinuation* cont) {
475 MipsOperandGenerator g(selector);
476 opcode = cont->Encode(opcode);
477 if (cont->IsBranch()) {
478 selector->Emit(opcode, NULL, left, right, g.Label(cont->true_block()),
479 g.Label(cont->false_block()))->MarkAsControl();
480 } else {
481 DCHECK(cont->IsSet());
482 // TODO(plind): Revisit and test this path.
483 selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
484 }
485 }
486
487
488 // Shared routine for multiple word compare operations.
489 static void VisitWordCompare(InstructionSelector* selector, Node* node,
490 InstructionCode opcode, FlagsContinuation* cont,
491 bool commutative) {
492 MipsOperandGenerator g(selector);
493 Node* left = node->InputAt(0);
494 Node* right = node->InputAt(1);
495
496 // Match immediates on left or right side of comparison.
497 if (g.CanBeImmediate(right, opcode)) {
498 VisitCompare(selector, opcode, g.UseRegister(left), g.UseImmediate(right),
499 cont);
500 } else if (g.CanBeImmediate(left, opcode)) {
501 if (!commutative) cont->Commute();
502 VisitCompare(selector, opcode, g.UseRegister(right), g.UseImmediate(left),
503 cont);
504 } else {
505 VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right),
506 cont);
507 }
508 }
509
510
511 void InstructionSelector::VisitWord32Test(Node* node, FlagsContinuation* cont) {
512 switch (node->opcode()) {
513 case IrOpcode::kWord32And:
514 // TODO(plind): understand the significance of 'IR and' special case.
515 return VisitWordCompare(this, node, kMipsTst, cont, true);
516 default:
517 break;
518 }
519
520 MipsOperandGenerator g(this);
521 // kMipsTst is a pseudo-instruction to do logical 'and' and leave the result
522 // in a dedicated tmp register.
523 VisitCompare(this, kMipsTst, g.UseRegister(node), g.UseRegister(node), cont);
524 }
525
526
527 void InstructionSelector::VisitWord32Compare(Node* node,
528 FlagsContinuation* cont) {
529 VisitWordCompare(this, node, kMipsCmp, cont, false);
530 }
531
532
533 void InstructionSelector::VisitFloat64Compare(Node* node,
534 FlagsContinuation* cont) {
535 MipsOperandGenerator g(this);
536 Node* left = node->InputAt(0);
537 Node* right = node->InputAt(1);
538 VisitCompare(this, kMipsCmpD, g.UseRegister(left), g.UseRegister(right),
539 cont);
540 }
541
542 } // namespace compiler
543 } // namespace internal
544 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/mips/instruction-codes-mips.h ('k') | src/compiler/mips/linkage-mips.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698