summaryrefslogtreecommitdiff
path: root/compiler/optimizing/scheduler.cc
diff options
context:
space:
mode:
author Evgeny Astigeevich <evgeny.astigeevich@linaro.org> 2019-04-03 10:46:13 +0100
committer Treehugger Robot <treehugger-gerrit@google.com> 2019-10-29 15:40:27 +0000
commit45217376b527cd17d758152c54960e6786288e31 (patch)
treecc2ae731f7ebfe61af74fa8150025064a0245a8a /compiler/optimizing/scheduler.cc
parent8b236fac816beb18e4919e2c4260da843257a4e3 (diff)
Fix intersecting live ranges created by instruction scheduler
When scheduling code like the following: LOOP: v2=phi(v0, v1) use(v2) v1=... goto LOOP the instruction scheduler can move 'v1=...' before 'use(v2)'. This causes live ranges of v1 and v2 to intersect and results to a MOV instruction to be created. The CL fixes this. Improvements, Pixel3: Little CPU, arm64 micro/GCCLoops Example12 14.1% Example10b 11.0% Example23 8.1% Example24 6.6% Example10a 5.0% FFT workload 4.7% Compress workload 1.2% Little CPU, arm32 micro/GCCLoops Example23 7.5% Example24 4.3% MonteCarlo workload 1.35% Big CPU, arm32 and arm64 No significant improvements No significant regressions (> 5%) are found. Test: test.py --host --optimizing --jit --gtest Test: test.py --target --optimizing --jit Test: run-gtests.sh Change-Id: I1e4282af18f2d51fde5325a0c00a57e8bbc4fbed
Diffstat (limited to 'compiler/optimizing/scheduler.cc')
-rw-r--r--compiler/optimizing/scheduler.cc38
1 files changed, 37 insertions, 1 deletions
diff --git a/compiler/optimizing/scheduler.cc b/compiler/optimizing/scheduler.cc
index e5ff8a886a..f722cf91a7 100644
--- a/compiler/optimizing/scheduler.cc
+++ b/compiler/optimizing/scheduler.cc
@@ -282,6 +282,36 @@ static bool IsBetterCandidateWithMoreLikelyDependencies(HInstruction* new_candid
}
}
+void SchedulingGraph::AddCrossIterationDependencies(SchedulingNode* node) {
+ for (HInstruction* instruction : node->GetInstruction()->GetInputs()) {
+ // Having a phi-function from a loop header as an input means the current node of the
+ // scheduling graph has a cross-iteration dependency because such phi-functions bring values
+ // from the previous iteration to the current iteration.
+ if (!instruction->IsLoopHeaderPhi()) {
+ continue;
+ }
+ for (HInstruction* phi_input : instruction->GetInputs()) {
+ // As a scheduling graph of the current basic block is built by
+ // processing instructions bottom-up, nullptr returned by GetNode means
+ // an instruction defining a value for the phi is either before the
+ // instruction represented by node or it is in a different basic block.
+ SchedulingNode* def_node = GetNode(phi_input);
+
+ // We don't create a dependency if there are uses besides the use in phi.
+ // In such cases a register to hold phi_input is usually allocated and
+ // a MOV instruction is generated. In cases with multiple uses and no MOV
+ // instruction, reordering creating a MOV instruction can improve
+ // performance more than an attempt to avoid a MOV instruction.
+ if (def_node != nullptr && def_node != node && phi_input->GetUses().HasExactlyOneElement()) {
+ // We have an implicit data dependency between node and def_node.
+ // AddAddDataDependency cannot be used because it is for explicit data dependencies.
+ // So AddOtherDependency is used.
+ AddOtherDependency(def_node, node);
+ }
+ }
+ }
+}
+
void SchedulingGraph::AddDependencies(SchedulingNode* instruction_node,
bool is_scheduling_barrier) {
HInstruction* instruction = instruction_node->GetInstruction();
@@ -340,7 +370,11 @@ void SchedulingGraph::AddDependencies(SchedulingNode* instruction_node,
if (other_node->IsSchedulingBarrier()) {
// We have reached a scheduling barrier so we can stop further
// processing.
- DCHECK(other_node->HasOtherDependency(instruction_node));
+ //
+ // As a "other" dependency is not set up if a data dependency exists, we need to check that
+ // one of them must exist.
+ DCHECK(other_node->HasOtherDependency(instruction_node)
+ || other_node->HasDataDependency(instruction_node));
break;
}
if (side_effect_dependency_analysis_.HasSideEffectDependency(other, instruction)) {
@@ -372,6 +406,8 @@ void SchedulingGraph::AddDependencies(SchedulingNode* instruction_node,
AddOtherDependency(GetNode(use.GetUser()->GetHolder()), instruction_node);
}
}
+
+ AddCrossIterationDependencies(instruction_node);
}
static const std::string InstructionTypeId(const HInstruction* instruction) {