deps: update v8 to 4.3.61.21
[platform/upstream/nodejs.git] / deps / v8 / src / compiler / mips / code-generator-mips.cc
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/mips/macro-assembler-mips.h"
10 #include "src/scopes.h"
11
12 namespace v8 {
13 namespace internal {
14 namespace compiler {
15
16 #define __ masm()->
17
18
19 // TODO(plind): Possibly avoid using these lithium names.
20 #define kScratchReg kLithiumScratchReg
21 #define kCompareReg kLithiumScratchReg2
22 #define kScratchReg2 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 FINAL : public InstructionOperandConverter {
38  public:
39   MipsOperandConverter(CodeGenerator* gen, Instruction* instr)
40       : InstructionOperandConverter(gen, instr) {}
41
42   FloatRegister OutputSingleRegister(size_t index = 0) {
43     return ToSingleRegister(instr_->OutputAt(index));
44   }
45
46   FloatRegister InputSingleRegister(size_t index) {
47     return ToSingleRegister(instr_->InputAt(index));
48   }
49
50   FloatRegister ToSingleRegister(InstructionOperand* op) {
51     // Single (Float) and Double register namespace is same on MIPS,
52     // both are typedefs of FPURegister.
53     return ToDoubleRegister(op);
54   }
55
56   Operand InputImmediate(size_t index) {
57     Constant constant = ToConstant(instr_->InputAt(index));
58     switch (constant.type()) {
59       case Constant::kInt32:
60         return Operand(constant.ToInt32());
61       case Constant::kFloat32:
62         return Operand(
63             isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED));
64       case Constant::kFloat64:
65         return Operand(
66             isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
67       case Constant::kInt64:
68       case Constant::kExternalReference:
69       case Constant::kHeapObject:
70         // TODO(plind): Maybe we should handle ExtRef & HeapObj here?
71         //    maybe not done on arm due to const pool ??
72         break;
73       case Constant::kRpoNumber:
74         UNREACHABLE();  // TODO(titzer): RPO immediates on mips?
75         break;
76     }
77     UNREACHABLE();
78     return Operand(zero_reg);
79   }
80
81   Operand InputOperand(size_t index) {
82     InstructionOperand* op = instr_->InputAt(index);
83     if (op->IsRegister()) {
84       return Operand(ToRegister(op));
85     }
86     return InputImmediate(index);
87   }
88
89   MemOperand MemoryOperand(size_t* first_index) {
90     const size_t index = *first_index;
91     switch (AddressingModeField::decode(instr_->opcode())) {
92       case kMode_None:
93         break;
94       case kMode_MRI:
95         *first_index += 2;
96         return MemOperand(InputRegister(index + 0), InputInt32(index + 1));
97       case kMode_MRR:
98         // TODO(plind): r6 address mode, to be implemented ...
99         UNREACHABLE();
100     }
101     UNREACHABLE();
102     return MemOperand(no_reg);
103   }
104
105   MemOperand MemoryOperand(size_t index = 0) { return MemoryOperand(&index); }
106
107   MemOperand ToMemOperand(InstructionOperand* op) const {
108     DCHECK(op != NULL);
109     DCHECK(!op->IsRegister());
110     DCHECK(!op->IsDoubleRegister());
111     DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
112     // The linkage computes where all spill slots are located.
113     FrameOffset offset = linkage()->GetFrameOffset(op->index(), frame(), 0);
114     return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
115   }
116 };
117
118
119 static inline bool HasRegisterInput(Instruction* instr, size_t index) {
120   return instr->InputAt(index)->IsRegister();
121 }
122
123
124 namespace {
125
126 class OutOfLineLoadSingle FINAL : public OutOfLineCode {
127  public:
128   OutOfLineLoadSingle(CodeGenerator* gen, FloatRegister result)
129       : OutOfLineCode(gen), result_(result) {}
130
131   void Generate() FINAL {
132     __ Move(result_, std::numeric_limits<float>::quiet_NaN());
133   }
134
135  private:
136   FloatRegister const result_;
137 };
138
139
140 class OutOfLineLoadDouble FINAL : public OutOfLineCode {
141  public:
142   OutOfLineLoadDouble(CodeGenerator* gen, DoubleRegister result)
143       : OutOfLineCode(gen), result_(result) {}
144
145   void Generate() FINAL {
146     __ Move(result_, std::numeric_limits<double>::quiet_NaN());
147   }
148
149  private:
150   DoubleRegister const result_;
151 };
152
153
154 class OutOfLineLoadInteger FINAL : public OutOfLineCode {
155  public:
156   OutOfLineLoadInteger(CodeGenerator* gen, Register result)
157       : OutOfLineCode(gen), result_(result) {}
158
159   void Generate() FINAL { __ mov(result_, zero_reg); }
160
161  private:
162   Register const result_;
163 };
164
165
166 class OutOfLineRound : public OutOfLineCode {
167  public:
168   OutOfLineRound(CodeGenerator* gen, DoubleRegister result)
169       : OutOfLineCode(gen), result_(result) {}
170
171   void Generate() FINAL {
172     // Handle rounding to zero case where sign has to be preserved.
173     // High bits of double input already in kScratchReg.
174     __ srl(at, kScratchReg, 31);
175     __ sll(at, at, 31);
176     __ Mthc1(at, result_);
177   }
178
179  private:
180   DoubleRegister const result_;
181 };
182
183
184 class OutOfLineTruncate FINAL : public OutOfLineRound {
185  public:
186   OutOfLineTruncate(CodeGenerator* gen, DoubleRegister result)
187       : OutOfLineRound(gen, result) {}
188 };
189
190
191 class OutOfLineFloor FINAL : public OutOfLineRound {
192  public:
193   OutOfLineFloor(CodeGenerator* gen, DoubleRegister result)
194       : OutOfLineRound(gen, result) {}
195 };
196
197
198 class OutOfLineCeil FINAL : public OutOfLineRound {
199  public:
200   OutOfLineCeil(CodeGenerator* gen, DoubleRegister result)
201       : OutOfLineRound(gen, result) {}
202 };
203
204
205 Condition FlagsConditionToConditionCmp(FlagsCondition condition) {
206   switch (condition) {
207     case kEqual:
208       return eq;
209     case kNotEqual:
210       return ne;
211     case kSignedLessThan:
212       return lt;
213     case kSignedGreaterThanOrEqual:
214       return ge;
215     case kSignedLessThanOrEqual:
216       return le;
217     case kSignedGreaterThan:
218       return gt;
219     case kUnsignedLessThan:
220       return lo;
221     case kUnsignedGreaterThanOrEqual:
222       return hs;
223     case kUnsignedLessThanOrEqual:
224       return ls;
225     case kUnsignedGreaterThan:
226       return hi;
227     case kUnorderedEqual:
228     case kUnorderedNotEqual:
229       break;
230     default:
231       break;
232   }
233   UNREACHABLE();
234   return kNoCondition;
235 }
236
237
238 Condition FlagsConditionToConditionTst(FlagsCondition condition) {
239   switch (condition) {
240     case kNotEqual:
241       return ne;
242     case kEqual:
243       return eq;
244     default:
245       break;
246   }
247   UNREACHABLE();
248   return kNoCondition;
249 }
250
251
252 Condition FlagsConditionToConditionOvf(FlagsCondition condition) {
253   switch (condition) {
254     case kOverflow:
255       return lt;
256     case kNotOverflow:
257       return ge;
258     default:
259       break;
260   }
261   UNREACHABLE();
262   return kNoCondition;
263 }
264
265 FPUCondition FlagsConditionToConditionCmpD(bool& predicate,
266                                            FlagsCondition condition) {
267   switch (condition) {
268     case kEqual:
269       predicate = true;
270       return EQ;
271     case kNotEqual:
272       predicate = false;
273       return EQ;
274     case kUnsignedLessThan:
275       predicate = true;
276       return OLT;
277     case kUnsignedGreaterThanOrEqual:
278       predicate = false;
279       return ULT;
280     case kUnsignedLessThanOrEqual:
281       predicate = true;
282       return OLE;
283     case kUnsignedGreaterThan:
284       predicate = false;
285       return ULE;
286     case kUnorderedEqual:
287     case kUnorderedNotEqual:
288       predicate = true;
289       break;
290     default:
291       predicate = true;
292       break;
293   }
294   UNREACHABLE();
295   return kNoFPUCondition;
296 }
297
298 }  // namespace
299
300
301 #define ASSEMBLE_CHECKED_LOAD_FLOAT(width, asm_instr)                         \
302   do {                                                                        \
303     auto result = i.Output##width##Register();                                \
304     auto ool = new (zone()) OutOfLineLoad##width(this, result);               \
305     if (instr->InputAt(0)->IsRegister()) {                                    \
306       auto offset = i.InputRegister(0);                                       \
307       __ Branch(USE_DELAY_SLOT, ool->entry(), hs, offset, i.InputOperand(1)); \
308       __ addu(at, i.InputRegister(2), offset);                                \
309       __ asm_instr(result, MemOperand(at, 0));                                \
310     } else {                                                                  \
311       auto offset = i.InputOperand(0).immediate();                            \
312       __ Branch(ool->entry(), ls, i.InputRegister(1), Operand(offset));       \
313       __ asm_instr(result, MemOperand(i.InputRegister(2), offset));           \
314     }                                                                         \
315     __ bind(ool->exit());                                                     \
316   } while (0)
317
318
319 #define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr)                              \
320   do {                                                                        \
321     auto result = i.OutputRegister();                                         \
322     auto ool = new (zone()) OutOfLineLoadInteger(this, result);               \
323     if (instr->InputAt(0)->IsRegister()) {                                    \
324       auto offset = i.InputRegister(0);                                       \
325       __ Branch(USE_DELAY_SLOT, ool->entry(), hs, offset, i.InputOperand(1)); \
326       __ addu(at, i.InputRegister(2), offset);                                \
327       __ asm_instr(result, MemOperand(at, 0));                                \
328     } else {                                                                  \
329       auto offset = i.InputOperand(0).immediate();                            \
330       __ Branch(ool->entry(), ls, i.InputRegister(1), Operand(offset));       \
331       __ asm_instr(result, MemOperand(i.InputRegister(2), offset));           \
332     }                                                                         \
333     __ bind(ool->exit());                                                     \
334   } while (0)
335
336
337 #define ASSEMBLE_CHECKED_STORE_FLOAT(width, asm_instr)                 \
338   do {                                                                 \
339     Label done;                                                        \
340     if (instr->InputAt(0)->IsRegister()) {                             \
341       auto offset = i.InputRegister(0);                                \
342       auto value = i.Input##width##Register(2);                        \
343       __ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \
344       __ addu(at, i.InputRegister(3), offset);                         \
345       __ asm_instr(value, MemOperand(at, 0));                          \
346     } else {                                                           \
347       auto offset = i.InputOperand(0).immediate();                     \
348       auto value = i.Input##width##Register(2);                        \
349       __ Branch(&done, ls, i.InputRegister(1), Operand(offset));       \
350       __ asm_instr(value, MemOperand(i.InputRegister(3), offset));     \
351     }                                                                  \
352     __ bind(&done);                                                    \
353   } while (0)
354
355
356 #define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr)                      \
357   do {                                                                 \
358     Label done;                                                        \
359     if (instr->InputAt(0)->IsRegister()) {                             \
360       auto offset = i.InputRegister(0);                                \
361       auto value = i.InputRegister(2);                                 \
362       __ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \
363       __ addu(at, i.InputRegister(3), offset);                         \
364       __ asm_instr(value, MemOperand(at, 0));                          \
365     } else {                                                           \
366       auto offset = i.InputOperand(0).immediate();                     \
367       auto value = i.InputRegister(2);                                 \
368       __ Branch(&done, ls, i.InputRegister(1), Operand(offset));       \
369       __ asm_instr(value, MemOperand(i.InputRegister(3), offset));     \
370     }                                                                  \
371     __ bind(&done);                                                    \
372   } while (0)
373
374
375 #define ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(asm_instr, operation)                  \
376   do {                                                                         \
377     auto ool =                                                                 \
378         new (zone()) OutOfLine##operation(this, i.OutputDoubleRegister());     \
379     Label done;                                                                \
380     __ Mfhc1(kScratchReg, i.InputDoubleRegister(0));                           \
381     __ Ext(at, kScratchReg, HeapNumber::kExponentShift,                        \
382            HeapNumber::kExponentBits);                                         \
383     __ Branch(USE_DELAY_SLOT, &done, hs, at,                                   \
384               Operand(HeapNumber::kExponentBias + HeapNumber::kMantissaBits)); \
385     __ mov_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));              \
386     __ asm_instr(i.OutputDoubleRegister(), i.InputDoubleRegister(0));          \
387     __ Move(at, kScratchReg2, i.OutputDoubleRegister());                       \
388     __ or_(at, at, kScratchReg2);                                              \
389     __ Branch(USE_DELAY_SLOT, ool->entry(), eq, at, Operand(zero_reg));        \
390     __ cvt_d_l(i.OutputDoubleRegister(), i.OutputDoubleRegister());            \
391     __ bind(ool->exit());                                                      \
392     __ bind(&done);                                                            \
393   } while (0)
394
395
396 // Assembles an instruction after register allocation, producing machine code.
397 void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
398   MipsOperandConverter i(this, instr);
399   InstructionCode opcode = instr->opcode();
400
401   switch (ArchOpcodeField::decode(opcode)) {
402     case kArchCallCodeObject: {
403       EnsureSpaceForLazyDeopt();
404       if (instr->InputAt(0)->IsImmediate()) {
405         __ Call(Handle<Code>::cast(i.InputHeapObject(0)),
406                 RelocInfo::CODE_TARGET);
407       } else {
408         __ addiu(at, i.InputRegister(0), Code::kHeaderSize - kHeapObjectTag);
409         __ Call(at);
410       }
411       RecordCallPosition(instr);
412       break;
413     }
414     case kArchCallJSFunction: {
415       EnsureSpaceForLazyDeopt();
416       Register func = i.InputRegister(0);
417       if (FLAG_debug_code) {
418         // Check the function's context matches the context argument.
419         __ lw(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset));
420         __ Assert(eq, kWrongFunctionContext, cp, Operand(kScratchReg));
421       }
422
423       __ lw(at, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
424       __ Call(at);
425       RecordCallPosition(instr);
426       break;
427     }
428     case kArchJmp:
429       AssembleArchJump(i.InputRpo(0));
430       break;
431     case kArchLookupSwitch:
432       AssembleArchLookupSwitch(instr);
433       break;
434     case kArchTableSwitch:
435       AssembleArchTableSwitch(instr);
436       break;
437     case kArchNop:
438       // don't emit code for nops.
439       break;
440     case kArchDeoptimize: {
441       int deopt_state_id =
442           BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
443       AssembleDeoptimizerCall(deopt_state_id, Deoptimizer::EAGER);
444       break;
445     }
446     case kArchRet:
447       AssembleReturn();
448       break;
449     case kArchStackPointer:
450       __ mov(i.OutputRegister(), sp);
451       break;
452     case kArchTruncateDoubleToI:
453       __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
454       break;
455     case kMipsAdd:
456       __ Addu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
457       break;
458     case kMipsAddOvf:
459       __ AdduAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0),
460                                  i.InputOperand(1), kCompareReg, kScratchReg);
461       break;
462     case kMipsSub:
463       __ Subu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
464       break;
465     case kMipsSubOvf:
466       __ SubuAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0),
467                                  i.InputOperand(1), kCompareReg, kScratchReg);
468       break;
469     case kMipsMul:
470       __ Mul(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
471       break;
472     case kMipsMulHigh:
473       __ Mulh(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
474       break;
475     case kMipsMulHighU:
476       __ Mulhu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
477       break;
478     case kMipsDiv:
479       __ Div(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
480       break;
481     case kMipsDivU:
482       __ Divu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
483       break;
484     case kMipsMod:
485       __ Mod(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
486       break;
487     case kMipsModU:
488       __ Modu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
489       break;
490     case kMipsAnd:
491       __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
492       break;
493     case kMipsOr:
494       __ Or(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
495       break;
496     case kMipsXor:
497       __ Xor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
498       break;
499     case kMipsClz:
500       __ Clz(i.OutputRegister(), i.InputRegister(0));
501       break;
502     case kMipsShl:
503       if (instr->InputAt(1)->IsRegister()) {
504         __ sllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
505       } else {
506         int32_t imm = i.InputOperand(1).immediate();
507         __ sll(i.OutputRegister(), i.InputRegister(0), imm);
508       }
509       break;
510     case kMipsShr:
511       if (instr->InputAt(1)->IsRegister()) {
512         __ srlv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
513       } else {
514         int32_t imm = i.InputOperand(1).immediate();
515         __ srl(i.OutputRegister(), i.InputRegister(0), imm);
516       }
517       break;
518     case kMipsSar:
519       if (instr->InputAt(1)->IsRegister()) {
520         __ srav(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
521       } else {
522         int32_t imm = i.InputOperand(1).immediate();
523         __ sra(i.OutputRegister(), i.InputRegister(0), imm);
524       }
525       break;
526     case kMipsRor:
527       __ Ror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
528       break;
529     case kMipsTst:
530       // Pseudo-instruction used for tst/branch. No opcode emitted here.
531       break;
532     case kMipsCmp:
533       // Pseudo-instruction used for cmp/branch. No opcode emitted here.
534       break;
535     case kMipsMov:
536       // TODO(plind): Should we combine mov/li like this, or use separate instr?
537       //    - Also see x64 ASSEMBLE_BINOP & RegisterOrOperandType
538       if (HasRegisterInput(instr, 0)) {
539         __ mov(i.OutputRegister(), i.InputRegister(0));
540       } else {
541         __ li(i.OutputRegister(), i.InputOperand(0));
542       }
543       break;
544
545     case kMipsCmpD:
546       // Psuedo-instruction used for FP cmp/branch. No opcode emitted here.
547       break;
548     case kMipsAddD:
549       // TODO(plind): add special case: combine mult & add.
550       __ add_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
551                i.InputDoubleRegister(1));
552       break;
553     case kMipsSubD:
554       __ sub_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
555                i.InputDoubleRegister(1));
556       break;
557     case kMipsMulD:
558       // TODO(plind): add special case: right op is -1.0, see arm port.
559       __ mul_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
560                i.InputDoubleRegister(1));
561       break;
562     case kMipsDivD:
563       __ div_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
564                i.InputDoubleRegister(1));
565       break;
566     case kMipsModD: {
567       // TODO(bmeurer): We should really get rid of this special instruction,
568       // and generate a CallAddress instruction instead.
569       FrameScope scope(masm(), StackFrame::MANUAL);
570       __ PrepareCallCFunction(0, 2, kScratchReg);
571       __ MovToFloatParameters(i.InputDoubleRegister(0),
572                               i.InputDoubleRegister(1));
573       __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
574                        0, 2);
575       // Move the result in the double result register.
576       __ MovFromFloatResult(i.OutputDoubleRegister());
577       break;
578     }
579     case kMipsFloat64RoundDown: {
580       ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(floor_l_d, Floor);
581       break;
582     }
583     case kMipsFloat64RoundTruncate: {
584       ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(trunc_l_d, Truncate);
585       break;
586     }
587     case kMipsFloat64RoundUp: {
588       ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(ceil_l_d, Ceil);
589       break;
590     }
591     case kMipsSqrtD: {
592       __ sqrt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
593       break;
594     }
595     case kMipsCvtSD: {
596       __ cvt_s_d(i.OutputSingleRegister(), i.InputDoubleRegister(0));
597       break;
598     }
599     case kMipsCvtDS: {
600       __ cvt_d_s(i.OutputDoubleRegister(), i.InputSingleRegister(0));
601       break;
602     }
603     case kMipsCvtDW: {
604       FPURegister scratch = kScratchDoubleReg;
605       __ mtc1(i.InputRegister(0), scratch);
606       __ cvt_d_w(i.OutputDoubleRegister(), scratch);
607       break;
608     }
609     case kMipsCvtDUw: {
610       FPURegister scratch = kScratchDoubleReg;
611       __ Cvt_d_uw(i.OutputDoubleRegister(), i.InputRegister(0), scratch);
612       break;
613     }
614     case kMipsTruncWD: {
615       FPURegister scratch = kScratchDoubleReg;
616       // Other arches use round to zero here, so we follow.
617       __ trunc_w_d(scratch, i.InputDoubleRegister(0));
618       __ mfc1(i.OutputRegister(), scratch);
619       break;
620     }
621     case kMipsTruncUwD: {
622       FPURegister scratch = kScratchDoubleReg;
623       // TODO(plind): Fix wrong param order of Trunc_uw_d() macro-asm function.
624       __ Trunc_uw_d(i.InputDoubleRegister(0), i.OutputRegister(), scratch);
625       break;
626     }
627     case kMipsFloat64ExtractLowWord32:
628       __ FmoveLow(i.OutputRegister(), i.InputDoubleRegister(0));
629       break;
630     case kMipsFloat64ExtractHighWord32:
631       __ FmoveHigh(i.OutputRegister(), i.InputDoubleRegister(0));
632       break;
633     case kMipsFloat64InsertLowWord32:
634       __ FmoveLow(i.OutputDoubleRegister(), i.InputRegister(1));
635       break;
636     case kMipsFloat64InsertHighWord32:
637       __ FmoveHigh(i.OutputDoubleRegister(), i.InputRegister(1));
638       break;
639     // ... more basic instructions ...
640
641     case kMipsLbu:
642       __ lbu(i.OutputRegister(), i.MemoryOperand());
643       break;
644     case kMipsLb:
645       __ lb(i.OutputRegister(), i.MemoryOperand());
646       break;
647     case kMipsSb:
648       __ sb(i.InputRegister(2), i.MemoryOperand());
649       break;
650     case kMipsLhu:
651       __ lhu(i.OutputRegister(), i.MemoryOperand());
652       break;
653     case kMipsLh:
654       __ lh(i.OutputRegister(), i.MemoryOperand());
655       break;
656     case kMipsSh:
657       __ sh(i.InputRegister(2), i.MemoryOperand());
658       break;
659     case kMipsLw:
660       __ lw(i.OutputRegister(), i.MemoryOperand());
661       break;
662     case kMipsSw:
663       __ sw(i.InputRegister(2), i.MemoryOperand());
664       break;
665     case kMipsLwc1: {
666       __ lwc1(i.OutputSingleRegister(), i.MemoryOperand());
667       break;
668     }
669     case kMipsSwc1: {
670       size_t index = 0;
671       MemOperand operand = i.MemoryOperand(&index);
672       __ swc1(i.InputSingleRegister(index), operand);
673       break;
674     }
675     case kMipsLdc1:
676       __ ldc1(i.OutputDoubleRegister(), i.MemoryOperand());
677       break;
678     case kMipsSdc1:
679       __ sdc1(i.InputDoubleRegister(2), i.MemoryOperand());
680       break;
681     case kMipsPush:
682       __ Push(i.InputRegister(0));
683       break;
684     case kMipsStackClaim: {
685       int words = MiscField::decode(instr->opcode());
686       __ Subu(sp, sp, Operand(words << kPointerSizeLog2));
687       break;
688     }
689     case kMipsStoreToStackSlot: {
690       int slot = MiscField::decode(instr->opcode());
691       __ sw(i.InputRegister(0), MemOperand(sp, slot << kPointerSizeLog2));
692       break;
693     }
694     case kMipsStoreWriteBarrier: {
695       Register object = i.InputRegister(0);
696       Register index = i.InputRegister(1);
697       Register value = i.InputRegister(2);
698       __ addu(index, object, index);
699       __ sw(value, MemOperand(index));
700       SaveFPRegsMode mode =
701           frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
702       RAStatus ra_status = kRAHasNotBeenSaved;
703       __ RecordWrite(object, index, value, ra_status, mode);
704       break;
705     }
706     case kCheckedLoadInt8:
707       ASSEMBLE_CHECKED_LOAD_INTEGER(lb);
708       break;
709     case kCheckedLoadUint8:
710       ASSEMBLE_CHECKED_LOAD_INTEGER(lbu);
711       break;
712     case kCheckedLoadInt16:
713       ASSEMBLE_CHECKED_LOAD_INTEGER(lh);
714       break;
715     case kCheckedLoadUint16:
716       ASSEMBLE_CHECKED_LOAD_INTEGER(lhu);
717       break;
718     case kCheckedLoadWord32:
719       ASSEMBLE_CHECKED_LOAD_INTEGER(lw);
720       break;
721     case kCheckedLoadFloat32:
722       ASSEMBLE_CHECKED_LOAD_FLOAT(Single, lwc1);
723       break;
724     case kCheckedLoadFloat64:
725       ASSEMBLE_CHECKED_LOAD_FLOAT(Double, ldc1);
726       break;
727     case kCheckedStoreWord8:
728       ASSEMBLE_CHECKED_STORE_INTEGER(sb);
729       break;
730     case kCheckedStoreWord16:
731       ASSEMBLE_CHECKED_STORE_INTEGER(sh);
732       break;
733     case kCheckedStoreWord32:
734       ASSEMBLE_CHECKED_STORE_INTEGER(sw);
735       break;
736     case kCheckedStoreFloat32:
737       ASSEMBLE_CHECKED_STORE_FLOAT(Single, swc1);
738       break;
739     case kCheckedStoreFloat64:
740       ASSEMBLE_CHECKED_STORE_FLOAT(Double, sdc1);
741       break;
742   }
743 }
744
745
746 #define UNSUPPORTED_COND(opcode, condition)                                  \
747   OFStream out(stdout);                                                      \
748   out << "Unsupported " << #opcode << " condition: \"" << condition << "\""; \
749   UNIMPLEMENTED();
750
751 // Assembles branches after an instruction.
752 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
753   MipsOperandConverter i(this, instr);
754   Label* tlabel = branch->true_label;
755   Label* flabel = branch->false_label;
756   Condition cc = kNoCondition;
757
758   // MIPS does not have condition code flags, so compare and branch are
759   // implemented differently than on the other arch's. The compare operations
760   // emit mips pseudo-instructions, which are handled here by branch
761   // instructions that do the actual comparison. Essential that the input
762   // registers to compare pseudo-op are not modified before this branch op, as
763   // they are tested here.
764   // TODO(plind): Add CHECK() to ensure that test/cmp and this branch were
765   //    not separated by other instructions.
766
767   if (instr->arch_opcode() == kMipsTst) {
768     cc = FlagsConditionToConditionTst(branch->condition);
769     __ And(at, i.InputRegister(0), i.InputOperand(1));
770     __ Branch(tlabel, cc, at, Operand(zero_reg));
771
772   } else if (instr->arch_opcode() == kMipsAddOvf ||
773              instr->arch_opcode() == kMipsSubOvf) {
774     // kMipsAddOvf, SubOvf emit negative result to 'kCompareReg' on overflow.
775     cc = FlagsConditionToConditionOvf(branch->condition);
776     __ Branch(tlabel, cc, kCompareReg, Operand(zero_reg));
777
778   } else if (instr->arch_opcode() == kMipsCmp) {
779     cc = FlagsConditionToConditionCmp(branch->condition);
780     __ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1));
781
782     if (!branch->fallthru) __ Branch(flabel);  // no fallthru to flabel.
783
784   } else if (instr->arch_opcode() == kMipsCmpD) {
785     // TODO(dusmil) optimize unordered checks to use fewer instructions
786     // even if we have to unfold BranchF macro.
787     Label* nan = flabel;
788     switch (branch->condition) {
789       case kEqual:
790         cc = eq;
791         break;
792       case kNotEqual:
793         cc = ne;
794         nan = tlabel;
795         break;
796       case kUnsignedLessThan:
797         cc = lt;
798         break;
799       case kUnsignedGreaterThanOrEqual:
800         cc = ge;
801         nan = tlabel;
802         break;
803       case kUnsignedLessThanOrEqual:
804         cc = le;
805         break;
806       case kUnsignedGreaterThan:
807         cc = gt;
808         nan = tlabel;
809         break;
810       default:
811         UNSUPPORTED_COND(kMipsCmpD, branch->condition);
812         break;
813     }
814     __ BranchF(tlabel, nan, cc, i.InputDoubleRegister(0),
815                i.InputDoubleRegister(1));
816
817     if (!branch->fallthru) __ Branch(flabel);  // no fallthru to flabel.
818
819   } else {
820     PrintF("AssembleArchBranch Unimplemented arch_opcode: %d\n",
821            instr->arch_opcode());
822     UNIMPLEMENTED();
823   }
824 }
825
826
827 void CodeGenerator::AssembleArchJump(RpoNumber target) {
828   if (!IsNextInAssemblyOrder(target)) __ Branch(GetLabel(target));
829 }
830
831
832 // Assembles boolean materializations after an instruction.
833 void CodeGenerator::AssembleArchBoolean(Instruction* instr,
834                                         FlagsCondition condition) {
835   MipsOperandConverter i(this, instr);
836   Label done;
837
838   // Materialize a full 32-bit 1 or 0 value. The result register is always the
839   // last output of the instruction.
840   Label false_value;
841   DCHECK_NE(0u, instr->OutputCount());
842   Register result = i.OutputRegister(instr->OutputCount() - 1);
843   Condition cc = kNoCondition;
844
845   // MIPS does not have condition code flags, so compare and branch are
846   // implemented differently than on the other arch's. The compare operations
847   // emit mips psuedo-instructions, which are checked and handled here.
848
849   // For materializations, we use delay slot to set the result true, and
850   // in the false case, where we fall thru the branch, we reset the result
851   // false.
852
853   if (instr->arch_opcode() == kMipsTst) {
854     cc = FlagsConditionToConditionTst(condition);
855     __ And(at, i.InputRegister(0), i.InputOperand(1));
856     __ Branch(USE_DELAY_SLOT, &done, cc, at, Operand(zero_reg));
857     __ li(result, Operand(1));  // In delay slot.
858
859   } else if (instr->arch_opcode() == kMipsAddOvf ||
860              instr->arch_opcode() == kMipsSubOvf) {
861     // kMipsAddOvf, SubOvf emits negative result to 'kCompareReg' on overflow.
862     cc = FlagsConditionToConditionOvf(condition);
863     __ Branch(USE_DELAY_SLOT, &done, cc, kCompareReg, Operand(zero_reg));
864     __ li(result, Operand(1));  // In delay slot.
865
866   } else if (instr->arch_opcode() == kMipsCmp) {
867     Register left = i.InputRegister(0);
868     Operand right = i.InputOperand(1);
869     cc = FlagsConditionToConditionCmp(condition);
870     __ Branch(USE_DELAY_SLOT, &done, cc, left, right);
871     __ li(result, Operand(1));  // In delay slot.
872
873   } else if (instr->arch_opcode() == kMipsCmpD) {
874     FPURegister left = i.InputDoubleRegister(0);
875     FPURegister right = i.InputDoubleRegister(1);
876
877     bool predicate;
878     FPUCondition cc = FlagsConditionToConditionCmpD(predicate, condition);
879     if (!IsMipsArchVariant(kMips32r6)) {
880       __ li(result, Operand(1));
881       __ c(cc, D, left, right);
882       if (predicate) {
883         __ Movf(result, zero_reg);
884       } else {
885         __ Movt(result, zero_reg);
886       }
887     } else {
888       __ cmp(cc, L, kDoubleCompareReg, left, right);
889       __ mfc1(at, kDoubleCompareReg);
890       __ srl(result, at, 31);  // Cmp returns all 1s for true.
891       if (!predicate)          // Toggle result for not equal.
892         __ xori(result, result, 1);
893     }
894     return;
895   } else {
896     PrintF("AssembleArchBranch Unimplemented arch_opcode is : %d\n",
897            instr->arch_opcode());
898     TRACE_UNIMPL();
899     UNIMPLEMENTED();
900   }
901
902   // Fallthrough case is the false materialization.
903   __ bind(&false_value);
904   __ li(result, Operand(0));
905   __ bind(&done);
906 }
907
908
909 void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
910   MipsOperandConverter i(this, instr);
911   Register input = i.InputRegister(0);
912   for (size_t index = 2; index < instr->InputCount(); index += 2) {
913     __ li(at, Operand(i.InputInt32(index + 0)));
914     __ beq(input, at, GetLabel(i.InputRpo(index + 1)));
915   }
916   __ nop();  // Branch delay slot of the last beq.
917   AssembleArchJump(i.InputRpo(1));
918 }
919
920
921 void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
922   MipsOperandConverter i(this, instr);
923   Register input = i.InputRegister(0);
924   size_t const case_count = instr->InputCount() - 2;
925   Label here;
926   __ Branch(GetLabel(i.InputRpo(1)), hs, input, Operand(case_count));
927   __ BlockTrampolinePoolFor(case_count + 6);
928   __ bal(&here);
929   __ sll(at, input, 2);  // Branch delay slot.
930   __ bind(&here);
931   __ addu(at, at, ra);
932   __ lw(at, MemOperand(at, 4 * v8::internal::Assembler::kInstrSize));
933   __ jr(at);
934   __ nop();  // Branch delay slot nop.
935   for (size_t index = 0; index < case_count; ++index) {
936     __ dd(GetLabel(i.InputRpo(index + 2)));
937   }
938 }
939
940
941 void CodeGenerator::AssembleDeoptimizerCall(
942     int deoptimization_id, Deoptimizer::BailoutType bailout_type) {
943   Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
944       isolate(), deoptimization_id, bailout_type);
945   __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
946 }
947
948
949 void CodeGenerator::AssemblePrologue() {
950   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
951   int stack_slots = frame()->GetSpillSlotCount();
952   if (descriptor->kind() == CallDescriptor::kCallAddress) {
953     __ Push(ra, fp);
954     __ mov(fp, sp);
955     const RegList saves = descriptor->CalleeSavedRegisters();
956     if (saves != 0) {  // Save callee-saved registers.
957       // TODO(plind): make callee save size const, possibly DCHECK it.
958       int register_save_area_size = 0;
959       for (int i = Register::kNumRegisters - 1; i >= 0; i--) {
960         if (!((1 << i) & saves)) continue;
961         register_save_area_size += kPointerSize;
962       }
963       frame()->SetRegisterSaveAreaSize(register_save_area_size);
964       __ MultiPush(saves);
965     }
966   } else if (descriptor->IsJSFunctionCall()) {
967     CompilationInfo* info = this->info();
968     __ Prologue(info->IsCodePreAgingActive());
969     frame()->SetRegisterSaveAreaSize(
970         StandardFrameConstants::kFixedFrameSizeFromFp);
971   } else if (stack_slots > 0) {
972     __ StubPrologue();
973     frame()->SetRegisterSaveAreaSize(
974         StandardFrameConstants::kFixedFrameSizeFromFp);
975   }
976
977   if (info()->is_osr()) {
978     // TurboFan OSR-compiled functions cannot be entered directly.
979     __ Abort(kShouldNotDirectlyEnterOsrFunction);
980
981     // Unoptimized code jumps directly to this entrypoint while the unoptimized
982     // frame is still on the stack. Optimized code uses OSR values directly from
983     // the unoptimized frame. Thus, all that needs to be done is to allocate the
984     // remaining stack slots.
985     if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
986     osr_pc_offset_ = __ pc_offset();
987     // TODO(titzer): cannot address target function == local #-1
988     __ lw(a1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
989     DCHECK(stack_slots >= frame()->GetOsrStackSlotCount());
990     stack_slots -= frame()->GetOsrStackSlotCount();
991   }
992
993   if (stack_slots > 0) {
994     __ Subu(sp, sp, Operand(stack_slots * kPointerSize));
995   }
996 }
997
998
999 void CodeGenerator::AssembleReturn() {
1000   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
1001   int stack_slots = frame()->GetSpillSlotCount();
1002   if (descriptor->kind() == CallDescriptor::kCallAddress) {
1003     if (frame()->GetRegisterSaveAreaSize() > 0) {
1004       // Remove this frame's spill slots first.
1005       if (stack_slots > 0) {
1006         __ Addu(sp, sp, Operand(stack_slots * kPointerSize));
1007       }
1008       // Restore registers.
1009       const RegList saves = descriptor->CalleeSavedRegisters();
1010       if (saves != 0) {
1011         __ MultiPop(saves);
1012       }
1013     }
1014     __ mov(sp, fp);
1015     __ Pop(ra, fp);
1016     __ Ret();
1017   } else if (descriptor->IsJSFunctionCall() || stack_slots > 0) {
1018     __ mov(sp, fp);
1019     __ Pop(ra, fp);
1020     int pop_count = descriptor->IsJSFunctionCall()
1021                         ? static_cast<int>(descriptor->JSParameterCount())
1022                         : 0;
1023     __ DropAndRet(pop_count);
1024   } else {
1025     __ Ret();
1026   }
1027 }
1028
1029
1030 void CodeGenerator::AssembleMove(InstructionOperand* source,
1031                                  InstructionOperand* destination) {
1032   MipsOperandConverter g(this, NULL);
1033   // Dispatch on the source and destination operand kinds.  Not all
1034   // combinations are possible.
1035   if (source->IsRegister()) {
1036     DCHECK(destination->IsRegister() || destination->IsStackSlot());
1037     Register src = g.ToRegister(source);
1038     if (destination->IsRegister()) {
1039       __ mov(g.ToRegister(destination), src);
1040     } else {
1041       __ sw(src, g.ToMemOperand(destination));
1042     }
1043   } else if (source->IsStackSlot()) {
1044     DCHECK(destination->IsRegister() || destination->IsStackSlot());
1045     MemOperand src = g.ToMemOperand(source);
1046     if (destination->IsRegister()) {
1047       __ lw(g.ToRegister(destination), src);
1048     } else {
1049       Register temp = kScratchReg;
1050       __ lw(temp, src);
1051       __ sw(temp, g.ToMemOperand(destination));
1052     }
1053   } else if (source->IsConstant()) {
1054     Constant src = g.ToConstant(source);
1055     if (destination->IsRegister() || destination->IsStackSlot()) {
1056       Register dst =
1057           destination->IsRegister() ? g.ToRegister(destination) : kScratchReg;
1058       switch (src.type()) {
1059         case Constant::kInt32:
1060           __ li(dst, Operand(src.ToInt32()));
1061           break;
1062         case Constant::kFloat32:
1063           __ li(dst, isolate()->factory()->NewNumber(src.ToFloat32(), TENURED));
1064           break;
1065         case Constant::kInt64:
1066           UNREACHABLE();
1067           break;
1068         case Constant::kFloat64:
1069           __ li(dst, isolate()->factory()->NewNumber(src.ToFloat64(), TENURED));
1070           break;
1071         case Constant::kExternalReference:
1072           __ li(dst, Operand(src.ToExternalReference()));
1073           break;
1074         case Constant::kHeapObject:
1075           __ li(dst, src.ToHeapObject());
1076           break;
1077         case Constant::kRpoNumber:
1078           UNREACHABLE();  // TODO(titzer): loading RPO numbers on mips.
1079           break;
1080       }
1081       if (destination->IsStackSlot()) __ sw(dst, g.ToMemOperand(destination));
1082     } else if (src.type() == Constant::kFloat32) {
1083       if (destination->IsDoubleStackSlot()) {
1084         MemOperand dst = g.ToMemOperand(destination);
1085         __ li(at, Operand(bit_cast<int32_t>(src.ToFloat32())));
1086         __ sw(at, dst);
1087       } else {
1088         FloatRegister dst = g.ToSingleRegister(destination);
1089         __ Move(dst, src.ToFloat32());
1090       }
1091     } else {
1092       DCHECK_EQ(Constant::kFloat64, src.type());
1093       DoubleRegister dst = destination->IsDoubleRegister()
1094                                ? g.ToDoubleRegister(destination)
1095                                : kScratchDoubleReg;
1096       __ Move(dst, src.ToFloat64());
1097       if (destination->IsDoubleStackSlot()) {
1098         __ sdc1(dst, g.ToMemOperand(destination));
1099       }
1100     }
1101   } else if (source->IsDoubleRegister()) {
1102     FPURegister src = g.ToDoubleRegister(source);
1103     if (destination->IsDoubleRegister()) {
1104       FPURegister dst = g.ToDoubleRegister(destination);
1105       __ Move(dst, src);
1106     } else {
1107       DCHECK(destination->IsDoubleStackSlot());
1108       __ sdc1(src, g.ToMemOperand(destination));
1109     }
1110   } else if (source->IsDoubleStackSlot()) {
1111     DCHECK(destination->IsDoubleRegister() || destination->IsDoubleStackSlot());
1112     MemOperand src = g.ToMemOperand(source);
1113     if (destination->IsDoubleRegister()) {
1114       __ ldc1(g.ToDoubleRegister(destination), src);
1115     } else {
1116       FPURegister temp = kScratchDoubleReg;
1117       __ ldc1(temp, src);
1118       __ sdc1(temp, g.ToMemOperand(destination));
1119     }
1120   } else {
1121     UNREACHABLE();
1122   }
1123 }
1124
1125
1126 void CodeGenerator::AssembleSwap(InstructionOperand* source,
1127                                  InstructionOperand* destination) {
1128   MipsOperandConverter g(this, NULL);
1129   // Dispatch on the source and destination operand kinds.  Not all
1130   // combinations are possible.
1131   if (source->IsRegister()) {
1132     // Register-register.
1133     Register temp = kScratchReg;
1134     Register src = g.ToRegister(source);
1135     if (destination->IsRegister()) {
1136       Register dst = g.ToRegister(destination);
1137       __ Move(temp, src);
1138       __ Move(src, dst);
1139       __ Move(dst, temp);
1140     } else {
1141       DCHECK(destination->IsStackSlot());
1142       MemOperand dst = g.ToMemOperand(destination);
1143       __ mov(temp, src);
1144       __ lw(src, dst);
1145       __ sw(temp, dst);
1146     }
1147   } else if (source->IsStackSlot()) {
1148     DCHECK(destination->IsStackSlot());
1149     Register temp_0 = kScratchReg;
1150     Register temp_1 = kCompareReg;
1151     MemOperand src = g.ToMemOperand(source);
1152     MemOperand dst = g.ToMemOperand(destination);
1153     __ lw(temp_0, src);
1154     __ lw(temp_1, dst);
1155     __ sw(temp_0, dst);
1156     __ sw(temp_1, src);
1157   } else if (source->IsDoubleRegister()) {
1158     FPURegister temp = kScratchDoubleReg;
1159     FPURegister src = g.ToDoubleRegister(source);
1160     if (destination->IsDoubleRegister()) {
1161       FPURegister dst = g.ToDoubleRegister(destination);
1162       __ Move(temp, src);
1163       __ Move(src, dst);
1164       __ Move(dst, temp);
1165     } else {
1166       DCHECK(destination->IsDoubleStackSlot());
1167       MemOperand dst = g.ToMemOperand(destination);
1168       __ Move(temp, src);
1169       __ ldc1(src, dst);
1170       __ sdc1(temp, dst);
1171     }
1172   } else if (source->IsDoubleStackSlot()) {
1173     DCHECK(destination->IsDoubleStackSlot());
1174     Register temp_0 = kScratchReg;
1175     FPURegister temp_1 = kScratchDoubleReg;
1176     MemOperand src0 = g.ToMemOperand(source);
1177     MemOperand src1(src0.rm(), src0.offset() + kIntSize);
1178     MemOperand dst0 = g.ToMemOperand(destination);
1179     MemOperand dst1(dst0.rm(), dst0.offset() + kIntSize);
1180     __ ldc1(temp_1, dst0);  // Save destination in temp_1.
1181     __ lw(temp_0, src0);    // Then use temp_0 to copy source to destination.
1182     __ sw(temp_0, dst0);
1183     __ lw(temp_0, src1);
1184     __ sw(temp_0, dst1);
1185     __ sdc1(temp_1, src0);
1186   } else {
1187     // No other combinations are possible.
1188     UNREACHABLE();
1189   }
1190 }
1191
1192
1193 void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
1194   // On 32-bit MIPS we emit the jump tables inline.
1195   UNREACHABLE();
1196 }
1197
1198
1199 void CodeGenerator::AddNopForSmiCodeInlining() {
1200   // Unused on 32-bit ARM. Still exists on 64-bit arm.
1201   // TODO(plind): Unclear when this is called now. Understand, fix if needed.
1202   __ nop();  // Maybe PROPERTY_ACCESS_INLINED?
1203 }
1204
1205
1206 void CodeGenerator::EnsureSpaceForLazyDeopt() {
1207   int space_needed = Deoptimizer::patch_size();
1208   if (!info()->IsStub()) {
1209     // Ensure that we have enough space after the previous lazy-bailout
1210     // instruction for patching the code here.
1211     int current_pc = masm()->pc_offset();
1212     if (current_pc < last_lazy_deopt_pc_ + space_needed) {
1213       // Block tramoline pool emission for duration of padding.
1214       v8::internal::Assembler::BlockTrampolinePoolScope block_trampoline_pool(
1215           masm());
1216       int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
1217       DCHECK_EQ(0, padding_size % v8::internal::Assembler::kInstrSize);
1218       while (padding_size > 0) {
1219         __ nop();
1220         padding_size -= v8::internal::Assembler::kInstrSize;
1221       }
1222     }
1223   }
1224   MarkLazyDeoptSite();
1225 }
1226
1227 #undef __
1228
1229 }  // namespace compiler
1230 }  // namespace internal
1231 }  // namespace v8