• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 "base/macros.h"
21 #include "nodes.h"
22 
23 namespace art HIDDEN {
24 
25 class CodeGenerator;
26 class InductionVarRange;
27 class LoopAnalysis;
28 
29 // Class to hold cached information on properties of the loop.
30 class LoopAnalysisInfo : public ValueObject {
31  public:
32   // No loop unrolling factor (just one copy of the loop-body).
33   static constexpr uint32_t kNoUnrollingFactor = 1;
34   // Used for unknown and non-constant trip counts (see InductionVarRange::HasKnownTripCount).
35   static constexpr int64_t kUnknownTripCount = -1;
36 
LoopAnalysisInfo(HLoopInformation * loop_info)37   explicit LoopAnalysisInfo(HLoopInformation* loop_info)
38       : trip_count_(kUnknownTripCount),
39         bb_num_(0),
40         instr_num_(0),
41         exits_num_(0),
42         invariant_exits_num_(0),
43         has_instructions_preventing_scalar_peeling_(false),
44         has_instructions_preventing_scalar_unrolling_(false),
45         has_long_type_instructions_(false),
46         loop_info_(loop_info) {}
47 
GetTripCount()48   int64_t GetTripCount() const { return trip_count_; }
GetNumberOfBasicBlocks()49   size_t GetNumberOfBasicBlocks() const { return bb_num_; }
GetNumberOfInstructions()50   size_t GetNumberOfInstructions() const { return instr_num_; }
GetNumberOfExits()51   size_t GetNumberOfExits() const { return exits_num_; }
GetNumberOfInvariantExits()52   size_t GetNumberOfInvariantExits() const { return invariant_exits_num_; }
53 
HasInstructionsPreventingScalarPeeling()54   bool HasInstructionsPreventingScalarPeeling() const {
55     return has_instructions_preventing_scalar_peeling_;
56   }
57 
HasInstructionsPreventingScalarUnrolling()58   bool HasInstructionsPreventingScalarUnrolling() const {
59     return has_instructions_preventing_scalar_unrolling_;
60   }
61 
HasInstructionsPreventingScalarOpts()62   bool HasInstructionsPreventingScalarOpts() const {
63     return HasInstructionsPreventingScalarPeeling() || HasInstructionsPreventingScalarUnrolling();
64   }
65 
HasLongTypeInstructions()66   bool HasLongTypeInstructions() const {
67     return has_long_type_instructions_;
68   }
69 
GetLoopInfo()70   HLoopInformation* GetLoopInfo() const { return loop_info_; }
71 
72  private:
73   // Trip count of the loop if known, kUnknownTripCount otherwise.
74   int64_t trip_count_;
75   // Number of basic blocks in the loop body.
76   size_t bb_num_;
77   // Number of instructions in the loop body.
78   size_t instr_num_;
79   // Number of loop's exits.
80   size_t exits_num_;
81   // Number of "if" loop exits (with HIf instruction) whose condition is loop-invariant.
82   size_t invariant_exits_num_;
83   // Whether the loop has instructions which make scalar loop peeling non-beneficial.
84   bool has_instructions_preventing_scalar_peeling_;
85   // Whether the loop has instructions which make scalar loop unrolling non-beneficial.
86   bool has_instructions_preventing_scalar_unrolling_;
87   // Whether the loop has instructions of primitive long type; unrolling these loop will
88   // likely introduce spill/fills on 32-bit targets.
89   bool has_long_type_instructions_;
90 
91   // Corresponding HLoopInformation.
92   HLoopInformation* loop_info_;
93 
94   friend class LoopAnalysis;
95 };
96 
97 // Placeholder class for methods and routines used to analyse loops, calculate loop properties
98 // and characteristics.
99 class LoopAnalysis : public ValueObject {
100  public:
101   // Calculates loops basic properties like body size, exits number, etc. and fills
102   // 'analysis_results' with this information.
103   static void CalculateLoopBasicProperties(HLoopInformation* loop_info,
104                                            LoopAnalysisInfo* analysis_results,
105                                            int64_t trip_count);
106 
107   // Returns the trip count of the loop if it is known and kUnknownTripCount otherwise.
108   static int64_t GetLoopTripCount(HLoopInformation* loop_info,
109                                   const InductionVarRange* induction_range);
110 
111  private:
112   // Returns whether an instruction makes scalar loop peeling/unrolling non-beneficial.
113   //
114   // If in the loop body we have a dex/runtime call then its contribution to the whole
115   // loop performance will probably prevail. So peeling/unrolling optimization will not bring
116   // any noticeable performance improvement. It will increase the code size.
MakesScalarPeelingUnrollingNonBeneficial(HInstruction * instruction)117   static bool MakesScalarPeelingUnrollingNonBeneficial(HInstruction* instruction) {
118     return (instruction->IsNewArray() ||
119         instruction->IsNewInstance() ||
120         instruction->IsUnresolvedInstanceFieldGet() ||
121         instruction->IsUnresolvedInstanceFieldSet() ||
122         instruction->IsUnresolvedStaticFieldGet() ||
123         instruction->IsUnresolvedStaticFieldSet() ||
124         // TODO: Support loops with intrinsified invokes.
125         instruction->IsInvoke());
126   }
127 };
128 
129 //
130 // Helper class which holds target-dependent methods and constants needed for loop optimizations.
131 //
132 // To support peeling/unrolling for a new architecture one needs to create new helper class,
133 // inherit it from this and add implementation for the following methods.
134 //
135 class ArchNoOptsLoopHelper : public ArenaObject<kArenaAllocOptimization> {
136  public:
ArchNoOptsLoopHelper(const CodeGenerator & codegen)137   explicit ArchNoOptsLoopHelper(const CodeGenerator& codegen) : codegen_(codegen) {}
~ArchNoOptsLoopHelper()138   virtual ~ArchNoOptsLoopHelper() {}
139 
140   // Creates an instance of specialised helper for the target or default helper if the target
141   // doesn't support loop peeling and unrolling.
142   static ArchNoOptsLoopHelper* Create(const CodeGenerator& codegen, ArenaAllocator* allocator);
143 
144   // Returns whether the loop is not beneficial for loop peeling/unrolling.
145   //
146   // For example, if the loop body has too many instructions then peeling/unrolling optimization
147   // will not bring any noticeable performance improvement however will increase the code size.
148   //
149   // Returns 'true' by default, should be overridden by particular target loop helper.
IsLoopNonBeneficialForScalarOpts(LoopAnalysisInfo * loop_analysis_info ATTRIBUTE_UNUSED)150   virtual bool IsLoopNonBeneficialForScalarOpts(
151       LoopAnalysisInfo* loop_analysis_info ATTRIBUTE_UNUSED) const { return true; }
152 
153   // Returns optimal scalar unrolling factor for the loop.
154   //
155   // Returns kNoUnrollingFactor by default, should be overridden by particular target loop helper.
GetScalarUnrollingFactor(const LoopAnalysisInfo * analysis_info ATTRIBUTE_UNUSED)156   virtual uint32_t GetScalarUnrollingFactor(
157       const LoopAnalysisInfo* analysis_info ATTRIBUTE_UNUSED) const {
158     return LoopAnalysisInfo::kNoUnrollingFactor;
159   }
160 
161   // Returns whether scalar loop peeling is enabled,
162   //
163   // Returns 'false' by default, should be overridden by particular target loop helper.
IsLoopPeelingEnabled()164   virtual bool IsLoopPeelingEnabled() const { return false; }
165 
166   // Returns whether it is beneficial to fully unroll the loop.
167   //
168   // Returns 'false' by default, should be overridden by particular target loop helper.
IsFullUnrollingBeneficial(LoopAnalysisInfo * analysis_info ATTRIBUTE_UNUSED)169   virtual bool IsFullUnrollingBeneficial(LoopAnalysisInfo* analysis_info ATTRIBUTE_UNUSED) const {
170     return false;
171   }
172 
173   // Returns optimal SIMD unrolling factor for the loop.
174   //
175   // Returns kNoUnrollingFactor by default, should be overridden by particular target loop helper.
GetSIMDUnrollingFactor(HBasicBlock * block ATTRIBUTE_UNUSED,int64_t trip_count ATTRIBUTE_UNUSED,uint32_t max_peel ATTRIBUTE_UNUSED,uint32_t vector_length ATTRIBUTE_UNUSED)176   virtual uint32_t GetSIMDUnrollingFactor(HBasicBlock* block ATTRIBUTE_UNUSED,
177                                           int64_t trip_count ATTRIBUTE_UNUSED,
178                                           uint32_t max_peel ATTRIBUTE_UNUSED,
179                                           uint32_t vector_length ATTRIBUTE_UNUSED) const {
180     return LoopAnalysisInfo::kNoUnrollingFactor;
181   }
182 
183  protected:
184   const CodeGenerator& codegen_;
185 };
186 
187 }  // namespace art
188 
189 #endif  // ART_COMPILER_OPTIMIZING_LOOP_ANALYSIS_H_
190