namespace internal {
namespace compiler {
-typedef ZoneList<MoveOperands>::iterator op_iterator;
+namespace {
-#ifdef ENABLE_SLOW_DCHECKS
-struct InstructionOperandComparator {
- bool operator()(const InstructionOperand* x,
- const InstructionOperand* y) const {
- return *x < *y;
- }
-};
-#endif
-
-// No operand should be the destination for more than one move.
-static void VerifyMovesAreInjective(ZoneList<MoveOperands>* moves) {
-#ifdef ENABLE_SLOW_DCHECKS
- std::set<InstructionOperand*, InstructionOperandComparator> seen;
- for (op_iterator i = moves->begin(); i != moves->end(); ++i) {
- SLOW_DCHECK(seen.find(i->destination()) == seen.end());
- seen.insert(i->destination());
- }
-#endif
+inline bool Blocks(MoveOperands* move, InstructionOperand destination) {
+ return move->Blocks(destination);
}
-void GapResolver::Resolve(ParallelMove* parallel_move) const {
- ZoneList<MoveOperands>* moves = parallel_move->move_operands();
- // TODO(svenpanne) Use the member version of remove_if when we use real lists.
- op_iterator end =
- std::remove_if(moves->begin(), moves->end(),
- std::mem_fun_ref(&MoveOperands::IsRedundant));
- moves->Rewind(static_cast<int>(end - moves->begin()));
+inline bool IsRedundant(MoveOperands* move) { return move->IsRedundant(); }
+
+} // namespace
- VerifyMovesAreInjective(moves);
- for (op_iterator move = moves->begin(); move != moves->end(); ++move) {
- if (!move->IsEliminated()) PerformMove(moves, &*move);
+void GapResolver::Resolve(ParallelMove* moves) const {
+ // Clear redundant moves.
+ auto it =
+ std::remove_if(moves->begin(), moves->end(), std::ptr_fun(IsRedundant));
+ moves->erase(it, moves->end());
+ for (auto move : *moves) {
+ if (!move->IsEliminated()) PerformMove(moves, move);
}
}
-void GapResolver::PerformMove(ZoneList<MoveOperands>* moves,
- MoveOperands* move) const {
+void GapResolver::PerformMove(ParallelMove* moves, MoveOperands* move) const {
// Each call to this function performs a move and deletes it from the move
// graph. We first recursively perform any move blocking this one. We mark a
// move as "pending" on entry to PerformMove in order to detect cycles in the
// Clear this move's destination to indicate a pending move. The actual
// destination is saved on the side.
- DCHECK_NOT_NULL(move->source()); // Or else it will look eliminated.
- InstructionOperand* destination = move->destination();
- move->set_destination(NULL);
+ DCHECK(!move->source().IsInvalid()); // Or else it will look eliminated.
+ InstructionOperand destination = move->destination();
+ move->SetPending();
// Perform a depth-first traversal of the move graph to resolve dependencies.
// Any unperformed, unpending move with a source the same as this one's
// destination blocks this one so recursively perform all such moves.
- for (op_iterator other = moves->begin(); other != moves->end(); ++other) {
+ for (auto other : *moves) {
if (other->Blocks(destination) && !other->IsPending()) {
// Though PerformMove can change any source operand in the move graph,
// this call cannot create a blocking move via a swap (this loop does not
// This move's source may have changed due to swaps to resolve cycles and so
// it may now be the last move in the cycle. If so remove it.
- InstructionOperand* source = move->source();
- if (source->Equals(destination)) {
+ InstructionOperand source = move->source();
+ if (source == destination) {
move->Eliminate();
return;
}
// The move may be blocked on a (at most one) pending move, in which case we
// have a cycle. Search for such a blocking move and perform a swap to
// resolve it.
- op_iterator blocker = std::find_if(
- moves->begin(), moves->end(),
- std::bind2nd(std::mem_fun_ref(&MoveOperands::Blocks), destination));
+ auto blocker = std::find_if(moves->begin(), moves->end(),
+ std::bind2nd(std::ptr_fun(&Blocks), destination));
if (blocker == moves->end()) {
// The easy case: This move is not blocked.
- assembler_->AssembleMove(source, destination);
+ assembler_->AssembleMove(&source, &destination);
move->Eliminate();
return;
}
- DCHECK(blocker->IsPending());
+ DCHECK((*blocker)->IsPending());
// Ensure source is a register or both are stack slots, to limit swap cases.
- if (source->IsStackSlot() || source->IsDoubleStackSlot()) {
+ if (source.IsStackSlot() || source.IsDoubleStackSlot()) {
std::swap(source, destination);
}
- assembler_->AssembleSwap(source, destination);
+ assembler_->AssembleSwap(&source, &destination);
move->Eliminate();
// Any unperformed (including pending) move with a source of either this
// move's source or destination needs to have their source changed to
// reflect the state of affairs after the swap.
- for (op_iterator other = moves->begin(); other != moves->end(); ++other) {
+ for (auto other : *moves) {
if (other->Blocks(source)) {
other->set_source(destination);
} else if (other->Blocks(destination)) {
private:
// Perform the given move, possibly requiring other moves to satisfy
// dependencies.
- void PerformMove(ZoneList<MoveOperands>* moves, MoveOperands* move) const;
+ void PerformMove(ParallelMove* moves, MoveOperands* move) const;
// Assembler used to emit moves and save registers.
Assembler* const assembler_;
std::ostream& operator<<(std::ostream& os,
const PrintableInstructionOperand& printable) {
- const InstructionOperand& op = *printable.op_;
+ const InstructionOperand& op = printable.op_;
const RegisterConfiguration* conf = printable.register_configuration_;
switch (op.kind()) {
case InstructionOperand::UNALLOCATED: {
const MoveOperands& mo = *printable.move_operands_;
PrintableInstructionOperand printable_op = {printable.register_configuration_,
mo.destination()};
-
os << printable_op;
- if (!mo.source()->Equals(mo.destination())) {
+ if (mo.source() != mo.destination()) {
printable_op.op_ = mo.source();
os << " = " << printable_op;
}
bool ParallelMove::IsRedundant() const {
- for (int i = 0; i < move_operands_.length(); ++i) {
- if (!move_operands_[i].IsRedundant()) return false;
+ for (auto move : *this) {
+ if (!move->IsRedundant()) return false;
}
return true;
}
MoveOperands* ParallelMove::PrepareInsertAfter(MoveOperands* move) const {
- auto move_ops = move_operands();
MoveOperands* replacement = nullptr;
MoveOperands* to_eliminate = nullptr;
- for (auto curr = move_ops->begin(); curr != move_ops->end(); ++curr) {
+ for (auto curr : *this) {
if (curr->IsEliminated()) continue;
- if (curr->destination()->Equals(move->source())) {
+ if (curr->destination() == move->source()) {
DCHECK(!replacement);
replacement = curr;
if (to_eliminate != nullptr) break;
- } else if (curr->destination()->Equals(move->destination())) {
+ } else if (curr->destination() == move->destination()) {
DCHECK(!to_eliminate);
to_eliminate = curr;
if (replacement != nullptr) break;
const PrintableParallelMove& printable) {
const ParallelMove& pm = *printable.parallel_move_;
bool first = true;
- for (ZoneList<MoveOperands>::iterator move = pm.move_operands()->begin();
- move != pm.move_operands()->end(); ++move) {
+ for (auto move : pm) {
if (move->IsEliminated()) continue;
if (!first) os << " ";
first = false;
os << "{";
bool first = true;
PrintableInstructionOperand poi = {RegisterConfiguration::ArchDefault(),
- nullptr};
+ InstructionOperand()};
for (auto& op : pm.reference_operands_) {
if (!first) {
os << ";";
} else {
first = false;
}
- poi.op_ = &op;
+ poi.op_ = op;
os << poi;
}
return os << "}";
const PrintableInstruction& printable) {
const Instruction& instr = *printable.instr_;
PrintableInstructionOperand printable_op = {printable.register_configuration_,
- NULL};
+ InstructionOperand()};
os << "gap ";
for (int i = Instruction::FIRST_GAP_POSITION;
i <= Instruction::LAST_GAP_POSITION; i++) {
if (instr.OutputCount() > 1) os << "(";
for (size_t i = 0; i < instr.OutputCount(); i++) {
if (i > 0) os << ", ";
- printable_op.op_ = instr.OutputAt(i);
+ printable_op.op_ = *instr.OutputAt(i);
os << printable_op;
}
}
if (instr.InputCount() > 0) {
for (size_t i = 0; i < instr.InputCount(); i++) {
- printable_op.op_ = instr.InputAt(i);
+ printable_op.op_ = *instr.InputAt(i);
os << " " << printable_op;
}
}
size_t input_count)
: virtual_register_(virtual_register),
output_(UnallocatedOperand(UnallocatedOperand::NONE, virtual_register)),
- operands_(input_count, zone),
- inputs_(input_count, zone) {}
+ operands_(input_count, InstructionOperand::kInvalidVirtualRegister,
+ zone) {}
void PhiInstruction::SetInput(size_t offset, int virtual_register) {
- DCHECK(inputs_[offset].IsInvalid());
- auto input = UnallocatedOperand(UnallocatedOperand::ANY, virtual_register);
- inputs_[offset] = input;
+ DCHECK_EQ(InstructionOperand::kInvalidVirtualRegister, operands_[offset]);
operands_[offset] = virtual_register;
}
for (auto phi : block->phis()) {
PrintableInstructionOperand printable_op = {
- printable.register_configuration_, &phi->output()};
+ printable.register_configuration_, phi->output()};
os << " phi: " << printable_op << " =";
- for (auto input : phi->inputs()) {
- printable_op.op_ = &input;
- os << " " << printable_op;
+ for (auto input : phi->operands()) {
+ os << " v" << input;
}
os << "\n";
}
inline bool IsStackSlot() const;
inline bool IsDoubleStackSlot() const;
- bool Equals(const InstructionOperand* other) const {
- return value_ == other->value_;
- }
-
// Useful for map/set keys.
bool operator<(const InstructionOperand& op) const {
return value_ < op.value_;
return value_ == op.value_;
}
+ bool operator!=(const InstructionOperand& op) const {
+ return value_ != op.value_;
+ }
+
template <typename SubKindOperand>
static SubKindOperand* New(Zone* zone, const SubKindOperand& op) {
void* buffer = zone->New(sizeof(op));
struct PrintableInstructionOperand {
const RegisterConfiguration* register_configuration_;
- const InstructionOperand* op_;
+ InstructionOperand op_;
};
std::ostream& operator<<(std::ostream& os,
value_ |= LifetimeField::encode(lifetime);
}
- UnallocatedOperand* Copy(Zone* zone) { return New(zone, *this); }
-
- UnallocatedOperand* CopyUnconstrained(Zone* zone) {
- return New(zone, UnallocatedOperand(ANY, virtual_register()));
- }
-
// Predicates for the operand policy.
bool HasAnyPolicy() const {
return basic_policy() == EXTENDED_POLICY && extended_policy() == ANY;
#undef ALLOCATED_OPERAND_CLASS
-class MoveOperands FINAL {
+class MoveOperands FINAL : public ZoneObject {
public:
- MoveOperands(InstructionOperand* source, InstructionOperand* destination)
- : source_(source), destination_(destination) {}
+ MoveOperands(const InstructionOperand& source,
+ const InstructionOperand& destination)
+ : source_(source), destination_(destination) {
+ DCHECK(!source.IsInvalid() && !destination.IsInvalid());
+ }
- InstructionOperand* source() const { return source_; }
- void set_source(InstructionOperand* operand) { source_ = operand; }
+ const InstructionOperand& source() const { return source_; }
+ InstructionOperand& source() { return source_; }
+ void set_source(const InstructionOperand& operand) { source_ = operand; }
- InstructionOperand* destination() const { return destination_; }
- void set_destination(InstructionOperand* operand) { destination_ = operand; }
+ const InstructionOperand& destination() const { return destination_; }
+ InstructionOperand& destination() { return destination_; }
+ void set_destination(const InstructionOperand& operand) {
+ destination_ = operand;
+ }
// The gap resolver marks moves as "in-progress" by clearing the
// destination (but not the source).
- bool IsPending() const { return destination_ == NULL && source_ != NULL; }
+ bool IsPending() const {
+ return destination_.IsInvalid() && !source_.IsInvalid();
+ }
+ void SetPending() { destination_ = InstructionOperand(); }
// True if this move a move into the given destination operand.
- bool Blocks(InstructionOperand* operand) const {
- return !IsEliminated() && source()->Equals(operand);
+ bool Blocks(const InstructionOperand& operand) const {
+ return !IsEliminated() && source() == operand;
}
// A move is redundant if it's been eliminated or if its source and
// destination are the same.
bool IsRedundant() const {
- DCHECK_IMPLIES(destination_ != nullptr, !destination_->IsConstant());
- return IsEliminated() || source_->Equals(destination_);
+ DCHECK_IMPLIES(!destination_.IsInvalid(), !destination_.IsConstant());
+ return IsEliminated() || source_ == destination_;
}
// We clear both operands to indicate move that's been eliminated.
- void Eliminate() { source_ = destination_ = NULL; }
+ void Eliminate() { source_ = destination_ = InstructionOperand(); }
bool IsEliminated() const {
- DCHECK(source_ != NULL || destination_ == NULL);
- return source_ == NULL;
+ DCHECK_IMPLIES(source_.IsInvalid(), destination_.IsInvalid());
+ return source_.IsInvalid();
}
private:
- InstructionOperand* source_;
- InstructionOperand* destination_;
+ InstructionOperand source_;
+ InstructionOperand destination_;
+
+ DISALLOW_COPY_AND_ASSIGN(MoveOperands);
};
std::ostream& operator<<(std::ostream& os, const PrintableMoveOperands& mo);
-class ParallelMove FINAL : public ZoneObject {
+class ParallelMove FINAL : public ZoneVector<MoveOperands*>, public ZoneObject {
public:
- explicit ParallelMove(Zone* zone) : move_operands_(4, zone) {}
+ explicit ParallelMove(Zone* zone) : ZoneVector<MoveOperands*>(zone) {
+ reserve(4);
+ }
- void AddMove(InstructionOperand* from, InstructionOperand* to, Zone* zone) {
- move_operands_.Add(MoveOperands(from, to), zone);
+ MoveOperands* AddMove(const InstructionOperand& from,
+ const InstructionOperand& to) {
+ auto zone = get_allocator().zone();
+ auto move = new (zone) MoveOperands(from, to);
+ push_back(move);
+ return move;
}
bool IsRedundant() const;
- ZoneList<MoveOperands>* move_operands() { return &move_operands_; }
- const ZoneList<MoveOperands>* move_operands() const {
- return &move_operands_;
- }
-
// Prepare this ParallelMove to insert move as if it happened in a subsequent
// ParallelMove. move->source() may be changed. The MoveOperand returned
- // must be Eliminated and, as it points directly into move_operands_, it must
- // be Eliminated before any further mutation.
+ // must be Eliminated.
MoveOperands* PrepareInsertAfter(MoveOperands* move) const;
private:
- ZoneList<MoveOperands> move_operands_;
+ DISALLOW_COPY_AND_ASSIGN(ParallelMove);
};
int virtual_register() const { return virtual_register_; }
const IntVector& operands() const { return operands_; }
+ // TODO(dcarney): this has no real business being here, since it's internal to
+ // the register allocator, but putting it here was convenient.
const InstructionOperand& output() const { return output_; }
InstructionOperand& output() { return output_; }
- const Inputs& inputs() const { return inputs_; }
- Inputs& inputs() { return inputs_; }
private:
- // TODO(dcarney): some of these fields are only for verification, move them to
- // verifier.
const int virtual_register_;
InstructionOperand output_;
IntVector operands_;
- Inputs inputs_;
};
int FindFirstNonEmptySlot(Instruction* instr) {
int i = Instruction::FIRST_GAP_POSITION;
for (; i <= Instruction::LAST_GAP_POSITION; i++) {
- auto move = instr->parallel_moves()[i];
- if (move == nullptr) continue;
- auto move_ops = move->move_operands();
- auto op = move_ops->begin();
- for (; op != move_ops->end(); ++op) {
- if (!op->IsRedundant()) break;
- op->Eliminate();
+ auto moves = instr->parallel_moves()[i];
+ if (moves == nullptr) continue;
+ for (auto move : *moves) {
+ if (!move->IsRedundant()) return i;
+ move->Eliminate();
}
- if (op != move_ops->end()) break; // Found non-redundant move.
- move_ops->Rewind(0); // Clear this redundant move.
+ moves->clear(); // Clear this redundant move.
}
return i;
}
void MoveOptimizer::CompressMoves(MoveOpVector* eliminated, ParallelMove* left,
ParallelMove* right) {
DCHECK(eliminated->empty());
- auto move_ops = right->move_operands();
- if (!left->move_operands()->is_empty()) {
+ if (!left->empty()) {
// Modify the right moves in place and collect moves that will be killed by
// merging the two gaps.
- for (auto op = move_ops->begin(); op != move_ops->end(); ++op) {
- if (op->IsRedundant()) continue;
- auto to_eliminate = left->PrepareInsertAfter(op);
+ for (auto move : *right) {
+ if (move->IsRedundant()) continue;
+ auto to_eliminate = left->PrepareInsertAfter(move);
if (to_eliminate != nullptr) eliminated->push_back(to_eliminate);
}
- // Eliminate dead moves. Must happen before insertion of new moves as the
- // contents of eliminated are pointers into a list.
+ // Eliminate dead moves.
for (auto to_eliminate : *eliminated) {
to_eliminate->Eliminate();
}
eliminated->clear();
}
// Add all possibly modified moves from right side.
- for (auto op = move_ops->begin(); op != move_ops->end(); ++op) {
- if (op->IsRedundant()) continue;
- left->move_operands()->Add(*op, code_zone());
+ for (auto move : *right) {
+ if (move->IsRedundant()) continue;
+ left->push_back(move);
}
// Nuke right.
- move_ops->Rewind(0);
+ right->clear();
}
auto pred = code()->InstructionBlockAt(pred_index);
auto instr = LastInstruction(pred);
if (instr->parallel_moves()[0] == nullptr ||
- instr->parallel_moves()[0]->move_operands()->is_empty()) {
+ instr->parallel_moves()[0]->empty()) {
return;
}
- auto move_ops = instr->parallel_moves()[0]->move_operands();
- for (auto op = move_ops->begin(); op != move_ops->end(); ++op) {
- if (op->IsRedundant()) continue;
- auto src = *op->source();
- auto dst = *op->destination();
+ for (auto move : *instr->parallel_moves()[0]) {
+ if (move->IsRedundant()) continue;
+ auto src = move->source();
+ auto dst = move->destination();
MoveKey key = {src, dst};
auto res = move_map.insert(std::make_pair(key, 1));
if (!res.second) {
DCHECK(instr != nullptr);
bool gap_initialized = true;
if (instr->parallel_moves()[0] == nullptr ||
- instr->parallel_moves()[0]->move_operands()->is_empty()) {
+ instr->parallel_moves()[0]->empty()) {
to_finalize_.push_back(instr);
} else {
// Will compress after insertion.
gap_initialized = false;
std::swap(instr->parallel_moves()[0], instr->parallel_moves()[1]);
}
- auto move = instr->GetOrCreateParallelMove(
+ auto moves = instr->GetOrCreateParallelMove(
static_cast<Instruction::GapPosition>(0), code_zone());
// Delete relevant entries in predecessors and move everything to block.
bool first_iteration = true;
for (auto pred_index : block->predecessors()) {
auto pred = code()->InstructionBlockAt(pred_index);
- auto move_ops = LastInstruction(pred)->parallel_moves()[0]->move_operands();
- for (auto op = move_ops->begin(); op != move_ops->end(); ++op) {
- if (op->IsRedundant()) continue;
- MoveKey key = {*op->source(), *op->destination()};
+ for (auto move : *LastInstruction(pred)->parallel_moves()[0]) {
+ if (move->IsRedundant()) continue;
+ MoveKey key = {move->source(), move->destination()};
auto it = move_map.find(key);
USE(it);
DCHECK(it != move_map.end());
if (first_iteration) {
- move->AddMove(op->source(), op->destination(), code_zone());
+ moves->AddMove(move->source(), move->destination());
}
- op->Eliminate();
+ move->Eliminate();
}
first_iteration = false;
}
}
+namespace {
+
+bool IsSlot(const InstructionOperand& op) {
+ return op.IsStackSlot() || op.IsDoubleStackSlot();
+}
+
+
+bool LoadCompare(const MoveOperands* a, const MoveOperands* b) {
+ if (a->source() != b->source()) return a->source() < b->source();
+ if (IsSlot(a->destination()) && !IsSlot(b->destination())) return false;
+ if (!IsSlot(a->destination()) && IsSlot(b->destination())) return true;
+ return a->destination() < b->destination();
+}
+
+} // namespace
+
+
// Split multiple loads of the same constant or stack slot off into the second
// slot and keep remaining moves in the first slot.
void MoveOptimizer::FinalizeMoves(Instruction* instr) {
auto loads = temp_vector_0();
DCHECK(loads.empty());
- auto new_moves = temp_vector_1();
- DCHECK(new_moves.empty());
- auto move_ops = instr->parallel_moves()[0]->move_operands();
- for (auto move = move_ops->begin(); move != move_ops->end(); ++move) {
- if (move->IsRedundant()) {
- move->Eliminate();
- continue;
- }
- if (!(move->source()->IsConstant() || move->source()->IsStackSlot() ||
- move->source()->IsDoubleStackSlot()))
- continue;
- // Search for existing move to this slot.
- MoveOperands* found = nullptr;
- for (auto load : loads) {
- if (load->source()->Equals(move->source())) {
- found = load;
- break;
- }
- }
- // Not found so insert.
- if (found == nullptr) {
+ // Find all the loads.
+ for (auto move : *instr->parallel_moves()[0]) {
+ if (move->IsRedundant()) continue;
+ if (move->source().IsConstant() || IsSlot(move->source())) {
loads.push_back(move);
- // Replace source with copy for later use.
- auto dest = move->destination();
- move->set_destination(InstructionOperand::New(code_zone(), *dest));
- continue;
}
- if ((found->destination()->IsStackSlot() ||
- found->destination()->IsDoubleStackSlot()) &&
- !(move->destination()->IsStackSlot() ||
- move->destination()->IsDoubleStackSlot())) {
- // Found a better source for this load. Smash it in place to affect other
- // loads that have already been split.
- auto next_dest =
- InstructionOperand::New(code_zone(), *found->destination());
- auto dest = move->destination();
- InstructionOperand::ReplaceWith(found->destination(), dest);
- move->set_destination(next_dest);
+ }
+ if (loads.empty()) return;
+ // Group the loads by source, moving the preferred destination to the
+ // beginning of the group.
+ std::sort(loads.begin(), loads.end(), LoadCompare);
+ MoveOperands* group_begin = nullptr;
+ for (auto load : loads) {
+ // New group.
+ if (group_begin == nullptr || load->source() != group_begin->source()) {
+ group_begin = load;
+ continue;
}
- // move from load destination.
- move->set_source(found->destination());
- new_moves.push_back(move);
+ // Nothing to be gained from splitting here.
+ if (IsSlot(group_begin->destination())) continue;
+ // Insert new move into slot 1.
+ auto slot_1 = instr->GetOrCreateParallelMove(
+ static_cast<Instruction::GapPosition>(1), code_zone());
+ slot_1->AddMove(group_begin->destination(), load->destination());
+ load->Eliminate();
}
loads.clear();
- if (new_moves.empty()) return;
- // Insert all new moves into slot 1.
- auto slot_1 = instr->GetOrCreateParallelMove(
- static_cast<Instruction::GapPosition>(1), code_zone());
- DCHECK(slot_1->move_operands()->is_empty());
- slot_1->move_operands()->AddBlock(MoveOperands(nullptr, nullptr),
- static_cast<int>(new_moves.size()),
- code_zone());
- auto it = slot_1->move_operands()->begin();
- for (auto new_move : new_moves) {
- std::swap(*new_move, *it);
- ++it;
- }
- DCHECK_EQ(it, slot_1->move_operands()->end());
- new_moves.clear();
}
} // namespace compiler
namespace internal {
namespace compiler {
-static size_t OperandCount(const Instruction* instr) {
+namespace {
+
+size_t OperandCount(const Instruction* instr) {
return instr->InputCount() + instr->OutputCount() + instr->TempCount();
}
-static void VerifyEmptyGaps(const Instruction* instr) {
+void VerifyEmptyGaps(const Instruction* instr) {
for (int i = Instruction::FIRST_GAP_POSITION;
i <= Instruction::LAST_GAP_POSITION; i++) {
Instruction::GapPosition inner_pos =
}
+void VerifyAllocatedGaps(const Instruction* instr) {
+ for (int i = Instruction::FIRST_GAP_POSITION;
+ i <= Instruction::LAST_GAP_POSITION; i++) {
+ Instruction::GapPosition inner_pos =
+ static_cast<Instruction::GapPosition>(i);
+ auto moves = instr->GetParallelMove(inner_pos);
+ if (moves == nullptr) continue;
+ for (auto move : *moves) {
+ if (move->IsRedundant()) continue;
+ CHECK(move->source().IsAllocated() || move->source().IsConstant());
+ CHECK(move->destination().IsAllocated());
+ }
+ }
+}
+
+} // namespace
+
+
void RegisterAllocatorVerifier::VerifyInput(
const OperandConstraint& constraint) {
CHECK_NE(kSameAsFirst, constraint.type_);
auto instr_it = sequence()->begin();
for (const auto& instr_constraint : *constraints()) {
const auto* instr = instr_constraint.instruction_;
+ // All gaps should be totally allocated at this point.
+ VerifyAllocatedGaps(instr);
const size_t operand_count = instr_constraint.operand_constaints_size_;
const auto* op_constraints = instr_constraint.operand_constraints_;
CHECK_EQ(instr, *instr_it);
this->erase(it++);
if (it == this->end()) return;
}
- if (it->first->Equals(o.first)) {
+ if (*it->first == *o.first) {
++it;
if (it == this->end()) return;
} else {
Map& map() { return map_; }
- void RunParallelMoves(Zone* zone, const ParallelMove* move) {
+ void RunParallelMoves(Zone* zone, const ParallelMove* moves) {
// Compute outgoing mappings.
Map to_insert(zone);
- auto moves = move->move_operands();
- for (auto i = moves->begin(); i != moves->end(); ++i) {
- if (i->IsEliminated()) continue;
- auto cur = map().find(i->source());
+ for (auto move : *moves) {
+ if (move->IsEliminated()) continue;
+ auto cur = map().find(&move->source());
CHECK(cur != map().end());
auto res =
- to_insert.insert(std::make_pair(i->destination(), cur->second));
+ to_insert.insert(std::make_pair(&move->destination(), cur->second));
// Ensure injectivity of moves.
CHECK(res.second);
}
// Drop current mappings.
- for (auto i = moves->begin(); i != moves->end(); ++i) {
- if (i->IsEliminated()) continue;
- auto cur = map().find(i->destination());
+ for (auto move : *moves) {
+ if (move->IsEliminated()) continue;
+ auto cur = map().find(&move->destination());
if (cur != map().end()) map().erase(cur);
}
// Insert new values.
void LiveRange::set_assigned_register(int reg) {
DCHECK(!HasRegisterAssigned() && !IsSpilled());
assigned_register_ = reg;
- // TODO(dcarney): stop aliasing hint operands.
- ConvertUsesToOperand(GetAssignedOperand(), nullptr);
}
// constraint move from a fixed output register to a slot.
if (might_be_duplicated) {
bool found = false;
- auto move_ops = move->move_operands();
- for (auto move_op = move_ops->begin(); move_op != move_ops->end();
- ++move_op) {
+ for (auto move_op : *move) {
if (move_op->IsEliminated()) continue;
- if (move_op->source()->Equals(to_spill->operand) &&
- move_op->destination()->Equals(op)) {
+ if (move_op->source() == *to_spill->operand &&
+ move_op->destination() == *op) {
found = true;
break;
}
}
if (found) continue;
}
- move->AddMove(to_spill->operand, op, zone);
+ move->AddMove(*to_spill->operand, *op);
}
}
}
-void RegisterAllocator::AddGapMove(int index, Instruction::GapPosition position,
- InstructionOperand* from,
- InstructionOperand* to) {
+MoveOperands* RegisterAllocator::AddGapMove(int index,
+ Instruction::GapPosition position,
+ const InstructionOperand& from,
+ const InstructionOperand& to) {
auto instr = code()->InstructionAt(index);
- auto move = instr->GetOrCreateParallelMove(position, code_zone());
- move->AddMove(from, to, code_zone());
+ auto moves = instr->GetOrCreateParallelMove(position, code_zone());
+ return moves->AddMove(from, to);
}
}
auto assigned = range->GetAssignedOperand();
range->ConvertUsesToOperand(assigned, spill_operand);
+ if (range->is_phi()) AssignPhiInput(range, assigned);
if (!range->IsChild() && spill_operand != nullptr) {
range->CommitSpillsAtDefinition(code(), spill_operand,
range->has_slot_use());
auto lookup = phi_map_.find(range->id());
DCHECK(lookup != phi_map_.end());
- auto phi = lookup->second.phi;
- auto block = lookup->second.block;
+ auto phi = lookup->second->phi;
+ auto block = lookup->second->block;
// Count the number of spilled operands.
size_t spilled_count = 0;
LiveRange* first_op = nullptr;
int gap_index = successor->first_instruction_index();
// Create an unconstrained operand for the same virtual register
// and insert a gap move from the fixed output to the operand.
- UnallocatedOperand* output_copy =
- UnallocatedOperand(UnallocatedOperand::ANY, output_vreg)
- .Copy(code_zone());
- AddGapMove(gap_index, Instruction::START, output, output_copy);
+ UnallocatedOperand output_copy(UnallocatedOperand::ANY, output_vreg);
+ AddGapMove(gap_index, Instruction::START, *output, output_copy);
}
}
auto range = LiveRangeFor(first_output->virtual_register());
bool assigned = false;
if (first_output->HasFixedPolicy()) {
- auto output_copy = first_output->CopyUnconstrained(code_zone());
- bool is_tagged = HasTaggedValue(first_output->virtual_register());
+ int output_vreg = first_output->virtual_register();
+ UnallocatedOperand output_copy(UnallocatedOperand::ANY, output_vreg);
+ bool is_tagged = HasTaggedValue(output_vreg);
AllocateFixed(first_output, instr_index, is_tagged);
// This value is produced on the stack, we never need to spill it.
range->SetSpillStartIndex(instr_index + 1);
assigned = true;
}
- AddGapMove(instr_index + 1, Instruction::START, first_output,
+ AddGapMove(instr_index + 1, Instruction::START, *first_output,
output_copy);
}
// Make sure we add a gap move for spilling (if we have not done
if (input->IsImmediate()) continue; // Ignore immediates.
auto cur_input = UnallocatedOperand::cast(input);
if (cur_input->HasFixedPolicy()) {
- auto input_copy = cur_input->CopyUnconstrained(code_zone());
- bool is_tagged = HasTaggedValue(cur_input->virtual_register());
+ int input_vreg = cur_input->virtual_register();
+ UnallocatedOperand input_copy(UnallocatedOperand::ANY, input_vreg);
+ bool is_tagged = HasTaggedValue(input_vreg);
AllocateFixed(cur_input, instr_index, is_tagged);
- AddGapMove(instr_index, Instruction::END, input_copy, cur_input);
+ AddGapMove(instr_index, Instruction::END, input_copy, *cur_input);
}
}
// Handle "output same as input" for second instruction.
UnallocatedOperand::cast(second->InputAt(0));
int output_vreg = second_output->virtual_register();
int input_vreg = cur_input->virtual_register();
- auto input_copy = cur_input->CopyUnconstrained(code_zone());
+ UnallocatedOperand input_copy(UnallocatedOperand::ANY, input_vreg);
cur_input->set_virtual_register(second_output->virtual_register());
- AddGapMove(instr_index, Instruction::END, input_copy, cur_input);
+ AddGapMove(instr_index, Instruction::END, input_copy, *cur_input);
if (HasTaggedValue(input_vreg) && !HasTaggedValue(output_vreg)) {
if (second->HasReferenceMap()) {
- second->reference_map()->RecordReference(*input_copy);
+ second->reference_map()->RecordReference(input_copy);
}
} else if (!HasTaggedValue(input_vreg) && HasTaggedValue(output_vreg)) {
// The input is assumed to immediately have a tagged representation,
} else {
curr_position = curr_position.Start();
}
- auto move_ops = move->move_operands();
- for (auto cur = move_ops->begin(); cur != move_ops->end(); ++cur) {
- auto from = cur->source();
- auto to = cur->destination();
- auto hint = to;
- if (to->IsUnallocated()) {
- int to_vreg = UnallocatedOperand::cast(to)->virtual_register();
+ for (auto cur : *move) {
+ auto& from = cur->source();
+ auto& to = cur->destination();
+ auto hint = &to;
+ if (to.IsUnallocated()) {
+ int to_vreg = UnallocatedOperand::cast(to).virtual_register();
auto to_range = LiveRangeFor(to_vreg);
if (to_range->is_phi()) {
if (to_range->is_non_loop_phi()) {
}
} else {
if (live->Contains(to_vreg)) {
- Define(curr_position, to, from);
+ Define(curr_position, &to, &from);
live->Remove(to_vreg);
} else {
cur->Eliminate();
}
}
} else {
- Define(curr_position, to, from);
+ Define(curr_position, &to, &from);
}
- Use(block_start_position, curr_position, from, hint);
- if (from->IsUnallocated()) {
- live->Add(UnallocatedOperand::cast(from)->virtual_register());
+ Use(block_start_position, curr_position, &from, hint);
+ if (from.IsUnallocated()) {
+ live->Add(UnallocatedOperand::cast(from).virtual_register());
}
}
}
void RegisterAllocator::ResolvePhis(const InstructionBlock* block) {
for (auto phi : block->phis()) {
int phi_vreg = phi->virtual_register();
- auto res =
- phi_map_.insert(std::make_pair(phi_vreg, PhiMapValue(phi, block)));
+ auto map_value = new (local_zone()) PhiMapValue(phi, block, local_zone());
+ auto res = phi_map_.insert(std::make_pair(phi_vreg, map_value));
DCHECK(res.second);
USE(res);
auto& output = phi->output();
for (size_t i = 0; i < phi->operands().size(); ++i) {
InstructionBlock* cur_block =
code()->InstructionBlockAt(block->predecessors()[i]);
- AddGapMove(cur_block->last_instruction_index(), Instruction::END,
- &phi->inputs()[i], &output);
+ UnallocatedOperand input(UnallocatedOperand::ANY, phi->operands()[i]);
+ auto move = AddGapMove(cur_block->last_instruction_index(),
+ Instruction::END, input, output);
+ map_value->incoming_moves.push_back(move);
DCHECK(!InstructionAt(cur_block->last_instruction_index())
->HasReferenceMap());
}
}
+void RegisterAllocator::AssignPhiInput(LiveRange* range,
+ const InstructionOperand& assignment) {
+ DCHECK(range->is_phi());
+ auto it = phi_map_.find(range->id());
+ DCHECK(it != phi_map_.end());
+ for (auto move : it->second->incoming_moves) {
+ move->set_destination(assignment);
+ }
+}
+
+
void RegisterAllocator::MeetRegisterConstraints() {
for (auto block : code()->instruction_blocks()) {
MeetRegisterConstraints(block);
void RegisterAllocator::ConnectRanges() {
- ZoneMap<std::pair<ParallelMove*, InstructionOperand*>, InstructionOperand*>
+ ZoneMap<std::pair<ParallelMove*, InstructionOperand>, InstructionOperand>
delayed_insertion_map(local_zone());
for (auto first_range : live_ranges()) {
if (first_range == nullptr || first_range->IsChild()) continue;
!CanEagerlyResolveControlFlow(GetInstructionBlock(pos))) {
continue;
}
- auto prev = first_range->GetAssignedOperand();
- auto cur = second_range->GetAssignedOperand();
- if (prev == cur) continue;
+ auto prev_operand = first_range->GetAssignedOperand();
+ auto cur_operand = second_range->GetAssignedOperand();
+ if (prev_operand == cur_operand) continue;
bool delay_insertion = false;
Instruction::GapPosition gap_pos;
int gap_index = pos.ToInstructionIndex();
}
auto move = code()->InstructionAt(gap_index)->GetOrCreateParallelMove(
gap_pos, code_zone());
- auto prev_operand = InstructionOperand::New(code_zone(), prev);
- auto cur_operand = InstructionOperand::New(code_zone(), cur);
if (!delay_insertion) {
- move->AddMove(prev_operand, cur_operand, code_zone());
+ move->AddMove(prev_operand, cur_operand);
} else {
delayed_insertion_map.insert(
std::make_pair(std::make_pair(move, prev_operand), cur_operand));
}
if (delayed_insertion_map.empty()) return;
// Insert all the moves which should occur after the stored move.
- ZoneVector<MoveOperands> to_insert(local_zone());
+ ZoneVector<MoveOperands*> to_insert(local_zone());
ZoneVector<MoveOperands*> to_eliminate(local_zone());
to_insert.reserve(4);
to_eliminate.reserve(4);
- auto move = delayed_insertion_map.begin()->first.first;
+ auto moves = delayed_insertion_map.begin()->first.first;
for (auto it = delayed_insertion_map.begin();; ++it) {
bool done = it == delayed_insertion_map.end();
- if (done || it->first.first != move) {
+ if (done || it->first.first != moves) {
// Commit the MoveOperands for current ParallelMove.
- for (auto move_ops : to_eliminate) {
- move_ops->Eliminate();
+ for (auto move : to_eliminate) {
+ move->Eliminate();
}
- for (auto move_ops : to_insert) {
- move->AddMove(move_ops.source(), move_ops.destination(), code_zone());
+ for (auto move : to_insert) {
+ moves->push_back(move);
}
if (done) break;
// Reset state.
to_eliminate.clear();
to_insert.clear();
- move = it->first.first;
+ moves = it->first.first;
}
// Gather all MoveOperands for a single ParallelMove.
- MoveOperands move_ops(it->first.second, it->second);
- auto eliminate = move->PrepareInsertAfter(&move_ops);
- to_insert.push_back(move_ops);
+ auto move = new (code_zone()) MoveOperands(it->first.second, it->second);
+ auto eliminate = moves->PrepareInsertAfter(move);
+ to_insert.push_back(move);
if (eliminate != nullptr) to_eliminate.push_back(eliminate);
}
}
auto pred_op = result.pred_cover_->GetAssignedOperand();
auto cur_op = result.cur_cover_->GetAssignedOperand();
if (pred_op == cur_op) continue;
- auto pred_ptr = InstructionOperand::New(code_zone(), pred_op);
- auto cur_ptr = InstructionOperand::New(code_zone(), cur_op);
- ResolveControlFlow(block, cur_ptr, pred_block, pred_ptr);
+ ResolveControlFlow(block, cur_op, pred_block, pred_op);
}
iterator.Advance();
}
void RegisterAllocator::ResolveControlFlow(const InstructionBlock* block,
- InstructionOperand* cur_op,
+ const InstructionOperand& cur_op,
const InstructionBlock* pred,
- InstructionOperand* pred_op) {
- DCHECK(!pred_op->Equals(cur_op));
+ const InstructionOperand& pred_op) {
+ DCHECK(pred_op != cur_op);
int gap_index;
Instruction::GapPosition position;
if (block->PredecessorCount() == 1) {
int phi_vreg = phi->virtual_register();
live->Remove(phi_vreg);
InstructionOperand* hint = nullptr;
- InstructionOperand* phi_operand = nullptr;
auto instr = GetLastInstruction(
code()->InstructionBlockAt(block->predecessors()[0]));
- auto move = instr->GetParallelMove(Instruction::END);
- for (int j = 0; j < move->move_operands()->length(); ++j) {
- auto to = move->move_operands()->at(j).destination();
- if (to->IsUnallocated() &&
- UnallocatedOperand::cast(to)->virtual_register() == phi_vreg) {
- hint = move->move_operands()->at(j).source();
- phi_operand = to;
+ for (auto move : *instr->GetParallelMove(Instruction::END)) {
+ auto& to = move->destination();
+ if (to.IsUnallocated() &&
+ UnallocatedOperand::cast(to).virtual_register() == phi_vreg) {
+ hint = &move->source();
break;
}
}
DCHECK(hint != nullptr);
auto block_start = LifetimePosition::GapFromInstructionIndex(
block->first_instruction_index());
- Define(block_start, phi_operand, hint);
+ Define(block_start, &phi->output(), hint);
}
// Now live is live_in for this block except not including values live
assigned_registers_->Add(reg);
}
range->set_assigned_register(reg);
+ auto assignment = range->GetAssignedOperand();
+ // TODO(dcarney): stop aliasing hint operands.
+ range->ConvertUsesToOperand(assignment, nullptr);
+ if (range->is_phi()) AssignPhiInput(range, assignment);
}
} // namespace compiler
InstructionOperand* hint);
void Use(LifetimePosition block_start, LifetimePosition position,
InstructionOperand* operand, InstructionOperand* hint);
- void AddGapMove(int index, Instruction::GapPosition position,
- InstructionOperand* from, InstructionOperand* to);
+ MoveOperands* AddGapMove(int index, Instruction::GapPosition position,
+ const InstructionOperand& from,
+ const InstructionOperand& to);
// Helper methods for updating the life range lists.
void AddToActive(LiveRange* range);
// Helper methods for resolving control flow.
void ResolveControlFlow(const InstructionBlock* block,
- InstructionOperand* cur_op,
+ const InstructionOperand& cur_op,
const InstructionBlock* pred,
- InstructionOperand* pred_op);
+ const InstructionOperand& pred_op);
void SetLiveRangeAssignedRegister(LiveRange* range, int reg);
const char* RegisterName(int allocation_index);
Instruction* InstructionAt(int index) { return code()->InstructionAt(index); }
+ void AssignPhiInput(LiveRange* range, const InstructionOperand& assignment);
Frame* frame() const { return frame_; }
const char* debug_name() const { return debug_name_; }
}
ZoneVector<SpillRange*>& spill_ranges() { return spill_ranges_; }
- struct PhiMapValue {
- PhiMapValue(PhiInstruction* phi, const InstructionBlock* block)
- : phi(phi), block(block) {}
+ class PhiMapValue : public ZoneObject {
+ public:
+ PhiMapValue(PhiInstruction* phi, const InstructionBlock* block, Zone* zone)
+ : phi(phi), block(block), incoming_moves(zone) {
+ incoming_moves.reserve(phi->operands().size());
+ }
PhiInstruction* const phi;
const InstructionBlock* const block;
+ ZoneVector<MoveOperands*> incoming_moves;
};
- typedef ZoneMap<int, PhiMapValue> PhiMap;
+ typedef ZoneMap<int, PhiMapValue*> PhiMap;
Zone* const local_zone_;
Frame* const frame_;
return zone_ != other.zone_;
}
+ Zone* zone() { return zone_; }
+
private:
zone_allocator();
Zone* zone_;
// that the actual values don't really matter, all we care about is equality.
class InterpreterState {
public:
- typedef std::vector<MoveOperands> Moves;
-
- void ExecuteInParallel(Moves moves) {
+ void ExecuteInParallel(const ParallelMove* moves) {
InterpreterState copy(*this);
- for (Moves::iterator it = moves.begin(); it != moves.end(); ++it) {
- if (!it->IsRedundant()) write(it->destination(), copy.read(it->source()));
+ for (const auto m : *moves) {
+ if (!m->IsRedundant()) write(m->destination(), copy.read(m->source()));
}
}
typedef Key Value;
typedef std::map<Key, Value> OperandMap;
- Value read(const InstructionOperand* op) const {
+ Value read(const InstructionOperand& op) const {
OperandMap::const_iterator it = values_.find(KeyFor(op));
return (it == values_.end()) ? ValueFor(op) : it->second;
}
- void write(const InstructionOperand* op, Value v) {
+ void write(const InstructionOperand& op, Value v) {
if (v == ValueFor(op)) {
values_.erase(KeyFor(op));
} else {
}
}
- static Key KeyFor(const InstructionOperand* op) {
- bool is_constant = op->IsConstant();
+ static Key KeyFor(const InstructionOperand& op) {
+ bool is_constant = op.IsConstant();
AllocatedOperand::AllocatedKind kind;
int index;
if (!is_constant) {
- index = AllocatedOperand::cast(op)->index();
- kind = AllocatedOperand::cast(op)->allocated_kind();
+ index = AllocatedOperand::cast(op).index();
+ kind = AllocatedOperand::cast(op).allocated_kind();
} else {
- index = ConstantOperand::cast(op)->virtual_register();
+ index = ConstantOperand::cast(op).virtual_register();
kind = AllocatedOperand::REGISTER;
}
Key key = {is_constant, kind, index};
return key;
}
- static Value ValueFor(const InstructionOperand* op) { return KeyFor(op); }
+ static Value ValueFor(const InstructionOperand& op) { return KeyFor(op); }
static InstructionOperand FromKey(Key key) {
if (key.is_constant) {
if (it != is.values_.begin()) os << " ";
InstructionOperand source = FromKey(it->first);
InstructionOperand destination = FromKey(it->second);
- MoveOperands mo(&source, &destination);
+ MoveOperands mo(source, destination);
PrintableMoveOperands pmo = {RegisterConfiguration::ArchDefault(), &mo};
os << pmo;
}
// An abstract interpreter for moves, swaps and parallel moves.
class MoveInterpreter : public GapResolver::Assembler {
public:
+ explicit MoveInterpreter(Zone* zone) : zone_(zone) {}
+
virtual void AssembleMove(InstructionOperand* source,
InstructionOperand* destination) OVERRIDE {
- InterpreterState::Moves moves;
- moves.push_back(MoveOperands(source, destination));
+ ParallelMove* moves = new (zone_) ParallelMove(zone_);
+ moves->AddMove(*source, *destination);
state_.ExecuteInParallel(moves);
}
virtual void AssembleSwap(InstructionOperand* source,
InstructionOperand* destination) OVERRIDE {
- InterpreterState::Moves moves;
- moves.push_back(MoveOperands(source, destination));
- moves.push_back(MoveOperands(destination, source));
+ ParallelMove* moves = new (zone_) ParallelMove(zone_);
+ moves->AddMove(*source, *destination);
+ moves->AddMove(*destination, *source);
state_.ExecuteInParallel(moves);
}
- void AssembleParallelMove(const ParallelMove* pm) {
- InterpreterState::Moves moves(pm->move_operands()->begin(),
- pm->move_operands()->end());
+ void AssembleParallelMove(const ParallelMove* moves) {
state_.ExecuteInParallel(moves);
}
InterpreterState state() const { return state_; }
private:
+ Zone* const zone_;
InterpreterState state_;
};
ParallelMove* Create(int size) {
ParallelMove* parallel_move = new (main_zone()) ParallelMove(main_zone());
- std::set<InstructionOperand*, InstructionOperandComparator> seen;
+ std::set<InstructionOperand> seen;
for (int i = 0; i < size; ++i) {
MoveOperands mo(CreateRandomOperand(true), CreateRandomOperand(false));
if (!mo.IsRedundant() && seen.find(mo.destination()) == seen.end()) {
- parallel_move->AddMove(mo.source(), mo.destination(), main_zone());
+ parallel_move->AddMove(mo.source(), mo.destination());
seen.insert(mo.destination());
}
}
}
private:
- struct InstructionOperandComparator {
- bool operator()(const InstructionOperand* x,
- const InstructionOperand* y) const {
- return *x < *y;
- }
- };
-
- InstructionOperand* CreateRandomOperand(bool is_source) {
+ InstructionOperand CreateRandomOperand(bool is_source) {
int index = rng_->NextInt(6);
// destination can't be Constant.
switch (rng_->NextInt(is_source ? 5 : 4)) {
case 0:
- return StackSlotOperand::New(main_zone(), index);
+ return StackSlotOperand(index);
case 1:
- return DoubleStackSlotOperand::New(main_zone(), index);
+ return DoubleStackSlotOperand(index);
case 2:
- return RegisterOperand::New(main_zone(), index);
+ return RegisterOperand(index);
case 3:
- return DoubleRegisterOperand::New(main_zone(), index);
+ return DoubleRegisterOperand(index);
case 4:
- return ConstantOperand::New(main_zone(), index);
+ return ConstantOperand(index);
}
UNREACHABLE();
- return NULL;
+ return InstructionOperand();
}
private:
ParallelMove* pm = pmc.Create(size);
// Note: The gap resolver modifies the ParallelMove, so interpret first.
- MoveInterpreter mi1;
+ MoveInterpreter mi1(pmc.main_zone());
mi1.AssembleParallelMove(pm);
- MoveInterpreter mi2;
+ MoveInterpreter mi2(pmc.main_zone());
GapResolver resolver(&mi2);
resolver.Resolve(pm);
return code->AddInstruction(instr);
}
- UnallocatedOperand* NewUnallocated(int vreg) {
- return UnallocatedOperand(UnallocatedOperand::ANY, vreg).Copy(zone());
+ UnallocatedOperand Unallocated(int vreg) {
+ return UnallocatedOperand(UnallocatedOperand::ANY, vreg);
}
RpoNumber RpoFor(BasicBlock* block) {
int index = 0;
for (auto instr : R.code->instructions()) {
- UnallocatedOperand* op1 = R.NewUnallocated(index++);
- UnallocatedOperand* op2 = R.NewUnallocated(index++);
+ UnallocatedOperand op1 = R.Unallocated(index++);
+ UnallocatedOperand op2 = R.Unallocated(index++);
instr->GetOrCreateParallelMove(TestInstr::START, R.zone())
- ->AddMove(op1, op2, R.zone());
+ ->AddMove(op1, op2);
ParallelMove* move = instr->GetParallelMove(TestInstr::START);
CHECK(move);
- const ZoneList<MoveOperands>* move_operands = move->move_operands();
- CHECK_EQ(1, move_operands->length());
- MoveOperands* cur = &move_operands->at(0);
- CHECK_EQ(op1, cur->source());
- CHECK_EQ(op2, cur->destination());
+ CHECK_EQ(1u, move->size());
+ MoveOperands* cur = move->at(0);
+ CHECK(op1 == cur->source());
+ CHECK(op2 == cur->destination());
}
}
CHECK(k == m->TempCount());
for (size_t z = 0; z < i; z++) {
- CHECK(outputs[z].Equals(m->OutputAt(z)));
+ CHECK(outputs[z] == *m->OutputAt(z));
}
for (size_t z = 0; z < j; z++) {
- CHECK(inputs[z].Equals(m->InputAt(z)));
+ CHECK(inputs[z] == *m->InputAt(z));
}
for (size_t z = 0; z < k; z++) {
- CHECK(temps[z].Equals(m->TempAt(z)));
+ CHECK(temps[z] == *m->TempAt(z));
}
}
}
Start();
sequence_.AddInstruction(Instruction::New(main_zone(), kArchNop));
int index = static_cast<int>(sequence_.instructions().size()) - 1;
- AddGapMove(index, RegisterOperand::New(main_zone(), 13),
- RegisterOperand::New(main_zone(), 13));
+ AddGapMove(index, RegisterOperand(13), RegisterOperand(13));
}
void NonRedundantMoves() {
Start();
sequence_.AddInstruction(Instruction::New(main_zone(), kArchNop));
int index = static_cast<int>(sequence_.instructions().size()) - 1;
- AddGapMove(index, ConstantOperand::New(main_zone(), 11),
- RegisterOperand::New(main_zone(), 11));
+ AddGapMove(index, ConstantOperand(11), RegisterOperand(11));
}
void Other() {
Start();
CHECK(current_ == NULL);
Start(true);
}
- void AddGapMove(int index, InstructionOperand* from, InstructionOperand* to) {
+ void AddGapMove(int index, const InstructionOperand& from,
+ const InstructionOperand& to) {
sequence_.InstructionAt(index)
->GetOrCreateParallelMove(Instruction::START, main_zone())
- ->AddMove(from, to, main_zone());
+ ->AddMove(from, to);
}
};
void AddMove(Instruction* instr, TestOperand from, TestOperand to,
Instruction::GapPosition pos = Instruction::START) {
auto parallel_move = instr->GetOrCreateParallelMove(pos, zone());
- parallel_move->AddMove(ConvertMoveArg(from), ConvertMoveArg(to), zone());
+ parallel_move->AddMove(ConvertMoveArg(from), ConvertMoveArg(to));
}
- int NonRedundantSize(ParallelMove* move) {
+ int NonRedundantSize(ParallelMove* moves) {
int i = 0;
- auto ops = move->move_operands();
- for (auto op = ops->begin(); op != ops->end(); ++op) {
- if (op->IsRedundant()) continue;
+ for (auto move : *moves) {
+ if (move->IsRedundant()) continue;
i++;
}
return i;
}
- bool Contains(ParallelMove* move, TestOperand from_op, TestOperand to_op) {
+ bool Contains(ParallelMove* moves, TestOperand from_op, TestOperand to_op) {
auto from = ConvertMoveArg(from_op);
auto to = ConvertMoveArg(to_op);
- auto ops = move->move_operands();
- for (auto op = ops->begin(); op != ops->end(); ++op) {
- if (op->IsRedundant()) continue;
- if (op->source()->Equals(from) && op->destination()->Equals(to)) {
+ for (auto move : *moves) {
+ if (move->IsRedundant()) continue;
+ if (move->source() == from && move->destination() == to) {
return true;
}
}
}
private:
- InstructionOperand* ConvertMoveArg(TestOperand op) {
+ InstructionOperand ConvertMoveArg(TestOperand op) {
CHECK_EQ(kNoValue, op.vreg_.value_);
CHECK_NE(kNoValue, op.value_);
switch (op.type_) {
case kConstant:
- return ConstantOperand::New(zone(), op.value_);
+ return ConstantOperand(op.value_);
case kFixedSlot:
- return StackSlotOperand::New(zone(), op.value_);
+ return StackSlotOperand(op.value_);
case kFixedRegister:
CHECK(0 <= op.value_ && op.value_ < num_general_registers());
- return RegisterOperand::New(zone(), op.value_);
+ return RegisterOperand(op.value_);
default:
break;
}
CHECK(false);
- return nullptr;
+ return InstructionOperand();
}
};