blob: bad406f10b848aadd150ee082cd3f6f5b10b5e42 [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),
36 has_instructions_preventing_scalar_unrolling_(false),
37 loop_info_(loop_info) {}
38
39 size_t GetNumberOfBasicBlocks() const { return bb_num_; }
40 size_t GetNumberOfInstructions() const { return instr_num_; }
41 size_t GetNumberOfExits() const { return exits_num_; }
42
43 bool HasInstructionsPreventingScalarUnrolling() const {
44 return has_instructions_preventing_scalar_unrolling_;
45 }
46
47 const HLoopInformation* GetLoopInfo() const { return loop_info_; }
48
49 private:
50 // Number of basic blocks in the loop body.
51 size_t bb_num_;
52 // Number of instructions in the loop body.
53 size_t instr_num_;
54 // Number of loop's exits.
55 size_t exits_num_;
56 // Whether the loop has instructions which make scalar loop unrolling non-beneficial.
57 bool has_instructions_preventing_scalar_unrolling_;
58
59 // Corresponding HLoopInformation.
60 const HLoopInformation* loop_info_;
61
62 friend class LoopAnalysis;
63};
64
65// Placeholder class for methods and routines used to analyse loops, calculate loop properties
66// and characteristics.
67class LoopAnalysis : public ValueObject {
68 public:
69 // Calculates loops basic properties like body size, exits number, etc. and fills
70 // 'analysis_results' with this information.
71 static void CalculateLoopBasicProperties(HLoopInformation* loop_info,
72 LoopAnalysisInfo* analysis_results);
73
74 private:
75 // Returns whether an instruction makes scalar loop unrolling non-beneficial.
76 //
77 // If in the loop body we have a dex/runtime call then its contribution to the whole
78 // loop performance will probably prevail. So unrolling optimization will not bring
79 // any noticeable performance improvement however will increase the code size.
80 static bool MakesScalarUnrollingNonBeneficial(HInstruction* instruction) {
81 return (instruction->IsNewArray() ||
82 instruction->IsNewInstance() ||
83 instruction->IsUnresolvedInstanceFieldGet() ||
84 instruction->IsUnresolvedInstanceFieldSet() ||
85 instruction->IsUnresolvedStaticFieldGet() ||
86 instruction->IsUnresolvedStaticFieldSet() ||
87 // TODO: Unroll loops with intrinsified invokes.
88 instruction->IsInvoke() ||
89 // TODO: Unroll loops with ClinitChecks.
90 instruction->IsClinitCheck());
91 }
92};
93
94//
95// Helper class which holds target-dependent methods and constants needed for loop optimizations.
96//
97// To support peeling/unrolling for a new architecture one needs to create new helper class,
98// inherit it from this and add implementation for the following methods.
99//
100class ArchDefaultLoopHelper : public ArenaObject<kArenaAllocOptimization> {
101 public:
102 virtual ~ArchDefaultLoopHelper() {}
103
104 // Creates an instance of specialised helper for the target or default helper if the target
105 // doesn't support loop peeling and unrolling.
106 static ArchDefaultLoopHelper* Create(InstructionSet isa, ArenaAllocator* allocator);
107
108 // Returns whether the loop is too big for loop unrolling by checking its total number of
109 // basic blocks and instructions.
110 //
111 // If the loop body has too many instructions then unrolling optimization will not bring
112 // any noticeable performance improvement however will increase the code size.
113 //
114 // Returns 'true' by default, should be overridden by particular target loop helper.
115 virtual bool IsLoopTooBigForScalarUnrolling(
116 LoopAnalysisInfo* loop_analysis_info ATTRIBUTE_UNUSED) const { return true; }
117
118 // Returns optimal scalar unrolling factor for the loop.
119 //
120 // Returns kNoUnrollingFactor by default, should be overridden by particular target loop helper.
121 virtual uint32_t GetScalarUnrollingFactor(HLoopInformation* loop_info ATTRIBUTE_UNUSED,
122 uint64_t trip_count ATTRIBUTE_UNUSED) const {
123 return kNoUnrollingFactor;
124 }
125
126 // Returns optimal SIMD unrolling factor for the loop.
127 //
128 // Returns kNoUnrollingFactor by default, should be overridden by particular target loop helper.
129 virtual uint32_t GetSIMDUnrollingFactor(HBasicBlock* block ATTRIBUTE_UNUSED,
130 int64_t trip_count ATTRIBUTE_UNUSED,
131 uint32_t max_peel ATTRIBUTE_UNUSED,
132 uint32_t vector_length ATTRIBUTE_UNUSED) const {
133 return kNoUnrollingFactor;
134 }
135};
136
137} // namespace art
138
139#endif // ART_COMPILER_OPTIMIZING_LOOP_ANALYSIS_H_