0234fcddca7596f9b76dff732faaa572fbc03285
[platform/upstream/nodejs.git] / deps / v8 / src / arm64 / lithium-arm64.cc
1 // Copyright 2013 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 <sstream>
6
7 #include "src/v8.h"
8
9 #include "src/arm64/lithium-codegen-arm64.h"
10 #include "src/hydrogen-osr.h"
11 #include "src/lithium-inl.h"
12
13 namespace v8 {
14 namespace internal {
15
16 #define DEFINE_COMPILE(type)                            \
17   void L##type::CompileToNative(LCodeGen* generator) {  \
18     generator->Do##type(this);                          \
19   }
20 LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)
21 #undef DEFINE_COMPILE
22
23 #ifdef DEBUG
24 void LInstruction::VerifyCall() {
25   // Call instructions can use only fixed registers as temporaries and
26   // outputs because all registers are blocked by the calling convention.
27   // Inputs operands must use a fixed register or use-at-start policy or
28   // a non-register policy.
29   DCHECK(Output() == NULL ||
30          LUnallocated::cast(Output())->HasFixedPolicy() ||
31          !LUnallocated::cast(Output())->HasRegisterPolicy());
32   for (UseIterator it(this); !it.Done(); it.Advance()) {
33     LUnallocated* operand = LUnallocated::cast(it.Current());
34     DCHECK(operand->HasFixedPolicy() ||
35            operand->IsUsedAtStart());
36   }
37   for (TempIterator it(this); !it.Done(); it.Advance()) {
38     LUnallocated* operand = LUnallocated::cast(it.Current());
39     DCHECK(operand->HasFixedPolicy() ||!operand->HasRegisterPolicy());
40   }
41 }
42 #endif
43
44
45 void LLabel::PrintDataTo(StringStream* stream) {
46   LGap::PrintDataTo(stream);
47   LLabel* rep = replacement();
48   if (rep != NULL) {
49     stream->Add(" Dead block replaced with B%d", rep->block_id());
50   }
51 }
52
53
54 void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
55   arguments()->PrintTo(stream);
56   stream->Add(" length ");
57   length()->PrintTo(stream);
58   stream->Add(" index ");
59   index()->PrintTo(stream);
60 }
61
62
63 void LBranch::PrintDataTo(StringStream* stream) {
64   stream->Add("B%d | B%d on ", true_block_id(), false_block_id());
65   value()->PrintTo(stream);
66 }
67
68
69 void LCallJSFunction::PrintDataTo(StringStream* stream) {
70   stream->Add("= ");
71   function()->PrintTo(stream);
72   stream->Add("#%d / ", arity());
73 }
74
75
76 void LCallWithDescriptor::PrintDataTo(StringStream* stream) {
77   for (int i = 0; i < InputCount(); i++) {
78     InputAt(i)->PrintTo(stream);
79     stream->Add(" ");
80   }
81   stream->Add("#%d / ", arity());
82 }
83
84
85 void LCallNew::PrintDataTo(StringStream* stream) {
86   stream->Add("= ");
87   constructor()->PrintTo(stream);
88   stream->Add(" #%d / ", arity());
89 }
90
91
92 void LCallNewArray::PrintDataTo(StringStream* stream) {
93   stream->Add("= ");
94   constructor()->PrintTo(stream);
95   stream->Add(" #%d / ", arity());
96   ElementsKind kind = hydrogen()->elements_kind();
97   stream->Add(" (%s) ", ElementsKindToString(kind));
98 }
99
100
101 void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
102   stream->Add("if class_of_test(");
103   value()->PrintTo(stream);
104   stream->Add(", \"%o\") then B%d else B%d",
105               *hydrogen()->class_name(),
106               true_block_id(),
107               false_block_id());
108 }
109
110
111 void LCompareNumericAndBranch::PrintDataTo(StringStream* stream) {
112   stream->Add("if ");
113   left()->PrintTo(stream);
114   stream->Add(" %s ", Token::String(op()));
115   right()->PrintTo(stream);
116   stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
117 }
118
119
120 void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) {
121   stream->Add("if has_cached_array_index(");
122   value()->PrintTo(stream);
123   stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
124 }
125
126
127 bool LGoto::HasInterestingComment(LCodeGen* gen) const {
128   return !gen->IsNextEmittedBlock(block_id());
129 }
130
131
132 void LGoto::PrintDataTo(StringStream* stream) {
133   stream->Add("B%d", block_id());
134 }
135
136
137 void LInnerAllocatedObject::PrintDataTo(StringStream* stream) {
138   stream->Add(" = ");
139   base_object()->PrintTo(stream);
140   stream->Add(" + ");
141   offset()->PrintTo(stream);
142 }
143
144
145 void LCallFunction::PrintDataTo(StringStream* stream) {
146   context()->PrintTo(stream);
147   stream->Add(" ");
148   function()->PrintTo(stream);
149   if (hydrogen()->HasVectorAndSlot()) {
150     stream->Add(" (type-feedback-vector ");
151     temp_vector()->PrintTo(stream);
152     stream->Add(" ");
153     temp_slot()->PrintTo(stream);
154     stream->Add(")");
155   }
156 }
157
158
159 void LInvokeFunction::PrintDataTo(StringStream* stream) {
160   stream->Add("= ");
161   function()->PrintTo(stream);
162   stream->Add(" #%d / ", arity());
163 }
164
165
166 void LInstruction::PrintTo(StringStream* stream) {
167   stream->Add("%s ", this->Mnemonic());
168
169   PrintOutputOperandTo(stream);
170
171   PrintDataTo(stream);
172
173   if (HasEnvironment()) {
174     stream->Add(" ");
175     environment()->PrintTo(stream);
176   }
177
178   if (HasPointerMap()) {
179     stream->Add(" ");
180     pointer_map()->PrintTo(stream);
181   }
182 }
183
184
185 void LInstruction::PrintDataTo(StringStream* stream) {
186   stream->Add("= ");
187   for (int i = 0; i < InputCount(); i++) {
188     if (i > 0) stream->Add(" ");
189     if (InputAt(i) == NULL) {
190       stream->Add("NULL");
191     } else {
192       InputAt(i)->PrintTo(stream);
193     }
194   }
195 }
196
197
198 void LInstruction::PrintOutputOperandTo(StringStream* stream) {
199   if (HasResult()) result()->PrintTo(stream);
200 }
201
202
203 void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
204   stream->Add("if has_instance_type(");
205   value()->PrintTo(stream);
206   stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
207 }
208
209
210 void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
211   stream->Add("if is_object(");
212   value()->PrintTo(stream);
213   stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
214 }
215
216
217 void LIsStringAndBranch::PrintDataTo(StringStream* stream) {
218   stream->Add("if is_string(");
219   value()->PrintTo(stream);
220   stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
221 }
222
223
224 void LIsSmiAndBranch::PrintDataTo(StringStream* stream) {
225   stream->Add("if is_smi(");
226   value()->PrintTo(stream);
227   stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
228 }
229
230
231 void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
232   stream->Add("if typeof ");
233   value()->PrintTo(stream);
234   stream->Add(" == \"%s\" then B%d else B%d",
235               hydrogen()->type_literal()->ToCString().get(),
236               true_block_id(), false_block_id());
237 }
238
239
240 void LIsUndetectableAndBranch::PrintDataTo(StringStream* stream) {
241   stream->Add("if is_undetectable(");
242   value()->PrintTo(stream);
243   stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
244 }
245
246
247 bool LGap::IsRedundant() const {
248   for (int i = 0; i < 4; i++) {
249     if ((parallel_moves_[i] != NULL) && !parallel_moves_[i]->IsRedundant()) {
250       return false;
251     }
252   }
253
254   return true;
255 }
256
257
258 void LGap::PrintDataTo(StringStream* stream) {
259   for (int i = 0; i < 4; i++) {
260     stream->Add("(");
261     if (parallel_moves_[i] != NULL) {
262       parallel_moves_[i]->PrintDataTo(stream);
263     }
264     stream->Add(") ");
265   }
266 }
267
268
269 void LLoadContextSlot::PrintDataTo(StringStream* stream) {
270   context()->PrintTo(stream);
271   stream->Add("[%d]", slot_index());
272 }
273
274
275 void LStoreCodeEntry::PrintDataTo(StringStream* stream) {
276   stream->Add(" = ");
277   function()->PrintTo(stream);
278   stream->Add(".code_entry = ");
279   code_object()->PrintTo(stream);
280 }
281
282
283 void LStoreContextSlot::PrintDataTo(StringStream* stream) {
284   context()->PrintTo(stream);
285   stream->Add("[%d] <- ", slot_index());
286   value()->PrintTo(stream);
287 }
288
289
290 void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
291   object()->PrintTo(stream);
292   stream->Add("[");
293   key()->PrintTo(stream);
294   stream->Add("] <- ");
295   value()->PrintTo(stream);
296 }
297
298
299 void LStoreNamedField::PrintDataTo(StringStream* stream) {
300   object()->PrintTo(stream);
301   std::ostringstream os;
302   os << hydrogen()->access();
303   stream->Add(os.str().c_str());
304   stream->Add(" <- ");
305   value()->PrintTo(stream);
306 }
307
308
309 void LStoreNamedGeneric::PrintDataTo(StringStream* stream) {
310   object()->PrintTo(stream);
311   stream->Add(".");
312   stream->Add(String::cast(*name())->ToCString().get());
313   stream->Add(" <- ");
314   value()->PrintTo(stream);
315 }
316
317
318 void LStringCompareAndBranch::PrintDataTo(StringStream* stream) {
319   stream->Add("if string_compare(");
320   left()->PrintTo(stream);
321   right()->PrintTo(stream);
322   stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
323 }
324
325
326 void LTransitionElementsKind::PrintDataTo(StringStream* stream) {
327   object()->PrintTo(stream);
328   stream->Add("%p -> %p", *original_map(), *transitioned_map());
329 }
330
331
332 template<int T>
333 void LUnaryMathOperation<T>::PrintDataTo(StringStream* stream) {
334   value()->PrintTo(stream);
335 }
336
337
338 const char* LArithmeticD::Mnemonic() const {
339   switch (op()) {
340     case Token::ADD: return "add-d";
341     case Token::SUB: return "sub-d";
342     case Token::MUL: return "mul-d";
343     case Token::DIV: return "div-d";
344     case Token::MOD: return "mod-d";
345     default:
346       UNREACHABLE();
347       return NULL;
348   }
349 }
350
351
352 const char* LArithmeticT::Mnemonic() const {
353   switch (op()) {
354     case Token::ADD: return "add-t";
355     case Token::SUB: return "sub-t";
356     case Token::MUL: return "mul-t";
357     case Token::MOD: return "mod-t";
358     case Token::DIV: return "div-t";
359     case Token::BIT_AND: return "bit-and-t";
360     case Token::BIT_OR: return "bit-or-t";
361     case Token::BIT_XOR: return "bit-xor-t";
362     case Token::ROR: return "ror-t";
363     case Token::SHL: return "shl-t";
364     case Token::SAR: return "sar-t";
365     case Token::SHR: return "shr-t";
366     default:
367       UNREACHABLE();
368       return NULL;
369   }
370 }
371
372
373 LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
374   return new(zone()) LUnallocated(LUnallocated::FIXED_REGISTER,
375                                   Register::ToAllocationIndex(reg));
376 }
377
378
379 LUnallocated* LChunkBuilder::ToUnallocated(DoubleRegister reg) {
380   return new(zone()) LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER,
381                                   DoubleRegister::ToAllocationIndex(reg));
382 }
383
384
385 LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
386   if (value->EmitAtUses()) {
387     HInstruction* instr = HInstruction::cast(value);
388     VisitInstruction(instr);
389   }
390   operand->set_virtual_register(value->id());
391   return operand;
392 }
393
394
395 LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) {
396   return Use(value, ToUnallocated(fixed_register));
397 }
398
399
400 LOperand* LChunkBuilder::UseFixedDouble(HValue* value,
401                                         DoubleRegister fixed_register) {
402   return Use(value, ToUnallocated(fixed_register));
403 }
404
405
406 LOperand* LChunkBuilder::UseRegister(HValue* value) {
407   return Use(value, new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
408 }
409
410
411 LOperand* LChunkBuilder::UseRegisterAndClobber(HValue* value) {
412   return Use(value, new(zone()) LUnallocated(LUnallocated::WRITABLE_REGISTER));
413 }
414
415
416 LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) {
417   return Use(value,
418              new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER,
419                                       LUnallocated::USED_AT_START));
420 }
421
422
423 LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) {
424   return value->IsConstant() ? UseConstant(value) : UseRegister(value);
425 }
426
427
428 LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) {
429   return value->IsConstant() ? UseConstant(value) : UseRegisterAtStart(value);
430 }
431
432
433 LConstantOperand* LChunkBuilder::UseConstant(HValue* value) {
434   return chunk_->DefineConstantOperand(HConstant::cast(value));
435 }
436
437
438 LOperand* LChunkBuilder::UseAny(HValue* value) {
439   return value->IsConstant()
440       ? UseConstant(value)
441       : Use(value, new(zone()) LUnallocated(LUnallocated::ANY));
442 }
443
444
445 LInstruction* LChunkBuilder::Define(LTemplateResultInstruction<1>* instr,
446                                     LUnallocated* result) {
447   result->set_virtual_register(current_instruction_->id());
448   instr->set_result(result);
449   return instr;
450 }
451
452
453 LInstruction* LChunkBuilder::DefineAsRegister(
454     LTemplateResultInstruction<1>* instr) {
455   return Define(instr,
456                 new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
457 }
458
459
460 LInstruction* LChunkBuilder::DefineAsSpilled(
461     LTemplateResultInstruction<1>* instr, int index) {
462   return Define(instr,
463                 new(zone()) LUnallocated(LUnallocated::FIXED_SLOT, index));
464 }
465
466
467 LInstruction* LChunkBuilder::DefineSameAsFirst(
468     LTemplateResultInstruction<1>* instr) {
469   return Define(instr,
470                 new(zone()) LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
471 }
472
473
474 LInstruction* LChunkBuilder::DefineFixed(
475     LTemplateResultInstruction<1>* instr, Register reg) {
476   return Define(instr, ToUnallocated(reg));
477 }
478
479
480 LInstruction* LChunkBuilder::DefineFixedDouble(
481     LTemplateResultInstruction<1>* instr, DoubleRegister reg) {
482   return Define(instr, ToUnallocated(reg));
483 }
484
485
486 LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
487                                         HInstruction* hinstr,
488                                         CanDeoptimize can_deoptimize) {
489   info()->MarkAsNonDeferredCalling();
490 #ifdef DEBUG
491   instr->VerifyCall();
492 #endif
493   instr->MarkAsCall();
494   instr = AssignPointerMap(instr);
495
496   // If instruction does not have side-effects lazy deoptimization
497   // after the call will try to deoptimize to the point before the call.
498   // Thus we still need to attach environment to this call even if
499   // call sequence can not deoptimize eagerly.
500   bool needs_environment =
501       (can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) ||
502       !hinstr->HasObservableSideEffects();
503   if (needs_environment && !instr->HasEnvironment()) {
504     instr = AssignEnvironment(instr);
505     // We can't really figure out if the environment is needed or not.
506     instr->environment()->set_has_been_used();
507   }
508
509   return instr;
510 }
511
512
513 LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
514   DCHECK(!instr->HasPointerMap());
515   instr->set_pointer_map(new(zone()) LPointerMap(zone()));
516   return instr;
517 }
518
519
520 LUnallocated* LChunkBuilder::TempRegister() {
521   LUnallocated* operand =
522       new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
523   int vreg = allocator_->GetVirtualRegister();
524   if (!allocator_->AllocationOk()) {
525     Abort(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister);
526     vreg = 0;
527   }
528   operand->set_virtual_register(vreg);
529   return operand;
530 }
531
532
533 LUnallocated* LChunkBuilder::TempDoubleRegister() {
534   LUnallocated* operand =
535       new(zone()) LUnallocated(LUnallocated::MUST_HAVE_DOUBLE_REGISTER);
536   int vreg = allocator_->GetVirtualRegister();
537   if (!allocator_->AllocationOk()) {
538     Abort(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister);
539     vreg = 0;
540   }
541   operand->set_virtual_register(vreg);
542   return operand;
543 }
544
545
546 int LPlatformChunk::GetNextSpillIndex() {
547   return spill_slot_count_++;
548 }
549
550
551 LOperand* LPlatformChunk::GetNextSpillSlot(RegisterKind kind) {
552   int index = GetNextSpillIndex();
553   if (kind == DOUBLE_REGISTERS) {
554     return LDoubleStackSlot::Create(index, zone());
555   } else {
556     DCHECK(kind == GENERAL_REGISTERS);
557     return LStackSlot::Create(index, zone());
558   }
559 }
560
561
562 LOperand* LChunkBuilder::FixedTemp(Register reg) {
563   LUnallocated* operand = ToUnallocated(reg);
564   DCHECK(operand->HasFixedPolicy());
565   return operand;
566 }
567
568
569 LOperand* LChunkBuilder::FixedTemp(DoubleRegister reg) {
570   LUnallocated* operand = ToUnallocated(reg);
571   DCHECK(operand->HasFixedPolicy());
572   return operand;
573 }
574
575
576 LPlatformChunk* LChunkBuilder::Build() {
577   DCHECK(is_unused());
578   chunk_ = new(zone()) LPlatformChunk(info_, graph_);
579   LPhase phase("L_Building chunk", chunk_);
580   status_ = BUILDING;
581
582   // If compiling for OSR, reserve space for the unoptimized frame,
583   // which will be subsumed into this frame.
584   if (graph()->has_osr()) {
585     // TODO(all): GetNextSpillIndex just increments a field. It has no other
586     // side effects, so we should get rid of this loop.
587     for (int i = graph()->osr()->UnoptimizedFrameSlots(); i > 0; i--) {
588       chunk_->GetNextSpillIndex();
589     }
590   }
591
592   const ZoneList<HBasicBlock*>* blocks = graph_->blocks();
593   for (int i = 0; i < blocks->length(); i++) {
594     DoBasicBlock(blocks->at(i));
595     if (is_aborted()) return NULL;
596   }
597   status_ = DONE;
598   return chunk_;
599 }
600
601
602 void LChunkBuilder::DoBasicBlock(HBasicBlock* block) {
603   DCHECK(is_building());
604   current_block_ = block;
605
606   if (block->IsStartBlock()) {
607     block->UpdateEnvironment(graph_->start_environment());
608     argument_count_ = 0;
609   } else if (block->predecessors()->length() == 1) {
610     // We have a single predecessor => copy environment and outgoing
611     // argument count from the predecessor.
612     DCHECK(block->phis()->length() == 0);
613     HBasicBlock* pred = block->predecessors()->at(0);
614     HEnvironment* last_environment = pred->last_environment();
615     DCHECK(last_environment != NULL);
616
617     // Only copy the environment, if it is later used again.
618     if (pred->end()->SecondSuccessor() == NULL) {
619       DCHECK(pred->end()->FirstSuccessor() == block);
620     } else {
621       if ((pred->end()->FirstSuccessor()->block_id() > block->block_id()) ||
622           (pred->end()->SecondSuccessor()->block_id() > block->block_id())) {
623         last_environment = last_environment->Copy();
624       }
625     }
626     block->UpdateEnvironment(last_environment);
627     DCHECK(pred->argument_count() >= 0);
628     argument_count_ = pred->argument_count();
629   } else {
630     // We are at a state join => process phis.
631     HBasicBlock* pred = block->predecessors()->at(0);
632     // No need to copy the environment, it cannot be used later.
633     HEnvironment* last_environment = pred->last_environment();
634     for (int i = 0; i < block->phis()->length(); ++i) {
635       HPhi* phi = block->phis()->at(i);
636       if (phi->HasMergedIndex()) {
637         last_environment->SetValueAt(phi->merged_index(), phi);
638       }
639     }
640     for (int i = 0; i < block->deleted_phis()->length(); ++i) {
641       if (block->deleted_phis()->at(i) < last_environment->length()) {
642         last_environment->SetValueAt(block->deleted_phis()->at(i),
643                                      graph_->GetConstantUndefined());
644       }
645     }
646     block->UpdateEnvironment(last_environment);
647     // Pick up the outgoing argument count of one of the predecessors.
648     argument_count_ = pred->argument_count();
649   }
650
651   // Translate hydrogen instructions to lithium ones for the current block.
652   HInstruction* current = block->first();
653   int start = chunk_->instructions()->length();
654   while ((current != NULL) && !is_aborted()) {
655     // Code for constants in registers is generated lazily.
656     if (!current->EmitAtUses()) {
657       VisitInstruction(current);
658     }
659     current = current->next();
660   }
661   int end = chunk_->instructions()->length() - 1;
662   if (end >= start) {
663     block->set_first_instruction_index(start);
664     block->set_last_instruction_index(end);
665   }
666   block->set_argument_count(argument_count_);
667   current_block_ = NULL;
668 }
669
670
671 void LChunkBuilder::VisitInstruction(HInstruction* current) {
672   HInstruction* old_current = current_instruction_;
673   current_instruction_ = current;
674
675   LInstruction* instr = NULL;
676   if (current->CanReplaceWithDummyUses()) {
677     if (current->OperandCount() == 0) {
678       instr = DefineAsRegister(new(zone()) LDummy());
679     } else {
680       DCHECK(!current->OperandAt(0)->IsControlInstruction());
681       instr = DefineAsRegister(new(zone())
682           LDummyUse(UseAny(current->OperandAt(0))));
683     }
684     for (int i = 1; i < current->OperandCount(); ++i) {
685       if (current->OperandAt(i)->IsControlInstruction()) continue;
686       LInstruction* dummy =
687           new(zone()) LDummyUse(UseAny(current->OperandAt(i)));
688       dummy->set_hydrogen_value(current);
689       chunk_->AddInstruction(dummy, current_block_);
690     }
691   } else {
692     HBasicBlock* successor;
693     if (current->IsControlInstruction() &&
694         HControlInstruction::cast(current)->KnownSuccessorBlock(&successor) &&
695         successor != NULL) {
696       instr = new(zone()) LGoto(successor);
697     } else {
698       instr = current->CompileToLithium(this);
699     }
700   }
701
702   argument_count_ += current->argument_delta();
703   DCHECK(argument_count_ >= 0);
704
705   if (instr != NULL) {
706     AddInstruction(instr, current);
707   }
708
709   current_instruction_ = old_current;
710 }
711
712
713 void LChunkBuilder::AddInstruction(LInstruction* instr,
714                                    HInstruction* hydrogen_val) {
715   // Associate the hydrogen instruction first, since we may need it for
716   // the ClobbersRegisters() or ClobbersDoubleRegisters() calls below.
717   instr->set_hydrogen_value(hydrogen_val);
718
719 #if DEBUG
720   // Make sure that the lithium instruction has either no fixed register
721   // constraints in temps or the result OR no uses that are only used at
722   // start. If this invariant doesn't hold, the register allocator can decide
723   // to insert a split of a range immediately before the instruction due to an
724   // already allocated register needing to be used for the instruction's fixed
725   // register constraint. In this case, the register allocator won't see an
726   // interference between the split child and the use-at-start (it would if
727   // the it was just a plain use), so it is free to move the split child into
728   // the same register that is used for the use-at-start.
729   // See https://code.google.com/p/chromium/issues/detail?id=201590
730   if (!(instr->ClobbersRegisters() &&
731         instr->ClobbersDoubleRegisters(isolate()))) {
732     int fixed = 0;
733     int used_at_start = 0;
734     for (UseIterator it(instr); !it.Done(); it.Advance()) {
735       LUnallocated* operand = LUnallocated::cast(it.Current());
736       if (operand->IsUsedAtStart()) ++used_at_start;
737     }
738     if (instr->Output() != NULL) {
739       if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed;
740     }
741     for (TempIterator it(instr); !it.Done(); it.Advance()) {
742       LUnallocated* operand = LUnallocated::cast(it.Current());
743       if (operand->HasFixedPolicy()) ++fixed;
744     }
745     DCHECK(fixed == 0 || used_at_start == 0);
746   }
747 #endif
748
749   if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
750     instr = AssignPointerMap(instr);
751   }
752   if (FLAG_stress_environments && !instr->HasEnvironment()) {
753     instr = AssignEnvironment(instr);
754   }
755   chunk_->AddInstruction(instr, current_block_);
756
757   if (instr->IsCall()) {
758     HValue* hydrogen_value_for_lazy_bailout = hydrogen_val;
759     LInstruction* instruction_needing_environment = NULL;
760     if (hydrogen_val->HasObservableSideEffects()) {
761       HSimulate* sim = HSimulate::cast(hydrogen_val->next());
762       instruction_needing_environment = instr;
763       sim->ReplayEnvironment(current_block_->last_environment());
764       hydrogen_value_for_lazy_bailout = sim;
765     }
766     LInstruction* bailout = AssignEnvironment(new(zone()) LLazyBailout());
767     bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
768     chunk_->AddInstruction(bailout, current_block_);
769     if (instruction_needing_environment != NULL) {
770       // Store the lazy deopt environment with the instruction if needed.
771       // Right now it is only used for LInstanceOfKnownGlobal.
772       instruction_needing_environment->
773           SetDeferredLazyDeoptimizationEnvironment(bailout->environment());
774     }
775   }
776 }
777
778
779 LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
780   HEnvironment* hydrogen_env = current_block_->last_environment();
781   int argument_index_accumulator = 0;
782   ZoneList<HValue*> objects_to_materialize(0, zone());
783   instr->set_environment(CreateEnvironment(hydrogen_env,
784                                            &argument_index_accumulator,
785                                            &objects_to_materialize));
786   return instr;
787 }
788
789
790 LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
791   // The control instruction marking the end of a block that completed
792   // abruptly (e.g., threw an exception). There is nothing specific to do.
793   return NULL;
794 }
795
796
797 LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
798                                            HArithmeticBinaryOperation* instr) {
799   DCHECK(instr->representation().IsDouble());
800   DCHECK(instr->left()->representation().IsDouble());
801   DCHECK(instr->right()->representation().IsDouble());
802
803   if (op == Token::MOD) {
804     LOperand* left = UseFixedDouble(instr->left(), d0);
805     LOperand* right = UseFixedDouble(instr->right(), d1);
806     LArithmeticD* result = new(zone()) LArithmeticD(Token::MOD, left, right);
807     return MarkAsCall(DefineFixedDouble(result, d0), instr);
808   } else {
809     LOperand* left = UseRegisterAtStart(instr->left());
810     LOperand* right = UseRegisterAtStart(instr->right());
811     LArithmeticD* result = new(zone()) LArithmeticD(op, left, right);
812     return DefineAsRegister(result);
813   }
814 }
815
816
817 LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op,
818                                            HBinaryOperation* instr) {
819   DCHECK((op == Token::ADD) || (op == Token::SUB) || (op == Token::MUL) ||
820          (op == Token::DIV) || (op == Token::MOD) || (op == Token::SHR) ||
821          (op == Token::SHL) || (op == Token::SAR) || (op == Token::ROR) ||
822          (op == Token::BIT_OR) || (op == Token::BIT_AND) ||
823          (op == Token::BIT_XOR));
824   HValue* left = instr->left();
825   HValue* right = instr->right();
826
827   // TODO(jbramley): Once we've implemented smi support for all arithmetic
828   // operations, these assertions should check IsTagged().
829   DCHECK(instr->representation().IsSmiOrTagged());
830   DCHECK(left->representation().IsSmiOrTagged());
831   DCHECK(right->representation().IsSmiOrTagged());
832
833   LOperand* context = UseFixed(instr->context(), cp);
834   LOperand* left_operand = UseFixed(left, x1);
835   LOperand* right_operand = UseFixed(right, x0);
836   LArithmeticT* result =
837       new(zone()) LArithmeticT(op, context, left_operand, right_operand);
838   return MarkAsCall(DefineFixed(result, x0), instr);
839 }
840
841
842 LInstruction* LChunkBuilder::DoBoundsCheckBaseIndexInformation(
843     HBoundsCheckBaseIndexInformation* instr) {
844   UNREACHABLE();
845   return NULL;
846 }
847
848
849 LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
850   info()->MarkAsRequiresFrame();
851   LOperand* args = NULL;
852   LOperand* length = NULL;
853   LOperand* index = NULL;
854
855   if (instr->length()->IsConstant() && instr->index()->IsConstant()) {
856     args = UseRegisterAtStart(instr->arguments());
857     length = UseConstant(instr->length());
858     index = UseConstant(instr->index());
859   } else {
860     args = UseRegister(instr->arguments());
861     length = UseRegisterAtStart(instr->length());
862     index = UseRegisterOrConstantAtStart(instr->index());
863   }
864
865   return DefineAsRegister(new(zone()) LAccessArgumentsAt(args, length, index));
866 }
867
868
869 LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
870   if (instr->representation().IsSmiOrInteger32()) {
871     DCHECK(instr->left()->representation().Equals(instr->representation()));
872     DCHECK(instr->right()->representation().Equals(instr->representation()));
873
874     LInstruction* shifted_operation = TryDoOpWithShiftedRightOperand(instr);
875     if (shifted_operation != NULL) {
876       return shifted_operation;
877     }
878
879     LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
880     LOperand* right =
881         UseRegisterOrConstantAtStart(instr->BetterRightOperand());
882     LInstruction* result = instr->representation().IsSmi() ?
883         DefineAsRegister(new(zone()) LAddS(left, right)) :
884         DefineAsRegister(new(zone()) LAddI(left, right));
885     if (instr->CheckFlag(HValue::kCanOverflow)) {
886       result = AssignEnvironment(result);
887     }
888     return result;
889   } else if (instr->representation().IsExternal()) {
890     DCHECK(instr->left()->representation().IsExternal());
891     DCHECK(instr->right()->representation().IsInteger32());
892     DCHECK(!instr->CheckFlag(HValue::kCanOverflow));
893     LOperand* left = UseRegisterAtStart(instr->left());
894     LOperand* right = UseRegisterOrConstantAtStart(instr->right());
895     return DefineAsRegister(new(zone()) LAddE(left, right));
896   } else if (instr->representation().IsDouble()) {
897     return DoArithmeticD(Token::ADD, instr);
898   } else {
899     DCHECK(instr->representation().IsTagged());
900     return DoArithmeticT(Token::ADD, instr);
901   }
902 }
903
904
905 LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) {
906   info()->MarkAsDeferredCalling();
907   LOperand* context = UseAny(instr->context());
908   LOperand* size = UseRegisterOrConstant(instr->size());
909   LOperand* temp1 = TempRegister();
910   LOperand* temp2 = TempRegister();
911   LOperand* temp3 = instr->MustPrefillWithFiller() ? TempRegister() : NULL;
912   LAllocate* result = new(zone()) LAllocate(context, size, temp1, temp2, temp3);
913   return AssignPointerMap(DefineAsRegister(result));
914 }
915
916
917 LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
918   LOperand* function = UseFixed(instr->function(), x1);
919   LOperand* receiver = UseFixed(instr->receiver(), x0);
920   LOperand* length = UseFixed(instr->length(), x2);
921   LOperand* elements = UseFixed(instr->elements(), x3);
922   LApplyArguments* result = new(zone()) LApplyArguments(function,
923                                                         receiver,
924                                                         length,
925                                                         elements);
926   return MarkAsCall(DefineFixed(result, x0), instr, CAN_DEOPTIMIZE_EAGERLY);
927 }
928
929
930 LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* instr) {
931   info()->MarkAsRequiresFrame();
932   LOperand* temp = instr->from_inlined() ? NULL : TempRegister();
933   return DefineAsRegister(new(zone()) LArgumentsElements(temp));
934 }
935
936
937 LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* instr) {
938   info()->MarkAsRequiresFrame();
939   LOperand* value = UseRegisterAtStart(instr->value());
940   return DefineAsRegister(new(zone()) LArgumentsLength(value));
941 }
942
943
944 LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
945   // There are no real uses of the arguments object.
946   // arguments.length and element access are supported directly on
947   // stack arguments, and any real arguments object use causes a bailout.
948   // So this value is never used.
949   return NULL;
950 }
951
952
953 LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
954   if (instr->representation().IsSmiOrInteger32()) {
955     DCHECK(instr->left()->representation().Equals(instr->representation()));
956     DCHECK(instr->right()->representation().Equals(instr->representation()));
957     DCHECK(instr->CheckFlag(HValue::kTruncatingToInt32));
958
959     LInstruction* shifted_operation = TryDoOpWithShiftedRightOperand(instr);
960     if (shifted_operation != NULL) {
961       return shifted_operation;
962     }
963
964     LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
965     LOperand* right =
966         UseRegisterOrConstantAtStart(instr->BetterRightOperand());
967     return instr->representation().IsSmi() ?
968         DefineAsRegister(new(zone()) LBitS(left, right)) :
969         DefineAsRegister(new(zone()) LBitI(left, right));
970   } else {
971     return DoArithmeticT(instr->op(), instr);
972   }
973 }
974
975
976 LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
977   // V8 expects a label to be generated for each basic block.
978   // This is used in some places like LAllocator::IsBlockBoundary
979   // in lithium-allocator.cc
980   return new(zone()) LLabel(instr->block());
981 }
982
983
984 LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
985   if (!FLAG_debug_code && instr->skip_check()) return NULL;
986   LOperand* index = UseRegisterOrConstantAtStart(instr->index());
987   LOperand* length = !index->IsConstantOperand()
988       ? UseRegisterOrConstantAtStart(instr->length())
989       : UseRegisterAtStart(instr->length());
990   LInstruction* result = new(zone()) LBoundsCheck(index, length);
991   if (!FLAG_debug_code || !instr->skip_check()) {
992     result = AssignEnvironment(result);
993   }
994   return result;
995 }
996
997
998 LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
999   HValue* value = instr->value();
1000   Representation r = value->representation();
1001   HType type = value->type();
1002
1003   if (r.IsInteger32() || r.IsSmi() || r.IsDouble()) {
1004     // These representations have simple checks that cannot deoptimize.
1005     return new(zone()) LBranch(UseRegister(value), NULL, NULL);
1006   } else {
1007     DCHECK(r.IsTagged());
1008     if (type.IsBoolean() || type.IsSmi() || type.IsJSArray() ||
1009         type.IsHeapNumber()) {
1010       // These types have simple checks that cannot deoptimize.
1011       return new(zone()) LBranch(UseRegister(value), NULL, NULL);
1012     }
1013
1014     if (type.IsString()) {
1015       // This type cannot deoptimize, but needs a scratch register.
1016       return new(zone()) LBranch(UseRegister(value), TempRegister(), NULL);
1017     }
1018
1019     ToBooleanStub::Types expected = instr->expected_input_types();
1020     bool needs_temps = expected.NeedsMap() || expected.IsEmpty();
1021     LOperand* temp1 = needs_temps ? TempRegister() : NULL;
1022     LOperand* temp2 = needs_temps ? TempRegister() : NULL;
1023
1024     if (expected.IsGeneric() || expected.IsEmpty()) {
1025       // The generic case cannot deoptimize because it already supports every
1026       // possible input type.
1027       DCHECK(needs_temps);
1028       return new(zone()) LBranch(UseRegister(value), temp1, temp2);
1029     } else {
1030       return AssignEnvironment(
1031           new(zone()) LBranch(UseRegister(value), temp1, temp2));
1032     }
1033   }
1034 }
1035
1036
1037 LInstruction* LChunkBuilder::DoCallJSFunction(
1038     HCallJSFunction* instr) {
1039   LOperand* function = UseFixed(instr->function(), x1);
1040
1041   LCallJSFunction* result = new(zone()) LCallJSFunction(function);
1042
1043   return MarkAsCall(DefineFixed(result, x0), instr);
1044 }
1045
1046
1047 LInstruction* LChunkBuilder::DoCallWithDescriptor(
1048     HCallWithDescriptor* instr) {
1049   CallInterfaceDescriptor descriptor = instr->descriptor();
1050
1051   LOperand* target = UseRegisterOrConstantAtStart(instr->target());
1052   ZoneList<LOperand*> ops(instr->OperandCount(), zone());
1053   ops.Add(target, zone());
1054   for (int i = 1; i < instr->OperandCount(); i++) {
1055     LOperand* op =
1056         UseFixed(instr->OperandAt(i), descriptor.GetParameterRegister(i - 1));
1057     ops.Add(op, zone());
1058   }
1059
1060   LCallWithDescriptor* result = new(zone()) LCallWithDescriptor(descriptor,
1061                                                                 ops,
1062                                                                 zone());
1063   return MarkAsCall(DefineFixed(result, x0), instr);
1064 }
1065
1066
1067 LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
1068   LOperand* context = UseFixed(instr->context(), cp);
1069   LOperand* function = UseFixed(instr->function(), x1);
1070   LOperand* slot = NULL;
1071   LOperand* vector = NULL;
1072   if (instr->HasVectorAndSlot()) {
1073     slot = FixedTemp(x3);
1074     vector = FixedTemp(x2);
1075   }
1076
1077   LCallFunction* call =
1078       new (zone()) LCallFunction(context, function, slot, vector);
1079   return MarkAsCall(DefineFixed(call, x0), instr);
1080 }
1081
1082
1083 LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
1084   LOperand* context = UseFixed(instr->context(), cp);
1085   // The call to CallConstructStub will expect the constructor to be in x1.
1086   LOperand* constructor = UseFixed(instr->constructor(), x1);
1087   LCallNew* result = new(zone()) LCallNew(context, constructor);
1088   return MarkAsCall(DefineFixed(result, x0), instr);
1089 }
1090
1091
1092 LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) {
1093   LOperand* context = UseFixed(instr->context(), cp);
1094   // The call to ArrayConstructCode will expect the constructor to be in x1.
1095   LOperand* constructor = UseFixed(instr->constructor(), x1);
1096   LCallNewArray* result = new(zone()) LCallNewArray(context, constructor);
1097   return MarkAsCall(DefineFixed(result, x0), instr);
1098 }
1099
1100
1101 LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
1102   LOperand* context = UseFixed(instr->context(), cp);
1103   return MarkAsCall(DefineFixed(new(zone()) LCallRuntime(context), x0), instr);
1104 }
1105
1106
1107 LInstruction* LChunkBuilder::DoCallStub(HCallStub* instr) {
1108   LOperand* context = UseFixed(instr->context(), cp);
1109   return MarkAsCall(DefineFixed(new(zone()) LCallStub(context), x0), instr);
1110 }
1111
1112
1113 LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
1114   instr->ReplayEnvironment(current_block_->last_environment());
1115
1116   // There are no real uses of a captured object.
1117   return NULL;
1118 }
1119
1120
1121 LInstruction* LChunkBuilder::DoChange(HChange* instr) {
1122   Representation from = instr->from();
1123   Representation to = instr->to();
1124   HValue* val = instr->value();
1125   if (from.IsSmi()) {
1126     if (to.IsTagged()) {
1127       LOperand* value = UseRegister(val);
1128       return DefineSameAsFirst(new(zone()) LDummyUse(value));
1129     }
1130     from = Representation::Tagged();
1131   }
1132   if (from.IsTagged()) {
1133     if (to.IsDouble()) {
1134       LOperand* value = UseRegister(val);
1135       LOperand* temp = TempRegister();
1136       LInstruction* result =
1137           DefineAsRegister(new(zone()) LNumberUntagD(value, temp));
1138       if (!val->representation().IsSmi()) result = AssignEnvironment(result);
1139       return result;
1140     } else if (to.IsSmi()) {
1141       LOperand* value = UseRegister(val);
1142       if (val->type().IsSmi()) {
1143         return DefineSameAsFirst(new(zone()) LDummyUse(value));
1144       }
1145       return AssignEnvironment(DefineSameAsFirst(new(zone()) LCheckSmi(value)));
1146     } else {
1147       DCHECK(to.IsInteger32());
1148       if (val->type().IsSmi() || val->representation().IsSmi()) {
1149         LOperand* value = UseRegisterAtStart(val);
1150         return DefineAsRegister(new(zone()) LSmiUntag(value, false));
1151       } else {
1152         LOperand* value = UseRegister(val);
1153         LOperand* temp1 = TempRegister();
1154         LOperand* temp2 = instr->CanTruncateToInt32()
1155             ? NULL : TempDoubleRegister();
1156         LInstruction* result =
1157             DefineAsRegister(new(zone()) LTaggedToI(value, temp1, temp2));
1158         if (!val->representation().IsSmi()) result = AssignEnvironment(result);
1159         return result;
1160       }
1161     }
1162   } else if (from.IsDouble()) {
1163     if (to.IsTagged()) {
1164       info()->MarkAsDeferredCalling();
1165       LOperand* value = UseRegister(val);
1166       LOperand* temp1 = TempRegister();
1167       LOperand* temp2 = TempRegister();
1168       LNumberTagD* result = new(zone()) LNumberTagD(value, temp1, temp2);
1169       return AssignPointerMap(DefineAsRegister(result));
1170     } else {
1171       DCHECK(to.IsSmi() || to.IsInteger32());
1172       if (instr->CanTruncateToInt32()) {
1173         LOperand* value = UseRegister(val);
1174         return DefineAsRegister(new(zone()) LTruncateDoubleToIntOrSmi(value));
1175       } else {
1176         LOperand* value = UseRegister(val);
1177         LDoubleToIntOrSmi* result = new(zone()) LDoubleToIntOrSmi(value);
1178         return AssignEnvironment(DefineAsRegister(result));
1179       }
1180     }
1181   } else if (from.IsInteger32()) {
1182     info()->MarkAsDeferredCalling();
1183     if (to.IsTagged()) {
1184       if (val->CheckFlag(HInstruction::kUint32)) {
1185         LOperand* value = UseRegister(val);
1186         LNumberTagU* result =
1187             new(zone()) LNumberTagU(value, TempRegister(), TempRegister());
1188         return AssignPointerMap(DefineAsRegister(result));
1189       } else {
1190         STATIC_ASSERT((kMinInt == Smi::kMinValue) &&
1191                       (kMaxInt == Smi::kMaxValue));
1192         LOperand* value = UseRegisterAtStart(val);
1193         return DefineAsRegister(new(zone()) LSmiTag(value));
1194       }
1195     } else if (to.IsSmi()) {
1196       LOperand* value = UseRegisterAtStart(val);
1197       LInstruction* result = DefineAsRegister(new(zone()) LSmiTag(value));
1198       if (val->CheckFlag(HInstruction::kUint32)) {
1199         result = AssignEnvironment(result);
1200       }
1201       return result;
1202     } else {
1203       DCHECK(to.IsDouble());
1204       if (val->CheckFlag(HInstruction::kUint32)) {
1205         return DefineAsRegister(
1206             new(zone()) LUint32ToDouble(UseRegisterAtStart(val)));
1207       } else {
1208         return DefineAsRegister(
1209             new(zone()) LInteger32ToDouble(UseRegisterAtStart(val)));
1210       }
1211     }
1212   }
1213   UNREACHABLE();
1214   return NULL;
1215 }
1216
1217
1218 LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) {
1219   LOperand* value = UseRegisterAtStart(instr->value());
1220   return AssignEnvironment(new(zone()) LCheckValue(value));
1221 }
1222
1223
1224 LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
1225   LOperand* value = UseRegisterAtStart(instr->value());
1226   LOperand* temp = TempRegister();
1227   LInstruction* result = new(zone()) LCheckInstanceType(value, temp);
1228   return AssignEnvironment(result);
1229 }
1230
1231
1232 LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
1233   if (instr->IsStabilityCheck()) return new(zone()) LCheckMaps;
1234   LOperand* value = UseRegisterAtStart(instr->value());
1235   LOperand* temp = TempRegister();
1236   LInstruction* result = AssignEnvironment(new(zone()) LCheckMaps(value, temp));
1237   if (instr->HasMigrationTarget()) {
1238     info()->MarkAsDeferredCalling();
1239     result = AssignPointerMap(result);
1240   }
1241   return result;
1242 }
1243
1244
1245 LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
1246   LOperand* value = UseRegisterAtStart(instr->value());
1247   LInstruction* result = new(zone()) LCheckNonSmi(value);
1248   if (!instr->value()->type().IsHeapObject()) {
1249     result = AssignEnvironment(result);
1250   }
1251   return result;
1252 }
1253
1254
1255 LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
1256   LOperand* value = UseRegisterAtStart(instr->value());
1257   return AssignEnvironment(new(zone()) LCheckSmi(value));
1258 }
1259
1260
1261 LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
1262   HValue* value = instr->value();
1263   Representation input_rep = value->representation();
1264   LOperand* reg = UseRegister(value);
1265   if (input_rep.IsDouble()) {
1266     return DefineAsRegister(new(zone()) LClampDToUint8(reg));
1267   } else if (input_rep.IsInteger32()) {
1268     return DefineAsRegister(new(zone()) LClampIToUint8(reg));
1269   } else {
1270     DCHECK(input_rep.IsSmiOrTagged());
1271     return AssignEnvironment(
1272         DefineAsRegister(new(zone()) LClampTToUint8(reg,
1273                                                     TempDoubleRegister())));
1274   }
1275 }
1276
1277
1278 LInstruction* LChunkBuilder::DoClassOfTestAndBranch(
1279     HClassOfTestAndBranch* instr) {
1280   DCHECK(instr->value()->representation().IsTagged());
1281   LOperand* value = UseRegisterAtStart(instr->value());
1282   return new(zone()) LClassOfTestAndBranch(value,
1283                                            TempRegister(),
1284                                            TempRegister());
1285 }
1286
1287
1288 LInstruction* LChunkBuilder::DoCompareNumericAndBranch(
1289     HCompareNumericAndBranch* instr) {
1290   Representation r = instr->representation();
1291   if (r.IsSmiOrInteger32()) {
1292     DCHECK(instr->left()->representation().Equals(r));
1293     DCHECK(instr->right()->representation().Equals(r));
1294     LOperand* left = UseRegisterOrConstantAtStart(instr->left());
1295     LOperand* right = UseRegisterOrConstantAtStart(instr->right());
1296     return new(zone()) LCompareNumericAndBranch(left, right);
1297   } else {
1298     DCHECK(r.IsDouble());
1299     DCHECK(instr->left()->representation().IsDouble());
1300     DCHECK(instr->right()->representation().IsDouble());
1301     if (instr->left()->IsConstant() && instr->right()->IsConstant()) {
1302       LOperand* left = UseConstant(instr->left());
1303       LOperand* right = UseConstant(instr->right());
1304       return new(zone()) LCompareNumericAndBranch(left, right);
1305     }
1306     LOperand* left = UseRegisterAtStart(instr->left());
1307     LOperand* right = UseRegisterAtStart(instr->right());
1308     return new(zone()) LCompareNumericAndBranch(left, right);
1309   }
1310 }
1311
1312
1313 LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
1314   DCHECK(instr->left()->representation().IsTagged());
1315   DCHECK(instr->right()->representation().IsTagged());
1316   LOperand* context = UseFixed(instr->context(), cp);
1317   LOperand* left = UseFixed(instr->left(), x1);
1318   LOperand* right = UseFixed(instr->right(), x0);
1319   LCmpT* result = new(zone()) LCmpT(context, left, right);
1320   return MarkAsCall(DefineFixed(result, x0), instr);
1321 }
1322
1323
1324 LInstruction* LChunkBuilder::DoCompareHoleAndBranch(
1325     HCompareHoleAndBranch* instr) {
1326   LOperand* value = UseRegister(instr->value());
1327   if (instr->representation().IsTagged()) {
1328     return new(zone()) LCmpHoleAndBranchT(value);
1329   } else {
1330     LOperand* temp = TempRegister();
1331     return new(zone()) LCmpHoleAndBranchD(value, temp);
1332   }
1333 }
1334
1335
1336 LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch(
1337     HCompareObjectEqAndBranch* instr) {
1338   LOperand* left = UseRegisterAtStart(instr->left());
1339   LOperand* right = UseRegisterAtStart(instr->right());
1340   return new(zone()) LCmpObjectEqAndBranch(left, right);
1341 }
1342
1343
1344 LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
1345   DCHECK(instr->value()->representation().IsTagged());
1346   LOperand* value = UseRegisterAtStart(instr->value());
1347   LOperand* temp = TempRegister();
1348   return new(zone()) LCmpMapAndBranch(value, temp);
1349 }
1350
1351
1352 LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
1353   Representation r = instr->representation();
1354   if (r.IsSmi()) {
1355     return DefineAsRegister(new(zone()) LConstantS);
1356   } else if (r.IsInteger32()) {
1357     return DefineAsRegister(new(zone()) LConstantI);
1358   } else if (r.IsDouble()) {
1359     return DefineAsRegister(new(zone()) LConstantD);
1360   } else if (r.IsExternal()) {
1361     return DefineAsRegister(new(zone()) LConstantE);
1362   } else if (r.IsTagged()) {
1363     return DefineAsRegister(new(zone()) LConstantT);
1364   } else {
1365     UNREACHABLE();
1366     return NULL;
1367   }
1368 }
1369
1370
1371 LInstruction* LChunkBuilder::DoContext(HContext* instr) {
1372   if (instr->HasNoUses()) return NULL;
1373
1374   if (info()->IsStub()) {
1375     return DefineFixed(new(zone()) LContext, cp);
1376   }
1377
1378   return DefineAsRegister(new(zone()) LContext);
1379 }
1380
1381
1382 LInstruction* LChunkBuilder::DoDateField(HDateField* instr) {
1383   LOperand* object = UseFixed(instr->value(), x0);
1384   LDateField* result = new(zone()) LDateField(object, instr->index());
1385   return MarkAsCall(DefineFixed(result, x0), instr, CAN_DEOPTIMIZE_EAGERLY);
1386 }
1387
1388
1389 LInstruction* LChunkBuilder::DoDebugBreak(HDebugBreak* instr) {
1390   return new(zone()) LDebugBreak();
1391 }
1392
1393
1394 LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) {
1395   LOperand* context = UseFixed(instr->context(), cp);
1396   return MarkAsCall(new(zone()) LDeclareGlobals(context), instr);
1397 }
1398
1399
1400 LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
1401   return AssignEnvironment(new(zone()) LDeoptimize);
1402 }
1403
1404
1405 LInstruction* LChunkBuilder::DoDivByPowerOf2I(HDiv* instr) {
1406   DCHECK(instr->representation().IsInteger32());
1407   DCHECK(instr->left()->representation().Equals(instr->representation()));
1408   DCHECK(instr->right()->representation().Equals(instr->representation()));
1409   LOperand* dividend = UseRegister(instr->left());
1410   int32_t divisor = instr->right()->GetInteger32Constant();
1411   LInstruction* result = DefineAsRegister(new(zone()) LDivByPowerOf2I(
1412           dividend, divisor));
1413   if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
1414       (instr->CheckFlag(HValue::kCanOverflow) && divisor == -1) ||
1415       (!instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
1416        divisor != 1 && divisor != -1)) {
1417     result = AssignEnvironment(result);
1418   }
1419   return result;
1420 }
1421
1422
1423 LInstruction* LChunkBuilder::DoDivByConstI(HDiv* instr) {
1424   DCHECK(instr->representation().IsInteger32());
1425   DCHECK(instr->left()->representation().Equals(instr->representation()));
1426   DCHECK(instr->right()->representation().Equals(instr->representation()));
1427   LOperand* dividend = UseRegister(instr->left());
1428   int32_t divisor = instr->right()->GetInteger32Constant();
1429   LOperand* temp = instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)
1430       ? NULL : TempRegister();
1431   LInstruction* result = DefineAsRegister(new(zone()) LDivByConstI(
1432           dividend, divisor, temp));
1433   if (divisor == 0 ||
1434       (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
1435       !instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
1436     result = AssignEnvironment(result);
1437   }
1438   return result;
1439 }
1440
1441
1442 LInstruction* LChunkBuilder::DoDivI(HBinaryOperation* instr) {
1443   DCHECK(instr->representation().IsSmiOrInteger32());
1444   DCHECK(instr->left()->representation().Equals(instr->representation()));
1445   DCHECK(instr->right()->representation().Equals(instr->representation()));
1446   LOperand* dividend = UseRegister(instr->left());
1447   LOperand* divisor = UseRegister(instr->right());
1448   LOperand* temp = instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)
1449       ? NULL : TempRegister();
1450   LInstruction* result =
1451       DefineAsRegister(new(zone()) LDivI(dividend, divisor, temp));
1452   if (!instr->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
1453     result = AssignEnvironment(result);
1454   }
1455   return result;
1456 }
1457
1458
1459 LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
1460   if (instr->representation().IsSmiOrInteger32()) {
1461     if (instr->RightIsPowerOf2()) {
1462       return DoDivByPowerOf2I(instr);
1463     } else if (instr->right()->IsConstant()) {
1464       return DoDivByConstI(instr);
1465     } else {
1466       return DoDivI(instr);
1467     }
1468   } else if (instr->representation().IsDouble()) {
1469     return DoArithmeticD(Token::DIV, instr);
1470   } else {
1471     return DoArithmeticT(Token::DIV, instr);
1472   }
1473 }
1474
1475
1476 LInstruction* LChunkBuilder::DoDummyUse(HDummyUse* instr) {
1477   return DefineAsRegister(new(zone()) LDummyUse(UseAny(instr->value())));
1478 }
1479
1480
1481 LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
1482   HEnvironment* outer = current_block_->last_environment();
1483   outer->set_ast_id(instr->ReturnId());
1484   HConstant* undefined = graph()->GetConstantUndefined();
1485   HEnvironment* inner = outer->CopyForInlining(instr->closure(),
1486                                                instr->arguments_count(),
1487                                                instr->function(),
1488                                                undefined,
1489                                                instr->inlining_kind());
1490   // Only replay binding of arguments object if it wasn't removed from graph.
1491   if ((instr->arguments_var() != NULL) &&
1492       instr->arguments_object()->IsLinked()) {
1493     inner->Bind(instr->arguments_var(), instr->arguments_object());
1494   }
1495   inner->BindContext(instr->closure_context());
1496   inner->set_entry(instr);
1497   current_block_->UpdateEnvironment(inner);
1498   chunk_->AddInlinedClosure(instr->closure());
1499   return NULL;
1500 }
1501
1502
1503 LInstruction* LChunkBuilder::DoEnvironmentMarker(HEnvironmentMarker* instr) {
1504   UNREACHABLE();
1505   return NULL;
1506 }
1507
1508
1509 LInstruction* LChunkBuilder::DoForceRepresentation(
1510     HForceRepresentation* instr) {
1511   // All HForceRepresentation instructions should be eliminated in the
1512   // representation change phase of Hydrogen.
1513   UNREACHABLE();
1514   return NULL;
1515 }
1516
1517
1518 LInstruction* LChunkBuilder::DoFunctionLiteral(HFunctionLiteral* instr) {
1519   LOperand* context = UseFixed(instr->context(), cp);
1520   return MarkAsCall(
1521       DefineFixed(new(zone()) LFunctionLiteral(context), x0), instr);
1522 }
1523
1524
1525 LInstruction* LChunkBuilder::DoGetCachedArrayIndex(
1526     HGetCachedArrayIndex* instr) {
1527   DCHECK(instr->value()->representation().IsTagged());
1528   LOperand* value = UseRegisterAtStart(instr->value());
1529   return DefineAsRegister(new(zone()) LGetCachedArrayIndex(value));
1530 }
1531
1532
1533 LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
1534   return new(zone()) LGoto(instr->FirstSuccessor());
1535 }
1536
1537
1538 LInstruction* LChunkBuilder::DoHasCachedArrayIndexAndBranch(
1539     HHasCachedArrayIndexAndBranch* instr) {
1540   DCHECK(instr->value()->representation().IsTagged());
1541   return new(zone()) LHasCachedArrayIndexAndBranch(
1542       UseRegisterAtStart(instr->value()), TempRegister());
1543 }
1544
1545
1546 LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
1547     HHasInstanceTypeAndBranch* instr) {
1548   DCHECK(instr->value()->representation().IsTagged());
1549   LOperand* value = UseRegisterAtStart(instr->value());
1550   return new(zone()) LHasInstanceTypeAndBranch(value, TempRegister());
1551 }
1552
1553
1554 LInstruction* LChunkBuilder::DoInnerAllocatedObject(
1555     HInnerAllocatedObject* instr) {
1556   LOperand* base_object = UseRegisterAtStart(instr->base_object());
1557   LOperand* offset = UseRegisterOrConstantAtStart(instr->offset());
1558   return DefineAsRegister(
1559       new(zone()) LInnerAllocatedObject(base_object, offset));
1560 }
1561
1562
1563 LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) {
1564   LOperand* context = UseFixed(instr->context(), cp);
1565   LInstanceOf* result = new(zone()) LInstanceOf(
1566       context,
1567       UseFixed(instr->left(), InstanceofStub::left()),
1568       UseFixed(instr->right(), InstanceofStub::right()));
1569   return MarkAsCall(DefineFixed(result, x0), instr);
1570 }
1571
1572
1573 LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal(
1574     HInstanceOfKnownGlobal* instr) {
1575   LInstanceOfKnownGlobal* result = new(zone()) LInstanceOfKnownGlobal(
1576       UseFixed(instr->context(), cp),
1577       UseFixed(instr->left(), InstanceofStub::left()));
1578   return MarkAsCall(DefineFixed(result, x0), instr);
1579 }
1580
1581
1582 LInstruction* LChunkBuilder::DoTailCallThroughMegamorphicCache(
1583     HTailCallThroughMegamorphicCache* instr) {
1584   LOperand* context = UseFixed(instr->context(), cp);
1585   LOperand* receiver_register =
1586       UseFixed(instr->receiver(), LoadDescriptor::ReceiverRegister());
1587   LOperand* name_register =
1588       UseFixed(instr->name(), LoadDescriptor::NameRegister());
1589   LOperand* slot = NULL;
1590   LOperand* vector = NULL;
1591   if (FLAG_vector_ics) {
1592     slot = UseFixed(instr->slot(), VectorLoadICDescriptor::SlotRegister());
1593     vector =
1594         UseFixed(instr->vector(), VectorLoadICDescriptor::VectorRegister());
1595   }
1596
1597   // Not marked as call. It can't deoptimize, and it never returns.
1598   return new (zone()) LTailCallThroughMegamorphicCache(
1599       context, receiver_register, name_register, slot, vector);
1600 }
1601
1602
1603 LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
1604   LOperand* context = UseFixed(instr->context(), cp);
1605   // The function is required (by MacroAssembler::InvokeFunction) to be in x1.
1606   LOperand* function = UseFixed(instr->function(), x1);
1607   LInvokeFunction* result = new(zone()) LInvokeFunction(context, function);
1608   return MarkAsCall(DefineFixed(result, x0), instr, CANNOT_DEOPTIMIZE_EAGERLY);
1609 }
1610
1611
1612 LInstruction* LChunkBuilder::DoIsConstructCallAndBranch(
1613     HIsConstructCallAndBranch* instr) {
1614   return new(zone()) LIsConstructCallAndBranch(TempRegister(), TempRegister());
1615 }
1616
1617
1618 LInstruction* LChunkBuilder::DoCompareMinusZeroAndBranch(
1619     HCompareMinusZeroAndBranch* instr) {
1620   LOperand* value = UseRegister(instr->value());
1621   LOperand* scratch = TempRegister();
1622   return new(zone()) LCompareMinusZeroAndBranch(value, scratch);
1623 }
1624
1625
1626 LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
1627   DCHECK(instr->value()->representation().IsTagged());
1628   LOperand* value = UseRegisterAtStart(instr->value());
1629   LOperand* temp1 = TempRegister();
1630   LOperand* temp2 = TempRegister();
1631   return new(zone()) LIsObjectAndBranch(value, temp1, temp2);
1632 }
1633
1634
1635 LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
1636   DCHECK(instr->value()->representation().IsTagged());
1637   LOperand* value = UseRegisterAtStart(instr->value());
1638   LOperand* temp = TempRegister();
1639   return new(zone()) LIsStringAndBranch(value, temp);
1640 }
1641
1642
1643 LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
1644   DCHECK(instr->value()->representation().IsTagged());
1645   return new(zone()) LIsSmiAndBranch(UseRegisterAtStart(instr->value()));
1646 }
1647
1648
1649 LInstruction* LChunkBuilder::DoIsUndetectableAndBranch(
1650     HIsUndetectableAndBranch* instr) {
1651   DCHECK(instr->value()->representation().IsTagged());
1652   LOperand* value = UseRegisterAtStart(instr->value());
1653   return new(zone()) LIsUndetectableAndBranch(value, TempRegister());
1654 }
1655
1656
1657 LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
1658   LInstruction* pop = NULL;
1659   HEnvironment* env = current_block_->last_environment();
1660
1661   if (env->entry()->arguments_pushed()) {
1662     int argument_count = env->arguments_environment()->parameter_count();
1663     pop = new(zone()) LDrop(argument_count);
1664     DCHECK(instr->argument_delta() == -argument_count);
1665   }
1666
1667   HEnvironment* outer =
1668       current_block_->last_environment()->DiscardInlined(false);
1669   current_block_->UpdateEnvironment(outer);
1670
1671   return pop;
1672 }
1673
1674
1675 LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
1676   LOperand* context = UseRegisterAtStart(instr->value());
1677   LInstruction* result =
1678       DefineAsRegister(new(zone()) LLoadContextSlot(context));
1679   if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
1680     result = AssignEnvironment(result);
1681   }
1682   return result;
1683 }
1684
1685
1686 LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
1687     HLoadFunctionPrototype* instr) {
1688   LOperand* function = UseRegister(instr->function());
1689   LOperand* temp = TempRegister();
1690   return AssignEnvironment(DefineAsRegister(
1691       new(zone()) LLoadFunctionPrototype(function, temp)));
1692 }
1693
1694
1695 LInstruction* LChunkBuilder::DoLoadGlobalCell(HLoadGlobalCell* instr) {
1696   LLoadGlobalCell* result = new(zone()) LLoadGlobalCell();
1697   return instr->RequiresHoleCheck()
1698       ? AssignEnvironment(DefineAsRegister(result))
1699       : DefineAsRegister(result);
1700 }
1701
1702
1703 LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) {
1704   LOperand* context = UseFixed(instr->context(), cp);
1705   LOperand* global_object =
1706       UseFixed(instr->global_object(), LoadDescriptor::ReceiverRegister());
1707   LOperand* vector = NULL;
1708   if (instr->HasVectorAndSlot()) {
1709     vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
1710   }
1711
1712   LLoadGlobalGeneric* result =
1713       new(zone()) LLoadGlobalGeneric(context, global_object, vector);
1714   return MarkAsCall(DefineFixed(result, x0), instr);
1715 }
1716
1717
1718 LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) {
1719   DCHECK(instr->key()->representation().IsSmiOrInteger32());
1720   ElementsKind elements_kind = instr->elements_kind();
1721   LOperand* elements = UseRegister(instr->elements());
1722   LOperand* key = UseRegisterOrConstant(instr->key());
1723
1724   if (!instr->is_typed_elements()) {
1725     if (instr->representation().IsDouble()) {
1726       LOperand* temp = (!instr->key()->IsConstant() ||
1727                         instr->RequiresHoleCheck())
1728              ? TempRegister()
1729              : NULL;
1730
1731       LLoadKeyedFixedDouble* result =
1732           new(zone()) LLoadKeyedFixedDouble(elements, key, temp);
1733       return instr->RequiresHoleCheck()
1734           ? AssignEnvironment(DefineAsRegister(result))
1735           : DefineAsRegister(result);
1736     } else {
1737       DCHECK(instr->representation().IsSmiOrTagged() ||
1738              instr->representation().IsInteger32());
1739       LOperand* temp = instr->key()->IsConstant() ? NULL : TempRegister();
1740       LLoadKeyedFixed* result =
1741           new(zone()) LLoadKeyedFixed(elements, key, temp);
1742       return instr->RequiresHoleCheck()
1743           ? AssignEnvironment(DefineAsRegister(result))
1744           : DefineAsRegister(result);
1745     }
1746   } else {
1747     DCHECK((instr->representation().IsInteger32() &&
1748             !IsDoubleOrFloatElementsKind(instr->elements_kind())) ||
1749            (instr->representation().IsDouble() &&
1750             IsDoubleOrFloatElementsKind(instr->elements_kind())));
1751
1752     LOperand* temp = instr->key()->IsConstant() ? NULL : TempRegister();
1753     LInstruction* result = DefineAsRegister(
1754         new(zone()) LLoadKeyedExternal(elements, key, temp));
1755     if ((elements_kind == EXTERNAL_UINT32_ELEMENTS ||
1756          elements_kind == UINT32_ELEMENTS) &&
1757         !instr->CheckFlag(HInstruction::kUint32)) {
1758       result = AssignEnvironment(result);
1759     }
1760     return result;
1761   }
1762 }
1763
1764
1765 LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
1766   LOperand* context = UseFixed(instr->context(), cp);
1767   LOperand* object =
1768       UseFixed(instr->object(), LoadDescriptor::ReceiverRegister());
1769   LOperand* key = UseFixed(instr->key(), LoadDescriptor::NameRegister());
1770   LOperand* vector = NULL;
1771   if (instr->HasVectorAndSlot()) {
1772     vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
1773   }
1774
1775   LInstruction* result =
1776       DefineFixed(new(zone()) LLoadKeyedGeneric(context, object, key, vector),
1777                   x0);
1778   return MarkAsCall(result, instr);
1779 }
1780
1781
1782 LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
1783   LOperand* object = UseRegisterAtStart(instr->object());
1784   return DefineAsRegister(new(zone()) LLoadNamedField(object));
1785 }
1786
1787
1788 LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
1789   LOperand* context = UseFixed(instr->context(), cp);
1790   LOperand* object =
1791       UseFixed(instr->object(), LoadDescriptor::ReceiverRegister());
1792   LOperand* vector = NULL;
1793   if (instr->HasVectorAndSlot()) {
1794     vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
1795   }
1796
1797   LInstruction* result =
1798       DefineFixed(new(zone()) LLoadNamedGeneric(context, object, vector), x0);
1799   return MarkAsCall(result, instr);
1800 }
1801
1802
1803 LInstruction* LChunkBuilder::DoLoadRoot(HLoadRoot* instr) {
1804   return DefineAsRegister(new(zone()) LLoadRoot);
1805 }
1806
1807
1808 LInstruction* LChunkBuilder::DoMapEnumLength(HMapEnumLength* instr) {
1809   LOperand* map = UseRegisterAtStart(instr->value());
1810   return DefineAsRegister(new(zone()) LMapEnumLength(map));
1811 }
1812
1813
1814 LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
1815   DCHECK(instr->representation().IsInteger32());
1816   DCHECK(instr->left()->representation().Equals(instr->representation()));
1817   DCHECK(instr->right()->representation().Equals(instr->representation()));
1818   LOperand* dividend = UseRegisterAtStart(instr->left());
1819   int32_t divisor = instr->right()->GetInteger32Constant();
1820   LInstruction* result = DefineAsRegister(new(zone()) LFlooringDivByPowerOf2I(
1821           dividend, divisor));
1822   if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
1823       (instr->CheckFlag(HValue::kLeftCanBeMinInt) && divisor == -1)) {
1824     result = AssignEnvironment(result);
1825   }
1826   return result;
1827 }
1828
1829
1830 LInstruction* LChunkBuilder::DoFlooringDivByConstI(HMathFloorOfDiv* instr) {
1831   DCHECK(instr->representation().IsInteger32());
1832   DCHECK(instr->left()->representation().Equals(instr->representation()));
1833   DCHECK(instr->right()->representation().Equals(instr->representation()));
1834   LOperand* dividend = UseRegister(instr->left());
1835   int32_t divisor = instr->right()->GetInteger32Constant();
1836   LOperand* temp =
1837       ((divisor > 0 && !instr->CheckFlag(HValue::kLeftCanBeNegative)) ||
1838        (divisor < 0 && !instr->CheckFlag(HValue::kLeftCanBePositive))) ?
1839       NULL : TempRegister();
1840   LInstruction* result = DefineAsRegister(
1841       new(zone()) LFlooringDivByConstI(dividend, divisor, temp));
1842   if (divisor == 0 ||
1843       (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0)) {
1844     result = AssignEnvironment(result);
1845   }
1846   return result;
1847 }
1848
1849
1850 LInstruction* LChunkBuilder::DoFlooringDivI(HMathFloorOfDiv* instr) {
1851   LOperand* dividend = UseRegister(instr->left());
1852   LOperand* divisor = UseRegister(instr->right());
1853   LOperand* remainder = TempRegister();
1854   LInstruction* result =
1855       DefineAsRegister(new(zone()) LFlooringDivI(dividend, divisor, remainder));
1856   return AssignEnvironment(result);
1857 }
1858
1859
1860 LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
1861   if (instr->RightIsPowerOf2()) {
1862     return DoFlooringDivByPowerOf2I(instr);
1863   } else if (instr->right()->IsConstant()) {
1864     return DoFlooringDivByConstI(instr);
1865   } else {
1866     return DoFlooringDivI(instr);
1867   }
1868 }
1869
1870
1871 LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
1872   LOperand* left = NULL;
1873   LOperand* right = NULL;
1874   if (instr->representation().IsSmiOrInteger32()) {
1875     DCHECK(instr->left()->representation().Equals(instr->representation()));
1876     DCHECK(instr->right()->representation().Equals(instr->representation()));
1877     left = UseRegisterAtStart(instr->BetterLeftOperand());
1878     right = UseRegisterOrConstantAtStart(instr->BetterRightOperand());
1879   } else {
1880     DCHECK(instr->representation().IsDouble());
1881     DCHECK(instr->left()->representation().IsDouble());
1882     DCHECK(instr->right()->representation().IsDouble());
1883     left = UseRegisterAtStart(instr->left());
1884     right = UseRegisterAtStart(instr->right());
1885   }
1886   return DefineAsRegister(new(zone()) LMathMinMax(left, right));
1887 }
1888
1889
1890 LInstruction* LChunkBuilder::DoModByPowerOf2I(HMod* instr) {
1891   DCHECK(instr->representation().IsInteger32());
1892   DCHECK(instr->left()->representation().Equals(instr->representation()));
1893   DCHECK(instr->right()->representation().Equals(instr->representation()));
1894   LOperand* dividend = UseRegisterAtStart(instr->left());
1895   int32_t divisor = instr->right()->GetInteger32Constant();
1896   LInstruction* result = DefineSameAsFirst(new(zone()) LModByPowerOf2I(
1897           dividend, divisor));
1898   if (instr->CheckFlag(HValue::kLeftCanBeNegative) &&
1899       instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1900     result = AssignEnvironment(result);
1901   }
1902   return result;
1903 }
1904
1905
1906 LInstruction* LChunkBuilder::DoModByConstI(HMod* instr) {
1907   DCHECK(instr->representation().IsInteger32());
1908   DCHECK(instr->left()->representation().Equals(instr->representation()));
1909   DCHECK(instr->right()->representation().Equals(instr->representation()));
1910   LOperand* dividend = UseRegister(instr->left());
1911   int32_t divisor = instr->right()->GetInteger32Constant();
1912   LOperand* temp = TempRegister();
1913   LInstruction* result = DefineAsRegister(new(zone()) LModByConstI(
1914           dividend, divisor, temp));
1915   if (divisor == 0 || instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1916     result = AssignEnvironment(result);
1917   }
1918   return result;
1919 }
1920
1921
1922 LInstruction* LChunkBuilder::DoModI(HMod* instr) {
1923   DCHECK(instr->representation().IsSmiOrInteger32());
1924   DCHECK(instr->left()->representation().Equals(instr->representation()));
1925   DCHECK(instr->right()->representation().Equals(instr->representation()));
1926   LOperand* dividend = UseRegister(instr->left());
1927   LOperand* divisor = UseRegister(instr->right());
1928   LInstruction* result = DefineAsRegister(new(zone()) LModI(dividend, divisor));
1929   if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
1930       instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1931     result = AssignEnvironment(result);
1932   }
1933   return result;
1934 }
1935
1936
1937 LInstruction* LChunkBuilder::DoMod(HMod* instr) {
1938   if (instr->representation().IsSmiOrInteger32()) {
1939     if (instr->RightIsPowerOf2()) {
1940       return DoModByPowerOf2I(instr);
1941     } else if (instr->right()->IsConstant()) {
1942       return DoModByConstI(instr);
1943     } else {
1944       return DoModI(instr);
1945     }
1946   } else if (instr->representation().IsDouble()) {
1947     return DoArithmeticD(Token::MOD, instr);
1948   } else {
1949     return DoArithmeticT(Token::MOD, instr);
1950   }
1951 }
1952
1953
1954 LInstruction* LChunkBuilder::DoMul(HMul* instr) {
1955   if (instr->representation().IsSmiOrInteger32()) {
1956     DCHECK(instr->left()->representation().Equals(instr->representation()));
1957     DCHECK(instr->right()->representation().Equals(instr->representation()));
1958
1959     bool can_overflow = instr->CheckFlag(HValue::kCanOverflow);
1960     bool bailout_on_minus_zero = instr->CheckFlag(HValue::kBailoutOnMinusZero);
1961
1962     HValue* least_const = instr->BetterLeftOperand();
1963     HValue* most_const = instr->BetterRightOperand();
1964
1965     // LMulConstI can handle a subset of constants:
1966     //  With support for overflow detection:
1967     //    -1, 0, 1, 2
1968     //    2^n, -(2^n)
1969     //  Without support for overflow detection:
1970     //    2^n + 1, -(2^n - 1)
1971     if (most_const->IsConstant()) {
1972       int32_t constant = HConstant::cast(most_const)->Integer32Value();
1973       bool small_constant = (constant >= -1) && (constant <= 2);
1974       bool end_range_constant = (constant <= -kMaxInt) || (constant == kMaxInt);
1975       int32_t constant_abs = Abs(constant);
1976
1977       if (!end_range_constant &&
1978           (small_constant || (base::bits::IsPowerOfTwo32(constant_abs)) ||
1979            (!can_overflow && (base::bits::IsPowerOfTwo32(constant_abs + 1) ||
1980                               base::bits::IsPowerOfTwo32(constant_abs - 1))))) {
1981         LConstantOperand* right = UseConstant(most_const);
1982         bool need_register =
1983             base::bits::IsPowerOfTwo32(constant_abs) && !small_constant;
1984         LOperand* left = need_register ? UseRegister(least_const)
1985                                        : UseRegisterAtStart(least_const);
1986         LInstruction* result =
1987             DefineAsRegister(new(zone()) LMulConstIS(left, right));
1988         if ((bailout_on_minus_zero && constant <= 0) ||
1989             (can_overflow && constant != 1 &&
1990              base::bits::IsPowerOfTwo32(constant_abs))) {
1991           result = AssignEnvironment(result);
1992         }
1993         return result;
1994       }
1995     }
1996
1997     // LMulI/S can handle all cases, but it requires that a register is
1998     // allocated for the second operand.
1999     LOperand* left = UseRegisterAtStart(least_const);
2000     LOperand* right = UseRegisterAtStart(most_const);
2001     LInstruction* result = instr->representation().IsSmi()
2002         ? DefineAsRegister(new(zone()) LMulS(left, right))
2003         : DefineAsRegister(new(zone()) LMulI(left, right));
2004     if ((bailout_on_minus_zero && least_const != most_const) || can_overflow) {
2005       result = AssignEnvironment(result);
2006     }
2007     return result;
2008   } else if (instr->representation().IsDouble()) {
2009     return DoArithmeticD(Token::MUL, instr);
2010   } else {
2011     return DoArithmeticT(Token::MUL, instr);
2012   }
2013 }
2014
2015
2016 LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
2017   DCHECK(argument_count_ == 0);
2018   allocator_->MarkAsOsrEntry();
2019   current_block_->last_environment()->set_ast_id(instr->ast_id());
2020   return AssignEnvironment(new(zone()) LOsrEntry);
2021 }
2022
2023
2024 LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
2025   LParameter* result = new(zone()) LParameter;
2026   if (instr->kind() == HParameter::STACK_PARAMETER) {
2027     int spill_index = chunk_->GetParameterStackSlot(instr->index());
2028     return DefineAsSpilled(result, spill_index);
2029   } else {
2030     DCHECK(info()->IsStub());
2031     CallInterfaceDescriptor descriptor =
2032         info()->code_stub()->GetCallInterfaceDescriptor();
2033     int index = static_cast<int>(instr->index());
2034     Register reg = descriptor.GetEnvironmentParameterRegister(index);
2035     return DefineFixed(result, reg);
2036   }
2037 }
2038
2039
2040 LInstruction* LChunkBuilder::DoPower(HPower* instr) {
2041   DCHECK(instr->representation().IsDouble());
2042   // We call a C function for double power. It can't trigger a GC.
2043   // We need to use fixed result register for the call.
2044   Representation exponent_type = instr->right()->representation();
2045   DCHECK(instr->left()->representation().IsDouble());
2046   LOperand* left = UseFixedDouble(instr->left(), d0);
2047   LOperand* right;
2048   if (exponent_type.IsInteger32()) {
2049     right = UseFixed(instr->right(), MathPowIntegerDescriptor::exponent());
2050   } else if (exponent_type.IsDouble()) {
2051     right = UseFixedDouble(instr->right(), d1);
2052   } else {
2053     right = UseFixed(instr->right(), MathPowTaggedDescriptor::exponent());
2054   }
2055   LPower* result = new(zone()) LPower(left, right);
2056   return MarkAsCall(DefineFixedDouble(result, d0),
2057                     instr,
2058                     CAN_DEOPTIMIZE_EAGERLY);
2059 }
2060
2061
2062 LInstruction* LChunkBuilder::DoPushArguments(HPushArguments* instr) {
2063   int argc = instr->OperandCount();
2064   AddInstruction(new(zone()) LPreparePushArguments(argc), instr);
2065
2066   LPushArguments* push_args = new(zone()) LPushArguments(zone());
2067
2068   for (int i = 0; i < argc; ++i) {
2069     if (push_args->ShouldSplitPush()) {
2070       AddInstruction(push_args, instr);
2071       push_args = new(zone()) LPushArguments(zone());
2072     }
2073     push_args->AddArgument(UseRegister(instr->argument(i)));
2074   }
2075
2076   return push_args;
2077 }
2078
2079
2080 LInstruction* LChunkBuilder::DoRegExpLiteral(HRegExpLiteral* instr) {
2081   LOperand* context = UseFixed(instr->context(), cp);
2082   return MarkAsCall(
2083       DefineFixed(new(zone()) LRegExpLiteral(context), x0), instr);
2084 }
2085
2086
2087 LInstruction* LChunkBuilder::DoDoubleBits(HDoubleBits* instr) {
2088   HValue* value = instr->value();
2089   DCHECK(value->representation().IsDouble());
2090   return DefineAsRegister(new(zone()) LDoubleBits(UseRegister(value)));
2091 }
2092
2093
2094 LInstruction* LChunkBuilder::DoConstructDouble(HConstructDouble* instr) {
2095   LOperand* lo = UseRegisterAndClobber(instr->lo());
2096   LOperand* hi = UseRegister(instr->hi());
2097   return DefineAsRegister(new(zone()) LConstructDouble(hi, lo));
2098 }
2099
2100
2101 LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
2102   LOperand* context = info()->IsStub()
2103       ? UseFixed(instr->context(), cp)
2104       : NULL;
2105   LOperand* parameter_count = UseRegisterOrConstant(instr->parameter_count());
2106   return new(zone()) LReturn(UseFixed(instr->value(), x0), context,
2107                              parameter_count);
2108 }
2109
2110
2111 LInstruction* LChunkBuilder::DoSeqStringGetChar(HSeqStringGetChar* instr) {
2112   LOperand* string = UseRegisterAtStart(instr->string());
2113   LOperand* index = UseRegisterOrConstantAtStart(instr->index());
2114   LOperand* temp = TempRegister();
2115   LSeqStringGetChar* result =
2116       new(zone()) LSeqStringGetChar(string, index, temp);
2117   return DefineAsRegister(result);
2118 }
2119
2120
2121 LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
2122   LOperand* string = UseRegister(instr->string());
2123   LOperand* index = FLAG_debug_code
2124       ? UseRegister(instr->index())
2125       : UseRegisterOrConstant(instr->index());
2126   LOperand* value = UseRegister(instr->value());
2127   LOperand* context = FLAG_debug_code ? UseFixed(instr->context(), cp) : NULL;
2128   LOperand* temp = TempRegister();
2129   LSeqStringSetChar* result =
2130       new(zone()) LSeqStringSetChar(context, string, index, value, temp);
2131   return DefineAsRegister(result);
2132 }
2133
2134
2135 HBitwiseBinaryOperation* LChunkBuilder::CanTransformToShiftedOp(HValue* val,
2136                                                                 HValue** left) {
2137   if (!val->representation().IsInteger32()) return NULL;
2138   if (!(val->IsBitwise() || val->IsAdd() || val->IsSub())) return NULL;
2139
2140   HBinaryOperation* hinstr = HBinaryOperation::cast(val);
2141   HValue* hleft = hinstr->left();
2142   HValue* hright = hinstr->right();
2143   DCHECK(hleft->representation().Equals(hinstr->representation()));
2144   DCHECK(hright->representation().Equals(hinstr->representation()));
2145
2146   if ((hright->IsConstant() &&
2147        LikelyFitsImmField(hinstr, HConstant::cast(hright)->Integer32Value())) ||
2148       (hinstr->IsCommutative() && hleft->IsConstant() &&
2149        LikelyFitsImmField(hinstr, HConstant::cast(hleft)->Integer32Value()))) {
2150     // The constant operand will likely fit in the immediate field. We are
2151     // better off with
2152     //     lsl x8, x9, #imm
2153     //     add x0, x8, #imm2
2154     // than with
2155     //     mov x16, #imm2
2156     //     add x0, x16, x9 LSL #imm
2157     return NULL;
2158   }
2159
2160   HBitwiseBinaryOperation* shift = NULL;
2161   // TODO(aleram): We will miss situations where a shift operation is used by
2162   // different instructions both as a left and right operands.
2163   if (hright->IsBitwiseBinaryShift() &&
2164       HBitwiseBinaryOperation::cast(hright)->right()->IsConstant()) {
2165     shift = HBitwiseBinaryOperation::cast(hright);
2166     if (left != NULL) {
2167       *left = hleft;
2168     }
2169   } else if (hinstr->IsCommutative() &&
2170              hleft->IsBitwiseBinaryShift() &&
2171              HBitwiseBinaryOperation::cast(hleft)->right()->IsConstant()) {
2172     shift = HBitwiseBinaryOperation::cast(hleft);
2173     if (left != NULL) {
2174       *left = hright;
2175     }
2176   } else {
2177     return NULL;
2178   }
2179
2180   if ((JSShiftAmountFromHConstant(shift->right()) == 0) && shift->IsShr()) {
2181     // Shifts right by zero can deoptimize.
2182     return NULL;
2183   }
2184
2185   return shift;
2186 }
2187
2188
2189 bool LChunkBuilder::ShiftCanBeOptimizedAway(HBitwiseBinaryOperation* shift) {
2190   if (!shift->representation().IsInteger32()) {
2191     return false;
2192   }
2193   for (HUseIterator it(shift->uses()); !it.Done(); it.Advance()) {
2194     if (shift != CanTransformToShiftedOp(it.value())) {
2195       return false;
2196     }
2197   }
2198   return true;
2199 }
2200
2201
2202 LInstruction* LChunkBuilder::TryDoOpWithShiftedRightOperand(
2203     HBinaryOperation* instr) {
2204   HValue* left;
2205   HBitwiseBinaryOperation* shift = CanTransformToShiftedOp(instr, &left);
2206
2207   if ((shift != NULL) && ShiftCanBeOptimizedAway(shift)) {
2208     return DoShiftedBinaryOp(instr, left, shift);
2209   }
2210   return NULL;
2211 }
2212
2213
2214 LInstruction* LChunkBuilder::DoShiftedBinaryOp(
2215     HBinaryOperation* hinstr, HValue* hleft, HBitwiseBinaryOperation* hshift) {
2216   DCHECK(hshift->IsBitwiseBinaryShift());
2217   DCHECK(!hshift->IsShr() || (JSShiftAmountFromHConstant(hshift->right()) > 0));
2218
2219   LTemplateResultInstruction<1>* res;
2220   LOperand* left = UseRegisterAtStart(hleft);
2221   LOperand* right = UseRegisterAtStart(hshift->left());
2222   LOperand* shift_amount = UseConstant(hshift->right());
2223   Shift shift_op;
2224   switch (hshift->opcode()) {
2225     case HValue::kShl: shift_op = LSL; break;
2226     case HValue::kShr: shift_op = LSR; break;
2227     case HValue::kSar: shift_op = ASR; break;
2228     default: UNREACHABLE(); shift_op = NO_SHIFT;
2229   }
2230
2231   if (hinstr->IsBitwise()) {
2232     res = new(zone()) LBitI(left, right, shift_op, shift_amount);
2233   } else if (hinstr->IsAdd()) {
2234     res = new(zone()) LAddI(left, right, shift_op, shift_amount);
2235   } else {
2236     DCHECK(hinstr->IsSub());
2237     res = new(zone()) LSubI(left, right, shift_op, shift_amount);
2238   }
2239   if (hinstr->CheckFlag(HValue::kCanOverflow)) {
2240     AssignEnvironment(res);
2241   }
2242   return DefineAsRegister(res);
2243 }
2244
2245
2246 LInstruction* LChunkBuilder::DoShift(Token::Value op,
2247                                      HBitwiseBinaryOperation* instr) {
2248   if (instr->representation().IsTagged()) {
2249     return DoArithmeticT(op, instr);
2250   }
2251
2252   DCHECK(instr->representation().IsSmiOrInteger32());
2253   DCHECK(instr->left()->representation().Equals(instr->representation()));
2254   DCHECK(instr->right()->representation().Equals(instr->representation()));
2255
2256   if (ShiftCanBeOptimizedAway(instr)) {
2257     return NULL;
2258   }
2259
2260   LOperand* left = instr->representation().IsSmi()
2261       ? UseRegister(instr->left())
2262       : UseRegisterAtStart(instr->left());
2263   LOperand* right = UseRegisterOrConstantAtStart(instr->right());
2264
2265   // The only shift that can deoptimize is `left >>> 0`, where left is negative.
2266   // In these cases, the result is a uint32 that is too large for an int32.
2267   bool right_can_be_zero = !instr->right()->IsConstant() ||
2268                            (JSShiftAmountFromHConstant(instr->right()) == 0);
2269   bool can_deopt = false;
2270   if ((op == Token::SHR) && right_can_be_zero) {
2271     can_deopt = !instr->CheckFlag(HInstruction::kUint32);
2272   }
2273
2274   LInstruction* result;
2275   if (instr->representation().IsInteger32()) {
2276     result = DefineAsRegister(new (zone()) LShiftI(op, left, right, can_deopt));
2277   } else {
2278     DCHECK(instr->representation().IsSmi());
2279     result = DefineAsRegister(new (zone()) LShiftS(op, left, right, can_deopt));
2280   }
2281
2282   return can_deopt ? AssignEnvironment(result) : result;
2283 }
2284
2285
2286 LInstruction* LChunkBuilder::DoRor(HRor* instr) {
2287   return DoShift(Token::ROR, instr);
2288 }
2289
2290
2291 LInstruction* LChunkBuilder::DoSar(HSar* instr) {
2292   return DoShift(Token::SAR, instr);
2293 }
2294
2295
2296 LInstruction* LChunkBuilder::DoShl(HShl* instr) {
2297   return DoShift(Token::SHL, instr);
2298 }
2299
2300
2301 LInstruction* LChunkBuilder::DoShr(HShr* instr) {
2302   return DoShift(Token::SHR, instr);
2303 }
2304
2305
2306 LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
2307   instr->ReplayEnvironment(current_block_->last_environment());
2308   return NULL;
2309 }
2310
2311
2312 LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
2313   if (instr->is_function_entry()) {
2314     LOperand* context = UseFixed(instr->context(), cp);
2315     return MarkAsCall(new(zone()) LStackCheck(context), instr);
2316   } else {
2317     DCHECK(instr->is_backwards_branch());
2318     LOperand* context = UseAny(instr->context());
2319     return AssignEnvironment(
2320         AssignPointerMap(new(zone()) LStackCheck(context)));
2321   }
2322 }
2323
2324
2325 LInstruction* LChunkBuilder::DoStoreCodeEntry(HStoreCodeEntry* instr) {
2326   LOperand* function = UseRegister(instr->function());
2327   LOperand* code_object = UseRegisterAtStart(instr->code_object());
2328   LOperand* temp = TempRegister();
2329   return new(zone()) LStoreCodeEntry(function, code_object, temp);
2330 }
2331
2332
2333 LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
2334   LOperand* temp = TempRegister();
2335   LOperand* context;
2336   LOperand* value;
2337   if (instr->NeedsWriteBarrier()) {
2338     // TODO(all): Replace these constraints when RecordWriteStub has been
2339     // rewritten.
2340     context = UseRegisterAndClobber(instr->context());
2341     value = UseRegisterAndClobber(instr->value());
2342   } else {
2343     context = UseRegister(instr->context());
2344     value = UseRegister(instr->value());
2345   }
2346   LInstruction* result = new(zone()) LStoreContextSlot(context, value, temp);
2347   if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
2348     result = AssignEnvironment(result);
2349   }
2350   return result;
2351 }
2352
2353
2354 LInstruction* LChunkBuilder::DoStoreGlobalCell(HStoreGlobalCell* instr) {
2355   LOperand* value = UseRegister(instr->value());
2356   if (instr->RequiresHoleCheck()) {
2357     return AssignEnvironment(new(zone()) LStoreGlobalCell(value,
2358                                                           TempRegister(),
2359                                                           TempRegister()));
2360   } else {
2361     return new(zone()) LStoreGlobalCell(value, TempRegister(), NULL);
2362   }
2363 }
2364
2365
2366 LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
2367   LOperand* key = UseRegisterOrConstant(instr->key());
2368   LOperand* temp = NULL;
2369   LOperand* elements = NULL;
2370   LOperand* val = NULL;
2371
2372   if (!instr->is_typed_elements() &&
2373       instr->value()->representation().IsTagged() &&
2374       instr->NeedsWriteBarrier()) {
2375     // RecordWrite() will clobber all registers.
2376     elements = UseRegisterAndClobber(instr->elements());
2377     val = UseRegisterAndClobber(instr->value());
2378     temp = TempRegister();
2379   } else {
2380     elements = UseRegister(instr->elements());
2381     val = UseRegister(instr->value());
2382     temp = instr->key()->IsConstant() ? NULL : TempRegister();
2383   }
2384
2385   if (instr->is_typed_elements()) {
2386     DCHECK((instr->value()->representation().IsInteger32() &&
2387             !IsDoubleOrFloatElementsKind(instr->elements_kind())) ||
2388            (instr->value()->representation().IsDouble() &&
2389             IsDoubleOrFloatElementsKind(instr->elements_kind())));
2390     DCHECK((instr->is_fixed_typed_array() &&
2391             instr->elements()->representation().IsTagged()) ||
2392            (instr->is_external() &&
2393             instr->elements()->representation().IsExternal()));
2394     return new(zone()) LStoreKeyedExternal(elements, key, val, temp);
2395
2396   } else if (instr->value()->representation().IsDouble()) {
2397     DCHECK(instr->elements()->representation().IsTagged());
2398     return new(zone()) LStoreKeyedFixedDouble(elements, key, val, temp);
2399
2400   } else {
2401     DCHECK(instr->elements()->representation().IsTagged());
2402     DCHECK(instr->value()->representation().IsSmiOrTagged() ||
2403            instr->value()->representation().IsInteger32());
2404     return new(zone()) LStoreKeyedFixed(elements, key, val, temp);
2405   }
2406 }
2407
2408
2409 LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
2410   LOperand* context = UseFixed(instr->context(), cp);
2411   LOperand* object =
2412       UseFixed(instr->object(), StoreDescriptor::ReceiverRegister());
2413   LOperand* key = UseFixed(instr->key(), StoreDescriptor::NameRegister());
2414   LOperand* value = UseFixed(instr->value(), StoreDescriptor::ValueRegister());
2415
2416   DCHECK(instr->object()->representation().IsTagged());
2417   DCHECK(instr->key()->representation().IsTagged());
2418   DCHECK(instr->value()->representation().IsTagged());
2419
2420   return MarkAsCall(
2421       new(zone()) LStoreKeyedGeneric(context, object, key, value), instr);
2422 }
2423
2424
2425 LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
2426   // TODO(jbramley): It might be beneficial to allow value to be a constant in
2427   // some cases. x64 makes use of this with FLAG_track_fields, for example.
2428
2429   LOperand* object = UseRegister(instr->object());
2430   LOperand* value;
2431   LOperand* temp0 = NULL;
2432   LOperand* temp1 = NULL;
2433
2434   if (instr->access().IsExternalMemory() ||
2435       (!FLAG_unbox_double_fields && instr->field_representation().IsDouble())) {
2436     value = UseRegister(instr->value());
2437   } else if (instr->NeedsWriteBarrier()) {
2438     value = UseRegisterAndClobber(instr->value());
2439     temp0 = TempRegister();
2440     temp1 = TempRegister();
2441   } else if (instr->NeedsWriteBarrierForMap()) {
2442     value = UseRegister(instr->value());
2443     temp0 = TempRegister();
2444     temp1 = TempRegister();
2445   } else {
2446     value = UseRegister(instr->value());
2447     temp0 = TempRegister();
2448   }
2449
2450   return new(zone()) LStoreNamedField(object, value, temp0, temp1);
2451 }
2452
2453
2454 LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
2455   LOperand* context = UseFixed(instr->context(), cp);
2456   LOperand* object =
2457       UseFixed(instr->object(), StoreDescriptor::ReceiverRegister());
2458   LOperand* value = UseFixed(instr->value(), StoreDescriptor::ValueRegister());
2459
2460   LInstruction* result = new(zone()) LStoreNamedGeneric(context, object, value);
2461   return MarkAsCall(result, instr);
2462 }
2463
2464
2465 LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
2466   LOperand* context = UseFixed(instr->context(), cp);
2467   LOperand* left = UseFixed(instr->left(), x1);
2468   LOperand* right = UseFixed(instr->right(), x0);
2469
2470   LStringAdd* result = new(zone()) LStringAdd(context, left, right);
2471   return MarkAsCall(DefineFixed(result, x0), instr);
2472 }
2473
2474
2475 LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
2476   LOperand* string = UseRegisterAndClobber(instr->string());
2477   LOperand* index = UseRegisterAndClobber(instr->index());
2478   LOperand* context = UseAny(instr->context());
2479   LStringCharCodeAt* result =
2480       new(zone()) LStringCharCodeAt(context, string, index);
2481   return AssignPointerMap(DefineAsRegister(result));
2482 }
2483
2484
2485 LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) {
2486   LOperand* char_code = UseRegister(instr->value());
2487   LOperand* context = UseAny(instr->context());
2488   LStringCharFromCode* result =
2489       new(zone()) LStringCharFromCode(context, char_code);
2490   return AssignPointerMap(DefineAsRegister(result));
2491 }
2492
2493
2494 LInstruction* LChunkBuilder::DoStringCompareAndBranch(
2495     HStringCompareAndBranch* instr) {
2496   DCHECK(instr->left()->representation().IsTagged());
2497   DCHECK(instr->right()->representation().IsTagged());
2498   LOperand* context = UseFixed(instr->context(), cp);
2499   LOperand* left = UseFixed(instr->left(), x1);
2500   LOperand* right = UseFixed(instr->right(), x0);
2501   LStringCompareAndBranch* result =
2502       new(zone()) LStringCompareAndBranch(context, left, right);
2503   return MarkAsCall(result, instr);
2504 }
2505
2506
2507 LInstruction* LChunkBuilder::DoSub(HSub* instr) {
2508   if (instr->representation().IsSmiOrInteger32()) {
2509     DCHECK(instr->left()->representation().Equals(instr->representation()));
2510     DCHECK(instr->right()->representation().Equals(instr->representation()));
2511
2512     LInstruction* shifted_operation = TryDoOpWithShiftedRightOperand(instr);
2513     if (shifted_operation != NULL) {
2514       return shifted_operation;
2515     }
2516
2517     LOperand *left;
2518     if (instr->left()->IsConstant() &&
2519         (HConstant::cast(instr->left())->Integer32Value() == 0)) {
2520       left = UseConstant(instr->left());
2521     } else {
2522       left = UseRegisterAtStart(instr->left());
2523     }
2524     LOperand* right = UseRegisterOrConstantAtStart(instr->right());
2525     LInstruction* result = instr->representation().IsSmi() ?
2526         DefineAsRegister(new(zone()) LSubS(left, right)) :
2527         DefineAsRegister(new(zone()) LSubI(left, right));
2528     if (instr->CheckFlag(HValue::kCanOverflow)) {
2529       result = AssignEnvironment(result);
2530     }
2531     return result;
2532   } else if (instr->representation().IsDouble()) {
2533     return DoArithmeticD(Token::SUB, instr);
2534   } else {
2535     return DoArithmeticT(Token::SUB, instr);
2536   }
2537 }
2538
2539
2540 LInstruction* LChunkBuilder::DoThisFunction(HThisFunction* instr) {
2541   if (instr->HasNoUses()) {
2542     return NULL;
2543   } else {
2544     return DefineAsRegister(new(zone()) LThisFunction);
2545   }
2546 }
2547
2548
2549 LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) {
2550   LOperand* object = UseFixed(instr->value(), x0);
2551   LToFastProperties* result = new(zone()) LToFastProperties(object);
2552   return MarkAsCall(DefineFixed(result, x0), instr);
2553 }
2554
2555
2556 LInstruction* LChunkBuilder::DoTransitionElementsKind(
2557     HTransitionElementsKind* instr) {
2558   if (IsSimpleMapChangeTransition(instr->from_kind(), instr->to_kind())) {
2559     LOperand* object = UseRegister(instr->object());
2560     LTransitionElementsKind* result =
2561         new(zone()) LTransitionElementsKind(object, NULL,
2562                                             TempRegister(), TempRegister());
2563     return result;
2564   } else {
2565     LOperand* object = UseFixed(instr->object(), x0);
2566     LOperand* context = UseFixed(instr->context(), cp);
2567     LTransitionElementsKind* result =
2568         new(zone()) LTransitionElementsKind(object, context, NULL, NULL);
2569     return MarkAsCall(result, instr);
2570   }
2571 }
2572
2573
2574 LInstruction* LChunkBuilder::DoTrapAllocationMemento(
2575     HTrapAllocationMemento* instr) {
2576   LOperand* object = UseRegister(instr->object());
2577   LOperand* temp1 = TempRegister();
2578   LOperand* temp2 = TempRegister();
2579   LTrapAllocationMemento* result =
2580       new(zone()) LTrapAllocationMemento(object, temp1, temp2);
2581   return AssignEnvironment(result);
2582 }
2583
2584
2585 LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
2586   LOperand* context = UseFixed(instr->context(), cp);
2587   // TODO(jbramley): In ARM, this uses UseFixed to force the input to x0.
2588   // However, LCodeGen::DoTypeof just pushes it to the stack (for CallRuntime)
2589   // anyway, so the input doesn't have to be in x0. We might be able to improve
2590   // the ARM back-end a little by relaxing this restriction.
2591   LTypeof* result =
2592       new(zone()) LTypeof(context, UseRegisterAtStart(instr->value()));
2593   return MarkAsCall(DefineFixed(result, x0), instr);
2594 }
2595
2596
2597 LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) {
2598   // We only need temp registers in some cases, but we can't dereference the
2599   // instr->type_literal() handle to test that here.
2600   LOperand* temp1 = TempRegister();
2601   LOperand* temp2 = TempRegister();
2602
2603   return new(zone()) LTypeofIsAndBranch(
2604       UseRegister(instr->value()), temp1, temp2);
2605 }
2606
2607
2608 LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
2609   switch (instr->op()) {
2610     case kMathAbs: {
2611       Representation r = instr->representation();
2612       if (r.IsTagged()) {
2613         // The tagged case might need to allocate a HeapNumber for the result,
2614         // so it is handled by a separate LInstruction.
2615         LOperand* context = UseFixed(instr->context(), cp);
2616         LOperand* input = UseRegister(instr->value());
2617         LOperand* temp1 = TempRegister();
2618         LOperand* temp2 = TempRegister();
2619         LOperand* temp3 = TempRegister();
2620         LInstruction* result = DefineAsRegister(
2621             new(zone()) LMathAbsTagged(context, input, temp1, temp2, temp3));
2622         return AssignEnvironment(AssignPointerMap(result));
2623       } else {
2624         LOperand* input = UseRegisterAtStart(instr->value());
2625         LInstruction* result = DefineAsRegister(new(zone()) LMathAbs(input));
2626         if (!r.IsDouble()) result = AssignEnvironment(result);
2627         return result;
2628       }
2629     }
2630     case kMathExp: {
2631       DCHECK(instr->representation().IsDouble());
2632       DCHECK(instr->value()->representation().IsDouble());
2633       LOperand* input = UseRegister(instr->value());
2634       LOperand* double_temp1 = TempDoubleRegister();
2635       LOperand* temp1 = TempRegister();
2636       LOperand* temp2 = TempRegister();
2637       LOperand* temp3 = TempRegister();
2638       LMathExp* result = new(zone()) LMathExp(input, double_temp1,
2639                                               temp1, temp2, temp3);
2640       return DefineAsRegister(result);
2641     }
2642     case kMathFloor: {
2643       DCHECK(instr->value()->representation().IsDouble());
2644       LOperand* input = UseRegisterAtStart(instr->value());
2645       if (instr->representation().IsInteger32()) {
2646         LMathFloorI* result = new(zone()) LMathFloorI(input);
2647         return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
2648       } else {
2649         DCHECK(instr->representation().IsDouble());
2650         LMathFloorD* result = new(zone()) LMathFloorD(input);
2651         return DefineAsRegister(result);
2652       }
2653     }
2654     case kMathLog: {
2655       DCHECK(instr->representation().IsDouble());
2656       DCHECK(instr->value()->representation().IsDouble());
2657       LOperand* input = UseFixedDouble(instr->value(), d0);
2658       LMathLog* result = new(zone()) LMathLog(input);
2659       return MarkAsCall(DefineFixedDouble(result, d0), instr);
2660     }
2661     case kMathPowHalf: {
2662       DCHECK(instr->representation().IsDouble());
2663       DCHECK(instr->value()->representation().IsDouble());
2664       LOperand* input = UseRegister(instr->value());
2665       return DefineAsRegister(new(zone()) LMathPowHalf(input));
2666     }
2667     case kMathRound: {
2668       DCHECK(instr->value()->representation().IsDouble());
2669       LOperand* input = UseRegister(instr->value());
2670       if (instr->representation().IsInteger32()) {
2671         LOperand* temp = TempDoubleRegister();
2672         LMathRoundI* result = new(zone()) LMathRoundI(input, temp);
2673         return AssignEnvironment(DefineAsRegister(result));
2674       } else {
2675         DCHECK(instr->representation().IsDouble());
2676         LMathRoundD* result = new(zone()) LMathRoundD(input);
2677         return DefineAsRegister(result);
2678       }
2679     }
2680     case kMathFround: {
2681       DCHECK(instr->value()->representation().IsDouble());
2682       LOperand* input = UseRegister(instr->value());
2683       LMathFround* result = new (zone()) LMathFround(input);
2684       return DefineAsRegister(result);
2685     }
2686     case kMathSqrt: {
2687       DCHECK(instr->representation().IsDouble());
2688       DCHECK(instr->value()->representation().IsDouble());
2689       LOperand* input = UseRegisterAtStart(instr->value());
2690       return DefineAsRegister(new(zone()) LMathSqrt(input));
2691     }
2692     case kMathClz32: {
2693       DCHECK(instr->representation().IsInteger32());
2694       DCHECK(instr->value()->representation().IsInteger32());
2695       LOperand* input = UseRegisterAtStart(instr->value());
2696       return DefineAsRegister(new(zone()) LMathClz32(input));
2697     }
2698     default:
2699       UNREACHABLE();
2700       return NULL;
2701   }
2702 }
2703
2704
2705 LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
2706   // Use an index that corresponds to the location in the unoptimized frame,
2707   // which the optimized frame will subsume.
2708   int env_index = instr->index();
2709   int spill_index = 0;
2710   if (instr->environment()->is_parameter_index(env_index)) {
2711     spill_index = chunk_->GetParameterStackSlot(env_index);
2712   } else {
2713     spill_index = env_index - instr->environment()->first_local_index();
2714     if (spill_index > LUnallocated::kMaxFixedSlotIndex) {
2715       Retry(kTooManySpillSlotsNeededForOSR);
2716       spill_index = 0;
2717     }
2718   }
2719   return DefineAsSpilled(new(zone()) LUnknownOSRValue, spill_index);
2720 }
2721
2722
2723 LInstruction* LChunkBuilder::DoUseConst(HUseConst* instr) {
2724   return NULL;
2725 }
2726
2727
2728 LInstruction* LChunkBuilder::DoForInPrepareMap(HForInPrepareMap* instr) {
2729   LOperand* context = UseFixed(instr->context(), cp);
2730   // Assign object to a fixed register different from those already used in
2731   // LForInPrepareMap.
2732   LOperand* object = UseFixed(instr->enumerable(), x0);
2733   LForInPrepareMap* result = new(zone()) LForInPrepareMap(context, object);
2734   return MarkAsCall(DefineFixed(result, x0), instr, CAN_DEOPTIMIZE_EAGERLY);
2735 }
2736
2737
2738 LInstruction* LChunkBuilder::DoForInCacheArray(HForInCacheArray* instr) {
2739   LOperand* map = UseRegister(instr->map());
2740   return AssignEnvironment(DefineAsRegister(new(zone()) LForInCacheArray(map)));
2741 }
2742
2743
2744 LInstruction* LChunkBuilder::DoCheckMapValue(HCheckMapValue* instr) {
2745   LOperand* value = UseRegisterAtStart(instr->value());
2746   LOperand* map = UseRegister(instr->map());
2747   LOperand* temp = TempRegister();
2748   return AssignEnvironment(new(zone()) LCheckMapValue(value, map, temp));
2749 }
2750
2751
2752 LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) {
2753   LOperand* object = UseRegisterAtStart(instr->object());
2754   LOperand* index = UseRegisterAndClobber(instr->index());
2755   LLoadFieldByIndex* load = new(zone()) LLoadFieldByIndex(object, index);
2756   LInstruction* result = DefineSameAsFirst(load);
2757   return AssignPointerMap(result);
2758 }
2759
2760
2761 LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) {
2762   LOperand* receiver = UseRegister(instr->receiver());
2763   LOperand* function = UseRegister(instr->function());
2764   LWrapReceiver* result = new(zone()) LWrapReceiver(receiver, function);
2765   return AssignEnvironment(DefineAsRegister(result));
2766 }
2767
2768
2769 LInstruction* LChunkBuilder::DoStoreFrameContext(HStoreFrameContext* instr) {
2770   LOperand* context = UseRegisterAtStart(instr->context());
2771   return new(zone()) LStoreFrameContext(context);
2772 }
2773
2774
2775 LInstruction* LChunkBuilder::DoAllocateBlockContext(
2776     HAllocateBlockContext* instr) {
2777   LOperand* context = UseFixed(instr->context(), cp);
2778   LOperand* function = UseRegisterAtStart(instr->function());
2779   LAllocateBlockContext* result =
2780       new(zone()) LAllocateBlockContext(context, function);
2781   return MarkAsCall(DefineFixed(result, cp), instr);
2782 }
2783
2784
2785 } }  // namespace v8::internal