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