#include <set>
#include "src/allocation.h"
+#include "src/bailout-reason.h"
#include "src/hydrogen.h"
#include "src/safepoint-table.h"
#include "src/zone-allocator.h"
namespace v8 {
namespace internal {
-#define LITHIUM_OPERAND_LIST(V) \
- V(ConstantOperand, CONSTANT_OPERAND, 128) \
- V(StackSlot, STACK_SLOT, 128) \
- V(DoubleStackSlot, DOUBLE_STACK_SLOT, 128) \
- V(Register, REGISTER, 16) \
- V(DoubleRegister, DOUBLE_REGISTER, 16)
-
+#define LITHIUM_OPERAND_LIST(V) \
+ V(ConstantOperand, CONSTANT_OPERAND, 128) \
+ V(StackSlot, STACK_SLOT, 128) \
+ V(DoubleStackSlot, DOUBLE_STACK_SLOT, 128) \
+ V(Float32x4StackSlot, FLOAT32x4_STACK_SLOT, 128) \
+ V(Float64x2StackSlot, FLOAT64x2_STACK_SLOT, 128) \
+ V(Int32x4StackSlot, INT32x4_STACK_SLOT, 128) \
+ V(Register, REGISTER, 16) \
+ V(DoubleRegister, DOUBLE_REGISTER, 16) \
+ V(Float32x4Register, FLOAT32x4_REGISTER, 16) \
+ V(Float64x2Register, FLOAT64x2_REGISTER, 16) \
+ V(Int32x4Register, INT32x4_REGISTER, 16)
class LOperand : public ZoneObject {
public:
CONSTANT_OPERAND,
STACK_SLOT,
DOUBLE_STACK_SLOT,
+ FLOAT32x4_STACK_SLOT,
+ FLOAT64x2_STACK_SLOT,
+ INT32x4_STACK_SLOT,
REGISTER,
- DOUBLE_REGISTER
+ DOUBLE_REGISTER,
+ FLOAT32x4_REGISTER,
+ FLOAT64x2_REGISTER,
+ INT32x4_REGISTER
};
LOperand() : value_(KindField::encode(INVALID)) { }
LITHIUM_OPERAND_PREDICATE(Unallocated, UNALLOCATED, 0)
LITHIUM_OPERAND_PREDICATE(Ignored, INVALID, 0)
#undef LITHIUM_OPERAND_PREDICATE
- bool Equals(LOperand* other) const { return value_ == other->value_; }
+ bool IsSIMD128Register() const {
+ return kind() == FLOAT32x4_REGISTER || kind() == FLOAT64x2_REGISTER ||
+ kind() == INT32x4_REGISTER;
+ }
+ bool IsSIMD128StackSlot() const {
+ return kind() == FLOAT32x4_STACK_SLOT || kind() == FLOAT64x2_STACK_SLOT ||
+ kind() == INT32x4_STACK_SLOT;
+ }
+ bool Equals(LOperand* other) const {
+ return value_ == other->value_ || (index() == other->index() &&
+ ((IsSIMD128Register() && other->IsSIMD128Register()) ||
+ (IsSIMD128StackSlot() && other->IsSIMD128StackSlot())));
+ }
void PrintTo(StringStream* stream);
void ConvertTo(Kind kind, int index) {
+ if (kind == REGISTER) DCHECK(index >= 0);
value_ = KindField::encode(kind);
value_ |= index << kKindFieldWidth;
- ASSERT(this->index() == index);
+ DCHECK(this->index() == index);
}
// Calls SetUpCache()/TearDownCache() for each subclass.
static void TearDownCaches();
protected:
- static const int kKindFieldWidth = 3;
+ static const int kKindFieldWidth = 4;
class KindField : public BitField<Kind, 0, kKindFieldWidth> { };
LOperand(Kind kind, int index) { ConvertTo(kind, index); }
}
LUnallocated(BasicPolicy policy, int index) : LOperand(UNALLOCATED, 0) {
- ASSERT(policy == FIXED_SLOT);
+ DCHECK(policy == FIXED_SLOT);
value_ |= BasicPolicyField::encode(policy);
value_ |= index << FixedSlotIndexField::kShift;
- ASSERT(this->fixed_slot_index() == index);
+ DCHECK(this->fixed_slot_index() == index);
}
LUnallocated(ExtendedPolicy policy, int index) : LOperand(UNALLOCATED, 0) {
- ASSERT(policy == FIXED_REGISTER || policy == FIXED_DOUBLE_REGISTER);
+ DCHECK(policy == FIXED_REGISTER || policy == FIXED_DOUBLE_REGISTER);
value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
value_ |= ExtendedPolicyField::encode(policy);
value_ |= LifetimeField::encode(USED_AT_END);
}
static LUnallocated* cast(LOperand* op) {
- ASSERT(op->IsUnallocated());
+ DCHECK(op->IsUnallocated());
return reinterpret_cast<LUnallocated*>(op);
}
// because it accommodates a larger pay-load.
//
// For FIXED_SLOT policy:
- // +------------------------------------------+
- // | slot_index | vreg | 0 | 001 |
- // +------------------------------------------+
+ // +-------------------------------------------+
+ // | slot_index | vreg | 0 | 0001 |
+ // +-------------------------------------------+
//
// For all other (extended) policies:
- // +------------------------------------------+
- // | reg_index | L | PPP | vreg | 1 | 001 | L ... Lifetime
- // +------------------------------------------+ P ... Policy
+ // +-------------------------------------------+
+ // | reg_index | L | PPP | vreg | 1 | 0001 | L ... Lifetime
+ // +-------------------------------------------+ P ... Policy
//
// The slot index is a signed value which requires us to decode it manually
// instead of using the BitField utility class.
// The superclass has a KindField.
- STATIC_ASSERT(kKindFieldWidth == 3);
+ STATIC_ASSERT(kKindFieldWidth == 4);
// BitFields for all unallocated operands.
- class BasicPolicyField : public BitField<BasicPolicy, 3, 1> {};
- class VirtualRegisterField : public BitField<unsigned, 4, 18> {};
+ class BasicPolicyField : public BitField<BasicPolicy, 4, 1> {};
+ class VirtualRegisterField : public BitField<unsigned, 5, 18> {};
// BitFields specific to BasicPolicy::FIXED_SLOT.
- class FixedSlotIndexField : public BitField<int, 22, 10> {};
+ class FixedSlotIndexField : public BitField<int, 23, 9> {};
// BitFields specific to BasicPolicy::EXTENDED_POLICY.
- class ExtendedPolicyField : public BitField<ExtendedPolicy, 22, 3> {};
- class LifetimeField : public BitField<Lifetime, 25, 1> {};
- class FixedRegisterField : public BitField<int, 26, 6> {};
+ class ExtendedPolicyField : public BitField<ExtendedPolicy, 23, 3> {};
+ class LifetimeField : public BitField<Lifetime, 26, 1> {};
+ class FixedRegisterField : public BitField<int, 27, 5> {};
static const int kMaxVirtualRegisters = VirtualRegisterField::kMax + 1;
static const int kFixedSlotIndexWidth = FixedSlotIndexField::kSize;
// [extended_policy]: Only for non-FIXED_SLOT. The finer-grained policy.
ExtendedPolicy extended_policy() const {
- ASSERT(basic_policy() == EXTENDED_POLICY);
+ DCHECK(basic_policy() == EXTENDED_POLICY);
return ExtendedPolicyField::decode(value_);
}
// [fixed_slot_index]: Only for FIXED_SLOT.
int fixed_slot_index() const {
- ASSERT(HasFixedSlotPolicy());
+ DCHECK(HasFixedSlotPolicy());
return static_cast<int>(value_) >> FixedSlotIndexField::kShift;
}
// [fixed_register_index]: Only for FIXED_REGISTER or FIXED_DOUBLE_REGISTER.
int fixed_register_index() const {
- ASSERT(HasFixedRegisterPolicy() || HasFixedDoubleRegisterPolicy());
+ DCHECK(HasFixedRegisterPolicy() || HasFixedDoubleRegisterPolicy());
return FixedRegisterField::decode(value_);
}
// [lifetime]: Only for non-FIXED_SLOT.
bool IsUsedAtStart() {
- ASSERT(basic_policy() == EXTENDED_POLICY);
+ DCHECK(basic_policy() == EXTENDED_POLICY);
return LifetimeField::decode(value_) == USED_AT_START;
}
};
-class LMoveOperands V8_FINAL BASE_EMBEDDED {
+class LMoveOperands FINAL BASE_EMBEDDED {
public:
LMoveOperands(LOperand* source, LOperand* destination)
: source_(source), destination_(destination) {
}
// A move is redundant if it's been eliminated, if its source and
- // destination are the same, or if its destination is unneeded.
+ // destination are the same, or if its destination is unneeded or constant.
bool IsRedundant() const {
- return IsEliminated() || source_->Equals(destination_) || IsIgnored();
+ return IsEliminated() || source_->Equals(destination_) || IsIgnored() ||
+ (destination_ != NULL && destination_->IsConstantOperand());
}
bool IsIgnored() const {
// We clear both operands to indicate move that's been eliminated.
void Eliminate() { source_ = destination_ = NULL; }
bool IsEliminated() const {
- ASSERT(source_ != NULL || destination_ == NULL);
+ DCHECK(source_ != NULL || destination_ == NULL);
return source_ == NULL;
}
template<LOperand::Kind kOperandKind, int kNumCachedOperands>
-class LSubKindOperand V8_FINAL : public LOperand {
+class LSubKindOperand FINAL : public LOperand {
public:
static LSubKindOperand* Create(int index, Zone* zone) {
- ASSERT(index >= 0);
+ DCHECK(index >= 0);
if (index < kNumCachedOperands) return &cache[index];
return new(zone) LSubKindOperand(index);
}
static LSubKindOperand* cast(LOperand* op) {
- ASSERT(op->kind() == kOperandKind);
+ DCHECK(op->kind() == kOperandKind);
return reinterpret_cast<LSubKindOperand*>(op);
}
#undef LITHIUM_TYPEDEF_SUBKIND_OPERAND_CLASS
-class LParallelMove V8_FINAL : public ZoneObject {
+class LParallelMove FINAL : public ZoneObject {
public:
explicit LParallelMove(Zone* zone) : move_operands_(4, zone) { }
bool IsRedundant() const;
- const ZoneList<LMoveOperands>* move_operands() const {
- return &move_operands_;
- }
+ ZoneList<LMoveOperands>* move_operands() { return &move_operands_; }
void PrintDataTo(StringStream* stream) const;
};
-class LPointerMap V8_FINAL : public ZoneObject {
+class LPointerMap FINAL : public ZoneObject {
public:
explicit LPointerMap(Zone* zone)
: pointer_operands_(8, zone),
int lithium_position() const { return lithium_position_; }
void set_lithium_position(int pos) {
- ASSERT(lithium_position_ == -1);
+ DCHECK(lithium_position_ == -1);
lithium_position_ = pos;
}
};
-class LEnvironment V8_FINAL : public ZoneObject {
+class LEnvironment FINAL : public ZoneObject {
public:
LEnvironment(Handle<JSFunction> closure,
FrameType frame_type,
bool is_uint32) {
values_.Add(operand, zone());
if (representation.IsSmiOrTagged()) {
- ASSERT(!is_uint32);
+ DCHECK(!is_uint32);
is_tagged_.Add(values_.length() - 1, zone());
}
}
int ObjectDuplicateOfAt(int index) {
- ASSERT(ObjectIsDuplicateAt(index));
+ DCHECK(ObjectIsDuplicateAt(index));
return LengthOrDupeField::decode(object_mapping_[index]);
}
int ObjectLengthAt(int index) {
- ASSERT(!ObjectIsDuplicateAt(index));
+ DCHECK(!ObjectIsDuplicateAt(index));
return LengthOrDupeField::decode(object_mapping_[index]);
}
bool ObjectIsArgumentsAt(int index) {
- ASSERT(!ObjectIsDuplicateAt(index));
+ DCHECK(!ObjectIsDuplicateAt(index));
return IsArgumentsField::decode(object_mapping_[index]);
}
void Register(int deoptimization_index,
int translation_index,
int pc_offset) {
- ASSERT(!HasBeenRegistered());
+ DCHECK(!HasBeenRegistered());
deoptimization_index_ = deoptimization_index;
translation_index_ = translation_index;
pc_offset_ = pc_offset;
// Iterates over the non-null, non-constant operands in an environment.
-class ShallowIterator V8_FINAL BASE_EMBEDDED {
+class ShallowIterator FINAL BASE_EMBEDDED {
public:
explicit ShallowIterator(LEnvironment* env)
: env_(env),
bool Done() { return current_ >= limit_; }
LOperand* Current() {
- ASSERT(!Done());
- ASSERT(env_->values()->at(current_) != NULL);
+ DCHECK(!Done());
+ DCHECK(env_->values()->at(current_) != NULL);
return env_->values()->at(current_);
}
void Advance() {
- ASSERT(!Done());
+ DCHECK(!Done());
++current_;
SkipUninteresting();
}
// Iterator for non-null, non-constant operands incl. outer environments.
-class DeepIterator V8_FINAL BASE_EMBEDDED {
+class DeepIterator FINAL BASE_EMBEDDED {
public:
explicit DeepIterator(LEnvironment* env)
: current_iterator_(env) {
bool Done() { return current_iterator_.Done(); }
LOperand* Current() {
- ASSERT(!current_iterator_.Done());
- ASSERT(current_iterator_.Current() != NULL);
+ DCHECK(!current_iterator_.Done());
+ DCHECK(current_iterator_.Current() != NULL);
return current_iterator_.Current();
}
}
void AddDeprecationDependency(Handle<Map> map) {
- ASSERT(!map->is_deprecated());
+ DCHECK(!map->is_deprecated());
if (!map->CanBeDeprecated()) return;
- ASSERT(!info_->IsStub());
+ DCHECK(!info_->IsStub());
deprecation_dependencies_.insert(map);
}
void AddStabilityDependency(Handle<Map> map) {
- ASSERT(map->is_stable());
+ DCHECK(map->is_stable());
if (!map->CanTransition()) return;
- ASSERT(!info_->IsStub());
+ DCHECK(!info_->IsStub());
stability_dependencies_.insert(map);
}
class LChunkBuilderBase BASE_EMBEDDED {
public:
- explicit LChunkBuilderBase(Zone* zone)
+ explicit LChunkBuilderBase(CompilationInfo* info, HGraph* graph)
: argument_count_(0),
- zone_(zone) { }
+ chunk_(NULL),
+ info_(info),
+ graph_(graph),
+ status_(UNUSED),
+ zone_(graph->zone()) {}
virtual ~LChunkBuilderBase() { }
+ void Abort(BailoutReason reason);
+ void Retry(BailoutReason reason);
+
protected:
+ enum Status { UNUSED, BUILDING, DONE, ABORTED };
+
+ LPlatformChunk* chunk() const { return chunk_; }
+ CompilationInfo* info() const { return info_; }
+ HGraph* graph() const { return graph_; }
+ int argument_count() const { return argument_count_; }
+ Isolate* isolate() const { return graph_->isolate(); }
+ Heap* heap() const { return isolate()->heap(); }
+
+ bool is_unused() const { return status_ == UNUSED; }
+ bool is_building() const { return status_ == BUILDING; }
+ bool is_done() const { return status_ == DONE; }
+ bool is_aborted() const { return status_ == ABORTED; }
+
// An input operand in register, stack slot or a constant operand.
// Will not be moved to a register even if one is freely available.
virtual MUST_USE_RESULT LOperand* UseAny(HValue* value) = 0;
Zone* zone() const { return zone_; }
int argument_count_;
+ LPlatformChunk* chunk_;
+ CompilationInfo* info_;
+ HGraph* const graph_;
+ Status status_;
private:
Zone* zone_;
};
+// A register-allocator view of a Lithium instruction. It contains the id of
+// the output operand and a list of input operand uses.
+enum RegisterKind {
+ UNALLOCATED_REGISTERS,
+ GENERAL_REGISTERS,
+ DOUBLE_REGISTERS,
+ FLOAT32x4_REGISTERS,
+ FLOAT64x2_REGISTERS,
+ INT32x4_REGISTERS
+};
+
+// Iterator for non-null temp operands.
+class TempIterator BASE_EMBEDDED {
+ public:
+ inline explicit TempIterator(LInstruction* instr);
+ inline bool Done();
+ inline LOperand* Current();
+ inline void Advance();
+
+ private:
+ inline void SkipUninteresting();
+ LInstruction* instr_;
+ int limit_;
+ int current_;
+};
+
+
+// Iterator for non-constant input operands.
+class InputIterator BASE_EMBEDDED {
+ public:
+ inline explicit InputIterator(LInstruction* instr);
+ inline bool Done();
+ inline LOperand* Current();
+ inline void Advance();
+
+ private:
+ inline void SkipUninteresting();
+ LInstruction* instr_;
+ int limit_;
+ int current_;
+};
+
+
+class UseIterator BASE_EMBEDDED {
+ public:
+ inline explicit UseIterator(LInstruction* instr);
+ inline bool Done();
+ inline LOperand* Current();
+ inline void Advance();
+
+ private:
+ InputIterator input_iterator_;
+ DeepIterator env_iterator_;
+};
+
+class LInstruction;
+class LCodeGen;
} } // namespace v8::internal
#endif // V8_LITHIUM_H_