blob: 023dbdb584c326e39f5129dae634bee69efe3300 [file] [log] [blame]
Vladimir Marko95a05972014-05-30 10:01:32 +01001/*
2 * Copyright (C) 2014 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_DEX_GLOBAL_VALUE_NUMBERING_H_
18#define ART_COMPILER_DEX_GLOBAL_VALUE_NUMBERING_H_
19
Andreas Gampe0b9203e2015-01-22 20:39:27 -080020#include "base/logging.h"
Vladimir Marko95a05972014-05-30 10:01:32 +010021#include "base/macros.h"
Andreas Gampe0b9203e2015-01-22 20:39:27 -080022#include "mir_graph.h"
23#include "compiler_ir.h"
24#include "dex_flags.h"
Ian Rogers6a3c1fc2014-10-31 00:33:20 -070025#include "utils/arena_object.h"
Vladimir Marko95a05972014-05-30 10:01:32 +010026
27namespace art {
28
29class LocalValueNumbering;
30class MirFieldInfo;
31
Ian Rogers6a3c1fc2014-10-31 00:33:20 -070032class GlobalValueNumbering : public DeletableArenaObject<kArenaAllocMisc> {
Vladimir Marko95a05972014-05-30 10:01:32 +010033 public:
Vladimir Marko415ac882014-09-30 18:09:14 +010034 enum Mode {
35 kModeGvn,
36 kModeGvnPostProcessing,
37 kModeLvn
38 };
39
40 static bool Skip(CompilationUnit* cu) {
41 return (cu->disable_opt & (1u << kGlobalValueNumbering)) != 0u ||
42 cu->mir_graph->GetMaxNestedLoops() > kMaxAllowedNestedLoops;
43 }
44
Vladimir Markoaf6925b2014-10-31 16:37:32 +000045 // Instance and static field id map is held by MIRGraph to avoid multiple recalculations
46 // when doing LVN.
47 template <typename Container> // Container of MirIFieldLoweringInfo or MirSFieldLoweringInfo.
48 static uint16_t* PrepareGvnFieldIds(ScopedArenaAllocator* allocator,
49 const Container& field_infos);
50
Vladimir Marko415ac882014-09-30 18:09:14 +010051 GlobalValueNumbering(CompilationUnit* cu, ScopedArenaAllocator* allocator, Mode mode);
Vladimir Marko95a05972014-05-30 10:01:32 +010052 ~GlobalValueNumbering();
53
Vladimir Marko55fff042014-07-10 12:42:52 +010054 // Prepare LVN for the basic block.
Vladimir Markob19955d2014-07-29 12:04:10 +010055 LocalValueNumbering* PrepareBasicBlock(BasicBlock* bb,
56 ScopedArenaAllocator* allocator = nullptr);
Vladimir Marko55fff042014-07-10 12:42:52 +010057
58 // Finish processing the basic block.
Vladimir Marko95a05972014-05-30 10:01:32 +010059 bool FinishBasicBlock(BasicBlock* bb);
60
61 // Checks that the value names didn't overflow.
62 bool Good() const {
63 return last_value_ < kNoValue;
64 }
65
66 // Allow modifications.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -070067 void StartPostProcessing();
Vladimir Marko95a05972014-05-30 10:01:32 +010068
69 bool CanModify() const {
Vladimir Marko95a05972014-05-30 10:01:32 +010070 return modifications_allowed_ && Good();
71 }
72
Vladimir Marko95a05972014-05-30 10:01:32 +010073 private:
74 static constexpr uint16_t kNoValue = 0xffffu;
75
76 // Allocate a new value name.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -070077 uint16_t NewValueName();
Vladimir Marko95a05972014-05-30 10:01:32 +010078
79 // Key is concatenation of opcode, operand1, operand2 and modifier, value is value name.
80 typedef ScopedArenaSafeMap<uint64_t, uint16_t> ValueMap;
81
82 static uint64_t BuildKey(uint16_t op, uint16_t operand1, uint16_t operand2, uint16_t modifier) {
83 return (static_cast<uint64_t>(op) << 48 | static_cast<uint64_t>(operand1) << 32 |
84 static_cast<uint64_t>(operand2) << 16 | static_cast<uint64_t>(modifier));
Andreas Gampec8ccf682014-09-29 20:07:43 -070085 }
Vladimir Marko95a05972014-05-30 10:01:32 +010086
87 // Look up a value in the global value map, adding a new entry if there was none before.
88 uint16_t LookupValue(uint16_t op, uint16_t operand1, uint16_t operand2, uint16_t modifier) {
89 uint16_t res;
90 uint64_t key = BuildKey(op, operand1, operand2, modifier);
91 ValueMap::iterator lb = global_value_map_.lower_bound(key);
92 if (lb != global_value_map_.end() && lb->first == key) {
93 res = lb->second;
94 } else {
95 res = NewValueName();
96 global_value_map_.PutBefore(lb, key, res);
97 }
98 return res;
Andreas Gampec8ccf682014-09-29 20:07:43 -070099 }
Vladimir Marko95a05972014-05-30 10:01:32 +0100100
Vladimir Markoa4426cf2014-10-22 17:15:53 +0100101 // Look up a value in the global value map, don't add a new entry if there was none before.
102 uint16_t FindValue(uint16_t op, uint16_t operand1, uint16_t operand2, uint16_t modifier) {
103 uint16_t res;
104 uint64_t key = BuildKey(op, operand1, operand2, modifier);
105 ValueMap::iterator lb = global_value_map_.lower_bound(key);
106 if (lb != global_value_map_.end() && lb->first == key) {
107 res = lb->second;
108 } else {
109 res = kNoValue;
110 }
111 return res;
112 }
113
Vladimir Marko95a05972014-05-30 10:01:32 +0100114 // Check if the exact value is stored in the global value map.
115 bool HasValue(uint16_t op, uint16_t operand1, uint16_t operand2, uint16_t modifier,
116 uint16_t value) const {
117 DCHECK(value != 0u || !Good());
118 DCHECK_LE(value, last_value_);
119 // This is equivalent to value == LookupValue(op, operand1, operand2, modifier)
120 // except that it doesn't add an entry to the global value map if it's not there.
121 uint64_t key = BuildKey(op, operand1, operand2, modifier);
122 ValueMap::const_iterator it = global_value_map_.find(key);
123 return (it != global_value_map_.end() && it->second == value);
Andreas Gampec8ccf682014-09-29 20:07:43 -0700124 }
Vladimir Marko95a05972014-05-30 10:01:32 +0100125
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000126 // Get an instance field id.
127 uint16_t GetIFieldId(MIR* mir) {
128 return GetMirGraph()->GetGvnIFieldId(mir);
129 }
Vladimir Marko95a05972014-05-30 10:01:32 +0100130
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000131 // Get a static field id.
132 uint16_t GetSFieldId(MIR* mir) {
133 return GetMirGraph()->GetGvnSFieldId(mir);
134 }
Vladimir Marko95a05972014-05-30 10:01:32 +0100135
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000136 // Get an instance field type based on field id.
137 uint16_t GetIFieldType(uint16_t field_id) {
138 return static_cast<uint16_t>(GetMirGraph()->GetIFieldLoweringInfo(field_id).MemAccessType());
139 }
Vladimir Marko95a05972014-05-30 10:01:32 +0100140
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000141 // Get a static field type based on field id.
142 uint16_t GetSFieldType(uint16_t field_id) {
143 return static_cast<uint16_t>(GetMirGraph()->GetSFieldLoweringInfo(field_id).MemAccessType());
Vladimir Marko95a05972014-05-30 10:01:32 +0100144 }
145
146 struct ArrayLocation {
147 uint16_t base;
148 uint16_t index;
149 };
150
151 struct ArrayLocationComparator {
152 bool operator()(const ArrayLocation& lhs, const ArrayLocation& rhs) const {
153 if (lhs.base != rhs.base) {
154 return lhs.base < rhs.base;
155 }
156 return lhs.index < rhs.index;
157 }
158 };
159
160 typedef ScopedArenaSafeMap<ArrayLocation, uint16_t, ArrayLocationComparator> ArrayLocationMap;
161
162 // Get an array location.
163 uint16_t GetArrayLocation(uint16_t base, uint16_t index);
164
165 // Get the array base from an array location.
166 uint16_t GetArrayLocationBase(uint16_t location) const {
167 return array_location_reverse_map_[location]->first.base;
168 }
169
170 // Get the array index from an array location.
171 uint16_t GetArrayLocationIndex(uint16_t location) const {
172 return array_location_reverse_map_[location]->first.index;
173 }
174
175 // A set of value names.
176 typedef ScopedArenaSet<uint16_t> ValueNameSet;
177
178 // A map from a set of references to the set id.
179 typedef ScopedArenaSafeMap<ValueNameSet, uint16_t> RefSetIdMap;
180
181 uint16_t GetRefSetId(const ValueNameSet& ref_set) {
182 uint16_t res = kNoValue;
183 auto lb = ref_set_map_.lower_bound(ref_set);
184 if (lb != ref_set_map_.end() && !ref_set_map_.key_comp()(ref_set, lb->first)) {
185 res = lb->second;
186 } else {
187 res = NewValueName();
188 ref_set_map_.PutBefore(lb, ref_set, res);
189 }
190 return res;
191 }
192
193 const BasicBlock* GetBasicBlock(uint16_t bb_id) const {
Vladimir Marko55fff042014-07-10 12:42:52 +0100194 return mir_graph_->GetBasicBlock(bb_id);
Vladimir Marko95a05972014-05-30 10:01:32 +0100195 }
196
197 static bool HasNullCheckLastInsn(const BasicBlock* pred_bb, BasicBlockId succ_id);
198
199 bool NullCheckedInAllPredecessors(const ScopedArenaVector<uint16_t>& merge_names) const;
200
Razvan A Lupusorue0951142014-11-14 14:36:55 -0800201 bool DivZeroCheckedInAllPredecessors(const ScopedArenaVector<uint16_t>& merge_names) const;
202
Vladimir Marko95a05972014-05-30 10:01:32 +0100203 CompilationUnit* GetCompilationUnit() const {
204 return cu_;
205 }
206
207 MIRGraph* GetMirGraph() const {
Vladimir Marko55fff042014-07-10 12:42:52 +0100208 return mir_graph_;
Vladimir Marko95a05972014-05-30 10:01:32 +0100209 }
210
211 ScopedArenaAllocator* Allocator() const {
212 return allocator_;
213 }
214
215 CompilationUnit* const cu_;
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700216 MIRGraph* const mir_graph_;
Vladimir Marko95a05972014-05-30 10:01:32 +0100217 ScopedArenaAllocator* const allocator_;
218
Vladimir Marko415ac882014-09-30 18:09:14 +0100219 // The maximum number of nested loops that we accept for GVN.
220 static constexpr size_t kMaxAllowedNestedLoops = 6u;
221
Vladimir Marko55fff042014-07-10 12:42:52 +0100222 // The number of BBs that we need to process grows exponentially with the number
223 // of nested loops. Don't allow excessive processing for too many nested loops or
224 // otherwise expensive methods.
225 static constexpr uint32_t kMaxBbsToProcessMultiplyFactor = 20u;
Vladimir Marko95a05972014-05-30 10:01:32 +0100226
Vladimir Marko55fff042014-07-10 12:42:52 +0100227 uint32_t bbs_processed_;
Vladimir Marko2d2365c2014-08-19 18:08:39 +0100228 uint32_t max_bbs_to_process_; // Doesn't apply after the main GVN has converged.
Vladimir Marko95a05972014-05-30 10:01:32 +0100229
230 // We have 32-bit last_value_ so that we can detect when we run out of value names, see Good().
231 // We usually don't check Good() until the end of LVN unless we're about to modify code.
232 uint32_t last_value_;
233
234 // Marks whether code modifications are allowed. The initial GVN is done without code
235 // modifications to settle the value names. Afterwards, we allow modifications and rerun
236 // LVN once for each BasicBlock.
237 bool modifications_allowed_;
238
Vladimir Marko415ac882014-09-30 18:09:14 +0100239 // Specifies the mode of operation.
240 Mode mode_;
241
Vladimir Marko95a05972014-05-30 10:01:32 +0100242 ValueMap global_value_map_;
Vladimir Marko95a05972014-05-30 10:01:32 +0100243 ArrayLocationMap array_location_map_;
244 ScopedArenaVector<const ArrayLocationMap::value_type*> array_location_reverse_map_;
245 RefSetIdMap ref_set_map_;
246
247 ScopedArenaVector<const LocalValueNumbering*> lvns_; // Owning.
248 std::unique_ptr<LocalValueNumbering> work_lvn_;
249 ScopedArenaVector<const LocalValueNumbering*> merge_lvns_; // Not owning.
250
251 friend class LocalValueNumbering;
Vladimir Markoa4426cf2014-10-22 17:15:53 +0100252 friend class GlobalValueNumberingTest;
Vladimir Marko95a05972014-05-30 10:01:32 +0100253
254 DISALLOW_COPY_AND_ASSIGN(GlobalValueNumbering);
255};
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700256std::ostream& operator<<(std::ostream& os, const GlobalValueNumbering::Mode& rhs);
257
Andreas Gampe0b9203e2015-01-22 20:39:27 -0800258inline void GlobalValueNumbering::StartPostProcessing() {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700259 DCHECK(Good());
260 DCHECK_EQ(mode_, kModeGvn);
261 mode_ = kModeGvnPostProcessing;
262}
263
264inline uint16_t GlobalValueNumbering::NewValueName() {
265 DCHECK_NE(mode_, kModeGvnPostProcessing);
266 ++last_value_;
267 return last_value_;
268}
Vladimir Marko95a05972014-05-30 10:01:32 +0100269
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000270template <typename Container> // Container of MirIFieldLoweringInfo or MirSFieldLoweringInfo.
271uint16_t* GlobalValueNumbering::PrepareGvnFieldIds(ScopedArenaAllocator* allocator,
272 const Container& field_infos) {
273 size_t size = field_infos.size();
Vladimir Markoe4fcc5b2015-02-13 10:28:29 +0000274 uint16_t* field_ids = allocator->AllocArray<uint16_t>(size, kArenaAllocMisc);
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000275 for (size_t i = 0u; i != size; ++i) {
276 size_t idx = i;
277 const MirFieldInfo& cur_info = field_infos[i];
278 if (cur_info.IsResolved()) {
279 for (size_t j = 0; j != i; ++j) {
280 const MirFieldInfo& prev_info = field_infos[j];
281 if (prev_info.IsResolved() &&
282 prev_info.DeclaringDexFile() == cur_info.DeclaringDexFile() &&
283 prev_info.DeclaringFieldIndex() == cur_info.DeclaringFieldIndex()) {
284 DCHECK_EQ(cur_info.MemAccessType(), prev_info.MemAccessType());
285 idx = j;
286 break;
287 }
288 }
289 }
290 field_ids[i] = idx;
291 }
292 return field_ids;
293}
294
Vladimir Marko95a05972014-05-30 10:01:32 +0100295} // namespace art
296
297#endif // ART_COMPILER_DEX_GLOBAL_VALUE_NUMBERING_H_