[turbofan] Use a map to cache values definition in instruction scheduler.

R=jarin@chromium.org

Review-Url: https://codereview.chromium.org/2193063003
Cr-Commit-Position: refs/heads/master@{#38632}
This commit is contained in:
baptiste.afsa 2016-08-15 02:15:17 -07:00 committed by Commit bot
parent f8776c5d39
commit 75a204583f
2 changed files with 28 additions and 36 deletions

View File

@ -83,8 +83,8 @@ InstructionScheduler::InstructionScheduler(Zone* zone,
last_side_effect_instr_(nullptr),
pending_loads_(zone),
last_live_in_reg_marker_(nullptr),
last_deopt_(nullptr) {
}
last_deopt_(nullptr),
operands_map_(zone) {}
void InstructionScheduler::StartBlock(RpoNumber rpo) {
@ -93,6 +93,7 @@ void InstructionScheduler::StartBlock(RpoNumber rpo) {
DCHECK(pending_loads_.empty());
DCHECK(last_live_in_reg_marker_ == nullptr);
DCHECK(last_deopt_ == nullptr);
DCHECK(operands_map_.empty());
sequence()->StartBlock(rpo);
}
@ -109,6 +110,7 @@ void InstructionScheduler::EndBlock(RpoNumber rpo) {
pending_loads_.clear();
last_live_in_reg_marker_ = nullptr;
last_deopt_ = nullptr;
operands_map_.clear();
}
@ -165,9 +167,26 @@ void InstructionScheduler::AddInstruction(Instruction* instr) {
}
// Look for operand dependencies.
for (ScheduleGraphNode* node : graph_) {
if (HasOperandDependency(node->instruction(), instr)) {
node->AddSuccessor(new_node);
for (size_t i = 0; i < instr->InputCount(); ++i) {
const InstructionOperand* input = instr->InputAt(i);
if (input->IsUnallocated()) {
int32_t vreg = UnallocatedOperand::cast(input)->virtual_register();
auto it = operands_map_.find(vreg);
if (it != operands_map_.end()) {
it->second->AddSuccessor(new_node);
}
}
}
// Record the virtual registers defined by this instruction.
for (size_t i = 0; i < instr->OutputCount(); ++i) {
const InstructionOperand* output = instr->OutputAt(i);
if (output->IsUnallocated()) {
operands_map_[UnallocatedOperand::cast(output)->virtual_register()] =
new_node;
} else if (output->IsConstant()) {
operands_map_[ConstantOperand::cast(output)->virtual_register()] =
new_node;
}
}
}
@ -317,33 +336,6 @@ int InstructionScheduler::GetInstructionFlags(const Instruction* instr) const {
}
bool InstructionScheduler::HasOperandDependency(
const Instruction* instr1, const Instruction* instr2) const {
for (size_t i = 0; i < instr1->OutputCount(); ++i) {
for (size_t j = 0; j < instr2->InputCount(); ++j) {
const InstructionOperand* output = instr1->OutputAt(i);
const InstructionOperand* input = instr2->InputAt(j);
if (output->IsUnallocated() && input->IsUnallocated() &&
(UnallocatedOperand::cast(output)->virtual_register() ==
UnallocatedOperand::cast(input)->virtual_register())) {
return true;
}
if (output->IsConstant() && input->IsUnallocated() &&
(ConstantOperand::cast(output)->virtual_register() ==
UnallocatedOperand::cast(input)->virtual_register())) {
return true;
}
}
}
// TODO(bafsa): Do we need to look for anti-dependencies/output-dependencies?
return false;
}
bool InstructionScheduler::IsBlockTerminator(const Instruction* instr) const {
return ((GetInstructionFlags(instr) & kIsBlockTerminator) ||
(instr->flags_mode() == kFlags_branch));

View File

@ -156,10 +156,6 @@ class InstructionScheduler final : public ZoneObject {
int GetInstructionFlags(const Instruction* instr) const;
int GetTargetInstructionFlags(const Instruction* instr) const;
// Return true if instr2 uses any value defined by instr1.
bool HasOperandDependency(const Instruction* instr1,
const Instruction* instr2) const;
// Return true if the instruction is a basic block terminator.
bool IsBlockTerminator(const Instruction* instr) const;
@ -214,6 +210,10 @@ class InstructionScheduler final : public ZoneObject {
// Last deoptimization instruction encountered while building the graph.
ScheduleGraphNode* last_deopt_;
// Keep track of definition points for virtual registers. This is used to
// record operand dependencies in the scheduling graph.
ZoneMap<int32_t, ScheduleGraphNode*> operands_map_;
};
} // namespace compiler