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