blob: fd50ee8f8b9df0f20d5b5ac70682ca5d633b6177 [file] [log] [blame]
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +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
28#ifndef V8_LITHIUM_H_
29#define V8_LITHIUM_H_
30
lrn@chromium.org1c092762011-05-09 09:42:16 +000031#include "allocation.h"
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000032#include "hydrogen.h"
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000033#include "safepoint-table.h"
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000034
35namespace v8 {
36namespace internal {
37
jkummerow@chromium.org1456e702012-03-30 08:38:13 +000038#define LITHIUM_OPERAND_LIST(V) \
39 V(ConstantOperand, CONSTANT_OPERAND) \
40 V(StackSlot, STACK_SLOT) \
41 V(DoubleStackSlot, DOUBLE_STACK_SLOT) \
42 V(Register, REGISTER) \
43 V(DoubleRegister, DOUBLE_REGISTER)
44
45
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000046class LOperand : public ZoneObject {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000047 public:
48 enum Kind {
49 INVALID,
50 UNALLOCATED,
51 CONSTANT_OPERAND,
52 STACK_SLOT,
53 DOUBLE_STACK_SLOT,
54 REGISTER,
55 DOUBLE_REGISTER,
56 ARGUMENT
57 };
58
59 LOperand() : value_(KindField::encode(INVALID)) { }
60
61 Kind kind() const { return KindField::decode(value_); }
62 int index() const { return static_cast<int>(value_) >> kKindFieldWidth; }
jkummerow@chromium.org1456e702012-03-30 08:38:13 +000063#define LITHIUM_OPERAND_PREDICATE(name, type) \
64 bool Is##name() const { return kind() == type; }
65 LITHIUM_OPERAND_LIST(LITHIUM_OPERAND_PREDICATE)
66 LITHIUM_OPERAND_PREDICATE(Argument, ARGUMENT)
67 LITHIUM_OPERAND_PREDICATE(Unallocated, UNALLOCATED)
68 LITHIUM_OPERAND_PREDICATE(Ignored, INVALID)
69#undef LITHIUM_OPERAND_PREDICATE
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000070 bool Equals(LOperand* other) const { return value_ == other->value_; }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000071
72 void PrintTo(StringStream* stream);
73 void ConvertTo(Kind kind, int index) {
74 value_ = KindField::encode(kind);
75 value_ |= index << kKindFieldWidth;
76 ASSERT(this->index() == index);
77 }
78
jkummerow@chromium.org1456e702012-03-30 08:38:13 +000079 // Calls SetUpCache()/TearDownCache() for each subclass.
80 static void SetUpCaches();
81 static void TearDownCaches();
82
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000083 protected:
84 static const int kKindFieldWidth = 3;
85 class KindField : public BitField<Kind, 0, kKindFieldWidth> { };
86
87 LOperand(Kind kind, int index) { ConvertTo(kind, index); }
88
89 unsigned value_;
90};
91
92
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000093class LUnallocated : public LOperand {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000094 public:
ulan@chromium.org57ff8812013-05-10 08:16:55 +000095 enum BasicPolicy {
96 FIXED_SLOT,
97 EXTENDED_POLICY
98 };
99
100 enum ExtendedPolicy {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000101 NONE,
102 ANY,
103 FIXED_REGISTER,
104 FIXED_DOUBLE_REGISTER,
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000105 MUST_HAVE_REGISTER,
106 WRITABLE_REGISTER,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000107 SAME_AS_FIRST_INPUT
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000108 };
109
110 // Lifetime of operand inside the instruction.
111 enum Lifetime {
112 // USED_AT_START operand is guaranteed to be live only at
113 // instruction start. Register allocator is free to assign the same register
114 // to some other operand used inside instruction (i.e. temporary or
115 // output).
116 USED_AT_START,
117
118 // USED_AT_END operand is treated as live until the end of
119 // instruction. This means that register allocator will not reuse it's
120 // register for any other operand inside instruction.
121 USED_AT_END
122 };
123
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000124 explicit LUnallocated(ExtendedPolicy policy) : LOperand(UNALLOCATED, 0) {
125 value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
126 value_ |= ExtendedPolicyField::encode(policy);
127 value_ |= LifetimeField::encode(USED_AT_END);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000128 }
129
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000130 LUnallocated(BasicPolicy policy, int index) : LOperand(UNALLOCATED, 0) {
131 ASSERT(policy == FIXED_SLOT);
132 value_ |= BasicPolicyField::encode(policy);
133 value_ |= index << FixedSlotIndexField::kShift;
134 ASSERT(this->fixed_slot_index() == index);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000135 }
136
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000137 LUnallocated(ExtendedPolicy policy, int index) : LOperand(UNALLOCATED, 0) {
138 ASSERT(policy == FIXED_REGISTER || policy == FIXED_DOUBLE_REGISTER);
139 value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
140 value_ |= ExtendedPolicyField::encode(policy);
141 value_ |= LifetimeField::encode(USED_AT_END);
142 value_ |= FixedRegisterField::encode(index);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000143 }
144
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000145 LUnallocated(ExtendedPolicy policy, Lifetime lifetime)
146 : LOperand(UNALLOCATED, 0) {
147 value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
148 value_ |= ExtendedPolicyField::encode(policy);
149 value_ |= LifetimeField::encode(lifetime);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000150 }
151
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000152 LUnallocated* CopyUnconstrained(Zone* zone) {
153 LUnallocated* result = new(zone) LUnallocated(ANY);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000154 result->set_virtual_register(virtual_register());
155 return result;
156 }
157
158 static LUnallocated* cast(LOperand* op) {
159 ASSERT(op->IsUnallocated());
160 return reinterpret_cast<LUnallocated*>(op);
161 }
162
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000163 // The encoding used for LUnallocated operands depends on the policy that is
164 // stored within the operand. The FIXED_SLOT policy uses a compact encoding
165 // because it accommodates a larger pay-load.
166 //
167 // For FIXED_SLOT policy:
168 // +------------------------------------------+
169 // | slot_index | vreg | 0 | 001 |
170 // +------------------------------------------+
171 //
172 // For all other (extended) policies:
173 // +------------------------------------------+
174 // | reg_index | L | PPP | vreg | 1 | 001 | L ... Lifetime
175 // +------------------------------------------+ P ... Policy
176 //
177 // The slot index is a signed value which requires us to decode it manually
178 // instead of using the BitField utility class.
179
180 // The superclass has a KindField.
181 STATIC_ASSERT(kKindFieldWidth == 3);
182
183 // BitFields for all unallocated operands.
184 class BasicPolicyField : public BitField<BasicPolicy, 3, 1> {};
185 class VirtualRegisterField : public BitField<unsigned, 4, 18> {};
186
187 // BitFields specific to BasicPolicy::FIXED_SLOT.
188 class FixedSlotIndexField : public BitField<int, 22, 10> {};
189
190 // BitFields specific to BasicPolicy::EXTENDED_POLICY.
191 class ExtendedPolicyField : public BitField<ExtendedPolicy, 22, 3> {};
192 class LifetimeField : public BitField<Lifetime, 25, 1> {};
193 class FixedRegisterField : public BitField<int, 26, 6> {};
194
195 static const int kMaxVirtualRegisters = VirtualRegisterField::kMax + 1;
196 static const int kFixedSlotIndexWidth = FixedSlotIndexField::kSize;
197 static const int kMaxFixedSlotIndex = (1 << (kFixedSlotIndexWidth - 1)) - 1;
198 static const int kMinFixedSlotIndex = -(1 << (kFixedSlotIndexWidth - 1));
199
200 // Predicates for the operand policy.
201 bool HasAnyPolicy() const {
202 return basic_policy() == EXTENDED_POLICY &&
203 extended_policy() == ANY;
204 }
205 bool HasFixedPolicy() const {
206 return basic_policy() == FIXED_SLOT ||
207 extended_policy() == FIXED_REGISTER ||
208 extended_policy() == FIXED_DOUBLE_REGISTER;
209 }
210 bool HasRegisterPolicy() const {
211 return basic_policy() == EXTENDED_POLICY && (
212 extended_policy() == WRITABLE_REGISTER ||
213 extended_policy() == MUST_HAVE_REGISTER);
214 }
215 bool HasSameAsInputPolicy() const {
216 return basic_policy() == EXTENDED_POLICY &&
217 extended_policy() == SAME_AS_FIRST_INPUT;
218 }
219 bool HasFixedSlotPolicy() const {
220 return basic_policy() == FIXED_SLOT;
221 }
222 bool HasFixedRegisterPolicy() const {
223 return basic_policy() == EXTENDED_POLICY &&
224 extended_policy() == FIXED_REGISTER;
225 }
226 bool HasFixedDoubleRegisterPolicy() const {
227 return basic_policy() == EXTENDED_POLICY &&
228 extended_policy() == FIXED_DOUBLE_REGISTER;
229 }
230 bool HasWritableRegisterPolicy() const {
231 return basic_policy() == EXTENDED_POLICY &&
232 extended_policy() == WRITABLE_REGISTER;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000233 }
234
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000235 // [basic_policy]: Distinguish between FIXED_SLOT and all other policies.
236 BasicPolicy basic_policy() const {
237 return BasicPolicyField::decode(value_);
238 }
239
240 // [extended_policy]: Only for non-FIXED_SLOT. The finer-grained policy.
241 ExtendedPolicy extended_policy() const {
242 ASSERT(basic_policy() == EXTENDED_POLICY);
243 return ExtendedPolicyField::decode(value_);
244 }
245
246 // [fixed_slot_index]: Only for FIXED_SLOT.
247 int fixed_slot_index() const {
248 ASSERT(HasFixedSlotPolicy());
249 return static_cast<int>(value_) >> FixedSlotIndexField::kShift;
250 }
251
252 // [fixed_register_index]: Only for FIXED_REGISTER or FIXED_DOUBLE_REGISTER.
253 int fixed_register_index() const {
254 ASSERT(HasFixedRegisterPolicy() || HasFixedDoubleRegisterPolicy());
255 return FixedRegisterField::decode(value_);
256 }
257
258 // [virtual_register]: The virtual register ID for this operand.
259 int virtual_register() const {
260 return VirtualRegisterField::decode(value_);
261 }
262 void set_virtual_register(unsigned id) {
263 value_ = VirtualRegisterField::update(value_, id);
264 }
265
266 // [lifetime]: Only for non-FIXED_SLOT.
267 bool IsUsedAtStart() {
268 ASSERT(basic_policy() == EXTENDED_POLICY);
269 return LifetimeField::decode(value_) == USED_AT_START;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000270 }
271};
272
273
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000274class LMoveOperands V8_FINAL BASE_EMBEDDED {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000275 public:
276 LMoveOperands(LOperand* source, LOperand* destination)
277 : source_(source), destination_(destination) {
278 }
279
280 LOperand* source() const { return source_; }
281 void set_source(LOperand* operand) { source_ = operand; }
282
283 LOperand* destination() const { return destination_; }
284 void set_destination(LOperand* operand) { destination_ = operand; }
285
286 // The gap resolver marks moves as "in-progress" by clearing the
287 // destination (but not the source).
288 bool IsPending() const {
289 return destination_ == NULL && source_ != NULL;
290 }
291
292 // True if this move a move into the given destination operand.
293 bool Blocks(LOperand* operand) const {
294 return !IsEliminated() && source()->Equals(operand);
295 }
296
297 // A move is redundant if it's been eliminated, if its source and
298 // destination are the same, or if its destination is unneeded.
299 bool IsRedundant() const {
300 return IsEliminated() || source_->Equals(destination_) || IsIgnored();
301 }
302
303 bool IsIgnored() const {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000304 return destination_ != NULL && destination_->IsIgnored();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000305 }
306
307 // We clear both operands to indicate move that's been eliminated.
308 void Eliminate() { source_ = destination_ = NULL; }
309 bool IsEliminated() const {
310 ASSERT(source_ != NULL || destination_ == NULL);
311 return source_ == NULL;
312 }
313
314 private:
315 LOperand* source_;
316 LOperand* destination_;
317};
318
319
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000320class LConstantOperand V8_FINAL : public LOperand {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000321 public:
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000322 static LConstantOperand* Create(int index, Zone* zone) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000323 ASSERT(index >= 0);
324 if (index < kNumCachedOperands) return &cache[index];
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000325 return new(zone) LConstantOperand(index);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000326 }
327
328 static LConstantOperand* cast(LOperand* op) {
329 ASSERT(op->IsConstantOperand());
330 return reinterpret_cast<LConstantOperand*>(op);
331 }
332
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000333 static void SetUpCache();
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000334 static void TearDownCache();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000335
336 private:
337 static const int kNumCachedOperands = 128;
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000338 static LConstantOperand* cache;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000339
340 LConstantOperand() : LOperand() { }
341 explicit LConstantOperand(int index) : LOperand(CONSTANT_OPERAND, index) { }
342};
343
344
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000345class LArgument V8_FINAL : public LOperand {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000346 public:
347 explicit LArgument(int index) : LOperand(ARGUMENT, index) { }
348
349 static LArgument* cast(LOperand* op) {
350 ASSERT(op->IsArgument());
351 return reinterpret_cast<LArgument*>(op);
352 }
353};
354
355
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000356class LStackSlot V8_FINAL : public LOperand {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000357 public:
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000358 static LStackSlot* Create(int index, Zone* zone) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000359 ASSERT(index >= 0);
360 if (index < kNumCachedOperands) return &cache[index];
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000361 return new(zone) LStackSlot(index);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000362 }
363
364 static LStackSlot* cast(LOperand* op) {
365 ASSERT(op->IsStackSlot());
366 return reinterpret_cast<LStackSlot*>(op);
367 }
368
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000369 static void SetUpCache();
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000370 static void TearDownCache();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000371
372 private:
373 static const int kNumCachedOperands = 128;
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000374 static LStackSlot* cache;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000375
376 LStackSlot() : LOperand() { }
377 explicit LStackSlot(int index) : LOperand(STACK_SLOT, index) { }
378};
379
380
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000381class LDoubleStackSlot V8_FINAL : public LOperand {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000382 public:
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000383 static LDoubleStackSlot* Create(int index, Zone* zone) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000384 ASSERT(index >= 0);
385 if (index < kNumCachedOperands) return &cache[index];
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000386 return new(zone) LDoubleStackSlot(index);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000387 }
388
389 static LDoubleStackSlot* cast(LOperand* op) {
390 ASSERT(op->IsStackSlot());
391 return reinterpret_cast<LDoubleStackSlot*>(op);
392 }
393
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000394 static void SetUpCache();
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000395 static void TearDownCache();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000396
397 private:
398 static const int kNumCachedOperands = 128;
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000399 static LDoubleStackSlot* cache;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000400
401 LDoubleStackSlot() : LOperand() { }
402 explicit LDoubleStackSlot(int index) : LOperand(DOUBLE_STACK_SLOT, index) { }
403};
404
405
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000406class LRegister V8_FINAL : public LOperand {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000407 public:
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000408 static LRegister* Create(int index, Zone* zone) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000409 ASSERT(index >= 0);
410 if (index < kNumCachedOperands) return &cache[index];
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000411 return new(zone) LRegister(index);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000412 }
413
414 static LRegister* cast(LOperand* op) {
415 ASSERT(op->IsRegister());
416 return reinterpret_cast<LRegister*>(op);
417 }
418
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000419 static void SetUpCache();
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000420 static void TearDownCache();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000421
422 private:
423 static const int kNumCachedOperands = 16;
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000424 static LRegister* cache;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000425
426 LRegister() : LOperand() { }
427 explicit LRegister(int index) : LOperand(REGISTER, index) { }
428};
429
430
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000431class LDoubleRegister V8_FINAL : public LOperand {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000432 public:
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000433 static LDoubleRegister* Create(int index, Zone* zone) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000434 ASSERT(index >= 0);
435 if (index < kNumCachedOperands) return &cache[index];
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000436 return new(zone) LDoubleRegister(index);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000437 }
438
439 static LDoubleRegister* cast(LOperand* op) {
440 ASSERT(op->IsDoubleRegister());
441 return reinterpret_cast<LDoubleRegister*>(op);
442 }
443
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000444 static void SetUpCache();
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000445 static void TearDownCache();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000446
447 private:
448 static const int kNumCachedOperands = 16;
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000449 static LDoubleRegister* cache;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000450
451 LDoubleRegister() : LOperand() { }
452 explicit LDoubleRegister(int index) : LOperand(DOUBLE_REGISTER, index) { }
453};
454
455
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000456class LParallelMove V8_FINAL : public ZoneObject {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000457 public:
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000458 explicit LParallelMove(Zone* zone) : move_operands_(4, zone) { }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000459
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000460 void AddMove(LOperand* from, LOperand* to, Zone* zone) {
461 move_operands_.Add(LMoveOperands(from, to), zone);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000462 }
463
464 bool IsRedundant() const;
465
466 const ZoneList<LMoveOperands>* move_operands() const {
467 return &move_operands_;
468 }
469
470 void PrintDataTo(StringStream* stream) const;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000471
472 private:
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000473 ZoneList<LMoveOperands> move_operands_;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000474};
475
476
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000477class LPointerMap V8_FINAL : public ZoneObject {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000478 public:
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000479 explicit LPointerMap(int position, Zone* zone)
480 : pointer_operands_(8, zone),
481 untagged_operands_(0, zone),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000482 position_(position),
483 lithium_position_(-1) { }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000484
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000485 const ZoneList<LOperand*>* GetNormalizedOperands() {
486 for (int i = 0; i < untagged_operands_.length(); ++i) {
487 RemovePointer(untagged_operands_[i]);
488 }
489 untagged_operands_.Clear();
490 return &pointer_operands_;
491 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000492 int position() const { return position_; }
493 int lithium_position() const { return lithium_position_; }
494
495 void set_lithium_position(int pos) {
496 ASSERT(lithium_position_ == -1);
497 lithium_position_ = pos;
498 }
499
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000500 void RecordPointer(LOperand* op, Zone* zone);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000501 void RemovePointer(LOperand* op);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000502 void RecordUntagged(LOperand* op, Zone* zone);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000503 void PrintTo(StringStream* stream);
504
505 private:
506 ZoneList<LOperand*> pointer_operands_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000507 ZoneList<LOperand*> untagged_operands_;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000508 int position_;
509 int lithium_position_;
510};
511
512
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000513class LEnvironment V8_FINAL : public ZoneObject {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000514 public:
515 LEnvironment(Handle<JSFunction> closure,
ulan@chromium.org967e2702012-02-28 09:49:15 +0000516 FrameType frame_type,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000517 BailoutId ast_id,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000518 int parameter_count,
519 int argument_count,
520 int value_count,
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000521 LEnvironment* outer,
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000522 HEnterInlined* entry,
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000523 Zone* zone)
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000524 : closure_(closure),
ulan@chromium.org967e2702012-02-28 09:49:15 +0000525 frame_type_(frame_type),
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000526 arguments_stack_height_(argument_count),
527 deoptimization_index_(Safepoint::kNoDeoptimizationIndex),
528 translation_index_(-1),
529 ast_id_(ast_id),
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000530 translation_size_(value_count),
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000531 parameter_count_(parameter_count),
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000532 pc_offset_(-1),
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000533 values_(value_count, zone),
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000534 is_tagged_(value_count, zone),
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000535 is_uint32_(value_count, zone),
danno@chromium.org59400602013-08-13 17:09:37 +0000536 object_mapping_(0, zone),
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000537 outer_(outer),
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000538 entry_(entry),
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000539 zone_(zone) { }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000540
541 Handle<JSFunction> closure() const { return closure_; }
ulan@chromium.org967e2702012-02-28 09:49:15 +0000542 FrameType frame_type() const { return frame_type_; }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000543 int arguments_stack_height() const { return arguments_stack_height_; }
544 int deoptimization_index() const { return deoptimization_index_; }
545 int translation_index() const { return translation_index_; }
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000546 BailoutId ast_id() const { return ast_id_; }
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000547 int translation_size() const { return translation_size_; }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000548 int parameter_count() const { return parameter_count_; }
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000549 int pc_offset() const { return pc_offset_; }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000550 const ZoneList<LOperand*>* values() const { return &values_; }
551 LEnvironment* outer() const { return outer_; }
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000552 HEnterInlined* entry() { return entry_; }
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000553 Zone* zone() const { return zone_; }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000554
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000555 void AddValue(LOperand* operand,
556 Representation representation,
557 bool is_uint32) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000558 values_.Add(operand, zone());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000559 if (representation.IsSmiOrTagged()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000560 ASSERT(!is_uint32);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000561 is_tagged_.Add(values_.length() - 1, zone());
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000562 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000563
564 if (is_uint32) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000565 is_uint32_.Add(values_.length() - 1, zone());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000566 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000567 }
568
569 bool HasTaggedValueAt(int index) const {
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000570 return is_tagged_.Contains(index);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000571 }
572
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000573 bool HasUint32ValueAt(int index) const {
574 return is_uint32_.Contains(index);
575 }
576
danno@chromium.org59400602013-08-13 17:09:37 +0000577 void AddNewObject(int length, bool is_arguments) {
578 uint32_t encoded = LengthOrDupeField::encode(length) |
579 IsArgumentsField::encode(is_arguments) |
580 IsDuplicateField::encode(false);
581 object_mapping_.Add(encoded, zone());
582 }
583
584 void AddDuplicateObject(int dupe_of) {
585 uint32_t encoded = LengthOrDupeField::encode(dupe_of) |
586 IsDuplicateField::encode(true);
587 object_mapping_.Add(encoded, zone());
588 }
589
590 int ObjectDuplicateOfAt(int index) {
591 ASSERT(ObjectIsDuplicateAt(index));
592 return LengthOrDupeField::decode(object_mapping_[index]);
593 }
594
595 int ObjectLengthAt(int index) {
596 ASSERT(!ObjectIsDuplicateAt(index));
597 return LengthOrDupeField::decode(object_mapping_[index]);
598 }
599
600 bool ObjectIsArgumentsAt(int index) {
601 ASSERT(!ObjectIsDuplicateAt(index));
602 return IsArgumentsField::decode(object_mapping_[index]);
603 }
604
605 bool ObjectIsDuplicateAt(int index) {
606 return IsDuplicateField::decode(object_mapping_[index]);
607 }
608
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000609 void Register(int deoptimization_index,
610 int translation_index,
611 int pc_offset) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000612 ASSERT(!HasBeenRegistered());
613 deoptimization_index_ = deoptimization_index;
614 translation_index_ = translation_index;
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000615 pc_offset_ = pc_offset;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000616 }
617 bool HasBeenRegistered() const {
618 return deoptimization_index_ != Safepoint::kNoDeoptimizationIndex;
619 }
620
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000621 void PrintTo(StringStream* stream);
622
danno@chromium.org59400602013-08-13 17:09:37 +0000623 // Marker value indicating a de-materialized object.
624 static LOperand* materialization_marker() { return NULL; }
625
626 // Encoding used for the object_mapping map below.
627 class LengthOrDupeField : public BitField<int, 0, 30> { };
628 class IsArgumentsField : public BitField<bool, 30, 1> { };
629 class IsDuplicateField : public BitField<bool, 31, 1> { };
630
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000631 private:
632 Handle<JSFunction> closure_;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000633 FrameType frame_type_;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000634 int arguments_stack_height_;
635 int deoptimization_index_;
636 int translation_index_;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000637 BailoutId ast_id_;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000638 int translation_size_;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000639 int parameter_count_;
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000640 int pc_offset_;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000641
642 // Value array: [parameters] [locals] [expression stack] [de-materialized].
643 // |>--------- translation_size ---------<|
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000644 ZoneList<LOperand*> values_;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000645 GrowableBitVector is_tagged_;
646 GrowableBitVector is_uint32_;
danno@chromium.org59400602013-08-13 17:09:37 +0000647
648 // Map with encoded information about materialization_marker operands.
649 ZoneList<uint32_t> object_mapping_;
650
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000651 LEnvironment* outer_;
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000652 HEnterInlined* entry_;
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000653 Zone* zone_;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000654};
655
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000656
657// Iterates over the non-null, non-constant operands in an environment.
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000658class ShallowIterator V8_FINAL BASE_EMBEDDED {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000659 public:
660 explicit ShallowIterator(LEnvironment* env)
661 : env_(env),
662 limit_(env != NULL ? env->values()->length() : 0),
663 current_(0) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000664 SkipUninteresting();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000665 }
666
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000667 bool Done() { return current_ >= limit_; }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000668
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000669 LOperand* Current() {
670 ASSERT(!Done());
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000671 ASSERT(env_->values()->at(current_) != NULL);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000672 return env_->values()->at(current_);
673 }
674
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000675 void Advance() {
676 ASSERT(!Done());
677 ++current_;
678 SkipUninteresting();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000679 }
680
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000681 LEnvironment* env() { return env_; }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000682
683 private:
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000684 bool ShouldSkip(LOperand* op) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000685 return op == NULL || op->IsConstantOperand() || op->IsArgument();
686 }
687
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000688 // Skip until something interesting, beginning with and including current_.
689 void SkipUninteresting() {
690 while (current_ < limit_ && ShouldSkip(env_->values()->at(current_))) {
691 ++current_;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000692 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000693 }
694
695 LEnvironment* env_;
696 int limit_;
697 int current_;
698};
699
700
701// Iterator for non-null, non-constant operands incl. outer environments.
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000702class DeepIterator V8_FINAL BASE_EMBEDDED {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000703 public:
704 explicit DeepIterator(LEnvironment* env)
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000705 : current_iterator_(env) {
706 SkipUninteresting();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000707 }
708
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000709 bool Done() { return current_iterator_.Done(); }
710
711 LOperand* Current() {
712 ASSERT(!current_iterator_.Done());
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000713 ASSERT(current_iterator_.Current() != NULL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000714 return current_iterator_.Current();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000715 }
716
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000717 void Advance() {
718 current_iterator_.Advance();
719 SkipUninteresting();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000720 }
721
722 private:
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000723 void SkipUninteresting() {
724 while (current_iterator_.env() != NULL && current_iterator_.Done()) {
725 current_iterator_ = ShallowIterator(current_iterator_.env()->outer());
726 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000727 }
728
729 ShallowIterator current_iterator_;
730};
731
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000732
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000733class LPlatformChunk;
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000734class LGap;
735class LLabel;
736
737// Superclass providing data and behavior common to all the
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000738// arch-specific LPlatformChunk classes.
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000739class LChunk : public ZoneObject {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000740 public:
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000741 static LChunk* NewChunk(HGraph* graph);
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000742
743 void AddInstruction(LInstruction* instruction, HBasicBlock* block);
744 LConstantOperand* DefineConstantOperand(HConstant* constant);
745 HConstant* LookupConstant(LConstantOperand* operand) const;
746 Representation LookupLiteralRepresentation(LConstantOperand* operand) const;
747
748 int ParameterAt(int index);
749 int GetParameterStackSlot(int index) const;
750 int spill_slot_count() const { return spill_slot_count_; }
751 CompilationInfo* info() const { return info_; }
752 HGraph* graph() const { return graph_; }
ulan@chromium.org750145a2013-03-07 15:14:13 +0000753 Isolate* isolate() const { return graph_->isolate(); }
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000754 const ZoneList<LInstruction*>* instructions() const { return &instructions_; }
755 void AddGapMove(int index, LOperand* from, LOperand* to);
756 LGap* GetGapAt(int index) const;
757 bool IsGapAt(int index) const;
758 int NearestGapPos(int index) const;
759 void MarkEmptyBlocks();
760 const ZoneList<LPointerMap*>* pointer_maps() const { return &pointer_maps_; }
761 LLabel* GetLabel(int block_id) const;
762 int LookupDestination(int block_id) const;
763 Label* GetAssemblyLabel(int block_id) const;
764
765 const ZoneList<Handle<JSFunction> >* inlined_closures() const {
766 return &inlined_closures_;
767 }
768
769 void AddInlinedClosure(Handle<JSFunction> closure) {
770 inlined_closures_.Add(closure, zone());
771 }
772
773 Zone* zone() const { return info_->zone(); }
774
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +0000775 Handle<Code> Codegen();
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000776
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000777 void set_allocated_double_registers(BitVector* allocated_registers);
778 BitVector* allocated_double_registers() {
779 return allocated_double_registers_;
780 }
781
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000782 protected:
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000783 LChunk(CompilationInfo* info, HGraph* graph);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000784
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000785 int spill_slot_count_;
786
787 private:
788 CompilationInfo* info_;
789 HGraph* const graph_;
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000790 BitVector* allocated_double_registers_;
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000791 ZoneList<LInstruction*> instructions_;
792 ZoneList<LPointerMap*> pointer_maps_;
793 ZoneList<Handle<JSFunction> > inlined_closures_;
794};
795
796
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000797int ElementsKindToShiftSize(ElementsKind elements_kind);
jkummerow@chromium.orgac360712013-02-11 09:00:07 +0000798int StackSlotOffset(int index);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000799
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000800enum NumberUntagDMode {
801 NUMBER_CANDIDATE_IS_SMI,
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +0000802 NUMBER_CANDIDATE_IS_ANY_TAGGED
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000803};
804
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000805
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000806class LPhase : public CompilationPhase {
807 public:
808 LPhase(const char* name, LChunk* chunk)
809 : CompilationPhase(name, chunk->info()),
810 chunk_(chunk) { }
811 ~LPhase();
812
813 private:
814 LChunk* chunk_;
815
816 DISALLOW_COPY_AND_ASSIGN(LPhase);
817};
818
819
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000820} } // namespace v8::internal
821
822#endif // V8_LITHIUM_H_