blob: 5b93f0af2eff2ab16190b9567645be5be45eb3a5 [file] [log] [blame]
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001// Copyright 2012 the V8 project authors. All rights reserved.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000028#include "v8.h"
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000029#include "lithium.h"
rossberg@chromium.org657d53b2012-07-12 11:06:03 +000030#include "scopes.h"
31
32#if V8_TARGET_ARCH_IA32
33#include "ia32/lithium-ia32.h"
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000034#include "ia32/lithium-codegen-ia32.h"
rossberg@chromium.org657d53b2012-07-12 11:06:03 +000035#elif V8_TARGET_ARCH_X64
36#include "x64/lithium-x64.h"
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000037#include "x64/lithium-codegen-x64.h"
rossberg@chromium.org657d53b2012-07-12 11:06:03 +000038#elif V8_TARGET_ARCH_ARM
39#include "arm/lithium-arm.h"
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000040#include "arm/lithium-codegen-arm.h"
rossberg@chromium.org657d53b2012-07-12 11:06:03 +000041#elif V8_TARGET_ARCH_MIPS
42#include "mips/lithium-mips.h"
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000043#include "mips/lithium-codegen-mips.h"
rossberg@chromium.org657d53b2012-07-12 11:06:03 +000044#else
45#error "Unknown architecture."
46#endif
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000047
48namespace v8 {
49namespace internal {
50
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000051
52void LOperand::PrintTo(StringStream* stream) {
53 LUnallocated* unalloc = NULL;
54 switch (kind()) {
55 case INVALID:
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000056 stream->Add("(0)");
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000057 break;
58 case UNALLOCATED:
59 unalloc = LUnallocated::cast(this);
60 stream->Add("v%d", unalloc->virtual_register());
61 switch (unalloc->policy()) {
62 case LUnallocated::NONE:
63 break;
64 case LUnallocated::FIXED_REGISTER: {
65 const char* register_name =
66 Register::AllocationIndexToString(unalloc->fixed_index());
67 stream->Add("(=%s)", register_name);
68 break;
69 }
70 case LUnallocated::FIXED_DOUBLE_REGISTER: {
71 const char* double_register_name =
72 DoubleRegister::AllocationIndexToString(unalloc->fixed_index());
73 stream->Add("(=%s)", double_register_name);
74 break;
75 }
76 case LUnallocated::FIXED_SLOT:
77 stream->Add("(=%dS)", unalloc->fixed_index());
78 break;
79 case LUnallocated::MUST_HAVE_REGISTER:
80 stream->Add("(R)");
81 break;
82 case LUnallocated::WRITABLE_REGISTER:
83 stream->Add("(WR)");
84 break;
85 case LUnallocated::SAME_AS_FIRST_INPUT:
86 stream->Add("(1)");
87 break;
88 case LUnallocated::ANY:
89 stream->Add("(-)");
90 break;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000091 }
92 break;
93 case CONSTANT_OPERAND:
94 stream->Add("[constant:%d]", index());
95 break;
96 case STACK_SLOT:
97 stream->Add("[stack:%d]", index());
98 break;
99 case DOUBLE_STACK_SLOT:
100 stream->Add("[double_stack:%d]", index());
101 break;
102 case REGISTER:
103 stream->Add("[%s|R]", Register::AllocationIndexToString(index()));
104 break;
105 case DOUBLE_REGISTER:
106 stream->Add("[%s|R]", DoubleRegister::AllocationIndexToString(index()));
107 break;
108 case ARGUMENT:
109 stream->Add("[arg:%d]", index());
110 break;
111 }
112}
113
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000114#define DEFINE_OPERAND_CACHE(name, type) \
115 L##name* L##name::cache = NULL; \
116 \
117 void L##name::SetUpCache() { \
118 if (cache) return; \
119 cache = new L##name[kNumCachedOperands]; \
120 for (int i = 0; i < kNumCachedOperands; i++) { \
121 cache[i].ConvertTo(type, i); \
122 } \
123 } \
124 \
125 void L##name::TearDownCache() { \
126 delete[] cache; \
127 }
128
129LITHIUM_OPERAND_LIST(DEFINE_OPERAND_CACHE)
130#undef DEFINE_OPERAND_CACHE
131
132void LOperand::SetUpCaches() {
133#define LITHIUM_OPERAND_SETUP(name, type) L##name::SetUpCache();
134 LITHIUM_OPERAND_LIST(LITHIUM_OPERAND_SETUP)
135#undef LITHIUM_OPERAND_SETUP
136}
137
138
139void LOperand::TearDownCaches() {
140#define LITHIUM_OPERAND_TEARDOWN(name, type) L##name::TearDownCache();
141 LITHIUM_OPERAND_LIST(LITHIUM_OPERAND_TEARDOWN)
142#undef LITHIUM_OPERAND_TEARDOWN
143}
144
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000145
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000146bool LParallelMove::IsRedundant() const {
147 for (int i = 0; i < move_operands_.length(); ++i) {
148 if (!move_operands_[i].IsRedundant()) return false;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000149 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000150 return true;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000151}
152
153
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000154void LParallelMove::PrintDataTo(StringStream* stream) const {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000155 bool first = true;
156 for (int i = 0; i < move_operands_.length(); ++i) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000157 if (!move_operands_[i].IsEliminated()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000158 LOperand* source = move_operands_[i].source();
159 LOperand* destination = move_operands_[i].destination();
160 if (!first) stream->Add(" ");
161 first = false;
162 if (source->Equals(destination)) {
163 destination->PrintTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000164 } else {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000165 destination->PrintTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000166 stream->Add(" = ");
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000167 source->PrintTo(stream);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000168 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000169 stream->Add(";");
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000170 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000171 }
172}
173
174
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000175void LEnvironment::PrintTo(StringStream* stream) {
176 stream->Add("[id=%d|", ast_id());
177 stream->Add("[parameters=%d|", parameter_count());
178 stream->Add("[arguments_stack_height=%d|", arguments_stack_height());
179 for (int i = 0; i < values_.length(); ++i) {
180 if (i != 0) stream->Add(";");
181 if (values_[i] == NULL) {
182 stream->Add("[hole]");
183 } else {
184 values_[i]->PrintTo(stream);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000185 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000186 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000187 stream->Add("]");
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000188}
189
190
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000191void LPointerMap::RecordPointer(LOperand* op, Zone* zone) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000192 // Do not record arguments as pointers.
193 if (op->IsStackSlot() && op->index() < 0) return;
194 ASSERT(!op->IsDoubleRegister() && !op->IsDoubleStackSlot());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000195 pointer_operands_.Add(op, zone);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000196}
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000197
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000198
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000199void LPointerMap::RemovePointer(LOperand* op) {
200 // Do not record arguments as pointers.
201 if (op->IsStackSlot() && op->index() < 0) return;
202 ASSERT(!op->IsDoubleRegister() && !op->IsDoubleStackSlot());
203 for (int i = 0; i < pointer_operands_.length(); ++i) {
204 if (pointer_operands_[i]->Equals(op)) {
205 pointer_operands_.Remove(i);
206 --i;
207 }
208 }
209}
210
211
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000212void LPointerMap::RecordUntagged(LOperand* op, Zone* zone) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000213 // Do not record arguments as pointers.
214 if (op->IsStackSlot() && op->index() < 0) return;
215 ASSERT(!op->IsDoubleRegister() && !op->IsDoubleStackSlot());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000216 untagged_operands_.Add(op, zone);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000217}
218
219
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000220void LPointerMap::PrintTo(StringStream* stream) {
221 stream->Add("{");
222 for (int i = 0; i < pointer_operands_.length(); ++i) {
223 if (i != 0) stream->Add(";");
224 pointer_operands_[i]->PrintTo(stream);
225 }
226 stream->Add("} @%d", position());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000227}
228
229
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000230int ElementsKindToShiftSize(ElementsKind elements_kind) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000231 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000232 case EXTERNAL_BYTE_ELEMENTS:
233 case EXTERNAL_PIXEL_ELEMENTS:
234 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000235 return 0;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000236 case EXTERNAL_SHORT_ELEMENTS:
237 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000238 return 1;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000239 case EXTERNAL_INT_ELEMENTS:
240 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
241 case EXTERNAL_FLOAT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000242 return 2;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000243 case EXTERNAL_DOUBLE_ELEMENTS:
244 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000245 case FAST_HOLEY_DOUBLE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000246 return 3;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000247 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000248 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000249 case FAST_HOLEY_SMI_ELEMENTS:
250 case FAST_HOLEY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000251 case DICTIONARY_ELEMENTS:
252 case NON_STRICT_ARGUMENTS_ELEMENTS:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000253 return kPointerSizeLog2;
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000254 }
255 UNREACHABLE();
256 return 0;
257}
258
259
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000260LLabel* LChunk::GetLabel(int block_id) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000261 HBasicBlock* block = graph_->blocks()->at(block_id);
262 int first_instruction = block->first_instruction_index();
263 return LLabel::cast(instructions_[first_instruction]);
264}
265
266
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000267int LChunk::LookupDestination(int block_id) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000268 LLabel* cur = GetLabel(block_id);
269 while (cur->replacement() != NULL) {
270 cur = cur->replacement();
271 }
272 return cur->block_id();
273}
274
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000275Label* LChunk::GetAssemblyLabel(int block_id) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000276 LLabel* label = GetLabel(block_id);
277 ASSERT(!label->HasReplacement());
278 return label->label();
279}
280
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000281void LChunk::MarkEmptyBlocks() {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000282 HPhase phase("L_Mark empty blocks", this);
283 for (int i = 0; i < graph()->blocks()->length(); ++i) {
284 HBasicBlock* block = graph()->blocks()->at(i);
285 int first = block->first_instruction_index();
286 int last = block->last_instruction_index();
287 LInstruction* first_instr = instructions()->at(first);
288 LInstruction* last_instr = instructions()->at(last);
289
290 LLabel* label = LLabel::cast(first_instr);
291 if (last_instr->IsGoto()) {
292 LGoto* goto_instr = LGoto::cast(last_instr);
293 if (label->IsRedundant() &&
294 !label->is_loop_header()) {
295 bool can_eliminate = true;
296 for (int i = first + 1; i < last && can_eliminate; ++i) {
297 LInstruction* cur = instructions()->at(i);
298 if (cur->IsGap()) {
299 LGap* gap = LGap::cast(cur);
300 if (!gap->IsRedundant()) {
301 can_eliminate = false;
302 }
303 } else {
304 can_eliminate = false;
305 }
306 }
307
308 if (can_eliminate) {
309 label->set_replacement(GetLabel(goto_instr->block_id()));
310 }
311 }
312 }
313 }
314}
315
316
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000317void LChunk::AddInstruction(LInstruction* instr, HBasicBlock* block) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000318 LInstructionGap* gap = new(graph_->zone()) LInstructionGap(block);
319 int index = -1;
320 if (instr->IsControl()) {
321 instructions_.Add(gap, zone());
322 index = instructions_.length();
323 instructions_.Add(instr, zone());
324 } else {
325 index = instructions_.length();
326 instructions_.Add(instr, zone());
327 instructions_.Add(gap, zone());
328 }
329 if (instr->HasPointerMap()) {
330 pointer_maps_.Add(instr->pointer_map(), zone());
331 instr->pointer_map()->set_lithium_position(index);
332 }
333}
334
335
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000336LConstantOperand* LChunk::DefineConstantOperand(HConstant* constant) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000337 return LConstantOperand::Create(constant->id(), zone());
338}
339
340
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000341int LChunk::GetParameterStackSlot(int index) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000342 // The receiver is at index 0, the first parameter at index 1, so we
343 // shift all parameter indexes down by the number of parameters, and
344 // make sure they end up negative so they are distinguishable from
345 // spill slots.
346 int result = index - info()->scope()->num_parameters() - 1;
347 ASSERT(result < 0);
348 return result;
349}
350
351
352// A parameter relative to ebp in the arguments stub.
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000353int LChunk::ParameterAt(int index) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000354 ASSERT(-1 <= index); // -1 is the receiver.
355 return (1 + info()->scope()->num_parameters() - index) *
356 kPointerSize;
357}
358
359
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000360LGap* LChunk::GetGapAt(int index) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000361 return LGap::cast(instructions_[index]);
362}
363
364
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000365bool LChunk::IsGapAt(int index) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000366 return instructions_[index]->IsGap();
367}
368
369
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000370int LChunk::NearestGapPos(int index) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000371 while (!IsGapAt(index)) index--;
372 return index;
373}
374
375
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000376void LChunk::AddGapMove(int index, LOperand* from, LOperand* to) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000377 GetGapAt(index)->GetOrCreateParallelMove(
378 LGap::START, zone())->AddMove(from, to, zone());
379}
380
381
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000382HConstant* LChunk::LookupConstant(LConstantOperand* operand) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000383 return HConstant::cast(graph_->LookupValue(operand->index()));
384}
385
386
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000387Representation LChunk::LookupLiteralRepresentation(
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000388 LConstantOperand* operand) const {
389 return graph_->LookupValue(operand->index())->representation();
390}
391
392
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000393LChunk* LChunk::NewChunk(HGraph* graph) {
394 NoHandleAllocation no_handles;
395 AssertNoAllocation no_gc;
396
397 int values = graph->GetMaximumValueID();
398 if (values > LUnallocated::kMaxVirtualRegisters) {
399 if (FLAG_trace_bailout) {
400 PrintF("Not enough virtual registers for (values).\n");
401 }
402 return NULL;
403 }
404 LAllocator allocator(values, graph);
405 LChunkBuilder builder(graph->info(), graph, &allocator);
406 LChunk* chunk = builder.Build();
407 if (chunk == NULL) return NULL;
408
409 if (!allocator.Allocate(chunk)) {
410 if (FLAG_trace_bailout) {
411 PrintF("Not enough virtual registers (regalloc).\n");
412 }
413 return NULL;
414 }
415
416 return chunk;
417}
418
419
420Handle<Code> LChunk::Codegen() {
421 MacroAssembler assembler(info()->isolate(), NULL, 0);
422 LCodeGen generator(this, &assembler, info());
423
424 MarkEmptyBlocks();
425
426 if (generator.GenerateCode()) {
427 if (FLAG_trace_codegen) {
428 PrintF("Crankshaft Compiler - ");
429 }
430 CodeGenerator::MakeCodePrologue(info());
431 Code::Flags flags = Code::ComputeFlags(Code::OPTIMIZED_FUNCTION);
432 Handle<Code> code =
433 CodeGenerator::MakeCodeEpilogue(&assembler, flags, info());
434 generator.FinishCode(code);
435 CodeGenerator::PrintCode(code, info());
436 return code;
437 }
438 return Handle<Code>::null();
439}
440
441
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000442} } // namespace v8::internal