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/mips/lithium-mips.h"
6
7#include <sstream>
8
9#if V8_TARGET_ARCH_MIPS
10
11#include "src/crankshaft/hydrogen-osr.h"
12#include "src/crankshaft/lithium-inl.h"
13#include "src/crankshaft/mips/lithium-codegen-mips.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 = TempRegister();
1258  LInstruction* result =
1259      DefineAsRegister(new(zone()) LDivI(dividend, divisor, temp));
1260  if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
1261      instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
1262      (instr->CheckFlag(HValue::kCanOverflow) &&
1263       !instr->CheckFlag(HValue::kAllUsesTruncatingToInt32)) ||
1264      (!instr->IsMathFloorOfDiv() &&
1265       !instr->CheckFlag(HValue::kAllUsesTruncatingToInt32))) {
1266    result = AssignEnvironment(result);
1267  }
1268  return result;
1269}
1270
1271
1272LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
1273  if (instr->representation().IsSmiOrInteger32()) {
1274    if (instr->RightIsPowerOf2()) {
1275      return DoDivByPowerOf2I(instr);
1276    } else if (instr->right()->IsConstant()) {
1277      return DoDivByConstI(instr);
1278    } else {
1279      return DoDivI(instr);
1280    }
1281  } else if (instr->representation().IsDouble()) {
1282    return DoArithmeticD(Token::DIV, instr);
1283  } else {
1284    return DoArithmeticT(Token::DIV, instr);
1285  }
1286}
1287
1288
1289LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
1290  LOperand* dividend = UseRegisterAtStart(instr->left());
1291  int32_t divisor = instr->right()->GetInteger32Constant();
1292  LInstruction* result = DefineAsRegister(new(zone()) LFlooringDivByPowerOf2I(
1293          dividend, divisor));
1294  if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
1295      (instr->CheckFlag(HValue::kLeftCanBeMinInt) && divisor == -1)) {
1296    result = AssignEnvironment(result);
1297  }
1298  return result;
1299}
1300
1301
1302LInstruction* LChunkBuilder::DoFlooringDivByConstI(HMathFloorOfDiv* instr) {
1303  DCHECK(instr->representation().IsInteger32());
1304  DCHECK(instr->left()->representation().Equals(instr->representation()));
1305  DCHECK(instr->right()->representation().Equals(instr->representation()));
1306  LOperand* dividend = UseRegister(instr->left());
1307  int32_t divisor = instr->right()->GetInteger32Constant();
1308  LOperand* temp =
1309      ((divisor > 0 && !instr->CheckFlag(HValue::kLeftCanBeNegative)) ||
1310       (divisor < 0 && !instr->CheckFlag(HValue::kLeftCanBePositive))) ?
1311      NULL : TempRegister();
1312  LInstruction* result = DefineAsRegister(
1313      new(zone()) LFlooringDivByConstI(dividend, divisor, temp));
1314  if (divisor == 0 ||
1315      (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0)) {
1316    result = AssignEnvironment(result);
1317  }
1318  return result;
1319}
1320
1321
1322LInstruction* LChunkBuilder::DoFlooringDivI(HMathFloorOfDiv* instr) {
1323  DCHECK(instr->representation().IsSmiOrInteger32());
1324  DCHECK(instr->left()->representation().Equals(instr->representation()));
1325  DCHECK(instr->right()->representation().Equals(instr->representation()));
1326  LOperand* dividend = UseRegister(instr->left());
1327  LOperand* divisor = UseRegister(instr->right());
1328  LInstruction* result =
1329      DefineAsRegister(new (zone()) LFlooringDivI(dividend, divisor));
1330  if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
1331      instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
1332      (instr->CheckFlag(HValue::kCanOverflow))) {
1333    result = AssignEnvironment(result);
1334  }
1335  return result;
1336}
1337
1338
1339LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
1340  if (instr->RightIsPowerOf2()) {
1341    return DoFlooringDivByPowerOf2I(instr);
1342  } else if (instr->right()->IsConstant()) {
1343    return DoFlooringDivByConstI(instr);
1344  } else {
1345    return DoFlooringDivI(instr);
1346  }
1347}
1348
1349
1350LInstruction* LChunkBuilder::DoModByPowerOf2I(HMod* instr) {
1351  DCHECK(instr->representation().IsSmiOrInteger32());
1352  DCHECK(instr->left()->representation().Equals(instr->representation()));
1353  DCHECK(instr->right()->representation().Equals(instr->representation()));
1354  LOperand* dividend = UseRegisterAtStart(instr->left());
1355  int32_t divisor = instr->right()->GetInteger32Constant();
1356  LInstruction* result = DefineSameAsFirst(new(zone()) LModByPowerOf2I(
1357          dividend, divisor));
1358  if (instr->CheckFlag(HValue::kLeftCanBeNegative) &&
1359      instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1360    result = AssignEnvironment(result);
1361  }
1362  return result;
1363}
1364
1365
1366LInstruction* LChunkBuilder::DoModByConstI(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 = UseRegister(instr->left());
1371  int32_t divisor = instr->right()->GetInteger32Constant();
1372  LInstruction* result = DefineAsRegister(new(zone()) LModByConstI(
1373          dividend, divisor));
1374  if (divisor == 0 || instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1375    result = AssignEnvironment(result);
1376  }
1377  return result;
1378}
1379
1380
1381LInstruction* LChunkBuilder::DoModI(HMod* instr) {
1382  DCHECK(instr->representation().IsSmiOrInteger32());
1383  DCHECK(instr->left()->representation().Equals(instr->representation()));
1384  DCHECK(instr->right()->representation().Equals(instr->representation()));
1385  LOperand* dividend = UseRegister(instr->left());
1386  LOperand* divisor = UseRegister(instr->right());
1387  LInstruction* result = DefineAsRegister(new(zone()) LModI(
1388      dividend, divisor));
1389  if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
1390      instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1391    result = AssignEnvironment(result);
1392  }
1393  return result;
1394}
1395
1396
1397LInstruction* LChunkBuilder::DoMod(HMod* instr) {
1398  if (instr->representation().IsSmiOrInteger32()) {
1399    return instr->RightIsPowerOf2() ? DoModByPowerOf2I(instr) : DoModI(instr);
1400  } else if (instr->representation().IsDouble()) {
1401    return DoArithmeticD(Token::MOD, instr);
1402  } else {
1403    return DoArithmeticT(Token::MOD, instr);
1404  }
1405}
1406
1407
1408LInstruction* LChunkBuilder::DoMul(HMul* instr) {
1409  if (instr->representation().IsSmiOrInteger32()) {
1410    DCHECK(instr->left()->representation().Equals(instr->representation()));
1411    DCHECK(instr->right()->representation().Equals(instr->representation()));
1412    HValue* left = instr->BetterLeftOperand();
1413    HValue* right = instr->BetterRightOperand();
1414    LOperand* left_op;
1415    LOperand* right_op;
1416    bool can_overflow = instr->CheckFlag(HValue::kCanOverflow);
1417    bool bailout_on_minus_zero = instr->CheckFlag(HValue::kBailoutOnMinusZero);
1418
1419    int32_t constant_value = 0;
1420    if (right->IsConstant()) {
1421      HConstant* constant = HConstant::cast(right);
1422      constant_value = constant->Integer32Value();
1423      // Constants -1, 0 and 1 can be optimized if the result can overflow.
1424      // For other constants, it can be optimized only without overflow.
1425      if (!can_overflow || ((constant_value >= -1) && (constant_value <= 1))) {
1426        left_op = UseRegisterAtStart(left);
1427        right_op = UseConstant(right);
1428      } else {
1429        if (bailout_on_minus_zero) {
1430          left_op = UseRegister(left);
1431        } else {
1432          left_op = UseRegisterAtStart(left);
1433        }
1434        right_op = UseRegister(right);
1435      }
1436    } else {
1437      if (bailout_on_minus_zero) {
1438        left_op = UseRegister(left);
1439      } else {
1440        left_op = UseRegisterAtStart(left);
1441      }
1442      right_op = UseRegister(right);
1443    }
1444    LMulI* mul = new(zone()) LMulI(left_op, right_op);
1445    if (right_op->IsConstantOperand()
1446            ? ((can_overflow && constant_value == -1) ||
1447               (bailout_on_minus_zero && constant_value <= 0))
1448            : (can_overflow || bailout_on_minus_zero)) {
1449      AssignEnvironment(mul);
1450    }
1451    return DefineAsRegister(mul);
1452
1453  } else if (instr->representation().IsDouble()) {
1454    if (IsMipsArchVariant(kMips32r2)) {
1455      if (instr->HasOneUse() && instr->uses().value()->IsAdd()) {
1456        HAdd* add = HAdd::cast(instr->uses().value());
1457        if (instr == add->left()) {
1458          // This mul is the lhs of an add. The add and mul will be folded
1459          // into a multiply-add.
1460          return NULL;
1461        }
1462        if (instr == add->right() && !add->left()->IsMul()) {
1463          // This mul is the rhs of an add, where the lhs is not another mul.
1464          // The add and mul will be folded into a multiply-add.
1465          return NULL;
1466        }
1467      }
1468    }
1469    return DoArithmeticD(Token::MUL, instr);
1470  } else {
1471    return DoArithmeticT(Token::MUL, instr);
1472  }
1473}
1474
1475
1476LInstruction* LChunkBuilder::DoSub(HSub* instr) {
1477  if (instr->representation().IsSmiOrInteger32()) {
1478    DCHECK(instr->left()->representation().Equals(instr->representation()));
1479    DCHECK(instr->right()->representation().Equals(instr->representation()));
1480    LOperand* left = UseRegisterAtStart(instr->left());
1481    LOperand* right = UseOrConstantAtStart(instr->right());
1482    LSubI* sub = new(zone()) LSubI(left, right);
1483    LInstruction* result = DefineAsRegister(sub);
1484    if (instr->CheckFlag(HValue::kCanOverflow)) {
1485      result = AssignEnvironment(result);
1486    }
1487    return result;
1488  } else if (instr->representation().IsDouble()) {
1489    return DoArithmeticD(Token::SUB, instr);
1490  } else {
1491    return DoArithmeticT(Token::SUB, instr);
1492  }
1493}
1494
1495
1496LInstruction* LChunkBuilder::DoMultiplyAdd(HMul* mul, HValue* addend) {
1497  LOperand* multiplier_op = UseRegisterAtStart(mul->left());
1498  LOperand* multiplicand_op = UseRegisterAtStart(mul->right());
1499  LOperand* addend_op = UseRegisterAtStart(addend);
1500  return DefineSameAsFirst(new(zone()) LMultiplyAddD(addend_op, multiplier_op,
1501                                                     multiplicand_op));
1502}
1503
1504
1505LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
1506  if (instr->representation().IsSmiOrInteger32()) {
1507    DCHECK(instr->left()->representation().Equals(instr->representation()));
1508    DCHECK(instr->right()->representation().Equals(instr->representation()));
1509    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1510    LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
1511    LAddI* add = new(zone()) LAddI(left, right);
1512    LInstruction* result = DefineAsRegister(add);
1513    if (instr->CheckFlag(HValue::kCanOverflow)) {
1514      result = AssignEnvironment(result);
1515    }
1516    return result;
1517  } else if (instr->representation().IsExternal()) {
1518    DCHECK(instr->IsConsistentExternalRepresentation());
1519    DCHECK(!instr->CheckFlag(HValue::kCanOverflow));
1520    LOperand* left = UseRegisterAtStart(instr->left());
1521    LOperand* right = UseOrConstantAtStart(instr->right());
1522    LAddI* add = new(zone()) LAddI(left, right);
1523    LInstruction* result = DefineAsRegister(add);
1524    return result;
1525  } else if (instr->representation().IsDouble()) {
1526    if (IsMipsArchVariant(kMips32r2)) {
1527      if (instr->left()->IsMul())
1528        return DoMultiplyAdd(HMul::cast(instr->left()), instr->right());
1529
1530      if (instr->right()->IsMul()) {
1531        DCHECK(!instr->left()->IsMul());
1532        return DoMultiplyAdd(HMul::cast(instr->right()), instr->left());
1533      }
1534    }
1535    return DoArithmeticD(Token::ADD, instr);
1536  } else {
1537    return DoArithmeticT(Token::ADD, instr);
1538  }
1539}
1540
1541
1542LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
1543  LOperand* left = NULL;
1544  LOperand* right = NULL;
1545  if (instr->representation().IsSmiOrInteger32()) {
1546    DCHECK(instr->left()->representation().Equals(instr->representation()));
1547    DCHECK(instr->right()->representation().Equals(instr->representation()));
1548    left = UseRegisterAtStart(instr->BetterLeftOperand());
1549    right = UseOrConstantAtStart(instr->BetterRightOperand());
1550  } else {
1551    DCHECK(instr->representation().IsDouble());
1552    DCHECK(instr->left()->representation().IsDouble());
1553    DCHECK(instr->right()->representation().IsDouble());
1554    left = UseRegisterAtStart(instr->left());
1555    right = UseRegisterAtStart(instr->right());
1556  }
1557  return DefineAsRegister(new(zone()) LMathMinMax(left, right));
1558}
1559
1560
1561LInstruction* LChunkBuilder::DoPower(HPower* instr) {
1562  DCHECK(instr->representation().IsDouble());
1563  // We call a C function for double power. It can't trigger a GC.
1564  // We need to use fixed result register for the call.
1565  Representation exponent_type = instr->right()->representation();
1566  DCHECK(instr->left()->representation().IsDouble());
1567  LOperand* left = UseFixedDouble(instr->left(), f2);
1568  LOperand* right =
1569      exponent_type.IsDouble()
1570          ? UseFixedDouble(instr->right(), f4)
1571          : UseFixed(instr->right(), MathPowTaggedDescriptor::exponent());
1572  LPower* result = new(zone()) LPower(left, right);
1573  return MarkAsCall(DefineFixedDouble(result, f0),
1574                    instr,
1575                    CAN_DEOPTIMIZE_EAGERLY);
1576}
1577
1578
1579LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
1580  DCHECK(instr->left()->representation().IsTagged());
1581  DCHECK(instr->right()->representation().IsTagged());
1582  LOperand* context = UseFixed(instr->context(), cp);
1583  LOperand* left = UseFixed(instr->left(), a1);
1584  LOperand* right = UseFixed(instr->right(), a0);
1585  LCmpT* result = new(zone()) LCmpT(context, left, right);
1586  return MarkAsCall(DefineFixed(result, v0), instr);
1587}
1588
1589
1590LInstruction* LChunkBuilder::DoCompareNumericAndBranch(
1591    HCompareNumericAndBranch* instr) {
1592  Representation r = instr->representation();
1593  if (r.IsSmiOrInteger32()) {
1594    DCHECK(instr->left()->representation().Equals(r));
1595    DCHECK(instr->right()->representation().Equals(r));
1596    LOperand* left = UseRegisterOrConstantAtStart(instr->left());
1597    LOperand* right = UseRegisterOrConstantAtStart(instr->right());
1598    return new(zone()) LCompareNumericAndBranch(left, right);
1599  } else {
1600    DCHECK(r.IsDouble());
1601    DCHECK(instr->left()->representation().IsDouble());
1602    DCHECK(instr->right()->representation().IsDouble());
1603    LOperand* left = UseRegisterAtStart(instr->left());
1604    LOperand* right = UseRegisterAtStart(instr->right());
1605    return new(zone()) LCompareNumericAndBranch(left, right);
1606  }
1607}
1608
1609
1610LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch(
1611    HCompareObjectEqAndBranch* instr) {
1612  LOperand* left = UseRegisterAtStart(instr->left());
1613  LOperand* right = UseRegisterAtStart(instr->right());
1614  return new(zone()) LCmpObjectEqAndBranch(left, right);
1615}
1616
1617
1618LInstruction* LChunkBuilder::DoCompareHoleAndBranch(
1619    HCompareHoleAndBranch* instr) {
1620  LOperand* value = UseRegisterAtStart(instr->value());
1621  return new(zone()) LCmpHoleAndBranch(value);
1622}
1623
1624
1625LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
1626  DCHECK(instr->value()->representation().IsTagged());
1627  LOperand* temp = TempRegister();
1628  return new(zone()) LIsStringAndBranch(UseRegisterAtStart(instr->value()),
1629                                        temp);
1630}
1631
1632
1633LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
1634  DCHECK(instr->value()->representation().IsTagged());
1635  return new(zone()) LIsSmiAndBranch(Use(instr->value()));
1636}
1637
1638
1639LInstruction* LChunkBuilder::DoIsUndetectableAndBranch(
1640    HIsUndetectableAndBranch* instr) {
1641  DCHECK(instr->value()->representation().IsTagged());
1642  return new(zone()) LIsUndetectableAndBranch(
1643      UseRegisterAtStart(instr->value()), TempRegister());
1644}
1645
1646
1647LInstruction* LChunkBuilder::DoStringCompareAndBranch(
1648    HStringCompareAndBranch* instr) {
1649  DCHECK(instr->left()->representation().IsTagged());
1650  DCHECK(instr->right()->representation().IsTagged());
1651  LOperand* context = UseFixed(instr->context(), cp);
1652  LOperand* left = UseFixed(instr->left(), a1);
1653  LOperand* right = UseFixed(instr->right(), a0);
1654  LStringCompareAndBranch* result =
1655      new(zone()) LStringCompareAndBranch(context, left, right);
1656  return MarkAsCall(result, instr);
1657}
1658
1659
1660LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
1661    HHasInstanceTypeAndBranch* instr) {
1662  DCHECK(instr->value()->representation().IsTagged());
1663  LOperand* value = UseRegisterAtStart(instr->value());
1664  return new(zone()) LHasInstanceTypeAndBranch(value);
1665}
1666
1667LInstruction* LChunkBuilder::DoClassOfTestAndBranch(
1668    HClassOfTestAndBranch* instr) {
1669  DCHECK(instr->value()->representation().IsTagged());
1670  return new(zone()) LClassOfTestAndBranch(UseRegister(instr->value()),
1671                                           TempRegister());
1672}
1673
1674
1675LInstruction* LChunkBuilder::DoSeqStringGetChar(HSeqStringGetChar* instr) {
1676  LOperand* string = UseRegisterAtStart(instr->string());
1677  LOperand* index = UseRegisterOrConstantAtStart(instr->index());
1678  return DefineAsRegister(new(zone()) LSeqStringGetChar(string, index));
1679}
1680
1681
1682LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
1683  LOperand* string = UseRegisterAtStart(instr->string());
1684  LOperand* index = FLAG_debug_code
1685      ? UseRegisterAtStart(instr->index())
1686      : UseRegisterOrConstantAtStart(instr->index());
1687  LOperand* value = UseRegisterAtStart(instr->value());
1688  LOperand* context = FLAG_debug_code ? UseFixed(instr->context(), cp) : NULL;
1689  return new(zone()) LSeqStringSetChar(context, string, index, value);
1690}
1691
1692
1693LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
1694  if (!FLAG_debug_code && instr->skip_check()) return NULL;
1695  LOperand* index = UseRegisterOrConstantAtStart(instr->index());
1696  LOperand* length = !index->IsConstantOperand()
1697  ? UseRegisterOrConstantAtStart(instr->length())
1698  : UseRegisterAtStart(instr->length());
1699  LInstruction* result = new(zone()) LBoundsCheck(index, length);
1700  if (!FLAG_debug_code || !instr->skip_check()) {
1701    result = AssignEnvironment(result);
1702  }
1703  return result;
1704}
1705
1706
1707LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
1708  // The control instruction marking the end of a block that completed
1709  // abruptly (e.g., threw an exception).  There is nothing specific to do.
1710  return NULL;
1711}
1712
1713
1714LInstruction* LChunkBuilder::DoUseConst(HUseConst* instr) {
1715  return NULL;
1716}
1717
1718
1719LInstruction* LChunkBuilder::DoForceRepresentation(HForceRepresentation* bad) {
1720  // All HForceRepresentation instructions should be eliminated in the
1721  // representation change phase of Hydrogen.
1722  UNREACHABLE();
1723  return NULL;
1724}
1725
1726
1727LInstruction* LChunkBuilder::DoChange(HChange* instr) {
1728  Representation from = instr->from();
1729  Representation to = instr->to();
1730  HValue* val = instr->value();
1731  if (from.IsSmi()) {
1732    if (to.IsTagged()) {
1733      LOperand* value = UseRegister(val);
1734      return DefineSameAsFirst(new(zone()) LDummyUse(value));
1735    }
1736    from = Representation::Tagged();
1737  }
1738  if (from.IsTagged()) {
1739    if (to.IsDouble()) {
1740      LOperand* value = UseRegister(val);
1741      LInstruction* result = DefineAsRegister(new(zone()) LNumberUntagD(value));
1742      if (!val->representation().IsSmi()) result = AssignEnvironment(result);
1743      return result;
1744    } else if (to.IsSmi()) {
1745      LOperand* value = UseRegister(val);
1746      if (val->type().IsSmi()) {
1747        return DefineSameAsFirst(new(zone()) LDummyUse(value));
1748      }
1749      return AssignEnvironment(DefineSameAsFirst(new(zone()) LCheckSmi(value)));
1750    } else {
1751      DCHECK(to.IsInteger32());
1752      if (val->type().IsSmi() || val->representation().IsSmi()) {
1753        LOperand* value = UseRegisterAtStart(val);
1754        return DefineAsRegister(new(zone()) LSmiUntag(value, false));
1755      } else {
1756        LOperand* value = UseRegister(val);
1757        LOperand* temp1 = TempRegister();
1758        LOperand* temp2 = TempDoubleRegister();
1759        LInstruction* result =
1760            DefineSameAsFirst(new(zone()) LTaggedToI(value, temp1, temp2));
1761        if (!val->representation().IsSmi()) result = AssignEnvironment(result);
1762        return result;
1763      }
1764    }
1765  } else if (from.IsDouble()) {
1766    if (to.IsTagged()) {
1767      info()->MarkAsDeferredCalling();
1768      LOperand* value = UseRegister(val);
1769      LOperand* temp1 = TempRegister();
1770      LOperand* temp2 = TempRegister();
1771      LUnallocated* result_temp = TempRegister();
1772      LNumberTagD* result = new(zone()) LNumberTagD(value, temp1, temp2);
1773      return AssignPointerMap(Define(result, result_temp));
1774    } else if (to.IsSmi()) {
1775      LOperand* value = UseRegister(val);
1776      return AssignEnvironment(
1777          DefineAsRegister(new(zone()) LDoubleToSmi(value)));
1778    } else {
1779      DCHECK(to.IsInteger32());
1780      LOperand* value = UseRegister(val);
1781      LInstruction* result = DefineAsRegister(new(zone()) LDoubleToI(value));
1782      if (!instr->CanTruncateToInt32()) result = AssignEnvironment(result);
1783      return result;
1784    }
1785  } else if (from.IsInteger32()) {
1786    info()->MarkAsDeferredCalling();
1787    if (to.IsTagged()) {
1788      if (!instr->CheckFlag(HValue::kCanOverflow)) {
1789        LOperand* value = UseRegisterAtStart(val);
1790        return DefineAsRegister(new(zone()) LSmiTag(value));
1791      } else if (val->CheckFlag(HInstruction::kUint32)) {
1792        LOperand* value = UseRegisterAtStart(val);
1793        LOperand* temp1 = TempRegister();
1794        LOperand* temp2 = TempRegister();
1795        LNumberTagU* result = new(zone()) LNumberTagU(value, temp1, temp2);
1796        return AssignPointerMap(DefineAsRegister(result));
1797      } else {
1798        LOperand* value = UseRegisterAtStart(val);
1799        LOperand* temp1 = TempRegister();
1800        LOperand* temp2 = TempRegister();
1801        LNumberTagI* result = new(zone()) LNumberTagI(value, temp1, temp2);
1802        return AssignPointerMap(DefineAsRegister(result));
1803      }
1804    } else if (to.IsSmi()) {
1805      LOperand* value = UseRegister(val);
1806      LInstruction* result = DefineAsRegister(new(zone()) LSmiTag(value));
1807      if (instr->CheckFlag(HValue::kCanOverflow)) {
1808        result = AssignEnvironment(result);
1809      }
1810      return result;
1811    } else {
1812      DCHECK(to.IsDouble());
1813      if (val->CheckFlag(HInstruction::kUint32)) {
1814        return DefineAsRegister(new(zone()) LUint32ToDouble(UseRegister(val)));
1815      } else {
1816        return DefineAsRegister(new(zone()) LInteger32ToDouble(Use(val)));
1817      }
1818    }
1819  }
1820  UNREACHABLE();
1821  return NULL;
1822}
1823
1824
1825LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
1826  LOperand* value = UseRegisterAtStart(instr->value());
1827  LInstruction* result = new(zone()) LCheckNonSmi(value);
1828  if (!instr->value()->type().IsHeapObject()) {
1829    result = AssignEnvironment(result);
1830  }
1831  return result;
1832}
1833
1834
1835LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
1836  LOperand* value = UseRegisterAtStart(instr->value());
1837  return AssignEnvironment(new(zone()) LCheckSmi(value));
1838}
1839
1840
1841LInstruction* LChunkBuilder::DoCheckArrayBufferNotNeutered(
1842    HCheckArrayBufferNotNeutered* instr) {
1843  LOperand* view = UseRegisterAtStart(instr->value());
1844  LCheckArrayBufferNotNeutered* result =
1845      new (zone()) LCheckArrayBufferNotNeutered(view);
1846  return AssignEnvironment(result);
1847}
1848
1849
1850LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
1851  LOperand* value = UseRegisterAtStart(instr->value());
1852  LInstruction* result = new(zone()) LCheckInstanceType(value);
1853  return AssignEnvironment(result);
1854}
1855
1856
1857LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) {
1858  LOperand* value = UseRegisterAtStart(instr->value());
1859  return AssignEnvironment(new(zone()) LCheckValue(value));
1860}
1861
1862
1863LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
1864  if (instr->IsStabilityCheck()) return new(zone()) LCheckMaps;
1865  LOperand* value = UseRegisterAtStart(instr->value());
1866  LInstruction* result = AssignEnvironment(new(zone()) LCheckMaps(value));
1867  if (instr->HasMigrationTarget()) {
1868    info()->MarkAsDeferredCalling();
1869    result = AssignPointerMap(result);
1870  }
1871  return result;
1872}
1873
1874
1875LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
1876  HValue* value = instr->value();
1877  Representation input_rep = value->representation();
1878  LOperand* reg = UseRegister(value);
1879  if (input_rep.IsDouble()) {
1880    // Revisit this decision, here and 8 lines below.
1881    return DefineAsRegister(new(zone()) LClampDToUint8(reg,
1882        TempDoubleRegister()));
1883  } else if (input_rep.IsInteger32()) {
1884    return DefineAsRegister(new(zone()) LClampIToUint8(reg));
1885  } else {
1886    DCHECK(input_rep.IsSmiOrTagged());
1887    LClampTToUint8* result =
1888        new(zone()) LClampTToUint8(reg, TempDoubleRegister());
1889    return AssignEnvironment(DefineAsRegister(result));
1890  }
1891}
1892
1893
1894LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
1895  LOperand* context = info()->IsStub()
1896      ? UseFixed(instr->context(), cp)
1897      : NULL;
1898  LOperand* parameter_count = UseRegisterOrConstant(instr->parameter_count());
1899  return new(zone()) LReturn(UseFixed(instr->value(), v0), context,
1900                             parameter_count);
1901}
1902
1903
1904LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
1905  Representation r = instr->representation();
1906  if (r.IsSmi()) {
1907    return DefineAsRegister(new(zone()) LConstantS);
1908  } else if (r.IsInteger32()) {
1909    return DefineAsRegister(new(zone()) LConstantI);
1910  } else if (r.IsDouble()) {
1911    return DefineAsRegister(new(zone()) LConstantD);
1912  } else if (r.IsExternal()) {
1913    return DefineAsRegister(new(zone()) LConstantE);
1914  } else if (r.IsTagged()) {
1915    return DefineAsRegister(new(zone()) LConstantT);
1916  } else {
1917    UNREACHABLE();
1918    return NULL;
1919  }
1920}
1921
1922
1923LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
1924  LOperand* context = UseRegisterAtStart(instr->value());
1925  LInstruction* result =
1926      DefineAsRegister(new(zone()) LLoadContextSlot(context));
1927  if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
1928    result = AssignEnvironment(result);
1929  }
1930  return result;
1931}
1932
1933
1934LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
1935  LOperand* context;
1936  LOperand* value;
1937  if (instr->NeedsWriteBarrier()) {
1938    context = UseTempRegister(instr->context());
1939    value = UseTempRegister(instr->value());
1940  } else {
1941    context = UseRegister(instr->context());
1942    value = UseRegister(instr->value());
1943  }
1944  LInstruction* result = new(zone()) LStoreContextSlot(context, value);
1945  if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
1946    result = AssignEnvironment(result);
1947  }
1948  return result;
1949}
1950
1951
1952LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
1953  LOperand* obj = UseRegisterAtStart(instr->object());
1954  return DefineAsRegister(new(zone()) LLoadNamedField(obj));
1955}
1956
1957
1958LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
1959    HLoadFunctionPrototype* instr) {
1960  return AssignEnvironment(DefineAsRegister(
1961      new(zone()) LLoadFunctionPrototype(UseRegister(instr->function()))));
1962}
1963
1964
1965LInstruction* LChunkBuilder::DoLoadRoot(HLoadRoot* instr) {
1966  return DefineAsRegister(new(zone()) LLoadRoot);
1967}
1968
1969
1970LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) {
1971  DCHECK(instr->key()->representation().IsSmiOrInteger32());
1972  ElementsKind elements_kind = instr->elements_kind();
1973  LOperand* key = UseRegisterOrConstantAtStart(instr->key());
1974  LInstruction* result = NULL;
1975
1976  if (!instr->is_fixed_typed_array()) {
1977    LOperand* obj = NULL;
1978    if (instr->representation().IsDouble()) {
1979      obj = UseRegister(instr->elements());
1980    } else {
1981      DCHECK(instr->representation().IsSmiOrTagged());
1982      obj = UseRegisterAtStart(instr->elements());
1983    }
1984    result = DefineAsRegister(new (zone()) LLoadKeyed(obj, key, nullptr));
1985  } else {
1986    DCHECK(
1987        (instr->representation().IsInteger32() &&
1988         !IsDoubleOrFloatElementsKind(elements_kind)) ||
1989        (instr->representation().IsDouble() &&
1990         IsDoubleOrFloatElementsKind(elements_kind)));
1991    LOperand* backing_store = UseRegister(instr->elements());
1992    LOperand* backing_store_owner = UseAny(instr->backing_store_owner());
1993    result = DefineAsRegister(
1994        new (zone()) LLoadKeyed(backing_store, key, backing_store_owner));
1995  }
1996
1997  bool needs_environment;
1998  if (instr->is_fixed_typed_array()) {
1999    // see LCodeGen::DoLoadKeyedExternalArray
2000    needs_environment = elements_kind == UINT32_ELEMENTS &&
2001                        !instr->CheckFlag(HInstruction::kUint32);
2002  } else {
2003    // see LCodeGen::DoLoadKeyedFixedDoubleArray and
2004    // LCodeGen::DoLoadKeyedFixedArray
2005    needs_environment =
2006        instr->RequiresHoleCheck() ||
2007        (instr->hole_mode() == CONVERT_HOLE_TO_UNDEFINED && info()->IsStub());
2008  }
2009
2010  if (needs_environment) {
2011    result = AssignEnvironment(result);
2012  }
2013  return result;
2014}
2015
2016
2017LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
2018  if (!instr->is_fixed_typed_array()) {
2019    DCHECK(instr->elements()->representation().IsTagged());
2020    bool needs_write_barrier = instr->NeedsWriteBarrier();
2021    LOperand* object = NULL;
2022    LOperand* val = NULL;
2023    LOperand* key = NULL;
2024
2025    if (instr->value()->representation().IsDouble()) {
2026      object = UseRegisterAtStart(instr->elements());
2027      key = UseRegisterOrConstantAtStart(instr->key());
2028      val = UseRegister(instr->value());
2029    } else {
2030      DCHECK(instr->value()->representation().IsSmiOrTagged());
2031      if (needs_write_barrier) {
2032        object = UseTempRegister(instr->elements());
2033        val = UseTempRegister(instr->value());
2034        key = UseTempRegister(instr->key());
2035      } else {
2036        object = UseRegisterAtStart(instr->elements());
2037        val = UseRegisterAtStart(instr->value());
2038        key = UseRegisterOrConstantAtStart(instr->key());
2039      }
2040    }
2041
2042    return new (zone()) LStoreKeyed(object, key, val, nullptr);
2043  }
2044
2045  DCHECK(
2046      (instr->value()->representation().IsInteger32() &&
2047       !IsDoubleOrFloatElementsKind(instr->elements_kind())) ||
2048      (instr->value()->representation().IsDouble() &&
2049       IsDoubleOrFloatElementsKind(instr->elements_kind())));
2050  DCHECK(instr->elements()->representation().IsExternal());
2051  LOperand* val = UseRegister(instr->value());
2052  LOperand* key = UseRegisterOrConstantAtStart(instr->key());
2053  LOperand* backing_store = UseRegister(instr->elements());
2054  LOperand* backing_store_owner = UseAny(instr->backing_store_owner());
2055  return new (zone()) LStoreKeyed(backing_store, key, val, backing_store_owner);
2056}
2057
2058
2059LInstruction* LChunkBuilder::DoTransitionElementsKind(
2060    HTransitionElementsKind* instr) {
2061  if (IsSimpleMapChangeTransition(instr->from_kind(), instr->to_kind())) {
2062    LOperand* object = UseRegister(instr->object());
2063    LOperand* new_map_reg = TempRegister();
2064    LTransitionElementsKind* result =
2065        new(zone()) LTransitionElementsKind(object, NULL, new_map_reg);
2066    return result;
2067  } else {
2068    LOperand* object = UseFixed(instr->object(), a0);
2069    LOperand* context = UseFixed(instr->context(), cp);
2070    LTransitionElementsKind* result =
2071        new(zone()) LTransitionElementsKind(object, context, NULL);
2072    return MarkAsCall(result, instr);
2073  }
2074}
2075
2076
2077LInstruction* LChunkBuilder::DoTrapAllocationMemento(
2078    HTrapAllocationMemento* instr) {
2079  LOperand* object = UseRegister(instr->object());
2080  LOperand* temp = TempRegister();
2081  LTrapAllocationMemento* result =
2082      new(zone()) LTrapAllocationMemento(object, temp);
2083  return AssignEnvironment(result);
2084}
2085
2086
2087LInstruction* LChunkBuilder::DoMaybeGrowElements(HMaybeGrowElements* instr) {
2088  info()->MarkAsDeferredCalling();
2089  LOperand* context = UseFixed(instr->context(), cp);
2090  LOperand* object = Use(instr->object());
2091  LOperand* elements = Use(instr->elements());
2092  LOperand* key = UseRegisterOrConstant(instr->key());
2093  LOperand* current_capacity = UseRegisterOrConstant(instr->current_capacity());
2094
2095  LMaybeGrowElements* result = new (zone())
2096      LMaybeGrowElements(context, object, elements, key, current_capacity);
2097  DefineFixed(result, v0);
2098  return AssignPointerMap(AssignEnvironment(result));
2099}
2100
2101
2102LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
2103  bool is_in_object = instr->access().IsInobject();
2104  bool needs_write_barrier = instr->NeedsWriteBarrier();
2105  bool needs_write_barrier_for_map = instr->has_transition() &&
2106      instr->NeedsWriteBarrierForMap();
2107
2108  LOperand* obj;
2109  if (needs_write_barrier) {
2110    obj = is_in_object
2111        ? UseRegister(instr->object())
2112        : UseTempRegister(instr->object());
2113  } else {
2114    obj = needs_write_barrier_for_map
2115        ? UseRegister(instr->object())
2116        : UseRegisterAtStart(instr->object());
2117  }
2118
2119  LOperand* val;
2120  if (needs_write_barrier) {
2121    val = UseTempRegister(instr->value());
2122  } else if (instr->field_representation().IsDouble()) {
2123    val = UseRegisterAtStart(instr->value());
2124  } else {
2125    val = UseRegister(instr->value());
2126  }
2127
2128  // We need a temporary register for write barrier of the map field.
2129  LOperand* temp = needs_write_barrier_for_map ? TempRegister() : NULL;
2130
2131  return new(zone()) LStoreNamedField(obj, val, temp);
2132}
2133
2134
2135LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
2136  LOperand* context = UseFixed(instr->context(), cp);
2137  LOperand* left = UseFixed(instr->left(), a1);
2138  LOperand* right = UseFixed(instr->right(), a0);
2139  return MarkAsCall(
2140      DefineFixed(new(zone()) LStringAdd(context, left, right), v0),
2141      instr);
2142}
2143
2144
2145LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
2146  LOperand* string = UseTempRegister(instr->string());
2147  LOperand* index = UseTempRegister(instr->index());
2148  LOperand* context = UseAny(instr->context());
2149  LStringCharCodeAt* result =
2150      new(zone()) LStringCharCodeAt(context, string, index);
2151  return AssignPointerMap(DefineAsRegister(result));
2152}
2153
2154
2155LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) {
2156  LOperand* char_code = UseRegister(instr->value());
2157  LOperand* context = UseAny(instr->context());
2158  LStringCharFromCode* result =
2159      new(zone()) LStringCharFromCode(context, char_code);
2160  return AssignPointerMap(DefineAsRegister(result));
2161}
2162
2163
2164LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) {
2165  LOperand* size = UseRegisterOrConstant(instr->size());
2166  LOperand* temp1 = TempRegister();
2167  LOperand* temp2 = TempRegister();
2168  if (instr->IsAllocationFolded()) {
2169    LFastAllocate* result = new (zone()) LFastAllocate(size, temp1, temp2);
2170    return DefineAsRegister(result);
2171  } else {
2172    info()->MarkAsDeferredCalling();
2173    LOperand* context = UseAny(instr->context());
2174    LAllocate* result = new (zone()) LAllocate(context, size, temp1, temp2);
2175    return AssignPointerMap(DefineAsRegister(result));
2176  }
2177}
2178
2179
2180LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
2181  DCHECK(argument_count_ == 0);
2182  allocator_->MarkAsOsrEntry();
2183  current_block_->last_environment()->set_ast_id(instr->ast_id());
2184  return AssignEnvironment(new(zone()) LOsrEntry);
2185}
2186
2187
2188LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
2189  LParameter* result = new(zone()) LParameter;
2190  if (instr->kind() == HParameter::STACK_PARAMETER) {
2191    int spill_index = chunk()->GetParameterStackSlot(instr->index());
2192    return DefineAsSpilled(result, spill_index);
2193  } else {
2194    DCHECK(info()->IsStub());
2195    CallInterfaceDescriptor descriptor = graph()->descriptor();
2196    int index = static_cast<int>(instr->index());
2197    Register reg = descriptor.GetRegisterParameter(index);
2198    return DefineFixed(result, reg);
2199  }
2200}
2201
2202
2203LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
2204  // Use an index that corresponds to the location in the unoptimized frame,
2205  // which the optimized frame will subsume.
2206  int env_index = instr->index();
2207  int spill_index = 0;
2208  if (instr->environment()->is_parameter_index(env_index)) {
2209    spill_index = chunk()->GetParameterStackSlot(env_index);
2210  } else {
2211    spill_index = env_index - instr->environment()->first_local_index();
2212    if (spill_index > LUnallocated::kMaxFixedSlotIndex) {
2213      Retry(kTooManySpillSlotsNeededForOSR);
2214      spill_index = 0;
2215    }
2216    spill_index += StandardFrameConstants::kFixedSlotCount;
2217  }
2218  return DefineAsSpilled(new(zone()) LUnknownOSRValue, spill_index);
2219}
2220
2221
2222LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
2223  // There are no real uses of the arguments object.
2224  // arguments.length and element access are supported directly on
2225  // stack arguments, and any real arguments object use causes a bailout.
2226  // So this value is never used.
2227  return NULL;
2228}
2229
2230
2231LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
2232  instr->ReplayEnvironment(current_block_->last_environment());
2233
2234  // There are no real uses of a captured object.
2235  return NULL;
2236}
2237
2238
2239LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
2240  info()->MarkAsRequiresFrame();
2241  LOperand* args = UseRegister(instr->arguments());
2242  LOperand* length = UseRegisterOrConstantAtStart(instr->length());
2243  LOperand* index = UseRegisterOrConstantAtStart(instr->index());
2244  return DefineAsRegister(new(zone()) LAccessArgumentsAt(args, length, index));
2245}
2246
2247
2248LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
2249  LOperand* context = UseFixed(instr->context(), cp);
2250  LOperand* value = UseFixed(instr->value(), a3);
2251  LTypeof* result = new (zone()) LTypeof(context, value);
2252  return MarkAsCall(DefineFixed(result, v0), instr);
2253}
2254
2255
2256LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) {
2257  return new(zone()) LTypeofIsAndBranch(UseTempRegister(instr->value()));
2258}
2259
2260
2261LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
2262  instr->ReplayEnvironment(current_block_->last_environment());
2263  return NULL;
2264}
2265
2266
2267LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
2268  if (instr->is_function_entry()) {
2269    LOperand* context = UseFixed(instr->context(), cp);
2270    return MarkAsCall(new(zone()) LStackCheck(context), instr);
2271  } else {
2272    DCHECK(instr->is_backwards_branch());
2273    LOperand* context = UseAny(instr->context());
2274    return AssignEnvironment(
2275        AssignPointerMap(new(zone()) LStackCheck(context)));
2276  }
2277}
2278
2279
2280LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
2281  HEnvironment* outer = current_block_->last_environment();
2282  outer->set_ast_id(instr->ReturnId());
2283  HConstant* undefined = graph()->GetConstantUndefined();
2284  HEnvironment* inner = outer->CopyForInlining(
2285      instr->closure(), instr->arguments_count(), instr->function(), undefined,
2286      instr->inlining_kind(), instr->syntactic_tail_call_mode());
2287  // Only replay binding of arguments object if it wasn't removed from graph.
2288  if (instr->arguments_var() != NULL && instr->arguments_object()->IsLinked()) {
2289    inner->Bind(instr->arguments_var(), instr->arguments_object());
2290  }
2291  inner->BindContext(instr->closure_context());
2292  inner->set_entry(instr);
2293  current_block_->UpdateEnvironment(inner);
2294  return NULL;
2295}
2296
2297
2298LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
2299  LInstruction* pop = NULL;
2300
2301  HEnvironment* env = current_block_->last_environment();
2302
2303  if (env->entry()->arguments_pushed()) {
2304    int argument_count = env->arguments_environment()->parameter_count();
2305    pop = new(zone()) LDrop(argument_count);
2306    DCHECK(instr->argument_delta() == -argument_count);
2307  }
2308
2309  HEnvironment* outer = current_block_->last_environment()->
2310      DiscardInlined(false);
2311  current_block_->UpdateEnvironment(outer);
2312
2313  return pop;
2314}
2315
2316
2317LInstruction* LChunkBuilder::DoForInPrepareMap(HForInPrepareMap* instr) {
2318  LOperand* context = UseFixed(instr->context(), cp);
2319  LOperand* object = UseFixed(instr->enumerable(), a0);
2320  LForInPrepareMap* result = new(zone()) LForInPrepareMap(context, object);
2321  return MarkAsCall(DefineFixed(result, v0), instr, CAN_DEOPTIMIZE_EAGERLY);
2322}
2323
2324
2325LInstruction* LChunkBuilder::DoForInCacheArray(HForInCacheArray* instr) {
2326  LOperand* map = UseRegister(instr->map());
2327  return AssignEnvironment(DefineAsRegister(new(zone()) LForInCacheArray(map)));
2328}
2329
2330
2331LInstruction* LChunkBuilder::DoCheckMapValue(HCheckMapValue* instr) {
2332  LOperand* value = UseRegisterAtStart(instr->value());
2333  LOperand* map = UseRegisterAtStart(instr->map());
2334  return AssignEnvironment(new(zone()) LCheckMapValue(value, map));
2335}
2336
2337
2338LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) {
2339  LOperand* object = UseRegister(instr->object());
2340  LOperand* index = UseTempRegister(instr->index());
2341  LLoadFieldByIndex* load = new(zone()) LLoadFieldByIndex(object, index);
2342  LInstruction* result = DefineSameAsFirst(load);
2343  return AssignPointerMap(result);
2344}
2345
2346}  // namespace internal
2347}  // namespace v8
2348
2349#endif  // V8_TARGET_ARCH_MIPS
2350