1// Copyright 2014 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/crankshaft/ppc/lithium-ppc.h"
6
7#include <sstream>
8
9#include "src/crankshaft/hydrogen-osr.h"
10#include "src/crankshaft/lithium-inl.h"
11#include "src/crankshaft/ppc/lithium-codegen-ppc.h"
12
13namespace v8 {
14namespace internal {
15
16#define DEFINE_COMPILE(type)                           \
17  void L##type::CompileToNative(LCodeGen* generator) { \
18    generator->Do##type(this);                         \
19  }
20LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)
21#undef DEFINE_COMPILE
22
23#ifdef DEBUG
24void LInstruction::VerifyCall() {
25  // Call instructions can use only fixed registers as temporaries and
26  // outputs because all registers are blocked by the calling convention.
27  // Inputs operands must use a fixed register or use-at-start policy or
28  // a non-register policy.
29  DCHECK(Output() == NULL || LUnallocated::cast(Output())->HasFixedPolicy() ||
30         !LUnallocated::cast(Output())->HasRegisterPolicy());
31  for (UseIterator it(this); !it.Done(); it.Advance()) {
32    LUnallocated* operand = LUnallocated::cast(it.Current());
33    DCHECK(operand->HasFixedPolicy() || operand->IsUsedAtStart());
34  }
35  for (TempIterator it(this); !it.Done(); it.Advance()) {
36    LUnallocated* operand = LUnallocated::cast(it.Current());
37    DCHECK(operand->HasFixedPolicy() || !operand->HasRegisterPolicy());
38  }
39}
40#endif
41
42
43void LInstruction::PrintTo(StringStream* stream) {
44  stream->Add("%s ", this->Mnemonic());
45
46  PrintOutputOperandTo(stream);
47
48  PrintDataTo(stream);
49
50  if (HasEnvironment()) {
51    stream->Add(" ");
52    environment()->PrintTo(stream);
53  }
54
55  if (HasPointerMap()) {
56    stream->Add(" ");
57    pointer_map()->PrintTo(stream);
58  }
59}
60
61
62void LInstruction::PrintDataTo(StringStream* stream) {
63  stream->Add("= ");
64  for (int i = 0; i < InputCount(); i++) {
65    if (i > 0) stream->Add(" ");
66    if (InputAt(i) == NULL) {
67      stream->Add("NULL");
68    } else {
69      InputAt(i)->PrintTo(stream);
70    }
71  }
72}
73
74
75void LInstruction::PrintOutputOperandTo(StringStream* stream) {
76  if (HasResult()) result()->PrintTo(stream);
77}
78
79
80void LLabel::PrintDataTo(StringStream* stream) {
81  LGap::PrintDataTo(stream);
82  LLabel* rep = replacement();
83  if (rep != NULL) {
84    stream->Add(" Dead block replaced with B%d", rep->block_id());
85  }
86}
87
88
89bool LGap::IsRedundant() const {
90  for (int i = 0; i < 4; i++) {
91    if (parallel_moves_[i] != NULL && !parallel_moves_[i]->IsRedundant()) {
92      return false;
93    }
94  }
95
96  return true;
97}
98
99
100void LGap::PrintDataTo(StringStream* stream) {
101  for (int i = 0; i < 4; i++) {
102    stream->Add("(");
103    if (parallel_moves_[i] != NULL) {
104      parallel_moves_[i]->PrintDataTo(stream);
105    }
106    stream->Add(") ");
107  }
108}
109
110
111const char* LArithmeticD::Mnemonic() const {
112  switch (op()) {
113    case Token::ADD:
114      return "add-d";
115    case Token::SUB:
116      return "sub-d";
117    case Token::MUL:
118      return "mul-d";
119    case Token::DIV:
120      return "div-d";
121    case Token::MOD:
122      return "mod-d";
123    default:
124      UNREACHABLE();
125      return NULL;
126  }
127}
128
129
130const char* LArithmeticT::Mnemonic() const {
131  switch (op()) {
132    case Token::ADD:
133      return "add-t";
134    case Token::SUB:
135      return "sub-t";
136    case Token::MUL:
137      return "mul-t";
138    case Token::MOD:
139      return "mod-t";
140    case Token::DIV:
141      return "div-t";
142    case Token::BIT_AND:
143      return "bit-and-t";
144    case Token::BIT_OR:
145      return "bit-or-t";
146    case Token::BIT_XOR:
147      return "bit-xor-t";
148    case Token::ROR:
149      return "ror-t";
150    case Token::SHL:
151      return "shl-t";
152    case Token::SAR:
153      return "sar-t";
154    case Token::SHR:
155      return "shr-t";
156    default:
157      UNREACHABLE();
158      return NULL;
159  }
160}
161
162
163bool LGoto::HasInterestingComment(LCodeGen* gen) const {
164  return !gen->IsNextEmittedBlock(block_id());
165}
166
167
168void LGoto::PrintDataTo(StringStream* stream) {
169  stream->Add("B%d", block_id());
170}
171
172
173void LBranch::PrintDataTo(StringStream* stream) {
174  stream->Add("B%d | B%d on ", true_block_id(), false_block_id());
175  value()->PrintTo(stream);
176}
177
178
179void LCompareNumericAndBranch::PrintDataTo(StringStream* stream) {
180  stream->Add("if ");
181  left()->PrintTo(stream);
182  stream->Add(" %s ", Token::String(op()));
183  right()->PrintTo(stream);
184  stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
185}
186
187
188void LIsStringAndBranch::PrintDataTo(StringStream* stream) {
189  stream->Add("if is_string(");
190  value()->PrintTo(stream);
191  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
192}
193
194
195void LIsSmiAndBranch::PrintDataTo(StringStream* stream) {
196  stream->Add("if is_smi(");
197  value()->PrintTo(stream);
198  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
199}
200
201
202void LIsUndetectableAndBranch::PrintDataTo(StringStream* stream) {
203  stream->Add("if is_undetectable(");
204  value()->PrintTo(stream);
205  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
206}
207
208
209void LStringCompareAndBranch::PrintDataTo(StringStream* stream) {
210  stream->Add("if string_compare(");
211  left()->PrintTo(stream);
212  right()->PrintTo(stream);
213  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
214}
215
216
217void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
218  stream->Add("if has_instance_type(");
219  value()->PrintTo(stream);
220  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
221}
222
223void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
224  stream->Add("if class_of_test(");
225  value()->PrintTo(stream);
226  stream->Add(", \"%o\") then B%d else B%d", *hydrogen()->class_name(),
227              true_block_id(), false_block_id());
228}
229
230
231void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
232  stream->Add("if typeof ");
233  value()->PrintTo(stream);
234  stream->Add(" == \"%s\" then B%d else B%d",
235              hydrogen()->type_literal()->ToCString().get(), true_block_id(),
236              false_block_id());
237}
238
239
240void LStoreCodeEntry::PrintDataTo(StringStream* stream) {
241  stream->Add(" = ");
242  function()->PrintTo(stream);
243  stream->Add(".code_entry = ");
244  code_object()->PrintTo(stream);
245}
246
247
248void LInnerAllocatedObject::PrintDataTo(StringStream* stream) {
249  stream->Add(" = ");
250  base_object()->PrintTo(stream);
251  stream->Add(" + ");
252  offset()->PrintTo(stream);
253}
254
255
256void LCallWithDescriptor::PrintDataTo(StringStream* stream) {
257  for (int i = 0; i < InputCount(); i++) {
258    InputAt(i)->PrintTo(stream);
259    stream->Add(" ");
260  }
261  stream->Add("#%d / ", arity());
262}
263
264
265void LLoadContextSlot::PrintDataTo(StringStream* stream) {
266  context()->PrintTo(stream);
267  stream->Add("[%d]", slot_index());
268}
269
270
271void LStoreContextSlot::PrintDataTo(StringStream* stream) {
272  context()->PrintTo(stream);
273  stream->Add("[%d] <- ", slot_index());
274  value()->PrintTo(stream);
275}
276
277
278void LInvokeFunction::PrintDataTo(StringStream* stream) {
279  stream->Add("= ");
280  function()->PrintTo(stream);
281  stream->Add(" #%d / ", arity());
282}
283
284
285void LCallNewArray::PrintDataTo(StringStream* stream) {
286  stream->Add("= ");
287  constructor()->PrintTo(stream);
288  stream->Add(" #%d / ", arity());
289  ElementsKind kind = hydrogen()->elements_kind();
290  stream->Add(" (%s) ", ElementsKindToString(kind));
291}
292
293
294void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
295  arguments()->PrintTo(stream);
296  stream->Add(" length ");
297  length()->PrintTo(stream);
298  stream->Add(" index ");
299  index()->PrintTo(stream);
300}
301
302
303void LStoreNamedField::PrintDataTo(StringStream* stream) {
304  object()->PrintTo(stream);
305  std::ostringstream os;
306  os << hydrogen()->access() << " <- ";
307  stream->Add(os.str().c_str());
308  value()->PrintTo(stream);
309}
310
311
312void LLoadKeyed::PrintDataTo(StringStream* stream) {
313  elements()->PrintTo(stream);
314  stream->Add("[");
315  key()->PrintTo(stream);
316  if (hydrogen()->IsDehoisted()) {
317    stream->Add(" + %d]", base_offset());
318  } else {
319    stream->Add("]");
320  }
321}
322
323
324void LStoreKeyed::PrintDataTo(StringStream* stream) {
325  elements()->PrintTo(stream);
326  stream->Add("[");
327  key()->PrintTo(stream);
328  if (hydrogen()->IsDehoisted()) {
329    stream->Add(" + %d] <-", base_offset());
330  } else {
331    stream->Add("] <- ");
332  }
333
334  if (value() == NULL) {
335    DCHECK(hydrogen()->IsConstantHoleStore() &&
336           hydrogen()->value()->representation().IsDouble());
337    stream->Add("<the hole(nan)>");
338  } else {
339    value()->PrintTo(stream);
340  }
341}
342
343
344void LTransitionElementsKind::PrintDataTo(StringStream* stream) {
345  object()->PrintTo(stream);
346  stream->Add(" %p -> %p", *original_map(), *transitioned_map());
347}
348
349
350int LPlatformChunk::GetNextSpillIndex(RegisterKind kind) {
351  // Skip a slot if for a double-width slot.
352  if (kind == DOUBLE_REGISTERS) current_frame_slots_++;
353  return current_frame_slots_++;
354}
355
356
357LOperand* LPlatformChunk::GetNextSpillSlot(RegisterKind kind) {
358  int index = GetNextSpillIndex(kind);
359  if (kind == DOUBLE_REGISTERS) {
360    return LDoubleStackSlot::Create(index, zone());
361  } else {
362    DCHECK(kind == GENERAL_REGISTERS);
363    return LStackSlot::Create(index, zone());
364  }
365}
366
367
368LPlatformChunk* LChunkBuilder::Build() {
369  DCHECK(is_unused());
370  chunk_ = new (zone()) LPlatformChunk(info(), graph());
371  LPhase phase("L_Building chunk", chunk_);
372  status_ = BUILDING;
373
374  // If compiling for OSR, reserve space for the unoptimized frame,
375  // which will be subsumed into this frame.
376  if (graph()->has_osr()) {
377    for (int i = graph()->osr()->UnoptimizedFrameSlots(); i > 0; i--) {
378      chunk_->GetNextSpillIndex(GENERAL_REGISTERS);
379    }
380  }
381
382  const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
383  for (int i = 0; i < blocks->length(); i++) {
384    HBasicBlock* next = NULL;
385    if (i < blocks->length() - 1) next = blocks->at(i + 1);
386    DoBasicBlock(blocks->at(i), next);
387    if (is_aborted()) return NULL;
388  }
389  status_ = DONE;
390  return chunk_;
391}
392
393
394LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
395  return new (zone()) LUnallocated(LUnallocated::FIXED_REGISTER, reg.code());
396}
397
398
399LUnallocated* LChunkBuilder::ToUnallocated(DoubleRegister reg) {
400  return new (zone())
401      LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER, reg.code());
402}
403
404
405LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) {
406  return Use(value, ToUnallocated(fixed_register));
407}
408
409
410LOperand* LChunkBuilder::UseFixedDouble(HValue* value, DoubleRegister reg) {
411  return Use(value, ToUnallocated(reg));
412}
413
414
415LOperand* LChunkBuilder::UseRegister(HValue* value) {
416  return Use(value,
417             new (zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
418}
419
420
421LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) {
422  return Use(value, new (zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER,
423                                              LUnallocated::USED_AT_START));
424}
425
426
427LOperand* LChunkBuilder::UseTempRegister(HValue* value) {
428  return Use(value, new (zone()) LUnallocated(LUnallocated::WRITABLE_REGISTER));
429}
430
431
432LOperand* LChunkBuilder::Use(HValue* value) {
433  return Use(value, new (zone()) LUnallocated(LUnallocated::NONE));
434}
435
436
437LOperand* LChunkBuilder::UseAtStart(HValue* value) {
438  return Use(value, new (zone())
439             LUnallocated(LUnallocated::NONE, LUnallocated::USED_AT_START));
440}
441
442
443LOperand* LChunkBuilder::UseOrConstant(HValue* value) {
444  return value->IsConstant()
445             ? chunk_->DefineConstantOperand(HConstant::cast(value))
446             : Use(value);
447}
448
449
450LOperand* LChunkBuilder::UseOrConstantAtStart(HValue* value) {
451  return value->IsConstant()
452             ? chunk_->DefineConstantOperand(HConstant::cast(value))
453             : UseAtStart(value);
454}
455
456
457LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) {
458  return value->IsConstant()
459             ? chunk_->DefineConstantOperand(HConstant::cast(value))
460             : UseRegister(value);
461}
462
463
464LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) {
465  return value->IsConstant()
466             ? chunk_->DefineConstantOperand(HConstant::cast(value))
467             : UseRegisterAtStart(value);
468}
469
470
471LOperand* LChunkBuilder::UseConstant(HValue* value) {
472  return chunk_->DefineConstantOperand(HConstant::cast(value));
473}
474
475
476LOperand* LChunkBuilder::UseAny(HValue* value) {
477  return value->IsConstant()
478             ? chunk_->DefineConstantOperand(HConstant::cast(value))
479             : Use(value, new (zone()) LUnallocated(LUnallocated::ANY));
480}
481
482
483LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
484  if (value->EmitAtUses()) {
485    HInstruction* instr = HInstruction::cast(value);
486    VisitInstruction(instr);
487  }
488  operand->set_virtual_register(value->id());
489  return operand;
490}
491
492
493LInstruction* LChunkBuilder::Define(LTemplateResultInstruction<1>* instr,
494                                    LUnallocated* result) {
495  result->set_virtual_register(current_instruction_->id());
496  instr->set_result(result);
497  return instr;
498}
499
500
501LInstruction* LChunkBuilder::DefineAsRegister(
502    LTemplateResultInstruction<1>* instr) {
503  return Define(instr,
504                new (zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
505}
506
507
508LInstruction* LChunkBuilder::DefineAsSpilled(
509    LTemplateResultInstruction<1>* instr, int index) {
510  return Define(instr,
511                new (zone()) LUnallocated(LUnallocated::FIXED_SLOT, index));
512}
513
514
515LInstruction* LChunkBuilder::DefineSameAsFirst(
516    LTemplateResultInstruction<1>* instr) {
517  return Define(instr,
518                new (zone()) LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
519}
520
521
522LInstruction* LChunkBuilder::DefineFixed(LTemplateResultInstruction<1>* instr,
523                                         Register reg) {
524  return Define(instr, ToUnallocated(reg));
525}
526
527
528LInstruction* LChunkBuilder::DefineFixedDouble(
529    LTemplateResultInstruction<1>* instr, DoubleRegister reg) {
530  return Define(instr, ToUnallocated(reg));
531}
532
533
534LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
535  HEnvironment* hydrogen_env = current_block_->last_environment();
536  return LChunkBuilderBase::AssignEnvironment(instr, hydrogen_env);
537}
538
539
540LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
541                                        HInstruction* hinstr,
542                                        CanDeoptimize can_deoptimize) {
543  info()->MarkAsNonDeferredCalling();
544#ifdef DEBUG
545  instr->VerifyCall();
546#endif
547  instr->MarkAsCall();
548  instr = AssignPointerMap(instr);
549
550  // If instruction does not have side-effects lazy deoptimization
551  // after the call will try to deoptimize to the point before the call.
552  // Thus we still need to attach environment to this call even if
553  // call sequence can not deoptimize eagerly.
554  bool needs_environment = (can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) ||
555                           !hinstr->HasObservableSideEffects();
556  if (needs_environment && !instr->HasEnvironment()) {
557    instr = AssignEnvironment(instr);
558    // We can't really figure out if the environment is needed or not.
559    instr->environment()->set_has_been_used();
560  }
561
562  return instr;
563}
564
565
566LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
567  DCHECK(!instr->HasPointerMap());
568  instr->set_pointer_map(new (zone()) LPointerMap(zone()));
569  return instr;
570}
571
572
573LUnallocated* LChunkBuilder::TempRegister() {
574  LUnallocated* operand =
575      new (zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
576  int vreg = allocator_->GetVirtualRegister();
577  if (!allocator_->AllocationOk()) {
578    Abort(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister);
579    vreg = 0;
580  }
581  operand->set_virtual_register(vreg);
582  return operand;
583}
584
585
586LUnallocated* LChunkBuilder::TempDoubleRegister() {
587  LUnallocated* operand =
588      new (zone()) LUnallocated(LUnallocated::MUST_HAVE_DOUBLE_REGISTER);
589  int vreg = allocator_->GetVirtualRegister();
590  if (!allocator_->AllocationOk()) {
591    Abort(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister);
592    vreg = 0;
593  }
594  operand->set_virtual_register(vreg);
595  return operand;
596}
597
598
599LOperand* LChunkBuilder::FixedTemp(Register reg) {
600  LUnallocated* operand = ToUnallocated(reg);
601  DCHECK(operand->HasFixedPolicy());
602  return operand;
603}
604
605
606LOperand* LChunkBuilder::FixedTemp(DoubleRegister reg) {
607  LUnallocated* operand = ToUnallocated(reg);
608  DCHECK(operand->HasFixedPolicy());
609  return operand;
610}
611
612
613LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
614  return new (zone()) LLabel(instr->block());
615}
616
617
618LInstruction* LChunkBuilder::DoDummyUse(HDummyUse* instr) {
619  return DefineAsRegister(new (zone()) LDummyUse(UseAny(instr->value())));
620}
621
622
623LInstruction* LChunkBuilder::DoEnvironmentMarker(HEnvironmentMarker* instr) {
624  UNREACHABLE();
625  return NULL;
626}
627
628
629LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
630  return AssignEnvironment(new (zone()) LDeoptimize);
631}
632
633
634LInstruction* LChunkBuilder::DoShift(Token::Value op,
635                                     HBitwiseBinaryOperation* instr) {
636  if (instr->representation().IsSmiOrInteger32()) {
637    DCHECK(instr->left()->representation().Equals(instr->representation()));
638    DCHECK(instr->right()->representation().Equals(instr->representation()));
639    LOperand* left = UseRegisterAtStart(instr->left());
640
641    HValue* right_value = instr->right();
642    LOperand* right = NULL;
643    int constant_value = 0;
644    bool does_deopt = false;
645    if (right_value->IsConstant()) {
646      HConstant* constant = HConstant::cast(right_value);
647      right = chunk_->DefineConstantOperand(constant);
648      constant_value = constant->Integer32Value() & 0x1f;
649      // Left shifts can deoptimize if we shift by > 0 and the result cannot be
650      // truncated to smi.
651      if (instr->representation().IsSmi() && constant_value > 0) {
652        does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToSmi);
653      }
654    } else {
655      right = UseRegisterAtStart(right_value);
656    }
657
658    // Shift operations can only deoptimize if we do a logical shift
659    // by 0 and the result cannot be truncated to int32.
660    if (op == Token::SHR && constant_value == 0) {
661      does_deopt = !instr->CheckFlag(HInstruction::kUint32);
662    }
663
664    LInstruction* result =
665        DefineAsRegister(new (zone()) LShiftI(op, left, right, does_deopt));
666    return does_deopt ? AssignEnvironment(result) : result;
667  } else {
668    return DoArithmeticT(op, instr);
669  }
670}
671
672
673LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
674                                           HArithmeticBinaryOperation* instr) {
675  DCHECK(instr->representation().IsDouble());
676  DCHECK(instr->left()->representation().IsDouble());
677  DCHECK(instr->right()->representation().IsDouble());
678  if (op == Token::MOD) {
679    LOperand* left = UseFixedDouble(instr->left(), d1);
680    LOperand* right = UseFixedDouble(instr->right(), d2);
681    LArithmeticD* result = new (zone()) LArithmeticD(op, left, right);
682    // We call a C function for double modulo. It can't trigger a GC. We need
683    // to use fixed result register for the call.
684    // TODO(fschneider): Allow any register as input registers.
685    return MarkAsCall(DefineFixedDouble(result, d1), instr);
686  } else {
687    LOperand* left = UseRegisterAtStart(instr->left());
688    LOperand* right = UseRegisterAtStart(instr->right());
689    LArithmeticD* result = new (zone()) LArithmeticD(op, left, right);
690    return DefineAsRegister(result);
691  }
692}
693
694
695LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op,
696                                           HBinaryOperation* instr) {
697  HValue* left = instr->left();
698  HValue* right = instr->right();
699  DCHECK(left->representation().IsTagged());
700  DCHECK(right->representation().IsTagged());
701  LOperand* context = UseFixed(instr->context(), cp);
702  LOperand* left_operand = UseFixed(left, r4);
703  LOperand* right_operand = UseFixed(right, r3);
704  LArithmeticT* result =
705      new (zone()) LArithmeticT(op, context, left_operand, right_operand);
706  return MarkAsCall(DefineFixed(result, r3), instr);
707}
708
709
710void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
711  DCHECK(is_building());
712  current_block_ = block;
713  next_block_ = next_block;
714  if (block->IsStartBlock()) {
715    block->UpdateEnvironment(graph_->start_environment());
716    argument_count_ = 0;
717  } else if (block->predecessors()->length() == 1) {
718    // We have a single predecessor => copy environment and outgoing
719    // argument count from the predecessor.
720    DCHECK(block->phis()->length() == 0);
721    HBasicBlock* pred = block->predecessors()->at(0);
722    HEnvironment* last_environment = pred->last_environment();
723    DCHECK(last_environment != NULL);
724    // Only copy the environment, if it is later used again.
725    if (pred->end()->SecondSuccessor() == NULL) {
726      DCHECK(pred->end()->FirstSuccessor() == block);
727    } else {
728      if (pred->end()->FirstSuccessor()->block_id() > block->block_id() ||
729          pred->end()->SecondSuccessor()->block_id() > block->block_id()) {
730        last_environment = last_environment->Copy();
731      }
732    }
733    block->UpdateEnvironment(last_environment);
734    DCHECK(pred->argument_count() >= 0);
735    argument_count_ = pred->argument_count();
736  } else {
737    // We are at a state join => process phis.
738    HBasicBlock* pred = block->predecessors()->at(0);
739    // No need to copy the environment, it cannot be used later.
740    HEnvironment* last_environment = pred->last_environment();
741    for (int i = 0; i < block->phis()->length(); ++i) {
742      HPhi* phi = block->phis()->at(i);
743      if (phi->HasMergedIndex()) {
744        last_environment->SetValueAt(phi->merged_index(), phi);
745      }
746    }
747    for (int i = 0; i < block->deleted_phis()->length(); ++i) {
748      if (block->deleted_phis()->at(i) < last_environment->length()) {
749        last_environment->SetValueAt(block->deleted_phis()->at(i),
750                                     graph_->GetConstantUndefined());
751      }
752    }
753    block->UpdateEnvironment(last_environment);
754    // Pick up the outgoing argument count of one of the predecessors.
755    argument_count_ = pred->argument_count();
756  }
757  HInstruction* current = block->first();
758  int start = chunk_->instructions()->length();
759  while (current != NULL && !is_aborted()) {
760    // Code for constants in registers is generated lazily.
761    if (!current->EmitAtUses()) {
762      VisitInstruction(current);
763    }
764    current = current->next();
765  }
766  int end = chunk_->instructions()->length() - 1;
767  if (end >= start) {
768    block->set_first_instruction_index(start);
769    block->set_last_instruction_index(end);
770  }
771  block->set_argument_count(argument_count_);
772  next_block_ = NULL;
773  current_block_ = NULL;
774}
775
776
777void LChunkBuilder::VisitInstruction(HInstruction* current) {
778  HInstruction* old_current = current_instruction_;
779  current_instruction_ = current;
780
781  LInstruction* instr = NULL;
782  if (current->CanReplaceWithDummyUses()) {
783    if (current->OperandCount() == 0) {
784      instr = DefineAsRegister(new (zone()) LDummy());
785    } else {
786      DCHECK(!current->OperandAt(0)->IsControlInstruction());
787      instr = DefineAsRegister(new (zone())
788                               LDummyUse(UseAny(current->OperandAt(0))));
789    }
790    for (int i = 1; i < current->OperandCount(); ++i) {
791      if (current->OperandAt(i)->IsControlInstruction()) continue;
792      LInstruction* dummy =
793          new (zone()) LDummyUse(UseAny(current->OperandAt(i)));
794      dummy->set_hydrogen_value(current);
795      chunk_->AddInstruction(dummy, current_block_);
796    }
797  } else {
798    HBasicBlock* successor;
799    if (current->IsControlInstruction() &&
800        HControlInstruction::cast(current)->KnownSuccessorBlock(&successor) &&
801        successor != NULL) {
802      instr = new (zone()) LGoto(successor);
803    } else {
804      instr = current->CompileToLithium(this);
805    }
806  }
807
808  argument_count_ += current->argument_delta();
809  DCHECK(argument_count_ >= 0);
810
811  if (instr != NULL) {
812    AddInstruction(instr, current);
813  }
814
815  current_instruction_ = old_current;
816}
817
818
819void LChunkBuilder::AddInstruction(LInstruction* instr,
820                                   HInstruction* hydrogen_val) {
821  // Associate the hydrogen instruction first, since we may need it for
822  // the ClobbersRegisters() or ClobbersDoubleRegisters() calls below.
823  instr->set_hydrogen_value(hydrogen_val);
824
825#if DEBUG
826  // Make sure that the lithium instruction has either no fixed register
827  // constraints in temps or the result OR no uses that are only used at
828  // start. If this invariant doesn't hold, the register allocator can decide
829  // to insert a split of a range immediately before the instruction due to an
830  // already allocated register needing to be used for the instruction's fixed
831  // register constraint. In this case, The register allocator won't see an
832  // interference between the split child and the use-at-start (it would if
833  // the it was just a plain use), so it is free to move the split child into
834  // the same register that is used for the use-at-start.
835  // See https://code.google.com/p/chromium/issues/detail?id=201590
836  if (!(instr->ClobbersRegisters() &&
837        instr->ClobbersDoubleRegisters(isolate()))) {
838    int fixed = 0;
839    int used_at_start = 0;
840    for (UseIterator it(instr); !it.Done(); it.Advance()) {
841      LUnallocated* operand = LUnallocated::cast(it.Current());
842      if (operand->IsUsedAtStart()) ++used_at_start;
843    }
844    if (instr->Output() != NULL) {
845      if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed;
846    }
847    for (TempIterator it(instr); !it.Done(); it.Advance()) {
848      LUnallocated* operand = LUnallocated::cast(it.Current());
849      if (operand->HasFixedPolicy()) ++fixed;
850    }
851    DCHECK(fixed == 0 || used_at_start == 0);
852  }
853#endif
854
855  if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
856    instr = AssignPointerMap(instr);
857  }
858  if (FLAG_stress_environments && !instr->HasEnvironment()) {
859    instr = AssignEnvironment(instr);
860  }
861  chunk_->AddInstruction(instr, current_block_);
862
863  CreateLazyBailoutForCall(current_block_, instr, hydrogen_val);
864}
865
866
867LInstruction* LChunkBuilder::DoPrologue(HPrologue* instr) {
868  LInstruction* result = new (zone()) LPrologue();
869  if (info_->scope()->NeedsContext()) {
870    result = MarkAsCall(result, instr);
871  }
872  return result;
873}
874
875
876LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
877  return new (zone()) LGoto(instr->FirstSuccessor());
878}
879
880
881LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
882  HValue* value = instr->value();
883  Representation r = value->representation();
884  HType type = value->type();
885  ToBooleanHints expected = instr->expected_input_types();
886  if (expected == ToBooleanHint::kNone) expected = ToBooleanHint::kAny;
887
888  bool easy_case = !r.IsTagged() || type.IsBoolean() || type.IsSmi() ||
889                   type.IsJSArray() || type.IsHeapNumber() || type.IsString();
890  LInstruction* branch = new (zone()) LBranch(UseRegister(value));
891  if (!easy_case && ((!(expected & ToBooleanHint::kSmallInteger) &&
892                      (expected & ToBooleanHint::kNeedsMap)) ||
893                     expected != ToBooleanHint::kAny)) {
894    branch = AssignEnvironment(branch);
895  }
896  return branch;
897}
898
899
900LInstruction* LChunkBuilder::DoDebugBreak(HDebugBreak* instr) {
901  return new (zone()) LDebugBreak();
902}
903
904
905LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
906  DCHECK(instr->value()->representation().IsTagged());
907  LOperand* value = UseRegisterAtStart(instr->value());
908  LOperand* temp = TempRegister();
909  return new (zone()) LCmpMapAndBranch(value, temp);
910}
911
912
913LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* instr) {
914  info()->MarkAsRequiresFrame();
915  LOperand* value = UseRegister(instr->value());
916  return DefineAsRegister(new (zone()) LArgumentsLength(value));
917}
918
919
920LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
921  info()->MarkAsRequiresFrame();
922  return DefineAsRegister(new (zone()) LArgumentsElements);
923}
924
925
926LInstruction* LChunkBuilder::DoHasInPrototypeChainAndBranch(
927    HHasInPrototypeChainAndBranch* instr) {
928  LOperand* object = UseRegister(instr->object());
929  LOperand* prototype = UseRegister(instr->prototype());
930  LHasInPrototypeChainAndBranch* result =
931      new (zone()) LHasInPrototypeChainAndBranch(object, prototype);
932  return AssignEnvironment(result);
933}
934
935
936LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) {
937  LOperand* receiver = UseRegisterAtStart(instr->receiver());
938  LOperand* function = UseRegisterAtStart(instr->function());
939  LWrapReceiver* result = new (zone()) LWrapReceiver(receiver, function);
940  return AssignEnvironment(DefineAsRegister(result));
941}
942
943
944LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
945  LOperand* function = UseFixed(instr->function(), r4);
946  LOperand* receiver = UseFixed(instr->receiver(), r3);
947  LOperand* length = UseFixed(instr->length(), r5);
948  LOperand* elements = UseFixed(instr->elements(), r6);
949  LApplyArguments* result =
950      new (zone()) LApplyArguments(function, receiver, length, elements);
951  return MarkAsCall(DefineFixed(result, r3), instr, CAN_DEOPTIMIZE_EAGERLY);
952}
953
954
955LInstruction* LChunkBuilder::DoPushArguments(HPushArguments* instr) {
956  int argc = instr->OperandCount();
957  for (int i = 0; i < argc; ++i) {
958    LOperand* argument = Use(instr->argument(i));
959    AddInstruction(new (zone()) LPushArgument(argument), instr);
960  }
961  return NULL;
962}
963
964
965LInstruction* LChunkBuilder::DoStoreCodeEntry(
966    HStoreCodeEntry* store_code_entry) {
967  LOperand* function = UseRegister(store_code_entry->function());
968  LOperand* code_object = UseTempRegister(store_code_entry->code_object());
969  return new (zone()) LStoreCodeEntry(function, code_object);
970}
971
972
973LInstruction* LChunkBuilder::DoInnerAllocatedObject(
974    HInnerAllocatedObject* instr) {
975  LOperand* base_object = UseRegisterAtStart(instr->base_object());
976  LOperand* offset = UseRegisterOrConstantAtStart(instr->offset());
977  return DefineAsRegister(new (zone())
978                          LInnerAllocatedObject(base_object, offset));
979}
980
981
982LInstruction* LChunkBuilder::DoThisFunction(HThisFunction* instr) {
983  return instr->HasNoUses() ? NULL
984                            : DefineAsRegister(new (zone()) LThisFunction);
985}
986
987
988LInstruction* LChunkBuilder::DoContext(HContext* instr) {
989  if (instr->HasNoUses()) return NULL;
990
991  if (info()->IsStub()) {
992    return DefineFixed(new (zone()) LContext, cp);
993  }
994
995  return DefineAsRegister(new (zone()) LContext);
996}
997
998
999LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) {
1000  LOperand* context = UseFixed(instr->context(), cp);
1001  return MarkAsCall(new (zone()) LDeclareGlobals(context), instr);
1002}
1003
1004
1005LInstruction* LChunkBuilder::DoCallWithDescriptor(HCallWithDescriptor* instr) {
1006  CallInterfaceDescriptor descriptor = instr->descriptor();
1007  DCHECK_EQ(descriptor.GetParameterCount() +
1008                LCallWithDescriptor::kImplicitRegisterParameterCount,
1009            instr->OperandCount());
1010
1011  LOperand* target = UseRegisterOrConstantAtStart(instr->target());
1012  ZoneList<LOperand*> ops(instr->OperandCount(), zone());
1013  // Target
1014  ops.Add(target, zone());
1015  // Context
1016  LOperand* op = UseFixed(instr->OperandAt(1), cp);
1017  ops.Add(op, zone());
1018  // Load register parameters.
1019  int i = 0;
1020  for (; i < descriptor.GetRegisterParameterCount(); i++) {
1021    op = UseFixed(instr->OperandAt(
1022                      i + LCallWithDescriptor::kImplicitRegisterParameterCount),
1023                  descriptor.GetRegisterParameter(i));
1024    ops.Add(op, zone());
1025  }
1026  // Push stack parameters.
1027  for (; i < descriptor.GetParameterCount(); i++) {
1028    op = UseAny(instr->OperandAt(
1029        i + LCallWithDescriptor::kImplicitRegisterParameterCount));
1030    AddInstruction(new (zone()) LPushArgument(op), instr);
1031  }
1032
1033  LCallWithDescriptor* result =
1034      new (zone()) LCallWithDescriptor(descriptor, ops, zone());
1035  if (instr->syntactic_tail_call_mode() == TailCallMode::kAllow) {
1036    result->MarkAsSyntacticTailCall();
1037  }
1038  return MarkAsCall(DefineFixed(result, r3), instr);
1039}
1040
1041
1042LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
1043  LOperand* context = UseFixed(instr->context(), cp);
1044  LOperand* function = UseFixed(instr->function(), r4);
1045  LInvokeFunction* result = new (zone()) LInvokeFunction(context, function);
1046  if (instr->syntactic_tail_call_mode() == TailCallMode::kAllow) {
1047    result->MarkAsSyntacticTailCall();
1048  }
1049  return MarkAsCall(DefineFixed(result, r3), instr, CANNOT_DEOPTIMIZE_EAGERLY);
1050}
1051
1052
1053LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
1054  switch (instr->op()) {
1055    case kMathFloor:
1056      return DoMathFloor(instr);
1057    case kMathRound:
1058      return DoMathRound(instr);
1059    case kMathFround:
1060      return DoMathFround(instr);
1061    case kMathAbs:
1062      return DoMathAbs(instr);
1063    case kMathLog:
1064      return DoMathLog(instr);
1065    case kMathCos:
1066      return DoMathCos(instr);
1067    case kMathSin:
1068      return DoMathSin(instr);
1069    case kMathExp:
1070      return DoMathExp(instr);
1071    case kMathSqrt:
1072      return DoMathSqrt(instr);
1073    case kMathPowHalf:
1074      return DoMathPowHalf(instr);
1075    case kMathClz32:
1076      return DoMathClz32(instr);
1077    default:
1078      UNREACHABLE();
1079      return NULL;
1080  }
1081}
1082
1083
1084LInstruction* LChunkBuilder::DoMathFloor(HUnaryMathOperation* instr) {
1085  DCHECK(instr->value()->representation().IsDouble());
1086  LOperand* input = UseRegister(instr->value());
1087  if (instr->representation().IsInteger32()) {
1088    LMathFloorI* result = new (zone()) LMathFloorI(input);
1089    return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
1090  } else {
1091    DCHECK(instr->representation().IsDouble());
1092    LMathFloorD* result = new (zone()) LMathFloorD(input);
1093    return DefineAsRegister(result);
1094  }
1095}
1096
1097LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) {
1098  DCHECK(instr->value()->representation().IsDouble());
1099  LOperand* input = UseRegister(instr->value());
1100  if (instr->representation().IsInteger32()) {
1101    LOperand* temp = TempDoubleRegister();
1102    LMathRoundI* result = new (zone()) LMathRoundI(input, temp);
1103    return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
1104  } else {
1105    DCHECK(instr->representation().IsDouble());
1106    LMathRoundD* result = new (zone()) LMathRoundD(input);
1107    return DefineAsRegister(result);
1108  }
1109}
1110
1111LInstruction* LChunkBuilder::DoMathFround(HUnaryMathOperation* instr) {
1112  LOperand* input = UseRegister(instr->value());
1113  LMathFround* result = new (zone()) LMathFround(input);
1114  return DefineAsRegister(result);
1115}
1116
1117
1118LInstruction* LChunkBuilder::DoMathAbs(HUnaryMathOperation* instr) {
1119  Representation r = instr->value()->representation();
1120  LOperand* context = (r.IsDouble() || r.IsSmiOrInteger32())
1121                          ? NULL
1122                          : UseFixed(instr->context(), cp);
1123  LOperand* input = UseRegister(instr->value());
1124  LInstruction* result =
1125      DefineAsRegister(new (zone()) LMathAbs(context, input));
1126  if (!r.IsDouble() && !r.IsSmiOrInteger32()) result = AssignPointerMap(result);
1127  if (!r.IsDouble()) result = AssignEnvironment(result);
1128  return result;
1129}
1130
1131
1132LInstruction* LChunkBuilder::DoMathLog(HUnaryMathOperation* instr) {
1133  DCHECK(instr->representation().IsDouble());
1134  DCHECK(instr->value()->representation().IsDouble());
1135  LOperand* input = UseFixedDouble(instr->value(), d0);
1136  return MarkAsCall(DefineFixedDouble(new (zone()) LMathLog(input), d0), instr);
1137}
1138
1139
1140LInstruction* LChunkBuilder::DoMathClz32(HUnaryMathOperation* instr) {
1141  LOperand* input = UseRegisterAtStart(instr->value());
1142  LMathClz32* result = new (zone()) LMathClz32(input);
1143  return DefineAsRegister(result);
1144}
1145
1146LInstruction* LChunkBuilder::DoMathCos(HUnaryMathOperation* instr) {
1147  DCHECK(instr->representation().IsDouble());
1148  DCHECK(instr->value()->representation().IsDouble());
1149  LOperand* input = UseFixedDouble(instr->value(), d0);
1150  return MarkAsCall(DefineFixedDouble(new (zone()) LMathCos(input), d0), instr);
1151}
1152
1153LInstruction* LChunkBuilder::DoMathSin(HUnaryMathOperation* instr) {
1154  DCHECK(instr->representation().IsDouble());
1155  DCHECK(instr->value()->representation().IsDouble());
1156  LOperand* input = UseFixedDouble(instr->value(), d0);
1157  return MarkAsCall(DefineFixedDouble(new (zone()) LMathSin(input), d0), instr);
1158}
1159
1160LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
1161  DCHECK(instr->representation().IsDouble());
1162  DCHECK(instr->value()->representation().IsDouble());
1163  LOperand* input = UseFixedDouble(instr->value(), d0);
1164  return MarkAsCall(DefineFixedDouble(new (zone()) LMathExp(input), d0), instr);
1165}
1166
1167
1168LInstruction* LChunkBuilder::DoMathSqrt(HUnaryMathOperation* instr) {
1169  LOperand* input = UseRegisterAtStart(instr->value());
1170  LMathSqrt* result = new (zone()) LMathSqrt(input);
1171  return DefineAsRegister(result);
1172}
1173
1174
1175LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
1176  LOperand* input = UseRegisterAtStart(instr->value());
1177  LMathPowHalf* result = new (zone()) LMathPowHalf(input);
1178  return DefineAsRegister(result);
1179}
1180
1181
1182LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) {
1183  LOperand* context = UseFixed(instr->context(), cp);
1184  LOperand* constructor = UseFixed(instr->constructor(), r4);
1185  LCallNewArray* result = new (zone()) LCallNewArray(context, constructor);
1186  return MarkAsCall(DefineFixed(result, r3), instr);
1187}
1188
1189
1190LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
1191  LOperand* context = UseFixed(instr->context(), cp);
1192  return MarkAsCall(DefineFixed(new (zone()) LCallRuntime(context), r3), instr);
1193}
1194
1195
1196LInstruction* LChunkBuilder::DoRor(HRor* instr) {
1197  return DoShift(Token::ROR, instr);
1198}
1199
1200
1201LInstruction* LChunkBuilder::DoShr(HShr* instr) {
1202  return DoShift(Token::SHR, instr);
1203}
1204
1205
1206LInstruction* LChunkBuilder::DoSar(HSar* instr) {
1207  return DoShift(Token::SAR, instr);
1208}
1209
1210
1211LInstruction* LChunkBuilder::DoShl(HShl* instr) {
1212  return DoShift(Token::SHL, instr);
1213}
1214
1215
1216LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
1217  if (instr->representation().IsSmiOrInteger32()) {
1218    DCHECK(instr->left()->representation().Equals(instr->representation()));
1219    DCHECK(instr->right()->representation().Equals(instr->representation()));
1220    DCHECK(instr->CheckFlag(HValue::kTruncatingToInt32));
1221
1222    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1223    LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
1224    return DefineAsRegister(new (zone()) LBitI(left, right));
1225  } else {
1226    return DoArithmeticT(instr->op(), instr);
1227  }
1228}
1229
1230
1231LInstruction* LChunkBuilder::DoDivByPowerOf2I(HDiv* instr) {
1232  DCHECK(instr->representation().IsSmiOrInteger32());
1233  DCHECK(instr->left()->representation().Equals(instr->representation()));
1234  DCHECK(instr->right()->representation().Equals(instr->representation()));
1235  LOperand* dividend = UseRegister(instr->left());
1236  int32_t divisor = instr->right()->GetInteger32Constant();
1237  LInstruction* result =
1238      DefineAsRegister(new (zone()) LDivByPowerOf2I(dividend, divisor));
1239  if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
1240      (instr->CheckFlag(HValue::kCanOverflow) && divisor == -1) ||
1241      (!instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
1242       divisor != 1 && divisor != -1)) {
1243    result = AssignEnvironment(result);
1244  }
1245  return result;
1246}
1247
1248
1249LInstruction* LChunkBuilder::DoDivByConstI(HDiv* instr) {
1250  DCHECK(instr->representation().IsInteger32());
1251  DCHECK(instr->left()->representation().Equals(instr->representation()));
1252  DCHECK(instr->right()->representation().Equals(instr->representation()));
1253  LOperand* dividend = UseRegister(instr->left());
1254  int32_t divisor = instr->right()->GetInteger32Constant();
1255  LInstruction* result =
1256      DefineAsRegister(new (zone()) LDivByConstI(dividend, divisor));
1257  if (divisor == 0 ||
1258      (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
1259      !instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
1260    result = AssignEnvironment(result);
1261  }
1262  return result;
1263}
1264
1265
1266LInstruction* LChunkBuilder::DoDivI(HDiv* instr) {
1267  DCHECK(instr->representation().IsSmiOrInteger32());
1268  DCHECK(instr->left()->representation().Equals(instr->representation()));
1269  DCHECK(instr->right()->representation().Equals(instr->representation()));
1270  LOperand* dividend = UseRegister(instr->left());
1271  LOperand* divisor = UseRegister(instr->right());
1272  LInstruction* result =
1273      DefineAsRegister(new (zone()) LDivI(dividend, divisor));
1274  if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
1275      instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
1276      (instr->CheckFlag(HValue::kCanOverflow) &&
1277       !instr->CheckFlag(HValue::kAllUsesTruncatingToInt32)) ||
1278      (!instr->IsMathFloorOfDiv() &&
1279       !instr->CheckFlag(HValue::kAllUsesTruncatingToInt32))) {
1280    result = AssignEnvironment(result);
1281  }
1282  return result;
1283}
1284
1285
1286LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
1287  if (instr->representation().IsSmiOrInteger32()) {
1288    if (instr->RightIsPowerOf2()) {
1289      return DoDivByPowerOf2I(instr);
1290    } else if (instr->right()->IsConstant()) {
1291      return DoDivByConstI(instr);
1292    } else {
1293      return DoDivI(instr);
1294    }
1295  } else if (instr->representation().IsDouble()) {
1296    return DoArithmeticD(Token::DIV, instr);
1297  } else {
1298    return DoArithmeticT(Token::DIV, instr);
1299  }
1300}
1301
1302
1303LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
1304  LOperand* dividend = UseRegisterAtStart(instr->left());
1305  int32_t divisor = instr->right()->GetInteger32Constant();
1306  LInstruction* result =
1307      DefineAsRegister(new (zone()) LFlooringDivByPowerOf2I(dividend, divisor));
1308  if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
1309      (instr->CheckFlag(HValue::kLeftCanBeMinInt) && divisor == -1)) {
1310    result = AssignEnvironment(result);
1311  }
1312  return result;
1313}
1314
1315
1316LInstruction* LChunkBuilder::DoFlooringDivByConstI(HMathFloorOfDiv* instr) {
1317  DCHECK(instr->representation().IsInteger32());
1318  DCHECK(instr->left()->representation().Equals(instr->representation()));
1319  DCHECK(instr->right()->representation().Equals(instr->representation()));
1320  LOperand* dividend = UseRegister(instr->left());
1321  int32_t divisor = instr->right()->GetInteger32Constant();
1322  LOperand* temp =
1323      ((divisor > 0 && !instr->CheckFlag(HValue::kLeftCanBeNegative)) ||
1324       (divisor < 0 && !instr->CheckFlag(HValue::kLeftCanBePositive)))
1325          ? NULL
1326          : TempRegister();
1327  LInstruction* result = DefineAsRegister(
1328      new (zone()) LFlooringDivByConstI(dividend, divisor, temp));
1329  if (divisor == 0 ||
1330      (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0)) {
1331    result = AssignEnvironment(result);
1332  }
1333  return result;
1334}
1335
1336
1337LInstruction* LChunkBuilder::DoFlooringDivI(HMathFloorOfDiv* instr) {
1338  DCHECK(instr->representation().IsSmiOrInteger32());
1339  DCHECK(instr->left()->representation().Equals(instr->representation()));
1340  DCHECK(instr->right()->representation().Equals(instr->representation()));
1341  LOperand* dividend = UseRegister(instr->left());
1342  LOperand* divisor = UseRegister(instr->right());
1343  LInstruction* result =
1344      DefineAsRegister(new (zone()) LFlooringDivI(dividend, divisor));
1345  if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
1346      instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
1347      (instr->CheckFlag(HValue::kCanOverflow) &&
1348       !instr->CheckFlag(HValue::kAllUsesTruncatingToInt32))) {
1349    result = AssignEnvironment(result);
1350  }
1351  return result;
1352}
1353
1354
1355LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
1356  if (instr->RightIsPowerOf2()) {
1357    return DoFlooringDivByPowerOf2I(instr);
1358  } else if (instr->right()->IsConstant()) {
1359    return DoFlooringDivByConstI(instr);
1360  } else {
1361    return DoFlooringDivI(instr);
1362  }
1363}
1364
1365
1366LInstruction* LChunkBuilder::DoModByPowerOf2I(HMod* instr) {
1367  DCHECK(instr->representation().IsSmiOrInteger32());
1368  DCHECK(instr->left()->representation().Equals(instr->representation()));
1369  DCHECK(instr->right()->representation().Equals(instr->representation()));
1370  LOperand* dividend = UseRegisterAtStart(instr->left());
1371  int32_t divisor = instr->right()->GetInteger32Constant();
1372  LInstruction* result =
1373      DefineSameAsFirst(new (zone()) LModByPowerOf2I(dividend, divisor));
1374  if (instr->CheckFlag(HValue::kLeftCanBeNegative) &&
1375      instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1376    result = AssignEnvironment(result);
1377  }
1378  return result;
1379}
1380
1381
1382LInstruction* LChunkBuilder::DoModByConstI(HMod* instr) {
1383  DCHECK(instr->representation().IsSmiOrInteger32());
1384  DCHECK(instr->left()->representation().Equals(instr->representation()));
1385  DCHECK(instr->right()->representation().Equals(instr->representation()));
1386  LOperand* dividend = UseRegister(instr->left());
1387  int32_t divisor = instr->right()->GetInteger32Constant();
1388  LInstruction* result =
1389      DefineAsRegister(new (zone()) LModByConstI(dividend, divisor));
1390  if (divisor == 0 || instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1391    result = AssignEnvironment(result);
1392  }
1393  return result;
1394}
1395
1396
1397LInstruction* LChunkBuilder::DoModI(HMod* instr) {
1398  DCHECK(instr->representation().IsSmiOrInteger32());
1399  DCHECK(instr->left()->representation().Equals(instr->representation()));
1400  DCHECK(instr->right()->representation().Equals(instr->representation()));
1401  LOperand* dividend = UseRegister(instr->left());
1402  LOperand* divisor = UseRegister(instr->right());
1403  LInstruction* result =
1404      DefineAsRegister(new (zone()) LModI(dividend, divisor));
1405  if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
1406      instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1407    result = AssignEnvironment(result);
1408  }
1409  return result;
1410}
1411
1412
1413LInstruction* LChunkBuilder::DoMod(HMod* instr) {
1414  if (instr->representation().IsSmiOrInteger32()) {
1415    if (instr->RightIsPowerOf2()) {
1416      return DoModByPowerOf2I(instr);
1417    } else if (instr->right()->IsConstant()) {
1418      return DoModByConstI(instr);
1419    } else {
1420      return DoModI(instr);
1421    }
1422  } else if (instr->representation().IsDouble()) {
1423    return DoArithmeticD(Token::MOD, instr);
1424  } else {
1425    return DoArithmeticT(Token::MOD, instr);
1426  }
1427}
1428
1429
1430LInstruction* LChunkBuilder::DoMul(HMul* instr) {
1431  if (instr->representation().IsSmiOrInteger32()) {
1432    DCHECK(instr->left()->representation().Equals(instr->representation()));
1433    DCHECK(instr->right()->representation().Equals(instr->representation()));
1434    HValue* left = instr->BetterLeftOperand();
1435    HValue* right = instr->BetterRightOperand();
1436    LOperand* left_op;
1437    LOperand* right_op;
1438    bool can_overflow = instr->CheckFlag(HValue::kCanOverflow);
1439    bool bailout_on_minus_zero = instr->CheckFlag(HValue::kBailoutOnMinusZero);
1440
1441    int32_t constant_value = 0;
1442    if (right->IsConstant()) {
1443      HConstant* constant = HConstant::cast(right);
1444      constant_value = constant->Integer32Value();
1445      // Constants -1, 0 and 1 can be optimized if the result can overflow.
1446      // For other constants, it can be optimized only without overflow.
1447      if (!can_overflow || ((constant_value >= -1) && (constant_value <= 1))) {
1448        left_op = UseRegisterAtStart(left);
1449        right_op = UseConstant(right);
1450      } else {
1451        if (bailout_on_minus_zero) {
1452          left_op = UseRegister(left);
1453        } else {
1454          left_op = UseRegisterAtStart(left);
1455        }
1456        right_op = UseRegister(right);
1457      }
1458    } else {
1459      if (bailout_on_minus_zero) {
1460        left_op = UseRegister(left);
1461      } else {
1462        left_op = UseRegisterAtStart(left);
1463      }
1464      right_op = UseRegister(right);
1465    }
1466    LMulI* mul = new (zone()) LMulI(left_op, right_op);
1467    if (right_op->IsConstantOperand()
1468            ? ((can_overflow && constant_value == -1) ||
1469               (bailout_on_minus_zero && constant_value <= 0))
1470            : (can_overflow || bailout_on_minus_zero)) {
1471      AssignEnvironment(mul);
1472    }
1473    return DefineAsRegister(mul);
1474
1475  } else if (instr->representation().IsDouble()) {
1476    return DoArithmeticD(Token::MUL, instr);
1477  } else {
1478    return DoArithmeticT(Token::MUL, instr);
1479  }
1480}
1481
1482
1483LInstruction* LChunkBuilder::DoSub(HSub* instr) {
1484  if (instr->representation().IsSmiOrInteger32()) {
1485    DCHECK(instr->left()->representation().Equals(instr->representation()));
1486    DCHECK(instr->right()->representation().Equals(instr->representation()));
1487
1488    if (instr->left()->IsConstant() &&
1489        !instr->CheckFlag(HValue::kCanOverflow)) {
1490      // If lhs is constant, do reverse subtraction instead.
1491      return DoRSub(instr);
1492    }
1493
1494    LOperand* left = UseRegisterAtStart(instr->left());
1495    LOperand* right = UseOrConstantAtStart(instr->right());
1496    LSubI* sub = new (zone()) LSubI(left, right);
1497    LInstruction* result = DefineAsRegister(sub);
1498    if (instr->CheckFlag(HValue::kCanOverflow)) {
1499      result = AssignEnvironment(result);
1500    }
1501    return result;
1502  } else if (instr->representation().IsDouble()) {
1503    return DoArithmeticD(Token::SUB, instr);
1504  } else {
1505    return DoArithmeticT(Token::SUB, instr);
1506  }
1507}
1508
1509
1510LInstruction* LChunkBuilder::DoRSub(HSub* instr) {
1511  DCHECK(instr->representation().IsSmiOrInteger32());
1512  DCHECK(instr->left()->representation().Equals(instr->representation()));
1513  DCHECK(instr->right()->representation().Equals(instr->representation()));
1514  DCHECK(!instr->CheckFlag(HValue::kCanOverflow));
1515
1516  // Note: The lhs of the subtraction becomes the rhs of the
1517  // reverse-subtraction.
1518  LOperand* left = UseRegisterAtStart(instr->right());
1519  LOperand* right = UseOrConstantAtStart(instr->left());
1520  LRSubI* rsb = new (zone()) LRSubI(left, right);
1521  LInstruction* result = DefineAsRegister(rsb);
1522  return result;
1523}
1524
1525
1526LInstruction* LChunkBuilder::DoMultiplyAdd(HMul* mul, HValue* addend) {
1527  LOperand* multiplier_op = UseRegisterAtStart(mul->left());
1528  LOperand* multiplicand_op = UseRegisterAtStart(mul->right());
1529  LOperand* addend_op = UseRegisterAtStart(addend);
1530  return DefineSameAsFirst(
1531      new (zone()) LMultiplyAddD(addend_op, multiplier_op, multiplicand_op));
1532}
1533
1534
1535LInstruction* LChunkBuilder::DoMultiplySub(HValue* minuend, HMul* mul) {
1536  LOperand* minuend_op = UseRegisterAtStart(minuend);
1537  LOperand* multiplier_op = UseRegisterAtStart(mul->left());
1538  LOperand* multiplicand_op = UseRegisterAtStart(mul->right());
1539
1540  return DefineSameAsFirst(
1541      new (zone()) LMultiplySubD(minuend_op, multiplier_op, multiplicand_op));
1542}
1543
1544
1545LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
1546  if (instr->representation().IsSmiOrInteger32()) {
1547    DCHECK(instr->left()->representation().Equals(instr->representation()));
1548    DCHECK(instr->right()->representation().Equals(instr->representation()));
1549    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1550    LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
1551    LAddI* add = new (zone()) LAddI(left, right);
1552    LInstruction* result = DefineAsRegister(add);
1553    if (instr->CheckFlag(HValue::kCanOverflow)) {
1554      result = AssignEnvironment(result);
1555    }
1556    return result;
1557  } else if (instr->representation().IsExternal()) {
1558    DCHECK(instr->IsConsistentExternalRepresentation());
1559    DCHECK(!instr->CheckFlag(HValue::kCanOverflow));
1560    LOperand* left = UseRegisterAtStart(instr->left());
1561    LOperand* right = UseOrConstantAtStart(instr->right());
1562    LAddI* add = new (zone()) LAddI(left, right);
1563    LInstruction* result = DefineAsRegister(add);
1564    return result;
1565  } else if (instr->representation().IsDouble()) {
1566    return DoArithmeticD(Token::ADD, instr);
1567  } else {
1568    return DoArithmeticT(Token::ADD, instr);
1569  }
1570}
1571
1572
1573LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
1574  LOperand* left = NULL;
1575  LOperand* right = NULL;
1576  if (instr->representation().IsSmiOrInteger32()) {
1577    DCHECK(instr->left()->representation().Equals(instr->representation()));
1578    DCHECK(instr->right()->representation().Equals(instr->representation()));
1579    left = UseRegisterAtStart(instr->BetterLeftOperand());
1580    right = UseOrConstantAtStart(instr->BetterRightOperand());
1581  } else {
1582    DCHECK(instr->representation().IsDouble());
1583    DCHECK(instr->left()->representation().IsDouble());
1584    DCHECK(instr->right()->representation().IsDouble());
1585    left = UseRegisterAtStart(instr->left());
1586    right = UseRegisterAtStart(instr->right());
1587  }
1588  return DefineAsRegister(new (zone()) LMathMinMax(left, right));
1589}
1590
1591
1592LInstruction* LChunkBuilder::DoPower(HPower* instr) {
1593  DCHECK(instr->representation().IsDouble());
1594  // We call a C function for double power. It can't trigger a GC.
1595  // We need to use fixed result register for the call.
1596  Representation exponent_type = instr->right()->representation();
1597  DCHECK(instr->left()->representation().IsDouble());
1598  LOperand* left = UseFixedDouble(instr->left(), d1);
1599  LOperand* right =
1600      exponent_type.IsDouble()
1601          ? UseFixedDouble(instr->right(), d2)
1602          : UseFixed(instr->right(), MathPowTaggedDescriptor::exponent());
1603  LPower* result = new (zone()) LPower(left, right);
1604  return MarkAsCall(DefineFixedDouble(result, d3), instr,
1605                    CAN_DEOPTIMIZE_EAGERLY);
1606}
1607
1608
1609LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
1610  DCHECK(instr->left()->representation().IsTagged());
1611  DCHECK(instr->right()->representation().IsTagged());
1612  LOperand* context = UseFixed(instr->context(), cp);
1613  LOperand* left = UseFixed(instr->left(), r4);
1614  LOperand* right = UseFixed(instr->right(), r3);
1615  LCmpT* result = new (zone()) LCmpT(context, left, right);
1616  return MarkAsCall(DefineFixed(result, r3), instr);
1617}
1618
1619
1620LInstruction* LChunkBuilder::DoCompareNumericAndBranch(
1621    HCompareNumericAndBranch* instr) {
1622  Representation r = instr->representation();
1623  if (r.IsSmiOrInteger32()) {
1624    DCHECK(instr->left()->representation().Equals(r));
1625    DCHECK(instr->right()->representation().Equals(r));
1626    LOperand* left = UseRegisterOrConstantAtStart(instr->left());
1627    LOperand* right = UseRegisterOrConstantAtStart(instr->right());
1628    return new (zone()) LCompareNumericAndBranch(left, right);
1629  } else {
1630    DCHECK(r.IsDouble());
1631    DCHECK(instr->left()->representation().IsDouble());
1632    DCHECK(instr->right()->representation().IsDouble());
1633    LOperand* left = UseRegisterAtStart(instr->left());
1634    LOperand* right = UseRegisterAtStart(instr->right());
1635    return new (zone()) LCompareNumericAndBranch(left, right);
1636  }
1637}
1638
1639
1640LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch(
1641    HCompareObjectEqAndBranch* instr) {
1642  LOperand* left = UseRegisterAtStart(instr->left());
1643  LOperand* right = UseRegisterAtStart(instr->right());
1644  return new (zone()) LCmpObjectEqAndBranch(left, right);
1645}
1646
1647
1648LInstruction* LChunkBuilder::DoCompareHoleAndBranch(
1649    HCompareHoleAndBranch* instr) {
1650  LOperand* value = UseRegisterAtStart(instr->value());
1651  return new (zone()) LCmpHoleAndBranch(value);
1652}
1653
1654
1655LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
1656  DCHECK(instr->value()->representation().IsTagged());
1657  LOperand* value = UseRegisterAtStart(instr->value());
1658  LOperand* temp = TempRegister();
1659  return new (zone()) LIsStringAndBranch(value, temp);
1660}
1661
1662
1663LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
1664  DCHECK(instr->value()->representation().IsTagged());
1665  return new (zone()) LIsSmiAndBranch(Use(instr->value()));
1666}
1667
1668
1669LInstruction* LChunkBuilder::DoIsUndetectableAndBranch(
1670    HIsUndetectableAndBranch* instr) {
1671  DCHECK(instr->value()->representation().IsTagged());
1672  LOperand* value = UseRegisterAtStart(instr->value());
1673  return new (zone()) LIsUndetectableAndBranch(value, TempRegister());
1674}
1675
1676
1677LInstruction* LChunkBuilder::DoStringCompareAndBranch(
1678    HStringCompareAndBranch* instr) {
1679  DCHECK(instr->left()->representation().IsTagged());
1680  DCHECK(instr->right()->representation().IsTagged());
1681  LOperand* context = UseFixed(instr->context(), cp);
1682  LOperand* left = UseFixed(instr->left(), r4);
1683  LOperand* right = UseFixed(instr->right(), r3);
1684  LStringCompareAndBranch* result =
1685      new (zone()) LStringCompareAndBranch(context, left, right);
1686  return MarkAsCall(result, instr);
1687}
1688
1689
1690LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
1691    HHasInstanceTypeAndBranch* instr) {
1692  DCHECK(instr->value()->representation().IsTagged());
1693  LOperand* value = UseRegisterAtStart(instr->value());
1694  return new (zone()) LHasInstanceTypeAndBranch(value);
1695}
1696
1697LInstruction* LChunkBuilder::DoClassOfTestAndBranch(
1698    HClassOfTestAndBranch* instr) {
1699  DCHECK(instr->value()->representation().IsTagged());
1700  LOperand* value = UseRegister(instr->value());
1701  return new (zone()) LClassOfTestAndBranch(value, TempRegister());
1702}
1703
1704
1705LInstruction* LChunkBuilder::DoSeqStringGetChar(HSeqStringGetChar* instr) {
1706  LOperand* string = UseRegisterAtStart(instr->string());
1707  LOperand* index = UseRegisterOrConstantAtStart(instr->index());
1708  return DefineAsRegister(new (zone()) LSeqStringGetChar(string, index));
1709}
1710
1711
1712LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
1713  LOperand* string = UseRegisterAtStart(instr->string());
1714  LOperand* index = FLAG_debug_code
1715                        ? UseRegisterAtStart(instr->index())
1716                        : UseRegisterOrConstantAtStart(instr->index());
1717  LOperand* value = UseRegisterAtStart(instr->value());
1718  LOperand* context = FLAG_debug_code ? UseFixed(instr->context(), cp) : NULL;
1719  return new (zone()) LSeqStringSetChar(context, string, index, value);
1720}
1721
1722
1723LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
1724  if (!FLAG_debug_code && instr->skip_check()) return NULL;
1725  LOperand* index = UseRegisterOrConstantAtStart(instr->index());
1726  LOperand* length = !index->IsConstantOperand()
1727                         ? UseRegisterOrConstantAtStart(instr->length())
1728                         : UseRegisterAtStart(instr->length());
1729  LInstruction* result = new (zone()) LBoundsCheck(index, length);
1730  if (!FLAG_debug_code || !instr->skip_check()) {
1731    result = AssignEnvironment(result);
1732  }
1733  return result;
1734}
1735
1736
1737LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
1738  // The control instruction marking the end of a block that completed
1739  // abruptly (e.g., threw an exception).  There is nothing specific to do.
1740  return NULL;
1741}
1742
1743
1744LInstruction* LChunkBuilder::DoUseConst(HUseConst* instr) { return NULL; }
1745
1746
1747LInstruction* LChunkBuilder::DoForceRepresentation(HForceRepresentation* bad) {
1748  // All HForceRepresentation instructions should be eliminated in the
1749  // representation change phase of Hydrogen.
1750  UNREACHABLE();
1751  return NULL;
1752}
1753
1754
1755LInstruction* LChunkBuilder::DoChange(HChange* instr) {
1756  Representation from = instr->from();
1757  Representation to = instr->to();
1758  HValue* val = instr->value();
1759  if (from.IsSmi()) {
1760    if (to.IsTagged()) {
1761      LOperand* value = UseRegister(val);
1762      return DefineSameAsFirst(new (zone()) LDummyUse(value));
1763    }
1764    from = Representation::Tagged();
1765  }
1766  if (from.IsTagged()) {
1767    if (to.IsDouble()) {
1768      LOperand* value = UseRegister(val);
1769      LInstruction* result =
1770          DefineAsRegister(new (zone()) LNumberUntagD(value));
1771      if (!val->representation().IsSmi()) result = AssignEnvironment(result);
1772      return result;
1773    } else if (to.IsSmi()) {
1774      LOperand* value = UseRegister(val);
1775      if (val->type().IsSmi()) {
1776        return DefineSameAsFirst(new (zone()) LDummyUse(value));
1777      }
1778      return AssignEnvironment(
1779          DefineSameAsFirst(new (zone()) LCheckSmi(value)));
1780    } else {
1781      DCHECK(to.IsInteger32());
1782      if (val->type().IsSmi() || val->representation().IsSmi()) {
1783        LOperand* value = UseRegisterAtStart(val);
1784        return DefineAsRegister(new (zone()) LSmiUntag(value, false));
1785      } else {
1786        LOperand* value = UseRegister(val);
1787        LOperand* temp1 = TempRegister();
1788        LOperand* temp2 = TempDoubleRegister();
1789        LInstruction* result =
1790            DefineSameAsFirst(new (zone()) LTaggedToI(value, temp1, temp2));
1791        if (!val->representation().IsSmi()) result = AssignEnvironment(result);
1792        return result;
1793      }
1794    }
1795  } else if (from.IsDouble()) {
1796    if (to.IsTagged()) {
1797      info()->MarkAsDeferredCalling();
1798      LOperand* value = UseRegister(val);
1799      LOperand* temp1 = TempRegister();
1800      LOperand* temp2 = TempRegister();
1801      LUnallocated* result_temp = TempRegister();
1802      LNumberTagD* result = new (zone()) LNumberTagD(value, temp1, temp2);
1803      return AssignPointerMap(Define(result, result_temp));
1804    } else if (to.IsSmi()) {
1805      LOperand* value = UseRegister(val);
1806      return AssignEnvironment(
1807          DefineAsRegister(new (zone()) LDoubleToSmi(value)));
1808    } else {
1809      DCHECK(to.IsInteger32());
1810      LOperand* value = UseRegister(val);
1811      LInstruction* result = DefineAsRegister(new (zone()) LDoubleToI(value));
1812      if (!instr->CanTruncateToInt32()) result = AssignEnvironment(result);
1813      return result;
1814    }
1815  } else if (from.IsInteger32()) {
1816    info()->MarkAsDeferredCalling();
1817    if (to.IsTagged()) {
1818      if (!instr->CheckFlag(HValue::kCanOverflow)) {
1819        LOperand* value = UseRegisterAtStart(val);
1820        return DefineAsRegister(new (zone()) LSmiTag(value));
1821      } else if (val->CheckFlag(HInstruction::kUint32)) {
1822        LOperand* value = UseRegisterAtStart(val);
1823        LOperand* temp1 = TempRegister();
1824        LOperand* temp2 = TempRegister();
1825        LNumberTagU* result = new (zone()) LNumberTagU(value, temp1, temp2);
1826        return AssignPointerMap(DefineAsRegister(result));
1827      } else {
1828        LOperand* value = UseRegisterAtStart(val);
1829        LOperand* temp1 = TempRegister();
1830        LOperand* temp2 = TempRegister();
1831        LNumberTagI* result = new (zone()) LNumberTagI(value, temp1, temp2);
1832        return AssignPointerMap(DefineAsRegister(result));
1833      }
1834    } else if (to.IsSmi()) {
1835      LOperand* value = UseRegister(val);
1836      LInstruction* result = DefineAsRegister(new (zone()) LSmiTag(value));
1837      if (instr->CheckFlag(HValue::kCanOverflow)) {
1838        result = AssignEnvironment(result);
1839      }
1840      return result;
1841    } else {
1842      DCHECK(to.IsDouble());
1843      if (val->CheckFlag(HInstruction::kUint32)) {
1844        return DefineAsRegister(new (zone()) LUint32ToDouble(UseRegister(val)));
1845      } else {
1846        return DefineAsRegister(new (zone()) LInteger32ToDouble(Use(val)));
1847      }
1848    }
1849  }
1850  UNREACHABLE();
1851  return NULL;
1852}
1853
1854
1855LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
1856  LOperand* value = UseRegisterAtStart(instr->value());
1857  LInstruction* result = new (zone()) LCheckNonSmi(value);
1858  if (!instr->value()->type().IsHeapObject()) {
1859    result = AssignEnvironment(result);
1860  }
1861  return result;
1862}
1863
1864
1865LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
1866  LOperand* value = UseRegisterAtStart(instr->value());
1867  return AssignEnvironment(new (zone()) LCheckSmi(value));
1868}
1869
1870
1871LInstruction* LChunkBuilder::DoCheckArrayBufferNotNeutered(
1872    HCheckArrayBufferNotNeutered* instr) {
1873  LOperand* view = UseRegisterAtStart(instr->value());
1874  LCheckArrayBufferNotNeutered* result =
1875      new (zone()) LCheckArrayBufferNotNeutered(view);
1876  return AssignEnvironment(result);
1877}
1878
1879
1880LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
1881  LOperand* value = UseRegisterAtStart(instr->value());
1882  LInstruction* result = new (zone()) LCheckInstanceType(value);
1883  return AssignEnvironment(result);
1884}
1885
1886
1887LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) {
1888  LOperand* value = UseRegisterAtStart(instr->value());
1889  return AssignEnvironment(new (zone()) LCheckValue(value));
1890}
1891
1892
1893LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
1894  if (instr->IsStabilityCheck()) return new (zone()) LCheckMaps;
1895  LOperand* value = UseRegisterAtStart(instr->value());
1896  LOperand* temp = TempRegister();
1897  LInstruction* result =
1898      AssignEnvironment(new (zone()) LCheckMaps(value, temp));
1899  if (instr->HasMigrationTarget()) {
1900    info()->MarkAsDeferredCalling();
1901    result = AssignPointerMap(result);
1902  }
1903  return result;
1904}
1905
1906
1907LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
1908  HValue* value = instr->value();
1909  Representation input_rep = value->representation();
1910  LOperand* reg = UseRegister(value);
1911  if (input_rep.IsDouble()) {
1912    return DefineAsRegister(new (zone()) LClampDToUint8(reg));
1913  } else if (input_rep.IsInteger32()) {
1914    return DefineAsRegister(new (zone()) LClampIToUint8(reg));
1915  } else {
1916    DCHECK(input_rep.IsSmiOrTagged());
1917    LClampTToUint8* result =
1918        new (zone()) LClampTToUint8(reg, TempDoubleRegister());
1919    return AssignEnvironment(DefineAsRegister(result));
1920  }
1921}
1922
1923
1924LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
1925  LOperand* context = info()->IsStub() ? UseFixed(instr->context(), cp) : NULL;
1926  LOperand* parameter_count = UseRegisterOrConstant(instr->parameter_count());
1927  return new (zone())
1928      LReturn(UseFixed(instr->value(), r3), context, parameter_count);
1929}
1930
1931
1932LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
1933  Representation r = instr->representation();
1934  if (r.IsSmi()) {
1935    return DefineAsRegister(new (zone()) LConstantS);
1936  } else if (r.IsInteger32()) {
1937    return DefineAsRegister(new (zone()) LConstantI);
1938  } else if (r.IsDouble()) {
1939    return DefineAsRegister(new (zone()) LConstantD);
1940  } else if (r.IsExternal()) {
1941    return DefineAsRegister(new (zone()) LConstantE);
1942  } else if (r.IsTagged()) {
1943    return DefineAsRegister(new (zone()) LConstantT);
1944  } else {
1945    UNREACHABLE();
1946    return NULL;
1947  }
1948}
1949
1950
1951LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
1952  LOperand* context = UseRegisterAtStart(instr->value());
1953  LInstruction* result =
1954      DefineAsRegister(new (zone()) LLoadContextSlot(context));
1955  if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
1956    result = AssignEnvironment(result);
1957  }
1958  return result;
1959}
1960
1961
1962LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
1963  LOperand* context;
1964  LOperand* value;
1965  if (instr->NeedsWriteBarrier()) {
1966    context = UseTempRegister(instr->context());
1967    value = UseTempRegister(instr->value());
1968  } else {
1969    context = UseRegister(instr->context());
1970    value = UseRegister(instr->value());
1971  }
1972  LInstruction* result = new (zone()) LStoreContextSlot(context, value);
1973  if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
1974    result = AssignEnvironment(result);
1975  }
1976  return result;
1977}
1978
1979
1980LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
1981  LOperand* obj = UseRegisterAtStart(instr->object());
1982  return DefineAsRegister(new (zone()) LLoadNamedField(obj));
1983}
1984
1985
1986LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
1987    HLoadFunctionPrototype* instr) {
1988  return AssignEnvironment(DefineAsRegister(
1989      new (zone()) LLoadFunctionPrototype(UseRegister(instr->function()))));
1990}
1991
1992
1993LInstruction* LChunkBuilder::DoLoadRoot(HLoadRoot* instr) {
1994  return DefineAsRegister(new (zone()) LLoadRoot);
1995}
1996
1997
1998LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) {
1999  DCHECK(instr->key()->representation().IsSmiOrInteger32());
2000  ElementsKind elements_kind = instr->elements_kind();
2001  LOperand* key = UseRegisterOrConstantAtStart(instr->key());
2002  LInstruction* result = NULL;
2003
2004  if (!instr->is_fixed_typed_array()) {
2005    LOperand* obj = NULL;
2006    if (instr->representation().IsDouble()) {
2007      obj = UseRegister(instr->elements());
2008    } else {
2009      obj = UseRegisterAtStart(instr->elements());
2010    }
2011    result = DefineAsRegister(new (zone()) LLoadKeyed(obj, key, nullptr));
2012  } else {
2013    DCHECK((instr->representation().IsInteger32() &&
2014            !IsDoubleOrFloatElementsKind(elements_kind)) ||
2015           (instr->representation().IsDouble() &&
2016            IsDoubleOrFloatElementsKind(elements_kind)));
2017    LOperand* backing_store = UseRegister(instr->elements());
2018    LOperand* backing_store_owner = UseAny(instr->backing_store_owner());
2019    result = DefineAsRegister(
2020        new (zone()) LLoadKeyed(backing_store, key, backing_store_owner));
2021  }
2022
2023  bool needs_environment;
2024  if (instr->is_fixed_typed_array()) {
2025    // see LCodeGen::DoLoadKeyedExternalArray
2026    needs_environment = elements_kind == UINT32_ELEMENTS &&
2027                        !instr->CheckFlag(HInstruction::kUint32);
2028  } else {
2029    // see LCodeGen::DoLoadKeyedFixedDoubleArray and
2030    // LCodeGen::DoLoadKeyedFixedArray
2031    needs_environment =
2032        instr->RequiresHoleCheck() ||
2033        (instr->hole_mode() == CONVERT_HOLE_TO_UNDEFINED && info()->IsStub());
2034  }
2035
2036  if (needs_environment) {
2037    result = AssignEnvironment(result);
2038  }
2039  return result;
2040}
2041
2042
2043LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
2044  if (!instr->is_fixed_typed_array()) {
2045    DCHECK(instr->elements()->representation().IsTagged());
2046    bool needs_write_barrier = instr->NeedsWriteBarrier();
2047    LOperand* object = NULL;
2048    LOperand* key = NULL;
2049    LOperand* val = NULL;
2050
2051    if (instr->value()->representation().IsDouble()) {
2052      object = UseRegisterAtStart(instr->elements());
2053      val = UseRegister(instr->value());
2054      key = UseRegisterOrConstantAtStart(instr->key());
2055    } else {
2056      if (needs_write_barrier) {
2057        object = UseTempRegister(instr->elements());
2058        val = UseTempRegister(instr->value());
2059        key = UseTempRegister(instr->key());
2060      } else {
2061        object = UseRegisterAtStart(instr->elements());
2062        val = UseRegisterAtStart(instr->value());
2063        key = UseRegisterOrConstantAtStart(instr->key());
2064      }
2065    }
2066
2067    return new (zone()) LStoreKeyed(object, key, val, nullptr);
2068  }
2069
2070  DCHECK((instr->value()->representation().IsInteger32() &&
2071          !IsDoubleOrFloatElementsKind(instr->elements_kind())) ||
2072         (instr->value()->representation().IsDouble() &&
2073          IsDoubleOrFloatElementsKind(instr->elements_kind())));
2074  DCHECK(instr->elements()->representation().IsExternal());
2075  LOperand* val = UseRegister(instr->value());
2076  LOperand* key = UseRegisterOrConstantAtStart(instr->key());
2077  LOperand* backing_store = UseRegister(instr->elements());
2078  LOperand* backing_store_owner = UseAny(instr->backing_store_owner());
2079  return new (zone()) LStoreKeyed(backing_store, key, val, backing_store_owner);
2080}
2081
2082
2083LInstruction* LChunkBuilder::DoTransitionElementsKind(
2084    HTransitionElementsKind* instr) {
2085  if (IsSimpleMapChangeTransition(instr->from_kind(), instr->to_kind())) {
2086    LOperand* object = UseRegister(instr->object());
2087    LOperand* new_map_reg = TempRegister();
2088    LTransitionElementsKind* result =
2089        new (zone()) LTransitionElementsKind(object, NULL, new_map_reg);
2090    return result;
2091  } else {
2092    LOperand* object = UseFixed(instr->object(), r3);
2093    LOperand* context = UseFixed(instr->context(), cp);
2094    LTransitionElementsKind* result =
2095        new (zone()) LTransitionElementsKind(object, context, NULL);
2096    return MarkAsCall(result, instr);
2097  }
2098}
2099
2100
2101LInstruction* LChunkBuilder::DoTrapAllocationMemento(
2102    HTrapAllocationMemento* instr) {
2103  LOperand* object = UseRegister(instr->object());
2104  LOperand* temp1 = TempRegister();
2105  LOperand* temp2 = TempRegister();
2106  LTrapAllocationMemento* result =
2107      new (zone()) LTrapAllocationMemento(object, temp1, temp2);
2108  return AssignEnvironment(result);
2109}
2110
2111
2112LInstruction* LChunkBuilder::DoMaybeGrowElements(HMaybeGrowElements* instr) {
2113  info()->MarkAsDeferredCalling();
2114  LOperand* context = UseFixed(instr->context(), cp);
2115  LOperand* object = Use(instr->object());
2116  LOperand* elements = Use(instr->elements());
2117  LOperand* key = UseRegisterOrConstant(instr->key());
2118  LOperand* current_capacity = UseRegisterOrConstant(instr->current_capacity());
2119
2120  LMaybeGrowElements* result = new (zone())
2121      LMaybeGrowElements(context, object, elements, key, current_capacity);
2122  DefineFixed(result, r3);
2123  return AssignPointerMap(AssignEnvironment(result));
2124}
2125
2126
2127LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
2128  bool is_in_object = instr->access().IsInobject();
2129  bool needs_write_barrier = instr->NeedsWriteBarrier();
2130  bool needs_write_barrier_for_map =
2131      instr->has_transition() && instr->NeedsWriteBarrierForMap();
2132
2133  LOperand* obj;
2134  if (needs_write_barrier) {
2135    obj = is_in_object ? UseRegister(instr->object())
2136                       : UseTempRegister(instr->object());
2137  } else {
2138    obj = needs_write_barrier_for_map ? UseRegister(instr->object())
2139                                      : UseRegisterAtStart(instr->object());
2140  }
2141
2142  LOperand* val;
2143  if (needs_write_barrier) {
2144    val = UseTempRegister(instr->value());
2145  } else if (instr->field_representation().IsDouble()) {
2146    val = UseRegisterAtStart(instr->value());
2147  } else {
2148    val = UseRegister(instr->value());
2149  }
2150
2151  // We need a temporary register for write barrier of the map field.
2152  LOperand* temp = needs_write_barrier_for_map ? TempRegister() : NULL;
2153
2154  return new (zone()) LStoreNamedField(obj, val, temp);
2155}
2156
2157
2158LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
2159  LOperand* context = UseFixed(instr->context(), cp);
2160  LOperand* left = UseFixed(instr->left(), r4);
2161  LOperand* right = UseFixed(instr->right(), r3);
2162  return MarkAsCall(
2163      DefineFixed(new (zone()) LStringAdd(context, left, right), r3), instr);
2164}
2165
2166
2167LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
2168  LOperand* string = UseTempRegister(instr->string());
2169  LOperand* index = UseTempRegister(instr->index());
2170  LOperand* context = UseAny(instr->context());
2171  LStringCharCodeAt* result =
2172      new (zone()) LStringCharCodeAt(context, string, index);
2173  return AssignPointerMap(DefineAsRegister(result));
2174}
2175
2176
2177LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) {
2178  LOperand* char_code = UseRegister(instr->value());
2179  LOperand* context = UseAny(instr->context());
2180  LStringCharFromCode* result =
2181      new (zone()) LStringCharFromCode(context, char_code);
2182  return AssignPointerMap(DefineAsRegister(result));
2183}
2184
2185
2186LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) {
2187  LOperand* size = UseRegisterOrConstant(instr->size());
2188  LOperand* temp1 = TempRegister();
2189  LOperand* temp2 = TempRegister();
2190  if (instr->IsAllocationFolded()) {
2191    LFastAllocate* result = new (zone()) LFastAllocate(size, temp1, temp2);
2192    return DefineAsRegister(result);
2193  } else {
2194    info()->MarkAsDeferredCalling();
2195    LOperand* context = UseAny(instr->context());
2196    LAllocate* result = new (zone()) LAllocate(context, size, temp1, temp2);
2197    return AssignPointerMap(DefineAsRegister(result));
2198  }
2199}
2200
2201
2202LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
2203  DCHECK(argument_count_ == 0);
2204  allocator_->MarkAsOsrEntry();
2205  current_block_->last_environment()->set_ast_id(instr->ast_id());
2206  return AssignEnvironment(new (zone()) LOsrEntry);
2207}
2208
2209
2210LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
2211  LParameter* result = new (zone()) LParameter;
2212  if (instr->kind() == HParameter::STACK_PARAMETER) {
2213    int spill_index = chunk()->GetParameterStackSlot(instr->index());
2214    return DefineAsSpilled(result, spill_index);
2215  } else {
2216    DCHECK(info()->IsStub());
2217    CallInterfaceDescriptor descriptor = graph()->descriptor();
2218    int index = static_cast<int>(instr->index());
2219    Register reg = descriptor.GetRegisterParameter(index);
2220    return DefineFixed(result, reg);
2221  }
2222}
2223
2224
2225LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
2226  // Use an index that corresponds to the location in the unoptimized frame,
2227  // which the optimized frame will subsume.
2228  int env_index = instr->index();
2229  int spill_index = 0;
2230  if (instr->environment()->is_parameter_index(env_index)) {
2231    spill_index = chunk()->GetParameterStackSlot(env_index);
2232  } else {
2233    spill_index = env_index - instr->environment()->first_local_index();
2234    if (spill_index > LUnallocated::kMaxFixedSlotIndex) {
2235      Retry(kTooManySpillSlotsNeededForOSR);
2236      spill_index = 0;
2237    }
2238    spill_index += StandardFrameConstants::kFixedSlotCount;
2239  }
2240  return DefineAsSpilled(new (zone()) LUnknownOSRValue, spill_index);
2241}
2242
2243
2244LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
2245  // There are no real uses of the arguments object.
2246  // arguments.length and element access are supported directly on
2247  // stack arguments, and any real arguments object use causes a bailout.
2248  // So this value is never used.
2249  return NULL;
2250}
2251
2252
2253LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
2254  instr->ReplayEnvironment(current_block_->last_environment());
2255
2256  // There are no real uses of a captured object.
2257  return NULL;
2258}
2259
2260
2261LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
2262  info()->MarkAsRequiresFrame();
2263  LOperand* args = UseRegister(instr->arguments());
2264  LOperand* length = UseRegisterOrConstantAtStart(instr->length());
2265  LOperand* index = UseRegisterOrConstantAtStart(instr->index());
2266  return DefineAsRegister(new (zone()) LAccessArgumentsAt(args, length, index));
2267}
2268
2269
2270LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
2271  LOperand* context = UseFixed(instr->context(), cp);
2272  LOperand* value = UseFixed(instr->value(), r6);
2273  LTypeof* result = new (zone()) LTypeof(context, value);
2274  return MarkAsCall(DefineFixed(result, r3), instr);
2275}
2276
2277
2278LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) {
2279  return new (zone()) LTypeofIsAndBranch(UseRegister(instr->value()));
2280}
2281
2282
2283LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
2284  instr->ReplayEnvironment(current_block_->last_environment());
2285  return NULL;
2286}
2287
2288
2289LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
2290  if (instr->is_function_entry()) {
2291    LOperand* context = UseFixed(instr->context(), cp);
2292    return MarkAsCall(new (zone()) LStackCheck(context), instr);
2293  } else {
2294    DCHECK(instr->is_backwards_branch());
2295    LOperand* context = UseAny(instr->context());
2296    return AssignEnvironment(
2297        AssignPointerMap(new (zone()) LStackCheck(context)));
2298  }
2299}
2300
2301
2302LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
2303  HEnvironment* outer = current_block_->last_environment();
2304  outer->set_ast_id(instr->ReturnId());
2305  HConstant* undefined = graph()->GetConstantUndefined();
2306  HEnvironment* inner = outer->CopyForInlining(
2307      instr->closure(), instr->arguments_count(), instr->function(), undefined,
2308      instr->inlining_kind(), instr->syntactic_tail_call_mode());
2309  // Only replay binding of arguments object if it wasn't removed from graph.
2310  if (instr->arguments_var() != NULL && instr->arguments_object()->IsLinked()) {
2311    inner->Bind(instr->arguments_var(), instr->arguments_object());
2312  }
2313  inner->BindContext(instr->closure_context());
2314  inner->set_entry(instr);
2315  current_block_->UpdateEnvironment(inner);
2316  return NULL;
2317}
2318
2319
2320LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
2321  LInstruction* pop = NULL;
2322
2323  HEnvironment* env = current_block_->last_environment();
2324
2325  if (env->entry()->arguments_pushed()) {
2326    int argument_count = env->arguments_environment()->parameter_count();
2327    pop = new (zone()) LDrop(argument_count);
2328    DCHECK(instr->argument_delta() == -argument_count);
2329  }
2330
2331  HEnvironment* outer =
2332      current_block_->last_environment()->DiscardInlined(false);
2333  current_block_->UpdateEnvironment(outer);
2334
2335  return pop;
2336}
2337
2338
2339LInstruction* LChunkBuilder::DoForInPrepareMap(HForInPrepareMap* instr) {
2340  LOperand* context = UseFixed(instr->context(), cp);
2341  LOperand* object = UseFixed(instr->enumerable(), r3);
2342  LForInPrepareMap* result = new (zone()) LForInPrepareMap(context, object);
2343  return MarkAsCall(DefineFixed(result, r3), instr, CAN_DEOPTIMIZE_EAGERLY);
2344}
2345
2346
2347LInstruction* LChunkBuilder::DoForInCacheArray(HForInCacheArray* instr) {
2348  LOperand* map = UseRegister(instr->map());
2349  return AssignEnvironment(
2350      DefineAsRegister(new (zone()) LForInCacheArray(map)));
2351}
2352
2353
2354LInstruction* LChunkBuilder::DoCheckMapValue(HCheckMapValue* instr) {
2355  LOperand* value = UseRegisterAtStart(instr->value());
2356  LOperand* map = UseRegisterAtStart(instr->map());
2357  return AssignEnvironment(new (zone()) LCheckMapValue(value, map));
2358}
2359
2360
2361LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) {
2362  LOperand* object = UseRegister(instr->object());
2363  LOperand* index = UseTempRegister(instr->index());
2364  LLoadFieldByIndex* load = new (zone()) LLoadFieldByIndex(object, index);
2365  LInstruction* result = DefineSameAsFirst(load);
2366  return AssignPointerMap(result);
2367}
2368
2369}  // namespace internal
2370}  // namespace v8
2371