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