Commit 6a08157e authored by jarin's avatar jarin Committed by Commit bot

[turbofan] Use a vector instead of a set in move optimizer.

The set of operands are really small, so STL set performs really poorly.

In Octane/TypeScript, I see move optimization going from >300ms to <100ms.

Review-Url: https://codereview.chromium.org/2481853002
Cr-Commit-Position: refs/heads/master@{#40835}
parent 4d6ff7df
...@@ -28,16 +28,27 @@ typedef ZoneMap<MoveKey, unsigned, MoveKeyCompare> MoveMap; ...@@ -28,16 +28,27 @@ typedef ZoneMap<MoveKey, unsigned, MoveKeyCompare> MoveMap;
class OperandSet { class OperandSet {
public: public:
explicit OperandSet(Zone* zone) : set_(zone), fp_reps_(0) {} explicit OperandSet(ZoneVector<InstructionOperand>* buffer)
: set_(buffer), fp_reps_(0) {
buffer->clear();
}
void InsertOp(const InstructionOperand& op) { void InsertOp(const InstructionOperand& op) {
set_.insert(op); set_->push_back(op);
if (!kSimpleFPAliasing && op.IsFPRegister()) if (!kSimpleFPAliasing && op.IsFPRegister())
fp_reps_ |= RepBit(LocationOperand::cast(op).representation()); fp_reps_ |= RepBit(LocationOperand::cast(op).representation());
} }
bool Contains(const InstructionOperand& op) const {
for (const InstructionOperand& elem : *set_) {
if (elem.EqualsCanonicalized(op)) return true;
}
return false;
}
bool ContainsOpOrAlias(const InstructionOperand& op) const { bool ContainsOpOrAlias(const InstructionOperand& op) const {
if (set_.find(op) != set_.end()) return true; if (Contains(op)) return true;
if (!kSimpleFPAliasing && op.IsFPRegister()) { if (!kSimpleFPAliasing && op.IsFPRegister()) {
// Platforms where FP registers have complex aliasing need extra checks. // Platforms where FP registers have complex aliasing need extra checks.
...@@ -71,16 +82,18 @@ class OperandSet { ...@@ -71,16 +82,18 @@ class OperandSet {
config->GetAliases(rep, loc.register_code(), other_rep1, &base); config->GetAliases(rep, loc.register_code(), other_rep1, &base);
DCHECK(aliases > 0 || (aliases == 0 && base == -1)); DCHECK(aliases > 0 || (aliases == 0 && base == -1));
while (aliases--) { while (aliases--) {
if (set_.find(AllocatedOperand(LocationOperand::REGISTER, other_rep1, if (Contains(AllocatedOperand(LocationOperand::REGISTER, other_rep1,
base + aliases)) != set_.end()) base + aliases))) {
return true; return true;
}
} }
aliases = config->GetAliases(rep, loc.register_code(), other_rep2, &base); aliases = config->GetAliases(rep, loc.register_code(), other_rep2, &base);
DCHECK(aliases > 0 || (aliases == 0 && base == -1)); DCHECK(aliases > 0 || (aliases == 0 && base == -1));
while (aliases--) { while (aliases--) {
if (set_.find(AllocatedOperand(LocationOperand::REGISTER, other_rep2, if (Contains(AllocatedOperand(LocationOperand::REGISTER, other_rep2,
base + aliases)) != set_.end()) base + aliases))) {
return true; return true;
}
} }
} }
return false; return false;
...@@ -95,7 +108,7 @@ class OperandSet { ...@@ -95,7 +108,7 @@ class OperandSet {
return reps && !base::bits::IsPowerOfTwo32(reps); return reps && !base::bits::IsPowerOfTwo32(reps);
} }
ZoneSet<InstructionOperand, CompareOperandModuloType> set_; ZoneVector<InstructionOperand>* set_;
int fp_reps_; int fp_reps_;
}; };
...@@ -115,12 +128,12 @@ int FindFirstNonEmptySlot(const Instruction* instr) { ...@@ -115,12 +128,12 @@ int FindFirstNonEmptySlot(const Instruction* instr) {
} // namespace } // namespace
MoveOptimizer::MoveOptimizer(Zone* local_zone, InstructionSequence* code) MoveOptimizer::MoveOptimizer(Zone* local_zone, InstructionSequence* code)
: local_zone_(local_zone), : local_zone_(local_zone),
code_(code), code_(code),
local_vector_(local_zone) {} local_vector_(local_zone),
operand_buffer1(local_zone),
operand_buffer2(local_zone) {}
void MoveOptimizer::Run() { void MoveOptimizer::Run() {
for (Instruction* instruction : code()->instructions()) { for (Instruction* instruction : code()->instructions()) {
...@@ -160,8 +173,8 @@ void MoveOptimizer::RemoveClobberedDestinations(Instruction* instruction) { ...@@ -160,8 +173,8 @@ void MoveOptimizer::RemoveClobberedDestinations(Instruction* instruction) {
DCHECK(instruction->parallel_moves()[1] == nullptr || DCHECK(instruction->parallel_moves()[1] == nullptr ||
instruction->parallel_moves()[1]->empty()); instruction->parallel_moves()[1]->empty());
OperandSet outputs(local_zone()); OperandSet outputs(&operand_buffer1);
OperandSet inputs(local_zone()); OperandSet inputs(&operand_buffer2);
// Outputs and temps are treated together as potentially clobbering a // Outputs and temps are treated together as potentially clobbering a
// destination operand. // destination operand.
...@@ -202,8 +215,8 @@ void MoveOptimizer::MigrateMoves(Instruction* to, Instruction* from) { ...@@ -202,8 +215,8 @@ void MoveOptimizer::MigrateMoves(Instruction* to, Instruction* from) {
ParallelMove* from_moves = from->parallel_moves()[0]; ParallelMove* from_moves = from->parallel_moves()[0];
if (from_moves == nullptr || from_moves->empty()) return; if (from_moves == nullptr || from_moves->empty()) return;
OperandSet dst_cant_be(local_zone()); OperandSet dst_cant_be(&operand_buffer1);
OperandSet src_cant_be(local_zone()); OperandSet src_cant_be(&operand_buffer2);
// If an operand is an input to the instruction, we cannot move assignments // If an operand is an input to the instruction, we cannot move assignments
// where it appears on the LHS. // where it appears on the LHS.
...@@ -417,7 +430,7 @@ void MoveOptimizer::OptimizeMerge(InstructionBlock* block) { ...@@ -417,7 +430,7 @@ void MoveOptimizer::OptimizeMerge(InstructionBlock* block) {
if (correct_counts != move_map.size()) { if (correct_counts != move_map.size()) {
// Moves that are unique to each predecessor won't be pushed to the common // Moves that are unique to each predecessor won't be pushed to the common
// successor. // successor.
OperandSet conflicting_srcs(local_zone()); OperandSet conflicting_srcs(&operand_buffer1);
for (auto iter = move_map.begin(), end = move_map.end(); iter != end;) { for (auto iter = move_map.begin(), end = move_map.end(); iter != end;) {
auto current = iter; auto current = iter;
++iter; ++iter;
......
...@@ -53,6 +53,11 @@ class V8_EXPORT_PRIVATE MoveOptimizer final { ...@@ -53,6 +53,11 @@ class V8_EXPORT_PRIVATE MoveOptimizer final {
InstructionSequence* const code_; InstructionSequence* const code_;
MoveOpVector local_vector_; MoveOpVector local_vector_;
// Reusable buffers for storing operand sets. We need at most two sets
// at any given time, so we create two buffers.
ZoneVector<InstructionOperand> operand_buffer1;
ZoneVector<InstructionOperand> operand_buffer2;
DISALLOW_COPY_AND_ASSIGN(MoveOptimizer); DISALLOW_COPY_AND_ASSIGN(MoveOptimizer);
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment