blob: daa83f29bc55dcad7b9d512911aa8b8a32e7e2fc [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2014 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#ifndef V8_COMPILER_INSTRUCTION_H_
6#define V8_COMPILER_INSTRUCTION_H_
7
8#include <deque>
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009#include <iosfwd>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010#include <map>
11#include <set>
12
13#include "src/compiler/common-operator.h"
14#include "src/compiler/frame.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015#include "src/compiler/instruction-codes.h"
16#include "src/compiler/opcodes.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040017#include "src/compiler/register-configuration.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018#include "src/compiler/schedule.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040019#include "src/compiler/source-position.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020#include "src/zone-allocator.h"
21
22namespace v8 {
23namespace internal {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000024namespace compiler {
25
Ben Murdochb8a8cc12014-11-26 15:28:44 +000026// A couple of reserved opcodes are used for internal use.
27const InstructionCode kGapInstruction = -1;
28const InstructionCode kBlockStartInstruction = -2;
29const InstructionCode kSourcePositionInstruction = -3;
30
Emily Bernierd0a1eb72015-03-24 16:35:39 -040031#define INSTRUCTION_OPERAND_LIST(V) \
32 V(Constant, CONSTANT, 0) \
33 V(Immediate, IMMEDIATE, 0) \
34 V(StackSlot, STACK_SLOT, 128) \
35 V(DoubleStackSlot, DOUBLE_STACK_SLOT, 128) \
36 V(Register, REGISTER, RegisterConfiguration::kMaxGeneralRegisters) \
37 V(DoubleRegister, DOUBLE_REGISTER, RegisterConfiguration::kMaxDoubleRegisters)
Ben Murdochb8a8cc12014-11-26 15:28:44 +000038
39class InstructionOperand : public ZoneObject {
40 public:
41 enum Kind {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000042 UNALLOCATED,
43 CONSTANT,
44 IMMEDIATE,
45 STACK_SLOT,
46 DOUBLE_STACK_SLOT,
47 REGISTER,
48 DOUBLE_REGISTER
49 };
50
Ben Murdochb8a8cc12014-11-26 15:28:44 +000051 InstructionOperand(Kind kind, int index) { ConvertTo(kind, index); }
52
53 Kind kind() const { return KindField::decode(value_); }
54 int index() const { return static_cast<int>(value_) >> KindField::kSize; }
55#define INSTRUCTION_OPERAND_PREDICATE(name, type, number) \
56 bool Is##name() const { return kind() == type; }
57 INSTRUCTION_OPERAND_LIST(INSTRUCTION_OPERAND_PREDICATE)
58 INSTRUCTION_OPERAND_PREDICATE(Unallocated, UNALLOCATED, 0)
Ben Murdochb8a8cc12014-11-26 15:28:44 +000059#undef INSTRUCTION_OPERAND_PREDICATE
Emily Bernierd0a1eb72015-03-24 16:35:39 -040060 bool Equals(const InstructionOperand* other) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000061 return value_ == other->value_;
62 }
63
64 void ConvertTo(Kind kind, int index) {
65 if (kind == REGISTER || kind == DOUBLE_REGISTER) DCHECK(index >= 0);
66 value_ = KindField::encode(kind);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040067 value_ |= bit_cast<unsigned>(index << KindField::kSize);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000068 DCHECK(this->index() == index);
69 }
70
71 // Calls SetUpCache()/TearDownCache() for each subclass.
72 static void SetUpCaches();
73 static void TearDownCaches();
74
75 protected:
Emily Bernierd0a1eb72015-03-24 16:35:39 -040076 typedef BitField64<Kind, 0, 3> KindField;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000077
Emily Bernierd0a1eb72015-03-24 16:35:39 -040078 uint64_t value_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000079};
80
81typedef ZoneVector<InstructionOperand*> InstructionOperandVector;
82
Emily Bernierd0a1eb72015-03-24 16:35:39 -040083struct PrintableInstructionOperand {
84 const RegisterConfiguration* register_configuration_;
85 const InstructionOperand* op_;
86};
87
88std::ostream& operator<<(std::ostream& os,
89 const PrintableInstructionOperand& op);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000090
91class UnallocatedOperand : public InstructionOperand {
92 public:
93 enum BasicPolicy { FIXED_SLOT, EXTENDED_POLICY };
94
95 enum ExtendedPolicy {
96 NONE,
97 ANY,
98 FIXED_REGISTER,
99 FIXED_DOUBLE_REGISTER,
100 MUST_HAVE_REGISTER,
101 SAME_AS_FIRST_INPUT
102 };
103
104 // Lifetime of operand inside the instruction.
105 enum Lifetime {
106 // USED_AT_START operand is guaranteed to be live only at
107 // instruction start. Register allocator is free to assign the same register
108 // to some other operand used inside instruction (i.e. temporary or
109 // output).
110 USED_AT_START,
111
112 // USED_AT_END operand is treated as live until the end of
113 // instruction. This means that register allocator will not reuse it's
114 // register for any other operand inside instruction.
115 USED_AT_END
116 };
117
118 explicit UnallocatedOperand(ExtendedPolicy policy)
119 : InstructionOperand(UNALLOCATED, 0) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400120 value_ |= VirtualRegisterField::encode(kInvalidVirtualRegister);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000121 value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
122 value_ |= ExtendedPolicyField::encode(policy);
123 value_ |= LifetimeField::encode(USED_AT_END);
124 }
125
126 UnallocatedOperand(BasicPolicy policy, int index)
127 : InstructionOperand(UNALLOCATED, 0) {
128 DCHECK(policy == FIXED_SLOT);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400129 value_ |= VirtualRegisterField::encode(kInvalidVirtualRegister);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000130 value_ |= BasicPolicyField::encode(policy);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400131 value_ |= static_cast<int64_t>(index) << FixedSlotIndexField::kShift;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000132 DCHECK(this->fixed_slot_index() == index);
133 }
134
135 UnallocatedOperand(ExtendedPolicy policy, int index)
136 : InstructionOperand(UNALLOCATED, 0) {
137 DCHECK(policy == FIXED_REGISTER || policy == FIXED_DOUBLE_REGISTER);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400138 value_ |= VirtualRegisterField::encode(kInvalidVirtualRegister);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000139 value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
140 value_ |= ExtendedPolicyField::encode(policy);
141 value_ |= LifetimeField::encode(USED_AT_END);
142 value_ |= FixedRegisterField::encode(index);
143 }
144
145 UnallocatedOperand(ExtendedPolicy policy, Lifetime lifetime)
146 : InstructionOperand(UNALLOCATED, 0) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400147 value_ |= VirtualRegisterField::encode(kInvalidVirtualRegister);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000148 value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
149 value_ |= ExtendedPolicyField::encode(policy);
150 value_ |= LifetimeField::encode(lifetime);
151 }
152
153 UnallocatedOperand* CopyUnconstrained(Zone* zone) {
154 UnallocatedOperand* result = new (zone) UnallocatedOperand(ANY);
155 result->set_virtual_register(virtual_register());
156 return result;
157 }
158
159 static const UnallocatedOperand* cast(const InstructionOperand* op) {
160 DCHECK(op->IsUnallocated());
161 return static_cast<const UnallocatedOperand*>(op);
162 }
163
164 static UnallocatedOperand* cast(InstructionOperand* op) {
165 DCHECK(op->IsUnallocated());
166 return static_cast<UnallocatedOperand*>(op);
167 }
168
169 // The encoding used for UnallocatedOperand operands depends on the policy
170 // that is
171 // stored within the operand. The FIXED_SLOT policy uses a compact encoding
172 // because it accommodates a larger pay-load.
173 //
174 // For FIXED_SLOT policy:
175 // +------------------------------------------+
176 // | slot_index | vreg | 0 | 001 |
177 // +------------------------------------------+
178 //
179 // For all other (extended) policies:
180 // +------------------------------------------+
181 // | reg_index | L | PPP | vreg | 1 | 001 | L ... Lifetime
182 // +------------------------------------------+ P ... Policy
183 //
184 // The slot index is a signed value which requires us to decode it manually
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400185 // instead of using the BitField64 utility class.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000186
187 // The superclass has a KindField.
188 STATIC_ASSERT(KindField::kSize == 3);
189
190 // BitFields for all unallocated operands.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400191 class BasicPolicyField : public BitField64<BasicPolicy, 3, 1> {};
192 class VirtualRegisterField : public BitField64<unsigned, 4, 30> {};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000193
194 // BitFields specific to BasicPolicy::FIXED_SLOT.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400195 class FixedSlotIndexField : public BitField64<int, 34, 30> {};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000196
197 // BitFields specific to BasicPolicy::EXTENDED_POLICY.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400198 class ExtendedPolicyField : public BitField64<ExtendedPolicy, 34, 3> {};
199 class LifetimeField : public BitField64<Lifetime, 37, 1> {};
200 class FixedRegisterField : public BitField64<int, 38, 6> {};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000201
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400202 static const int kInvalidVirtualRegister = VirtualRegisterField::kMax;
203 static const int kMaxVirtualRegisters = VirtualRegisterField::kMax;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000204 static const int kFixedSlotIndexWidth = FixedSlotIndexField::kSize;
205 static const int kMaxFixedSlotIndex = (1 << (kFixedSlotIndexWidth - 1)) - 1;
206 static const int kMinFixedSlotIndex = -(1 << (kFixedSlotIndexWidth - 1));
207
208 // Predicates for the operand policy.
209 bool HasAnyPolicy() const {
210 return basic_policy() == EXTENDED_POLICY && extended_policy() == ANY;
211 }
212 bool HasFixedPolicy() const {
213 return basic_policy() == FIXED_SLOT ||
214 extended_policy() == FIXED_REGISTER ||
215 extended_policy() == FIXED_DOUBLE_REGISTER;
216 }
217 bool HasRegisterPolicy() const {
218 return basic_policy() == EXTENDED_POLICY &&
219 extended_policy() == MUST_HAVE_REGISTER;
220 }
221 bool HasSameAsInputPolicy() const {
222 return basic_policy() == EXTENDED_POLICY &&
223 extended_policy() == SAME_AS_FIRST_INPUT;
224 }
225 bool HasFixedSlotPolicy() const { return basic_policy() == FIXED_SLOT; }
226 bool HasFixedRegisterPolicy() const {
227 return basic_policy() == EXTENDED_POLICY &&
228 extended_policy() == FIXED_REGISTER;
229 }
230 bool HasFixedDoubleRegisterPolicy() const {
231 return basic_policy() == EXTENDED_POLICY &&
232 extended_policy() == FIXED_DOUBLE_REGISTER;
233 }
234
235 // [basic_policy]: Distinguish between FIXED_SLOT and all other policies.
236 BasicPolicy basic_policy() const { return BasicPolicyField::decode(value_); }
237
238 // [extended_policy]: Only for non-FIXED_SLOT. The finer-grained policy.
239 ExtendedPolicy extended_policy() const {
240 DCHECK(basic_policy() == EXTENDED_POLICY);
241 return ExtendedPolicyField::decode(value_);
242 }
243
244 // [fixed_slot_index]: Only for FIXED_SLOT.
245 int fixed_slot_index() const {
246 DCHECK(HasFixedSlotPolicy());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400247 return static_cast<int>(bit_cast<int64_t>(value_) >>
248 FixedSlotIndexField::kShift);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000249 }
250
251 // [fixed_register_index]: Only for FIXED_REGISTER or FIXED_DOUBLE_REGISTER.
252 int fixed_register_index() const {
253 DCHECK(HasFixedRegisterPolicy() || HasFixedDoubleRegisterPolicy());
254 return FixedRegisterField::decode(value_);
255 }
256
257 // [virtual_register]: The virtual register ID for this operand.
258 int virtual_register() const { return VirtualRegisterField::decode(value_); }
259 void set_virtual_register(unsigned id) {
260 value_ = VirtualRegisterField::update(value_, id);
261 }
262
263 // [lifetime]: Only for non-FIXED_SLOT.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400264 bool IsUsedAtStart() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000265 DCHECK(basic_policy() == EXTENDED_POLICY);
266 return LifetimeField::decode(value_) == USED_AT_START;
267 }
268};
269
270
271class MoveOperands FINAL {
272 public:
273 MoveOperands(InstructionOperand* source, InstructionOperand* destination)
274 : source_(source), destination_(destination) {}
275
276 InstructionOperand* source() const { return source_; }
277 void set_source(InstructionOperand* operand) { source_ = operand; }
278
279 InstructionOperand* destination() const { return destination_; }
280 void set_destination(InstructionOperand* operand) { destination_ = operand; }
281
282 // The gap resolver marks moves as "in-progress" by clearing the
283 // destination (but not the source).
284 bool IsPending() const { return destination_ == NULL && source_ != NULL; }
285
286 // True if this move a move into the given destination operand.
287 bool Blocks(InstructionOperand* operand) const {
288 return !IsEliminated() && source()->Equals(operand);
289 }
290
291 // A move is redundant if it's been eliminated, if its source and
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400292 // destination are the same, or if its destination is constant.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000293 bool IsRedundant() const {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400294 return IsEliminated() || source_->Equals(destination_) ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000295 (destination_ != NULL && destination_->IsConstant());
296 }
297
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000298 // We clear both operands to indicate move that's been eliminated.
299 void Eliminate() { source_ = destination_ = NULL; }
300 bool IsEliminated() const {
301 DCHECK(source_ != NULL || destination_ == NULL);
302 return source_ == NULL;
303 }
304
305 private:
306 InstructionOperand* source_;
307 InstructionOperand* destination_;
308};
309
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400310
311struct PrintableMoveOperands {
312 const RegisterConfiguration* register_configuration_;
313 const MoveOperands* move_operands_;
314};
315
316
317std::ostream& operator<<(std::ostream& os, const PrintableMoveOperands& mo);
318
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000319
320template <InstructionOperand::Kind kOperandKind, int kNumCachedOperands>
321class SubKindOperand FINAL : public InstructionOperand {
322 public:
323 static SubKindOperand* Create(int index, Zone* zone) {
324 DCHECK(index >= 0);
325 if (index < kNumCachedOperands) return &cache[index];
326 return new (zone) SubKindOperand(index);
327 }
328
329 static SubKindOperand* cast(InstructionOperand* op) {
330 DCHECK(op->kind() == kOperandKind);
331 return reinterpret_cast<SubKindOperand*>(op);
332 }
333
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400334 static const SubKindOperand* cast(const InstructionOperand* op) {
335 DCHECK(op->kind() == kOperandKind);
336 return reinterpret_cast<const SubKindOperand*>(op);
337 }
338
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000339 static void SetUpCache();
340 static void TearDownCache();
341
342 private:
343 static SubKindOperand* cache;
344
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400345 SubKindOperand() : InstructionOperand(kOperandKind, 0) {} // For the caches.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000346 explicit SubKindOperand(int index)
347 : InstructionOperand(kOperandKind, index) {}
348};
349
350
351#define INSTRUCTION_TYPEDEF_SUBKIND_OPERAND_CLASS(name, type, number) \
352 typedef SubKindOperand<InstructionOperand::type, number> name##Operand;
353INSTRUCTION_OPERAND_LIST(INSTRUCTION_TYPEDEF_SUBKIND_OPERAND_CLASS)
354#undef INSTRUCTION_TYPEDEF_SUBKIND_OPERAND_CLASS
355
356
357class ParallelMove FINAL : public ZoneObject {
358 public:
359 explicit ParallelMove(Zone* zone) : move_operands_(4, zone) {}
360
361 void AddMove(InstructionOperand* from, InstructionOperand* to, Zone* zone) {
362 move_operands_.Add(MoveOperands(from, to), zone);
363 }
364
365 bool IsRedundant() const;
366
367 ZoneList<MoveOperands>* move_operands() { return &move_operands_; }
368 const ZoneList<MoveOperands>* move_operands() const {
369 return &move_operands_;
370 }
371
372 private:
373 ZoneList<MoveOperands> move_operands_;
374};
375
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400376
377struct PrintableParallelMove {
378 const RegisterConfiguration* register_configuration_;
379 const ParallelMove* parallel_move_;
380};
381
382
383std::ostream& operator<<(std::ostream& os, const PrintableParallelMove& pm);
384
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000385
386class PointerMap FINAL : public ZoneObject {
387 public:
388 explicit PointerMap(Zone* zone)
389 : pointer_operands_(8, zone),
390 untagged_operands_(0, zone),
391 instruction_position_(-1) {}
392
393 const ZoneList<InstructionOperand*>* GetNormalizedOperands() {
394 for (int i = 0; i < untagged_operands_.length(); ++i) {
395 RemovePointer(untagged_operands_[i]);
396 }
397 untagged_operands_.Clear();
398 return &pointer_operands_;
399 }
400 int instruction_position() const { return instruction_position_; }
401
402 void set_instruction_position(int pos) {
403 DCHECK(instruction_position_ == -1);
404 instruction_position_ = pos;
405 }
406
407 void RecordPointer(InstructionOperand* op, Zone* zone);
408 void RemovePointer(InstructionOperand* op);
409 void RecordUntagged(InstructionOperand* op, Zone* zone);
410
411 private:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400412 friend std::ostream& operator<<(std::ostream& os, const PointerMap& pm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000413
414 ZoneList<InstructionOperand*> pointer_operands_;
415 ZoneList<InstructionOperand*> untagged_operands_;
416 int instruction_position_;
417};
418
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400419std::ostream& operator<<(std::ostream& os, const PointerMap& pm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000420
421// TODO(titzer): s/PointerMap/ReferenceMap/
422class Instruction : public ZoneObject {
423 public:
424 size_t OutputCount() const { return OutputCountField::decode(bit_field_); }
425 InstructionOperand* OutputAt(size_t i) const {
426 DCHECK(i < OutputCount());
427 return operands_[i];
428 }
429
430 bool HasOutput() const { return OutputCount() == 1; }
431 InstructionOperand* Output() const { return OutputAt(0); }
432
433 size_t InputCount() const { return InputCountField::decode(bit_field_); }
434 InstructionOperand* InputAt(size_t i) const {
435 DCHECK(i < InputCount());
436 return operands_[OutputCount() + i];
437 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400438 void SetInputAt(size_t i, InstructionOperand* operand) {
439 DCHECK(i < InputCount());
440 operands_[OutputCount() + i] = operand;
441 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000442
443 size_t TempCount() const { return TempCountField::decode(bit_field_); }
444 InstructionOperand* TempAt(size_t i) const {
445 DCHECK(i < TempCount());
446 return operands_[OutputCount() + InputCount() + i];
447 }
448
449 InstructionCode opcode() const { return opcode_; }
450 ArchOpcode arch_opcode() const { return ArchOpcodeField::decode(opcode()); }
451 AddressingMode addressing_mode() const {
452 return AddressingModeField::decode(opcode());
453 }
454 FlagsMode flags_mode() const { return FlagsModeField::decode(opcode()); }
455 FlagsCondition flags_condition() const {
456 return FlagsConditionField::decode(opcode());
457 }
458
459 // TODO(titzer): make control and call into flags.
460 static Instruction* New(Zone* zone, InstructionCode opcode) {
461 return New(zone, opcode, 0, NULL, 0, NULL, 0, NULL);
462 }
463
464 static Instruction* New(Zone* zone, InstructionCode opcode,
465 size_t output_count, InstructionOperand** outputs,
466 size_t input_count, InstructionOperand** inputs,
467 size_t temp_count, InstructionOperand** temps) {
468 DCHECK(opcode >= 0);
469 DCHECK(output_count == 0 || outputs != NULL);
470 DCHECK(input_count == 0 || inputs != NULL);
471 DCHECK(temp_count == 0 || temps != NULL);
472 InstructionOperand* none = NULL;
473 USE(none);
474 int size = static_cast<int>(RoundUp(sizeof(Instruction), kPointerSize) +
475 (output_count + input_count + temp_count - 1) *
476 sizeof(none));
477 return new (zone->New(size)) Instruction(
478 opcode, output_count, outputs, input_count, inputs, temp_count, temps);
479 }
480
481 // TODO(titzer): another holdover from lithium days; register allocator
482 // should not need to know about control instructions.
483 Instruction* MarkAsControl() {
484 bit_field_ = IsControlField::update(bit_field_, true);
485 return this;
486 }
487 Instruction* MarkAsCall() {
488 bit_field_ = IsCallField::update(bit_field_, true);
489 return this;
490 }
491 bool IsControl() const { return IsControlField::decode(bit_field_); }
492 bool IsCall() const { return IsCallField::decode(bit_field_); }
493 bool NeedsPointerMap() const { return IsCall(); }
494 bool HasPointerMap() const { return pointer_map_ != NULL; }
495
496 bool IsGapMoves() const {
497 return opcode() == kGapInstruction || opcode() == kBlockStartInstruction;
498 }
499 bool IsBlockStart() const { return opcode() == kBlockStartInstruction; }
500 bool IsSourcePosition() const {
501 return opcode() == kSourcePositionInstruction;
502 }
503
504 bool ClobbersRegisters() const { return IsCall(); }
505 bool ClobbersTemps() const { return IsCall(); }
506 bool ClobbersDoubleRegisters() const { return IsCall(); }
507 PointerMap* pointer_map() const { return pointer_map_; }
508
509 void set_pointer_map(PointerMap* map) {
510 DCHECK(NeedsPointerMap());
511 DCHECK_EQ(NULL, pointer_map_);
512 pointer_map_ = map;
513 }
514
515 // Placement new operator so that we can smash instructions into
516 // zone-allocated memory.
517 void* operator new(size_t, void* location) { return location; }
518
519 void operator delete(void* pointer, void* location) { UNREACHABLE(); }
520
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400521 void OverwriteWithNop() {
522 opcode_ = ArchOpcodeField::encode(kArchNop);
523 bit_field_ = 0;
524 pointer_map_ = NULL;
525 }
526
527 bool IsNop() const {
528 return arch_opcode() == kArchNop && InputCount() == 0 &&
529 OutputCount() == 0 && TempCount() == 0;
530 }
531
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000532 protected:
533 explicit Instruction(InstructionCode opcode)
534 : opcode_(opcode),
535 bit_field_(OutputCountField::encode(0) | InputCountField::encode(0) |
536 TempCountField::encode(0) | IsCallField::encode(false) |
537 IsControlField::encode(false)),
538 pointer_map_(NULL) {}
539
540 Instruction(InstructionCode opcode, size_t output_count,
541 InstructionOperand** outputs, size_t input_count,
542 InstructionOperand** inputs, size_t temp_count,
543 InstructionOperand** temps)
544 : opcode_(opcode),
545 bit_field_(OutputCountField::encode(output_count) |
546 InputCountField::encode(input_count) |
547 TempCountField::encode(temp_count) |
548 IsCallField::encode(false) | IsControlField::encode(false)),
549 pointer_map_(NULL) {
550 for (size_t i = 0; i < output_count; ++i) {
551 operands_[i] = outputs[i];
552 }
553 for (size_t i = 0; i < input_count; ++i) {
554 operands_[output_count + i] = inputs[i];
555 }
556 for (size_t i = 0; i < temp_count; ++i) {
557 operands_[output_count + input_count + i] = temps[i];
558 }
559 }
560
561 protected:
562 typedef BitField<size_t, 0, 8> OutputCountField;
563 typedef BitField<size_t, 8, 16> InputCountField;
564 typedef BitField<size_t, 24, 6> TempCountField;
565 typedef BitField<bool, 30, 1> IsCallField;
566 typedef BitField<bool, 31, 1> IsControlField;
567
568 InstructionCode opcode_;
569 uint32_t bit_field_;
570 PointerMap* pointer_map_;
571 InstructionOperand* operands_[1];
572};
573
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400574
575struct PrintableInstruction {
576 const RegisterConfiguration* register_configuration_;
577 const Instruction* instr_;
578};
579std::ostream& operator<<(std::ostream& os, const PrintableInstruction& instr);
580
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000581
582// Represents moves inserted before an instruction due to register allocation.
583// TODO(titzer): squash GapInstruction back into Instruction, since essentially
584// every instruction can possibly have moves inserted before it.
585class GapInstruction : public Instruction {
586 public:
587 enum InnerPosition {
588 BEFORE,
589 START,
590 END,
591 AFTER,
592 FIRST_INNER_POSITION = BEFORE,
593 LAST_INNER_POSITION = AFTER
594 };
595
596 ParallelMove* GetOrCreateParallelMove(InnerPosition pos, Zone* zone) {
597 if (parallel_moves_[pos] == NULL) {
598 parallel_moves_[pos] = new (zone) ParallelMove(zone);
599 }
600 return parallel_moves_[pos];
601 }
602
603 ParallelMove* GetParallelMove(InnerPosition pos) {
604 return parallel_moves_[pos];
605 }
606
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400607 const ParallelMove* GetParallelMove(InnerPosition pos) const {
608 return parallel_moves_[pos];
609 }
610
611 bool IsRedundant() const;
612
613 ParallelMove** parallel_moves() { return parallel_moves_; }
614
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000615 static GapInstruction* New(Zone* zone) {
616 void* buffer = zone->New(sizeof(GapInstruction));
617 return new (buffer) GapInstruction(kGapInstruction);
618 }
619
620 static GapInstruction* cast(Instruction* instr) {
621 DCHECK(instr->IsGapMoves());
622 return static_cast<GapInstruction*>(instr);
623 }
624
625 static const GapInstruction* cast(const Instruction* instr) {
626 DCHECK(instr->IsGapMoves());
627 return static_cast<const GapInstruction*>(instr);
628 }
629
630 protected:
631 explicit GapInstruction(InstructionCode opcode) : Instruction(opcode) {
632 parallel_moves_[BEFORE] = NULL;
633 parallel_moves_[START] = NULL;
634 parallel_moves_[END] = NULL;
635 parallel_moves_[AFTER] = NULL;
636 }
637
638 private:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400639 friend std::ostream& operator<<(std::ostream& os,
640 const PrintableInstruction& instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000641 ParallelMove* parallel_moves_[LAST_INNER_POSITION + 1];
642};
643
644
645// This special kind of gap move instruction represents the beginning of a
646// block of code.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000647class BlockStartInstruction FINAL : public GapInstruction {
648 public:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400649 static BlockStartInstruction* New(Zone* zone) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000650 void* buffer = zone->New(sizeof(BlockStartInstruction));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400651 return new (buffer) BlockStartInstruction();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000652 }
653
654 static BlockStartInstruction* cast(Instruction* instr) {
655 DCHECK(instr->IsBlockStart());
656 return static_cast<BlockStartInstruction*>(instr);
657 }
658
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400659 static const BlockStartInstruction* cast(const Instruction* instr) {
660 DCHECK(instr->IsBlockStart());
661 return static_cast<const BlockStartInstruction*>(instr);
662 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000663
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400664 private:
665 BlockStartInstruction() : GapInstruction(kBlockStartInstruction) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000666};
667
668
669class SourcePositionInstruction FINAL : public Instruction {
670 public:
671 static SourcePositionInstruction* New(Zone* zone, SourcePosition position) {
672 void* buffer = zone->New(sizeof(SourcePositionInstruction));
673 return new (buffer) SourcePositionInstruction(position);
674 }
675
676 SourcePosition source_position() const { return source_position_; }
677
678 static SourcePositionInstruction* cast(Instruction* instr) {
679 DCHECK(instr->IsSourcePosition());
680 return static_cast<SourcePositionInstruction*>(instr);
681 }
682
683 static const SourcePositionInstruction* cast(const Instruction* instr) {
684 DCHECK(instr->IsSourcePosition());
685 return static_cast<const SourcePositionInstruction*>(instr);
686 }
687
688 private:
689 explicit SourcePositionInstruction(SourcePosition source_position)
690 : Instruction(kSourcePositionInstruction),
691 source_position_(source_position) {
692 DCHECK(!source_position_.IsInvalid());
693 DCHECK(!source_position_.IsUnknown());
694 }
695
696 SourcePosition source_position_;
697};
698
699
700class Constant FINAL {
701 public:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400702 enum Type {
703 kInt32,
704 kInt64,
705 kFloat32,
706 kFloat64,
707 kExternalReference,
708 kHeapObject,
709 kRpoNumber
710 };
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000711
712 explicit Constant(int32_t v) : type_(kInt32), value_(v) {}
713 explicit Constant(int64_t v) : type_(kInt64), value_(v) {}
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400714 explicit Constant(float v) : type_(kFloat32), value_(bit_cast<int32_t>(v)) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000715 explicit Constant(double v) : type_(kFloat64), value_(bit_cast<int64_t>(v)) {}
716 explicit Constant(ExternalReference ref)
717 : type_(kExternalReference), value_(bit_cast<intptr_t>(ref)) {}
718 explicit Constant(Handle<HeapObject> obj)
719 : type_(kHeapObject), value_(bit_cast<intptr_t>(obj)) {}
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400720 explicit Constant(BasicBlock::RpoNumber rpo)
721 : type_(kRpoNumber), value_(rpo.ToInt()) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000722
723 Type type() const { return type_; }
724
725 int32_t ToInt32() const {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400726 DCHECK(type() == kInt32 || type() == kInt64);
727 const int32_t value = static_cast<int32_t>(value_);
728 DCHECK_EQ(value_, static_cast<int64_t>(value));
729 return value;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000730 }
731
732 int64_t ToInt64() const {
733 if (type() == kInt32) return ToInt32();
734 DCHECK_EQ(kInt64, type());
735 return value_;
736 }
737
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400738 float ToFloat32() const {
739 DCHECK_EQ(kFloat32, type());
740 return bit_cast<float>(static_cast<int32_t>(value_));
741 }
742
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000743 double ToFloat64() const {
744 if (type() == kInt32) return ToInt32();
745 DCHECK_EQ(kFloat64, type());
746 return bit_cast<double>(value_);
747 }
748
749 ExternalReference ToExternalReference() const {
750 DCHECK_EQ(kExternalReference, type());
751 return bit_cast<ExternalReference>(static_cast<intptr_t>(value_));
752 }
753
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400754 BasicBlock::RpoNumber ToRpoNumber() const {
755 DCHECK_EQ(kRpoNumber, type());
756 return BasicBlock::RpoNumber::FromInt(static_cast<int>(value_));
757 }
758
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000759 Handle<HeapObject> ToHeapObject() const {
760 DCHECK_EQ(kHeapObject, type());
761 return bit_cast<Handle<HeapObject> >(static_cast<intptr_t>(value_));
762 }
763
764 private:
765 Type type_;
766 int64_t value_;
767};
768
769
770class FrameStateDescriptor : public ZoneObject {
771 public:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400772 FrameStateDescriptor(Zone* zone, const FrameStateCallInfo& state_info,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000773 size_t parameters_count, size_t locals_count,
774 size_t stack_count,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400775 FrameStateDescriptor* outer_state = NULL);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000776
777 FrameStateType type() const { return type_; }
778 BailoutId bailout_id() const { return bailout_id_; }
779 OutputFrameStateCombine state_combine() const { return frame_state_combine_; }
780 size_t parameters_count() const { return parameters_count_; }
781 size_t locals_count() const { return locals_count_; }
782 size_t stack_count() const { return stack_count_; }
783 FrameStateDescriptor* outer_state() const { return outer_state_; }
784 MaybeHandle<JSFunction> jsfunction() const { return jsfunction_; }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000785 bool HasContext() const { return type_ == JS_FRAME; }
786
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400787 size_t GetSize(OutputFrameStateCombine combine =
788 OutputFrameStateCombine::Ignore()) const;
789 size_t GetTotalSize() const;
790 size_t GetFrameCount() const;
791 size_t GetJSFrameCount() const;
792
793 MachineType GetType(size_t index) const;
794 void SetType(size_t index, MachineType type);
795
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000796 private:
797 FrameStateType type_;
798 BailoutId bailout_id_;
799 OutputFrameStateCombine frame_state_combine_;
800 size_t parameters_count_;
801 size_t locals_count_;
802 size_t stack_count_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400803 ZoneVector<MachineType> types_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000804 FrameStateDescriptor* outer_state_;
805 MaybeHandle<JSFunction> jsfunction_;
806};
807
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400808std::ostream& operator<<(std::ostream& os, const Constant& constant);
809
810
811class PhiInstruction FINAL : public ZoneObject {
812 public:
813 typedef ZoneVector<InstructionOperand*> Inputs;
814
815 PhiInstruction(Zone* zone, int virtual_register, size_t reserved_input_count)
816 : virtual_register_(virtual_register),
817 operands_(zone),
818 output_(nullptr),
819 inputs_(zone) {
820 UnallocatedOperand* output =
821 new (zone) UnallocatedOperand(UnallocatedOperand::NONE);
822 output->set_virtual_register(virtual_register);
823 output_ = output;
824 inputs_.reserve(reserved_input_count);
825 operands_.reserve(reserved_input_count);
826 }
827
828 int virtual_register() const { return virtual_register_; }
829 const IntVector& operands() const { return operands_; }
830
831 void Extend(Zone* zone, int virtual_register) {
832 UnallocatedOperand* input =
833 new (zone) UnallocatedOperand(UnallocatedOperand::ANY);
834 input->set_virtual_register(virtual_register);
835 operands_.push_back(virtual_register);
836 inputs_.push_back(input);
837 }
838
839 InstructionOperand* output() const { return output_; }
840 const Inputs& inputs() const { return inputs_; }
841 Inputs& inputs() { return inputs_; }
842
843 private:
844 // TODO(dcarney): some of these fields are only for verification, move them to
845 // verifier.
846 const int virtual_register_;
847 IntVector operands_;
848 InstructionOperand* output_;
849 Inputs inputs_;
850};
851
852
853// Analogue of BasicBlock for Instructions instead of Nodes.
854class InstructionBlock FINAL : public ZoneObject {
855 public:
856 InstructionBlock(Zone* zone, BasicBlock::Id id,
857 BasicBlock::RpoNumber rpo_number,
858 BasicBlock::RpoNumber loop_header,
859 BasicBlock::RpoNumber loop_end, bool deferred);
860
861 // Instruction indexes (used by the register allocator).
862 int first_instruction_index() const {
863 DCHECK(code_start_ >= 0);
864 DCHECK(code_end_ > 0);
865 DCHECK(code_end_ >= code_start_);
866 return code_start_;
867 }
868 int last_instruction_index() const {
869 DCHECK(code_start_ >= 0);
870 DCHECK(code_end_ > 0);
871 DCHECK(code_end_ >= code_start_);
872 return code_end_ - 1;
873 }
874
875 int32_t code_start() const { return code_start_; }
876 void set_code_start(int32_t start) { code_start_ = start; }
877
878 int32_t code_end() const { return code_end_; }
879 void set_code_end(int32_t end) { code_end_ = end; }
880
881 bool IsDeferred() const { return deferred_; }
882
883 BasicBlock::Id id() const { return id_; }
884 BasicBlock::RpoNumber ao_number() const { return ao_number_; }
885 BasicBlock::RpoNumber rpo_number() const { return rpo_number_; }
886 BasicBlock::RpoNumber loop_header() const { return loop_header_; }
887 BasicBlock::RpoNumber loop_end() const {
888 DCHECK(IsLoopHeader());
889 return loop_end_;
890 }
891 inline bool IsLoopHeader() const { return loop_end_.IsValid(); }
892
893 typedef ZoneVector<BasicBlock::RpoNumber> Predecessors;
894 Predecessors& predecessors() { return predecessors_; }
895 const Predecessors& predecessors() const { return predecessors_; }
896 size_t PredecessorCount() const { return predecessors_.size(); }
897 size_t PredecessorIndexOf(BasicBlock::RpoNumber rpo_number) const;
898
899 typedef ZoneVector<BasicBlock::RpoNumber> Successors;
900 Successors& successors() { return successors_; }
901 const Successors& successors() const { return successors_; }
902 size_t SuccessorCount() const { return successors_.size(); }
903
904 typedef ZoneVector<PhiInstruction*> PhiInstructions;
905 const PhiInstructions& phis() const { return phis_; }
906 void AddPhi(PhiInstruction* phi) { phis_.push_back(phi); }
907
908 void set_ao_number(BasicBlock::RpoNumber ao_number) {
909 ao_number_ = ao_number;
910 }
911
912 private:
913 Successors successors_;
914 Predecessors predecessors_;
915 PhiInstructions phis_;
916 const BasicBlock::Id id_;
917 BasicBlock::RpoNumber ao_number_; // Assembly order number.
918 const BasicBlock::RpoNumber rpo_number_;
919 const BasicBlock::RpoNumber loop_header_;
920 const BasicBlock::RpoNumber loop_end_;
921 int32_t code_start_; // start index of arch-specific code.
922 int32_t code_end_; // end index of arch-specific code.
923 const bool deferred_; // Block contains deferred code.
924};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000925
926typedef ZoneDeque<Constant> ConstantDeque;
927typedef std::map<int, Constant, std::less<int>,
928 zone_allocator<std::pair<int, Constant> > > ConstantMap;
929
930typedef ZoneDeque<Instruction*> InstructionDeque;
931typedef ZoneDeque<PointerMap*> PointerMapDeque;
932typedef ZoneVector<FrameStateDescriptor*> DeoptimizationVector;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400933typedef ZoneVector<InstructionBlock*> InstructionBlocks;
934
935struct PrintableInstructionSequence;
936
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000937
938// Represents architecture-specific generated code before, during, and after
939// register allocation.
940// TODO(titzer): s/IsDouble/IsFloat64/
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400941class InstructionSequence FINAL : public ZoneObject {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000942 public:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400943 static InstructionBlocks* InstructionBlocksFor(Zone* zone,
944 const Schedule* schedule);
945 // Puts the deferred blocks last.
946 static void ComputeAssemblyOrder(InstructionBlocks* blocks);
947
948 InstructionSequence(Zone* zone, InstructionBlocks* instruction_blocks);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000949
950 int NextVirtualRegister() { return next_virtual_register_++; }
951 int VirtualRegisterCount() const { return next_virtual_register_; }
952
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400953 const InstructionBlocks& instruction_blocks() const {
954 return *instruction_blocks_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000955 }
956
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400957 int InstructionBlockCount() const {
958 return static_cast<int>(instruction_blocks_->size());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000959 }
960
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400961 InstructionBlock* InstructionBlockAt(BasicBlock::RpoNumber rpo_number) {
962 return instruction_blocks_->at(rpo_number.ToSize());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000963 }
964
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400965 int LastLoopInstructionIndex(const InstructionBlock* block) {
966 return instruction_blocks_->at(block->loop_end().ToSize() - 1)
967 ->last_instruction_index();
968 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000969
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400970 const InstructionBlock* InstructionBlockAt(
971 BasicBlock::RpoNumber rpo_number) const {
972 return instruction_blocks_->at(rpo_number.ToSize());
973 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000974
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400975 const InstructionBlock* GetInstructionBlock(int instruction_index) const;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000976
977 bool IsReference(int virtual_register) const;
978 bool IsDouble(int virtual_register) const;
979
980 void MarkAsReference(int virtual_register);
981 void MarkAsDouble(int virtual_register);
982
983 void AddGapMove(int index, InstructionOperand* from, InstructionOperand* to);
984
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400985 BlockStartInstruction* GetBlockStart(BasicBlock::RpoNumber rpo) const;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000986
987 typedef InstructionDeque::const_iterator const_iterator;
988 const_iterator begin() const { return instructions_.begin(); }
989 const_iterator end() const { return instructions_.end(); }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400990 const InstructionDeque& instructions() const { return instructions_; }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000991
992 GapInstruction* GapAt(int index) const {
993 return GapInstruction::cast(InstructionAt(index));
994 }
995 bool IsGapAt(int index) const { return InstructionAt(index)->IsGapMoves(); }
996 Instruction* InstructionAt(int index) const {
997 DCHECK(index >= 0);
998 DCHECK(index < static_cast<int>(instructions_.size()));
999 return instructions_[index];
1000 }
1001
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001002 Isolate* isolate() const { return zone()->isolate(); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001003 const PointerMapDeque* pointer_maps() const { return &pointer_maps_; }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001004 Zone* zone() const { return zone_; }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001005
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001006 // Used by the instruction selector while adding instructions.
1007 int AddInstruction(Instruction* instr);
1008 void StartBlock(BasicBlock::RpoNumber rpo);
1009 void EndBlock(BasicBlock::RpoNumber rpo);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001010
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001011 int AddConstant(int virtual_register, Constant constant) {
1012 // TODO(titzer): allow RPO numbers as constants?
1013 DCHECK(constant.type() != Constant::kRpoNumber);
1014 DCHECK(virtual_register >= 0 && virtual_register < next_virtual_register_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001015 DCHECK(constants_.find(virtual_register) == constants_.end());
1016 constants_.insert(std::make_pair(virtual_register, constant));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001017 return virtual_register;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001018 }
1019 Constant GetConstant(int virtual_register) const {
1020 ConstantMap::const_iterator it = constants_.find(virtual_register);
1021 DCHECK(it != constants_.end());
1022 DCHECK_EQ(virtual_register, it->first);
1023 return it->second;
1024 }
1025
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001026 typedef ZoneVector<Constant> Immediates;
1027 Immediates& immediates() { return immediates_; }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001028
1029 int AddImmediate(Constant constant) {
1030 int index = static_cast<int>(immediates_.size());
1031 immediates_.push_back(constant);
1032 return index;
1033 }
1034 Constant GetImmediate(int index) const {
1035 DCHECK(index >= 0);
1036 DCHECK(index < static_cast<int>(immediates_.size()));
1037 return immediates_[index];
1038 }
1039
1040 class StateId {
1041 public:
1042 static StateId FromInt(int id) { return StateId(id); }
1043 int ToInt() const { return id_; }
1044
1045 private:
1046 explicit StateId(int id) : id_(id) {}
1047 int id_;
1048 };
1049
1050 StateId AddFrameStateDescriptor(FrameStateDescriptor* descriptor);
1051 FrameStateDescriptor* GetFrameStateDescriptor(StateId deoptimization_id);
1052 int GetFrameStateDescriptorCount();
1053
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001054 BasicBlock::RpoNumber InputRpo(Instruction* instr, size_t index) {
1055 InstructionOperand* operand = instr->InputAt(index);
1056 Constant constant = operand->IsImmediate() ? GetImmediate(operand->index())
1057 : GetConstant(operand->index());
1058 return constant.ToRpoNumber();
1059 }
1060
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001061 private:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001062 friend std::ostream& operator<<(std::ostream& os,
1063 const PrintableInstructionSequence& code);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001064
1065 typedef std::set<int, std::less<int>, ZoneIntAllocator> VirtualRegisterSet;
1066
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001067 Zone* const zone_;
1068 InstructionBlocks* const instruction_blocks_;
1069 IntVector block_starts_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001070 ConstantMap constants_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001071 Immediates immediates_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001072 InstructionDeque instructions_;
1073 int next_virtual_register_;
1074 PointerMapDeque pointer_maps_;
1075 VirtualRegisterSet doubles_;
1076 VirtualRegisterSet references_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001077 DeoptimizationVector deoptimization_entries_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001078
1079 DISALLOW_COPY_AND_ASSIGN(InstructionSequence);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001080};
1081
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001082
1083struct PrintableInstructionSequence {
1084 const RegisterConfiguration* register_configuration_;
1085 const InstructionSequence* sequence_;
1086};
1087
1088
1089std::ostream& operator<<(std::ostream& os,
1090 const PrintableInstructionSequence& code);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001091
1092} // namespace compiler
1093} // namespace internal
1094} // namespace v8
1095
1096#endif // V8_COMPILER_INSTRUCTION_H_