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