blob: ece98581367cc90dc96555725dbff3d64576e87b [file] [log] [blame]
Artem Serov121f2032017-10-23 19:19:06 +01001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ART_COMPILER_OPTIMIZING_LOOP_ANALYSIS_H_
18#define ART_COMPILER_OPTIMIZING_LOOP_ANALYSIS_H_
19
20#include "nodes.h"
21
22namespace art {
23
24class LoopAnalysis;
25
26// No loop unrolling factor (just one copy of the loop-body).
27static constexpr uint32_t kNoUnrollingFactor = 1;
28
29// Class to hold cached information on properties of the loop.
30class LoopAnalysisInfo : public ValueObject {
31 public:
32 explicit LoopAnalysisInfo(HLoopInformation* loop_info)
33 : bb_num_(0),
34 instr_num_(0),
35 exits_num_(0),
Artem Serov72411e62017-10-19 16:18:07 +010036 has_instructions_preventing_scalar_peeling_(false),
Artem Serov121f2032017-10-23 19:19:06 +010037 has_instructions_preventing_scalar_unrolling_(false),
38 loop_info_(loop_info) {}
39
40 size_t GetNumberOfBasicBlocks() const { return bb_num_; }
41 size_t GetNumberOfInstructions() const { return instr_num_; }
42 size_t GetNumberOfExits() const { return exits_num_; }
43
Artem Serov72411e62017-10-19 16:18:07 +010044 bool HasInstructionsPreventingScalarPeeling() const {
45 return has_instructions_preventing_scalar_peeling_;
46 }
47
Artem Serov121f2032017-10-23 19:19:06 +010048 bool HasInstructionsPreventingScalarUnrolling() const {
49 return has_instructions_preventing_scalar_unrolling_;
50 }
51
52 const HLoopInformation* GetLoopInfo() const { return loop_info_; }
53
54 private:
55 // Number of basic blocks in the loop body.
56 size_t bb_num_;
57 // Number of instructions in the loop body.
58 size_t instr_num_;
59 // Number of loop's exits.
60 size_t exits_num_;
Artem Serov72411e62017-10-19 16:18:07 +010061 // Whether the loop has instructions which make scalar loop peeling non-beneficial.
62 bool has_instructions_preventing_scalar_peeling_;
Artem Serov121f2032017-10-23 19:19:06 +010063 // Whether the loop has instructions which make scalar loop unrolling non-beneficial.
64 bool has_instructions_preventing_scalar_unrolling_;
65
66 // Corresponding HLoopInformation.
67 const HLoopInformation* loop_info_;
68
69 friend class LoopAnalysis;
70};
71
72// Placeholder class for methods and routines used to analyse loops, calculate loop properties
73// and characteristics.
74class LoopAnalysis : public ValueObject {
75 public:
76 // Calculates loops basic properties like body size, exits number, etc. and fills
77 // 'analysis_results' with this information.
78 static void CalculateLoopBasicProperties(HLoopInformation* loop_info,
79 LoopAnalysisInfo* analysis_results);
80
Artem Serov72411e62017-10-19 16:18:07 +010081 // Returns whether the loop has at least one loop invariant exit.
82 static bool HasLoopAtLeastOneInvariantExit(HLoopInformation* loop_info);
83
84 // Returns whether HIf's true or false successor is outside the specified loop.
85 //
86 // Prerequisite: HIf must be in the specified loop.
87 static bool IsLoopExit(HLoopInformation* loop_info, const HIf* hif) {
88 DCHECK(loop_info->Contains(*hif->GetBlock()));
89 HBasicBlock* true_succ = hif->IfTrueSuccessor();
90 HBasicBlock* false_succ = hif->IfFalseSuccessor();
91 return (!loop_info->Contains(*true_succ) || !loop_info->Contains(*false_succ));
92 }
93
Artem Serov121f2032017-10-23 19:19:06 +010094 private:
Artem Serov72411e62017-10-19 16:18:07 +010095 // Returns whether an instruction makes scalar loop peeling/unrolling non-beneficial.
Artem Serov121f2032017-10-23 19:19:06 +010096 //
97 // If in the loop body we have a dex/runtime call then its contribution to the whole
Artem Serov72411e62017-10-19 16:18:07 +010098 // loop performance will probably prevail. So peeling/unrolling optimization will not bring
99 // any noticeable performance improvement. It will increase the code size.
100 static bool MakesScalarPeelingUnrollingNonBeneficial(HInstruction* instruction) {
Artem Serov121f2032017-10-23 19:19:06 +0100101 return (instruction->IsNewArray() ||
102 instruction->IsNewInstance() ||
103 instruction->IsUnresolvedInstanceFieldGet() ||
104 instruction->IsUnresolvedInstanceFieldSet() ||
105 instruction->IsUnresolvedStaticFieldGet() ||
106 instruction->IsUnresolvedStaticFieldSet() ||
Artem Serov72411e62017-10-19 16:18:07 +0100107 // TODO: Support loops with intrinsified invokes.
Artem Serov121f2032017-10-23 19:19:06 +0100108 instruction->IsInvoke() ||
Artem Serov72411e62017-10-19 16:18:07 +0100109 // TODO: Support loops with ClinitChecks.
Artem Serov121f2032017-10-23 19:19:06 +0100110 instruction->IsClinitCheck());
111 }
112};
113
114//
115// Helper class which holds target-dependent methods and constants needed for loop optimizations.
116//
117// To support peeling/unrolling for a new architecture one needs to create new helper class,
118// inherit it from this and add implementation for the following methods.
119//
120class ArchDefaultLoopHelper : public ArenaObject<kArenaAllocOptimization> {
121 public:
122 virtual ~ArchDefaultLoopHelper() {}
123
124 // Creates an instance of specialised helper for the target or default helper if the target
125 // doesn't support loop peeling and unrolling.
126 static ArchDefaultLoopHelper* Create(InstructionSet isa, ArenaAllocator* allocator);
127
Artem Serov72411e62017-10-19 16:18:07 +0100128 // Returns whether the loop is too big for loop peeling/unrolling by checking its total number of
Artem Serov121f2032017-10-23 19:19:06 +0100129 // basic blocks and instructions.
130 //
Artem Serov72411e62017-10-19 16:18:07 +0100131 // If the loop body has too many instructions then peeling/unrolling optimization will not bring
Artem Serov121f2032017-10-23 19:19:06 +0100132 // any noticeable performance improvement however will increase the code size.
133 //
134 // Returns 'true' by default, should be overridden by particular target loop helper.
Artem Serov72411e62017-10-19 16:18:07 +0100135 virtual bool IsLoopTooBigForScalarPeelingUnrolling(
Artem Serov121f2032017-10-23 19:19:06 +0100136 LoopAnalysisInfo* loop_analysis_info ATTRIBUTE_UNUSED) const { return true; }
137
138 // Returns optimal scalar unrolling factor for the loop.
139 //
140 // Returns kNoUnrollingFactor by default, should be overridden by particular target loop helper.
141 virtual uint32_t GetScalarUnrollingFactor(HLoopInformation* loop_info ATTRIBUTE_UNUSED,
142 uint64_t trip_count ATTRIBUTE_UNUSED) const {
143 return kNoUnrollingFactor;
144 }
145
Artem Serov72411e62017-10-19 16:18:07 +0100146 // Returns whether scalar loop peeling is enabled,
147 //
148 // Returns 'false' by default, should be overridden by particular target loop helper.
149 virtual bool IsLoopPeelingEnabled() const { return false; }
150
Artem Serov121f2032017-10-23 19:19:06 +0100151 // Returns optimal SIMD unrolling factor for the loop.
152 //
153 // Returns kNoUnrollingFactor by default, should be overridden by particular target loop helper.
154 virtual uint32_t GetSIMDUnrollingFactor(HBasicBlock* block ATTRIBUTE_UNUSED,
155 int64_t trip_count ATTRIBUTE_UNUSED,
156 uint32_t max_peel ATTRIBUTE_UNUSED,
157 uint32_t vector_length ATTRIBUTE_UNUSED) const {
158 return kNoUnrollingFactor;
159 }
160};
161
162} // namespace art
163
164#endif // ART_COMPILER_OPTIMIZING_LOOP_ANALYSIS_H_