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

Side by Side Diff: src/compiler/mips/code-generator-mips.cc

Issue 601723002: MIPS: Add turbofan support for mips32. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: minor cleanups 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
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/compiler/code-generator.h"
6 #include "src/compiler/code-generator-impl.h"
7 #include "src/compiler/gap-resolver.h"
8 #include "src/compiler/node-matchers.h"
9 #include "src/compiler/node-properties-inl.h"
10 #include "src/mips/macro-assembler-mips.h"
11 #include "src/scopes.h"
12
13 namespace v8 {
14 namespace internal {
15 namespace compiler {
16
17 #define __ masm()->
18
19
20 // TODO(plind): Possibly avoid using these lithium names.
21 #define kScratchReg kLithiumScratchReg
22 #define kCompareReg kLithiumScratchReg2
23 #define kScratchDoubleReg kLithiumScratchDouble
24
25
26 // TODO(plind): consider renaming these macros.
27 #define TRACE_MSG(msg) \
28 PrintF("code_gen: \'%s\' in function %s at line %d\n", msg, __FUNCTION__, \
29 __LINE__)
30
31 #define TRACE_UNIMPL() \
32 PrintF("UNIMPLEMENTED code_generator_mips: %s at line %d\n", __FUNCTION__, \
33 __LINE__)
34
35
36 // Adds Mips-specific methods to convert InstructionOperands.
37 class MipsOperandConverter : public InstructionOperandConverter {
38 public:
39 MipsOperandConverter(CodeGenerator* gen, Instruction* instr)
40 : InstructionOperandConverter(gen, instr) {}
41
42 Operand InputImmediate(int index) {
43 Constant constant = ToConstant(instr_->InputAt(index));
44 switch (constant.type()) {
45 case Constant::kInt32:
46 return Operand(constant.ToInt32());
47 case Constant::kFloat64:
48 return Operand(
49 isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
50 case Constant::kInt64:
51 case Constant::kExternalReference:
52 case Constant::kHeapObject:
53 // TODO(plind): Maybe we should handle ExtRef & HeapObj here?
54 // maybe not done on arm due to const pool ??
55 break;
56 }
57 UNREACHABLE();
58 return Operand(zero_reg);
59 }
60
61 Operand InputOperand(int index) {
62 InstructionOperand* op = instr_->InputAt(index);
63 if (op->IsRegister()) {
64 return Operand(ToRegister(op));
65 }
66 return InputImmediate(index);
67 }
68
69 MemOperand MemoryOperand(int* first_index) {
70 const int index = *first_index;
71 switch (AddressingModeField::decode(instr_->opcode())) {
72 case kMode_None:
73 break;
74 case kMode_MRI:
75 *first_index += 2;
76 return MemOperand(InputRegister(index + 0), InputInt32(index + 1));
77 case kMode_MRR:
78 // TODO(plind): r6 address mode, to be implemented ...
79 UNREACHABLE();
80 }
81 UNREACHABLE();
82 return MemOperand(no_reg);
83 }
84
85 MemOperand MemoryOperand() {
86 int index = 0;
87 return MemoryOperand(&index);
88 }
89
90 MemOperand ToMemOperand(InstructionOperand* op) const {
91 DCHECK(op != NULL);
92 DCHECK(!op->IsRegister());
93 DCHECK(!op->IsDoubleRegister());
94 DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
95 // The linkage computes where all spill slots are located.
96 FrameOffset offset = linkage()->GetFrameOffset(op->index(), frame(), 0);
97 return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
98 }
99 };
100
101
102 static inline bool HasRegisterInput(Instruction* instr, int index) {
103 return instr->InputAt(index)->IsRegister();
104 }
105
106
107 // TODO(plind): There are only 3 shift ops, does that justify this slightly
108 // messy macro? Consider expanding this in place for sll, srl, sra ops.
titzer 2014/09/24 15:23:31 I agree that you should kill this macro here.
paul.l... 2014/09/25 17:18:38 Done.
109 #define ASSEMBLE_SHIFT(asm_instr) \
110 do { \
111 if (instr->InputAt(1)->IsRegister()) { \
112 __ asm_instr##v(i.OutputRegister(), i.InputRegister(0), \
113 i.InputRegister(1)); \
114 } else { \
115 int32_t imm = i.InputOperand(1).immediate(); \
116 __ asm_instr(i.OutputRegister(), i.InputRegister(0), imm); \
117 } \
118 } while (0);
119
120
121 // Assembles an instruction after register allocation, producing machine code.
122 void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
123 MipsOperandConverter i(this, instr);
124 InstructionCode opcode = instr->opcode();
125
126 switch (ArchOpcodeField::decode(opcode)) {
127 case kArchCallCodeObject: {
128 EnsureSpaceForLazyDeopt();
129 if (instr->InputAt(0)->IsImmediate()) {
130 __ Call(Handle<Code>::cast(i.InputHeapObject(0)),
131 RelocInfo::CODE_TARGET);
132 } else {
133 __ addiu(at, i.InputRegister(0), Code::kHeaderSize - kHeapObjectTag);
134 __ Call(at);
135 }
136 AddSafepointAndDeopt(instr);
137 break;
138 }
139 case kArchCallJSFunction: {
140 EnsureSpaceForLazyDeopt();
141 Register func = i.InputRegister(0);
142 if (FLAG_debug_code) {
143 // Check the function's context matches the context argument.
144 __ lw(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset));
145 __ Assert(eq, kWrongFunctionContext, cp, Operand(kScratchReg));
146 }
147
148 __ lw(at, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
149 __ Call(at);
150 AddSafepointAndDeopt(instr);
151 break;
152 }
153 case kArchJmp:
154 __ Branch(code_->GetLabel(i.InputBlock(0)));
155 break;
156 case kArchNop:
157 // don't emit code for nops.
158 break;
159 case kArchRet:
160 AssembleReturn();
161 break;
162 case kArchTruncateDoubleToI:
163 __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
164 break;
165 case kMipsAdd:
166 __ Addu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
167 break;
168 case kMipsAddOvf:
169 __ AdduAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0),
170 i.InputOperand(1), kCompareReg, kScratchReg);
titzer 2014/09/24 15:23:31 The macro assembler methods here generate a lot of
paul.l... 2014/09/25 17:18:39 Yes, Overflow checking is an issue for MIPS. We ha
titzer 2014/09/26 10:36:21 I meant in the front end, when we lower a v8 repre
171 break;
172 case kMipsSub:
173 __ Subu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
174 break;
175 case kMipsSubOvf:
176 __ SubuAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0),
177 i.InputOperand(1), kCompareReg, kScratchReg);
178 break;
179 case kMipsMul:
180 __ Mul(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
181 break;
182 case kMipsDiv:
183 __ Div(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
184 break;
185 case kMipsDivU:
186 __ Divu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
187 break;
188 case kMipsMod:
189 __ Mod(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
190 break;
191 case kMipsModU:
192 __ Modu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
193 break;
194 case kMipsAnd:
195 __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
196 break;
197 case kMipsOr:
198 __ Or(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
199 break;
200 case kMipsXor:
201 __ Xor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
202 break;
203 case kMipsShl:
204 ASSEMBLE_SHIFT(sll);
205 break;
206 case kMipsShr:
207 ASSEMBLE_SHIFT(srl);
208 break;
209 case kMipsSar:
210 ASSEMBLE_SHIFT(sra);
211 break;
212 case kMipsRor:
213 __ Ror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
214 break;
215 case kMipsTst:
216 // Psuedo-instruction used for tst/branch.
217 __ And(kCompareReg, i.InputRegister(0), i.InputOperand(1));
218 break;
219 case kMipsCmp:
220 // Psuedo-instruction used for cmp/branch. No opcode emitted here.
221 break;
222 case kMipsMov:
223 // TODO(plind): Should we combine mov/li like this, or use separate instr?
224 // - Also see x64 ASSEMBLE_BINOP & RegisterOrOperandType
225 if (HasRegisterInput(instr, 0)) {
226 __ mov(i.OutputRegister(), i.InputRegister(0));
227 } else {
228 __ li(i.OutputRegister(), i.InputOperand(0));
229 }
230 break;
231
232 case kMipsFloat64Cmp:
233 // Psuedo-instruction used for FP cmp/branch. No opcode emitted here.
234 break;
235 case kMipsFloat64Add:
236 // TODO(plind): add special case: combine mult & add.
237 __ add_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
238 i.InputDoubleRegister(1));
239 break;
240 case kMipsFloat64Sub:
241 __ sub_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
242 i.InputDoubleRegister(1));
243 break;
244 case kMipsFloat64Mul:
245 // TODO(plind): add special case: right op is -1.0, see arm port.
246 __ mul_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
247 i.InputDoubleRegister(1));
248 break;
249 case kMipsFloat64Div:
250 __ div_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
251 i.InputDoubleRegister(1));
252 break;
253 case kMipsFloat64Mod: {
254 // TODO(bmeurer): We should really get rid of this special instruction,
255 // and generate a CallAddress instruction instead.
256 FrameScope scope(masm(), StackFrame::MANUAL);
257 __ PrepareCallCFunction(0, 2, kScratchReg);
258 __ MovToFloatParameters(i.InputDoubleRegister(0),
259 i.InputDoubleRegister(1));
260 __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
261 0, 2);
262 // Move the result in the double result register.
263 __ MovFromFloatResult(i.OutputDoubleRegister());
264 break;
265 }
266 case kMipsInt32ToFloat64: {
267 FPURegister scratch = kScratchDoubleReg;
268 __ mtc1(i.InputRegister(0), scratch);
269 __ cvt_d_w(i.OutputDoubleRegister(), scratch);
270 break;
271 }
272 case kMipsUint32ToFloat64: {
273 FPURegister scratch = kScratchDoubleReg;
274 __ Cvt_d_uw(i.OutputDoubleRegister(), i.InputRegister(0), scratch);
275 break;
276 }
277 case kMipsFloat64ToInt32: {
278 FPURegister scratch = kScratchDoubleReg;
279 // Other arches use round to zero here, so we follow.
280 __ trunc_w_d(scratch, i.InputDoubleRegister(0));
281 __ mfc1(i.OutputRegister(), scratch);
282 break;
283 }
284 case kMipsFloat64ToUint32: {
285 FPURegister scratch = kScratchDoubleReg;
286 // TODO(plind): Fix wrong param order of Trunc_uw_d() macro-asm function.
287 __ Trunc_uw_d(i.InputDoubleRegister(0), i.OutputRegister(), scratch);
288 break;
289 }
290 // ... more basic instructions ...
291
292 case kMipsLbu:
293 __ lbu(i.OutputRegister(), i.MemoryOperand());
294 break;
295 case kMipsLb:
296 __ lb(i.OutputRegister(), i.MemoryOperand());
297 break;
298 case kMipsSb:
299 __ sb(i.InputRegister(2), i.MemoryOperand());
300 break;
301 case kMipsLhu:
302 __ lhu(i.OutputRegister(), i.MemoryOperand());
303 break;
304 case kMipsLh:
305 __ lh(i.OutputRegister(), i.MemoryOperand());
306 break;
307 case kMipsSh:
308 __ sh(i.InputRegister(2), i.MemoryOperand());
309 break;
310 case kMipsLw:
311 __ lw(i.OutputRegister(), i.MemoryOperand());
312 break;
313 case kMipsSw:
314 __ sw(i.InputRegister(2), i.MemoryOperand());
315 break;
316 case kMipsLwc1: {
317 FPURegister scratch = kScratchDoubleReg;
318 __ lwc1(scratch, i.MemoryOperand());
319 __ cvt_d_s(i.OutputDoubleRegister(), scratch);
320 break;
321 }
322 case kMipsSwc1: {
323 int index = 0;
324 FPURegister scratch = kScratchDoubleReg;
325 MemOperand operand = i.MemoryOperand(&index);
326 __ cvt_s_d(scratch, i.InputDoubleRegister(index));
327 __ swc1(scratch, operand);
328 break;
329 }
330 case kMipsLdc1:
331 __ ldc1(i.OutputDoubleRegister(), i.MemoryOperand());
332 break;
333 case kMipsSdc1:
334 __ sdc1(i.InputDoubleRegister(2), i.MemoryOperand());
335 break;
336 case kMipsPush:
337 __ Push(i.InputRegister(0));
338 break;
339 case kMipsStoreWriteBarrier:
340 Register object = i.InputRegister(0);
341 Register index = i.InputRegister(1);
342 Register value = i.InputRegister(2);
343 __ addu(index, object, index);
344 __ sw(value, MemOperand(index));
345 SaveFPRegsMode mode =
346 frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
347 RAStatus ra_status = kRAHasNotBeenSaved;
348 __ RecordWrite(object, index, value, ra_status, mode);
349 break;
350 }
351 }
352
353
354 #define UNSUPPORTED_COND(opcode, condition) \
355 OFStream out(stdout); \
356 out << "Unsupported " << #opcode << " condition: \"" << condition << "\""; \
357 UNIMPLEMENTED();
358
359 // Assembles branches after an instruction.
360 void CodeGenerator::AssembleArchBranch(Instruction* instr,
361 FlagsCondition condition) {
titzer 2014/09/24 15:23:32 The handling of branches here is tough to follow.
Benedikt Meurer 2014/09/25 05:37:10 Hm, we may need to refactor the AssembleArchBranch
paul.l... 2014/09/25 17:18:39 Complications arise from MIPS not having condition
titzer 2014/09/26 10:36:21 Ok, in that case maybe using a FlagsContinuation o
362 MipsOperandConverter i(this, instr);
363 Label done;
364
365 // Emit a branch. The true and false targets are always the last two inputs
366 // to the instruction.
367 BasicBlock* tblock = i.InputBlock(instr->InputCount() - 2);
368 BasicBlock* fblock = i.InputBlock(instr->InputCount() - 1);
369 bool fallthru = IsNextInAssemblyOrder(fblock);
370 Label* tlabel = code()->GetLabel(tblock);
371 Label* flabel = fallthru ? &done : code()->GetLabel(fblock);
372 Condition cc = kNoCondition;
373
374 // MIPS does not have condition code flags, so compare and branch are
375 // implemented differently than on the other arch's. The compare operations
376 // emit mips psuedo-instructions, which are handled here by branch
377 // instructions that do the actual comparison. Essential that the input
378 // registers to compare psuedo-op are not modified before this branch op, as
379 // they are tested here.
380 // TODO(plind): Add CHECK() to ensure that test/cmp and this branch were
381 // not separated by other instructions.
382
383 if (instr->arch_opcode() == kMipsTst) {
384 // The kMipsTst psuedo-instruction emits And to 'kCompareReg' register.
385 switch (condition) {
386 case kNotEqual:
387 cc = ne;
388 break;
389 case kEqual:
390 cc = eq;
391 break;
392 default:
393 UNSUPPORTED_COND(kMipsTst, condition);
394 break;
395 }
396 __ Branch(tlabel, cc, kCompareReg, Operand(zero_reg));
397
398 } else if (instr->arch_opcode() == kMipsAddOvf ||
399 instr->arch_opcode() == kMipsSubOvf) {
400 // kMipsAddOvf, SubOvf emit negative result to 'kCompareReg' on overflow.
401 switch (condition) {
402 case kOverflow:
403 cc = lt;
404 break;
405 case kNotOverflow:
406 cc = ge;
407 break;
408 default:
409 UNSUPPORTED_COND(kMipsAddOvf, condition);
410 break;
411 }
412 __ Branch(tlabel, cc, kCompareReg, Operand(zero_reg));
413
414 } else if (instr->arch_opcode() == kMipsCmp) {
415 switch (condition) {
416 case kEqual:
417 cc = eq;
418 break;
419 case kNotEqual:
420 cc = ne;
421 break;
422 case kSignedLessThan:
423 cc = lt;
424 break;
425 case kSignedGreaterThanOrEqual:
426 cc = ge;
427 break;
428 case kSignedLessThanOrEqual:
429 cc = le;
430 break;
431 case kSignedGreaterThan:
432 cc = gt;
433 break;
434 case kUnsignedLessThan:
435 cc = lo;
436 break;
437 case kUnsignedGreaterThanOrEqual:
438 cc = hs;
439 break;
440 case kUnsignedLessThanOrEqual:
441 cc = ls;
442 break;
443 case kUnsignedGreaterThan:
444 cc = hi;
445 break;
446 default:
447 UNSUPPORTED_COND(kMipsCmp, condition);
448 break;
449 }
450 __ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1));
451
452 if (!fallthru) __ Branch(flabel); // no fallthru to flabel.
453 __ bind(&done);
454
455 } else if (instr->arch_opcode() == kMipsFloat64Cmp) {
456 // TODO(dusmil) optimize unordered checks to use less instructions
457 // even if we have to unfold BranchF macro.
458 Label* nan = flabel;
459 switch (condition) {
460 case kUnorderedEqual:
461 cc = eq;
462 break;
463 case kUnorderedNotEqual:
464 cc = ne;
465 nan = tlabel;
466 break;
467 case kUnorderedLessThan:
468 cc = lt;
469 break;
470 case kUnorderedGreaterThanOrEqual:
471 cc = ge;
472 nan = tlabel;
473 break;
474 case kUnorderedLessThanOrEqual:
475 cc = le;
476 break;
477 case kUnorderedGreaterThan:
478 cc = gt;
479 nan = tlabel;
480 break;
481 default:
482 UNSUPPORTED_COND(kMipsFloat64Cmp, condition);
483 break;
484 }
485 __ BranchF(tlabel, nan, cc, i.InputDoubleRegister(0),
486 i.InputDoubleRegister(1));
487
488 if (!fallthru) __ Branch(flabel); // no fallthru to flabel.
489 __ bind(&done);
490
491 } else {
492 PrintF("AssembleArchBranch Unimplemented arch_opcode: %d\n",
493 instr->arch_opcode());
494 UNIMPLEMENTED();
495 }
496 }
497
498
499 // Assembles boolean materializations after an instruction.
500 void CodeGenerator::AssembleArchBoolean(Instruction* instr,
501 FlagsCondition condition) {
502 MipsOperandConverter i(this, instr);
503 Label done;
504
505 // Materialize a full 32-bit 1 or 0 value. The result register is always the
506 // last output of the instruction.
507 Label false_value;
508 DCHECK_NE(0, instr->OutputCount());
509 Register result = i.OutputRegister(instr->OutputCount() - 1);
510 Condition cc = kNoCondition;
511
512 // MIPS does not have condition code flags, so compare and branch are
513 // implemented differently than on the other arch's. The compare operations
514 // emit mips psuedo-instructions, which are checked and handled here.
515
516 // For materializations, we use delay slot to set the result true, and
517 // in the false case, where we fall thru the branch, we reset the result
518 // false.
519
520 // TODO(plind): Add CHECK() to ensure that test/cmp and this branch were
521 // not separated by other instructions.
522 if (instr->arch_opcode() == kMipsTst) {
523 // The kMipsTst psuedo-instruction emits And to 'kCompareReg' register.
524 switch (condition) {
525 case kNotEqual:
526 cc = ne;
527 break;
528 case kEqual:
529 cc = eq;
530 break;
531 default:
532 UNSUPPORTED_COND(kMipsTst, condition);
533 break;
534 }
535 __ Branch(USE_DELAY_SLOT, &done, cc, kCompareReg, Operand(zero_reg));
536 __ li(result, Operand(1)); // In delay slot.
537
538 } else if (instr->arch_opcode() == kMipsAddOvf ||
539 instr->arch_opcode() == kMipsSubOvf) {
540 // kMipsAddOvf, SubOvf emits negative result to 'kCompareReg' on overflow.
541 switch (condition) {
542 case kOverflow:
543 cc = lt;
544 break;
545 case kNotOverflow:
546 cc = ge;
547 break;
548 default:
549 UNSUPPORTED_COND(kMipsAddOvf, condition);
550 break;
551 }
552 __ Branch(USE_DELAY_SLOT, &done, cc, kCompareReg, Operand(zero_reg));
553 __ li(result, Operand(1)); // In delay slot.
554
555
556 } else if (instr->arch_opcode() == kMipsCmp) {
557 Register left = i.InputRegister(0);
558 Operand right = i.InputOperand(1);
559 switch (condition) {
560 case kEqual:
561 cc = eq;
562 break;
563 case kNotEqual:
564 cc = ne;
565 break;
566 case kSignedLessThan:
567 cc = lt;
568 break;
569 case kSignedGreaterThanOrEqual:
570 cc = ge;
571 break;
572 case kSignedLessThanOrEqual:
573 cc = le;
574 break;
575 case kSignedGreaterThan:
576 cc = gt;
577 break;
578 case kUnsignedLessThan:
579 cc = lo;
580 break;
581 case kUnsignedGreaterThanOrEqual:
582 cc = hs;
583 break;
584 case kUnsignedLessThanOrEqual:
585 cc = ls;
586 break;
587 case kUnsignedGreaterThan:
588 cc = hi;
589 break;
590 default:
591 UNSUPPORTED_COND(kMipsCmp, condition);
592 break;
593 }
594 __ Branch(USE_DELAY_SLOT, &done, cc, left, right);
595 __ li(result, Operand(1)); // In delay slot.
596
597 } else if (instr->arch_opcode() == kMipsFloat64Cmp) {
598 FPURegister left = i.InputDoubleRegister(0);
599 FPURegister right = i.InputDoubleRegister(1);
600 // TODO(plind): Provide NaN-testing macro-asm function without need for
601 // BranchF.
602 FPURegister dummy1 = f0;
603 FPURegister dummy2 = f2;
604 switch (condition) {
605 case kUnorderedEqual:
606 // TODO(plind): improve the NaN testing throughout this function.
607 __ BranchF(NULL, &false_value, kNoCondition, dummy1, dummy2);
608 cc = eq;
609 break;
610 case kUnorderedNotEqual:
611 __ BranchF(USE_DELAY_SLOT, NULL, &done, kNoCondition, dummy1, dummy2);
612 __ li(result, Operand(1)); // In delay slot - returns 1 on NaN.
613 cc = ne;
614 break;
615 case kUnorderedLessThan:
616 __ BranchF(NULL, &false_value, kNoCondition, dummy1, dummy2);
617 cc = lt;
618 break;
619 case kUnorderedGreaterThanOrEqual:
620 __ BranchF(USE_DELAY_SLOT, NULL, &done, kNoCondition, dummy1, dummy2);
621 __ li(result, Operand(1)); // In delay slot - returns 1 on NaN.
622 cc = ge;
623 break;
624 case kUnorderedLessThanOrEqual:
625 __ BranchF(NULL, &false_value, kNoCondition, dummy1, dummy2);
626 cc = le;
627 break;
628 case kUnorderedGreaterThan:
629 __ BranchF(USE_DELAY_SLOT, NULL, &done, kNoCondition, dummy1, dummy2);
630 __ li(result, Operand(1)); // In delay slot - returns 1 on NaN.
631 cc = gt;
632 break;
633 default:
634 UNSUPPORTED_COND(kMipsCmp, condition);
635 break;
636 }
637 __ BranchF(USE_DELAY_SLOT, &done, NULL, cc, left, right);
638 __ li(result, Operand(1)); // In delay slot - branch taken returns 1.
639 // Fall-thru (branch not taken) returns 0.
640
641 } else {
642 PrintF("AssembleArchBranch Unimplemented arch_opcode is : %d\n",
643 instr->arch_opcode());
644 TRACE_UNIMPL();
645 UNIMPLEMENTED();
646 }
647 // Fallthru case is the false materialization.
648 __ bind(&false_value);
649 __ li(result, Operand(0));
650 __ bind(&done);
651 }
652
653
654 void CodeGenerator::AssembleDeoptimizerCall(int deoptimization_id) {
655 Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
656 isolate(), deoptimization_id, Deoptimizer::LAZY);
657 __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
658 }
659
660
661 void CodeGenerator::AssemblePrologue() {
662 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
663 if (descriptor->kind() == CallDescriptor::kCallAddress) {
664 __ Push(ra, fp);
665 __ mov(fp, sp);
666 const RegList saves = descriptor->CalleeSavedRegisters();
667 if (saves != 0) { // Save callee-saved registers.
668 // TODO(plind): make callee save size const, possibly DCHECK it.
669 int register_save_area_size = 0;
670 for (int i = Register::kNumRegisters - 1; i >= 0; i--) {
671 if (!((1 << i) & saves)) continue;
672 register_save_area_size += kPointerSize;
673 }
674 frame()->SetRegisterSaveAreaSize(register_save_area_size);
675 __ MultiPush(saves);
676 }
677 } else if (descriptor->IsJSFunctionCall()) {
678 CompilationInfo* info = linkage()->info();
679 __ Prologue(info->IsCodePreAgingActive());
680 frame()->SetRegisterSaveAreaSize(
681 StandardFrameConstants::kFixedFrameSizeFromFp);
682
683 // Sloppy mode functions and builtins need to replace the receiver with the
684 // global proxy when called as functions (without an explicit receiver
685 // object).
686 // TODO(mstarzinger/verwaest): Should this be moved back into the CallIC?
687 if (info->strict_mode() == SLOPPY && !info->is_native()) {
688 Label ok;
689 // +2 for return address and saved frame pointer.
690 int receiver_slot = info->scope()->num_parameters() + 2;
691 __ lw(a2, MemOperand(fp, receiver_slot * kPointerSize));
692 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
693 __ Branch(&ok, ne, a2, Operand(at));
694
695 __ lw(a2, GlobalObjectOperand());
696 __ lw(a2, FieldMemOperand(a2, GlobalObject::kGlobalProxyOffset));
697 __ sw(a2, MemOperand(fp, receiver_slot * kPointerSize));
698 __ bind(&ok);
699 }
700 } else {
701 __ StubPrologue();
702 frame()->SetRegisterSaveAreaSize(
703 StandardFrameConstants::kFixedFrameSizeFromFp);
704 }
705 int stack_slots = frame()->GetSpillSlotCount();
706 if (stack_slots > 0) {
707 __ Subu(sp, sp, Operand(stack_slots * kPointerSize));
708 }
709 }
710
711
712 void CodeGenerator::AssembleReturn() {
713 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
714 if (descriptor->kind() == CallDescriptor::kCallAddress) {
715 if (frame()->GetRegisterSaveAreaSize() > 0) {
716 // Remove this frame's spill slots first.
717 int stack_slots = frame()->GetSpillSlotCount();
718 if (stack_slots > 0) {
719 __ Addu(sp, sp, Operand(stack_slots * kPointerSize));
720 }
721 // Restore registers.
722 const RegList saves = descriptor->CalleeSavedRegisters();
723 if (saves != 0) {
724 __ MultiPop(saves);
725 }
726 }
727 __ mov(sp, fp);
728 __ Pop(ra, fp);
729 __ Ret();
730 } else {
731 __ mov(sp, fp);
732 __ Pop(ra, fp);
733 int pop_count = descriptor->IsJSFunctionCall()
734 ? static_cast<int>(descriptor->JSParameterCount())
735 : 0;
736 __ DropAndRet(pop_count);
737 }
738 }
739
740
741 void CodeGenerator::AssembleMove(InstructionOperand* source,
742 InstructionOperand* destination) {
743 MipsOperandConverter g(this, NULL);
744 // Dispatch on the source and destination operand kinds. Not all
745 // combinations are possible.
746 if (source->IsRegister()) {
747 DCHECK(destination->IsRegister() || destination->IsStackSlot());
748 Register src = g.ToRegister(source);
749 if (destination->IsRegister()) {
750 __ mov(g.ToRegister(destination), src);
751 } else {
752 __ sw(src, g.ToMemOperand(destination));
753 }
754 } else if (source->IsStackSlot()) {
755 DCHECK(destination->IsRegister() || destination->IsStackSlot());
756 MemOperand src = g.ToMemOperand(source);
757 if (destination->IsRegister()) {
758 __ lw(g.ToRegister(destination), src);
759 } else {
760 Register temp = kScratchReg;
761 __ lw(temp, src);
762 __ sw(temp, g.ToMemOperand(destination));
763 }
764 } else if (source->IsConstant()) {
765 if (destination->IsRegister() || destination->IsStackSlot()) {
766 Register dst =
767 destination->IsRegister() ? g.ToRegister(destination) : kScratchReg;
768 Constant src = g.ToConstant(source);
769 switch (src.type()) {
770 case Constant::kInt32:
771 __ li(dst, Operand(src.ToInt32()));
772 break;
773 case Constant::kInt64:
774 UNREACHABLE();
775 break;
776 case Constant::kFloat64:
777 __ li(dst, isolate()->factory()->NewNumber(src.ToFloat64(), TENURED));
778 break;
779 case Constant::kExternalReference:
780 __ li(dst, Operand(src.ToExternalReference()));
781 break;
782 case Constant::kHeapObject:
783 __ li(dst, src.ToHeapObject());
784 break;
785 }
786 if (destination->IsStackSlot()) __ sw(dst, g.ToMemOperand(destination));
787 } else if (destination->IsDoubleRegister()) {
788 FPURegister result = g.ToDoubleRegister(destination);
789 __ Move(result, g.ToDouble(source));
790 } else {
791 DCHECK(destination->IsDoubleStackSlot());
792 FPURegister temp = kScratchDoubleReg;
793 __ Move(temp, g.ToDouble(source));
794 __ sdc1(temp, g.ToMemOperand(destination));
795 }
796 } else if (source->IsDoubleRegister()) {
797 FPURegister src = g.ToDoubleRegister(source);
798 if (destination->IsDoubleRegister()) {
799 FPURegister dst = g.ToDoubleRegister(destination);
800 __ Move(dst, src);
801 } else {
802 DCHECK(destination->IsDoubleStackSlot());
803 __ sdc1(src, g.ToMemOperand(destination));
804 }
805 } else if (source->IsDoubleStackSlot()) {
806 DCHECK(destination->IsDoubleRegister() || destination->IsDoubleStackSlot());
807 MemOperand src = g.ToMemOperand(source);
808 if (destination->IsDoubleRegister()) {
809 __ ldc1(g.ToDoubleRegister(destination), src);
810 } else {
811 FPURegister temp = kScratchDoubleReg;
812 __ ldc1(temp, src);
813 __ sdc1(temp, g.ToMemOperand(destination));
814 }
815 } else {
816 UNREACHABLE();
817 }
818 }
819
820
821 void CodeGenerator::AssembleSwap(InstructionOperand* source,
822 InstructionOperand* destination) {
823 MipsOperandConverter g(this, NULL);
824 // Dispatch on the source and destination operand kinds. Not all
825 // combinations are possible.
826 if (source->IsRegister()) {
827 // Register-register.
828 Register temp = kScratchReg;
829 Register src = g.ToRegister(source);
830 if (destination->IsRegister()) {
831 Register dst = g.ToRegister(destination);
832 __ Move(temp, src);
833 __ Move(src, dst);
834 __ Move(dst, temp);
835 } else {
836 DCHECK(destination->IsStackSlot());
837 MemOperand dst = g.ToMemOperand(destination);
838 __ mov(temp, src);
839 __ lw(src, dst);
840 __ sw(temp, dst);
841 }
842 } else if (source->IsStackSlot()) {
843 DCHECK(destination->IsStackSlot());
844 Register temp_0 = kScratchReg;
845 Register temp_1 = kCompareReg;
846 MemOperand src = g.ToMemOperand(source);
847 MemOperand dst = g.ToMemOperand(destination);
848 __ lw(temp_0, src);
849 __ lw(temp_1, dst);
850 __ sw(temp_0, dst);
851 __ sw(temp_1, src);
852 } else if (source->IsDoubleRegister()) {
853 FPURegister temp = kScratchDoubleReg;
854 FPURegister src = g.ToDoubleRegister(source);
855 if (destination->IsDoubleRegister()) {
856 FPURegister dst = g.ToDoubleRegister(destination);
857 __ Move(temp, src);
858 __ Move(src, dst);
859 __ Move(dst, temp);
860 } else {
861 DCHECK(destination->IsDoubleStackSlot());
862 MemOperand dst = g.ToMemOperand(destination);
863 __ Move(temp, src);
864 __ ldc1(src, dst);
865 __ sdc1(temp, dst);
866 }
867 } else if (source->IsDoubleStackSlot()) {
868 DCHECK(destination->IsDoubleStackSlot());
869 Register temp_0 = kScratchReg;
870 FPURegister temp_1 = kScratchDoubleReg;
871 MemOperand src0 = g.ToMemOperand(source);
872 MemOperand src1(src0.rm(), src0.offset() + kPointerSize);
873 MemOperand dst0 = g.ToMemOperand(destination);
874 MemOperand dst1(dst0.rm(), dst0.offset() + kPointerSize);
875 __ ldc1(temp_1, dst0); // Save destination in temp_1.
876 __ lw(temp_0, src0); // Then use temp_0 to copy source to destination.
877 __ sw(temp_0, dst0);
878 __ lw(temp_0, src1);
879 __ sw(temp_0, dst1);
880 __ sdc1(temp_1, src0);
881 } else {
882 // No other combinations are possible.
883 UNREACHABLE();
884 }
885 }
886
887
888 void CodeGenerator::AddNopForSmiCodeInlining() {
889 // Unused on 32-bit ARM. Still exists on 64-bit arm.
890 // TODO(plind): Unclear when this is called now. Understand, fix if needed.
891 __ nop(); // Maybe PROPERTY_ACCESS_INLINED?
892 }
893
894
895 void CodeGenerator::EnsureSpaceForLazyDeopt() {
896 int space_needed = Deoptimizer::patch_size();
897 if (!linkage()->info()->IsStub()) {
898 // Ensure that we have enough space after the previous lazy-bailout
899 // instruction for patching the code here.
900 int current_pc = masm()->pc_offset();
901 if (current_pc < last_lazy_deopt_pc_ + space_needed) {
902 // Block tramoline pool emission for duration of padding.
903 v8::internal::Assembler::BlockTrampolinePoolScope block_trampoline_pool(
904 masm());
905 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
906 DCHECK_EQ(0, padding_size % v8::internal::Assembler::kInstrSize);
907 while (padding_size > 0) {
908 __ nop();
909 padding_size -= v8::internal::Assembler::kInstrSize;
910 }
911 }
912 }
913 MarkLazyDeoptSite();
914 }
915
916 #undef __
917
918 } // namespace compiler
919 } // namespace internal
920 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698