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