ART: Implement scalar loop peeling.
Implement scalar loop peeling for invariant exits elimination
(on arm64). If the loop exit condition is loop invariant then
loop peeling + GVN + DCE can eliminate this exit in the loop
body. Note: GVN and DCE aren't applied during loop optimizations.
Note: this functionality is turned off by default now.
Test: test-art-host, test-art-target, boot-to-gui.
Change-Id: I98d20054a431838b452dc06bd25c075eb445960c
diff --git a/compiler/optimizing/loop_analysis.h b/compiler/optimizing/loop_analysis.h
index bad406f..ece9858 100644
--- a/compiler/optimizing/loop_analysis.h
+++ b/compiler/optimizing/loop_analysis.h
@@ -33,6 +33,7 @@
: bb_num_(0),
instr_num_(0),
exits_num_(0),
+ has_instructions_preventing_scalar_peeling_(false),
has_instructions_preventing_scalar_unrolling_(false),
loop_info_(loop_info) {}
@@ -40,6 +41,10 @@
size_t GetNumberOfInstructions() const { return instr_num_; }
size_t GetNumberOfExits() const { return exits_num_; }
+ bool HasInstructionsPreventingScalarPeeling() const {
+ return has_instructions_preventing_scalar_peeling_;
+ }
+
bool HasInstructionsPreventingScalarUnrolling() const {
return has_instructions_preventing_scalar_unrolling_;
}
@@ -53,6 +58,8 @@
size_t instr_num_;
// Number of loop's exits.
size_t exits_num_;
+ // Whether the loop has instructions which make scalar loop peeling non-beneficial.
+ bool has_instructions_preventing_scalar_peeling_;
// Whether the loop has instructions which make scalar loop unrolling non-beneficial.
bool has_instructions_preventing_scalar_unrolling_;
@@ -71,22 +78,35 @@
static void CalculateLoopBasicProperties(HLoopInformation* loop_info,
LoopAnalysisInfo* analysis_results);
+ // Returns whether the loop has at least one loop invariant exit.
+ static bool HasLoopAtLeastOneInvariantExit(HLoopInformation* loop_info);
+
+ // Returns whether HIf's true or false successor is outside the specified loop.
+ //
+ // Prerequisite: HIf must be in the specified loop.
+ static bool IsLoopExit(HLoopInformation* loop_info, const HIf* hif) {
+ DCHECK(loop_info->Contains(*hif->GetBlock()));
+ HBasicBlock* true_succ = hif->IfTrueSuccessor();
+ HBasicBlock* false_succ = hif->IfFalseSuccessor();
+ return (!loop_info->Contains(*true_succ) || !loop_info->Contains(*false_succ));
+ }
+
private:
- // Returns whether an instruction makes scalar loop unrolling non-beneficial.
+ // Returns whether an instruction makes scalar loop peeling/unrolling non-beneficial.
//
// If in the loop body we have a dex/runtime call then its contribution to the whole
- // loop performance will probably prevail. So unrolling optimization will not bring
- // any noticeable performance improvement however will increase the code size.
- static bool MakesScalarUnrollingNonBeneficial(HInstruction* instruction) {
+ // loop performance will probably prevail. So peeling/unrolling optimization will not bring
+ // any noticeable performance improvement. It will increase the code size.
+ static bool MakesScalarPeelingUnrollingNonBeneficial(HInstruction* instruction) {
return (instruction->IsNewArray() ||
instruction->IsNewInstance() ||
instruction->IsUnresolvedInstanceFieldGet() ||
instruction->IsUnresolvedInstanceFieldSet() ||
instruction->IsUnresolvedStaticFieldGet() ||
instruction->IsUnresolvedStaticFieldSet() ||
- // TODO: Unroll loops with intrinsified invokes.
+ // TODO: Support loops with intrinsified invokes.
instruction->IsInvoke() ||
- // TODO: Unroll loops with ClinitChecks.
+ // TODO: Support loops with ClinitChecks.
instruction->IsClinitCheck());
}
};
@@ -105,14 +125,14 @@
// doesn't support loop peeling and unrolling.
static ArchDefaultLoopHelper* Create(InstructionSet isa, ArenaAllocator* allocator);
- // Returns whether the loop is too big for loop unrolling by checking its total number of
+ // Returns whether the loop is too big for loop peeling/unrolling by checking its total number of
// basic blocks and instructions.
//
- // If the loop body has too many instructions then unrolling optimization will not bring
+ // If the loop body has too many instructions then peeling/unrolling optimization will not bring
// any noticeable performance improvement however will increase the code size.
//
// Returns 'true' by default, should be overridden by particular target loop helper.
- virtual bool IsLoopTooBigForScalarUnrolling(
+ virtual bool IsLoopTooBigForScalarPeelingUnrolling(
LoopAnalysisInfo* loop_analysis_info ATTRIBUTE_UNUSED) const { return true; }
// Returns optimal scalar unrolling factor for the loop.
@@ -123,6 +143,11 @@
return kNoUnrollingFactor;
}
+ // Returns whether scalar loop peeling is enabled,
+ //
+ // Returns 'false' by default, should be overridden by particular target loop helper.
+ virtual bool IsLoopPeelingEnabled() const { return false; }
+
// Returns optimal SIMD unrolling factor for the loop.
//
// Returns kNoUnrollingFactor by default, should be overridden by particular target loop helper.