blob: a12a7791ab520a3d420bdc04dd6e2f13d6feceb0 [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
20#include "base/macros.h"
21#include "compiler_internals.h"
22#include "utils/scoped_arena_containers.h"
23
24namespace art {
25
26class LocalValueNumbering;
27class MirFieldInfo;
28
29class GlobalValueNumbering {
30 public:
31 GlobalValueNumbering(CompilationUnit* cu, ScopedArenaAllocator* allocator);
32 ~GlobalValueNumbering();
33
Vladimir Marko55fff042014-07-10 12:42:52 +010034 // Prepare LVN for the basic block.
Vladimir Marko95a05972014-05-30 10:01:32 +010035 LocalValueNumbering* PrepareBasicBlock(BasicBlock* bb);
Vladimir Marko55fff042014-07-10 12:42:52 +010036
37 // Finish processing the basic block.
Vladimir Marko95a05972014-05-30 10:01:32 +010038 bool FinishBasicBlock(BasicBlock* bb);
39
40 // Checks that the value names didn't overflow.
41 bool Good() const {
42 return last_value_ < kNoValue;
43 }
44
45 // Allow modifications.
46 void AllowModifications() {
47 DCHECK(Good());
Vladimir Marko95a05972014-05-30 10:01:32 +010048 modifications_allowed_ = true;
49 }
50
51 bool CanModify() const {
52 // TODO: DCHECK(Good()), see AllowModifications() and NewValueName().
53 return modifications_allowed_ && Good();
54 }
55
56 // GlobalValueNumbering should be allocated on the ArenaStack (or the native stack).
57 static void* operator new(size_t size, ScopedArenaAllocator* allocator) {
58 return allocator->Alloc(sizeof(GlobalValueNumbering), kArenaAllocMIR);
59 }
60
61 // Allow delete-expression to destroy a GlobalValueNumbering object without deallocation.
62 static void operator delete(void* ptr) { UNUSED(ptr); }
63
64 private:
65 static constexpr uint16_t kNoValue = 0xffffu;
66
67 // Allocate a new value name.
68 uint16_t NewValueName() {
69 // TODO: No new values should be needed once we allow modifications.
70 // DCHECK(!modifications_allowed_);
71 ++last_value_;
72 return last_value_;
73 }
74
75 // Key is concatenation of opcode, operand1, operand2 and modifier, value is value name.
76 typedef ScopedArenaSafeMap<uint64_t, uint16_t> ValueMap;
77
78 static uint64_t BuildKey(uint16_t op, uint16_t operand1, uint16_t operand2, uint16_t modifier) {
79 return (static_cast<uint64_t>(op) << 48 | static_cast<uint64_t>(operand1) << 32 |
80 static_cast<uint64_t>(operand2) << 16 | static_cast<uint64_t>(modifier));
81 };
82
83 // Look up a value in the global value map, adding a new entry if there was none before.
84 uint16_t LookupValue(uint16_t op, uint16_t operand1, uint16_t operand2, uint16_t modifier) {
85 uint16_t res;
86 uint64_t key = BuildKey(op, operand1, operand2, modifier);
87 ValueMap::iterator lb = global_value_map_.lower_bound(key);
88 if (lb != global_value_map_.end() && lb->first == key) {
89 res = lb->second;
90 } else {
91 res = NewValueName();
92 global_value_map_.PutBefore(lb, key, res);
93 }
94 return res;
95 };
96
97 // Check if the exact value is stored in the global value map.
98 bool HasValue(uint16_t op, uint16_t operand1, uint16_t operand2, uint16_t modifier,
99 uint16_t value) const {
100 DCHECK(value != 0u || !Good());
101 DCHECK_LE(value, last_value_);
102 // This is equivalent to value == LookupValue(op, operand1, operand2, modifier)
103 // except that it doesn't add an entry to the global value map if it's not there.
104 uint64_t key = BuildKey(op, operand1, operand2, modifier);
105 ValueMap::const_iterator it = global_value_map_.find(key);
106 return (it != global_value_map_.end() && it->second == value);
107 };
108
109 // FieldReference represents a unique resolved field.
110 struct FieldReference {
111 const DexFile* dex_file;
112 uint16_t field_idx;
113 uint16_t type; // See comments for LocalValueNumbering::kFieldTypeCount.
114 };
115
116 struct FieldReferenceComparator {
117 bool operator()(const FieldReference& lhs, const FieldReference& rhs) const {
118 if (lhs.field_idx != rhs.field_idx) {
119 return lhs.field_idx < rhs.field_idx;
120 }
121 // If the field_idx and dex_file match, the type must also match.
122 DCHECK(lhs.dex_file != rhs.dex_file || lhs.type == rhs.type);
123 return lhs.dex_file < rhs.dex_file;
124 }
125 };
126
127 // Maps field key to field id for resolved fields.
128 typedef ScopedArenaSafeMap<FieldReference, uint32_t, FieldReferenceComparator> FieldIndexMap;
129
130 // Get a field id.
131 uint16_t GetFieldId(const MirFieldInfo& field_info, uint16_t type);
132
133 // Get a field type based on field id.
134 uint16_t GetFieldType(uint16_t field_id) {
135 DCHECK_LT(field_id, field_index_reverse_map_.size());
136 return field_index_reverse_map_[field_id]->first.type;
137 }
138
139 struct ArrayLocation {
140 uint16_t base;
141 uint16_t index;
142 };
143
144 struct ArrayLocationComparator {
145 bool operator()(const ArrayLocation& lhs, const ArrayLocation& rhs) const {
146 if (lhs.base != rhs.base) {
147 return lhs.base < rhs.base;
148 }
149 return lhs.index < rhs.index;
150 }
151 };
152
153 typedef ScopedArenaSafeMap<ArrayLocation, uint16_t, ArrayLocationComparator> ArrayLocationMap;
154
155 // Get an array location.
156 uint16_t GetArrayLocation(uint16_t base, uint16_t index);
157
158 // Get the array base from an array location.
159 uint16_t GetArrayLocationBase(uint16_t location) const {
160 return array_location_reverse_map_[location]->first.base;
161 }
162
163 // Get the array index from an array location.
164 uint16_t GetArrayLocationIndex(uint16_t location) const {
165 return array_location_reverse_map_[location]->first.index;
166 }
167
168 // A set of value names.
169 typedef ScopedArenaSet<uint16_t> ValueNameSet;
170
171 // A map from a set of references to the set id.
172 typedef ScopedArenaSafeMap<ValueNameSet, uint16_t> RefSetIdMap;
173
174 uint16_t GetRefSetId(const ValueNameSet& ref_set) {
175 uint16_t res = kNoValue;
176 auto lb = ref_set_map_.lower_bound(ref_set);
177 if (lb != ref_set_map_.end() && !ref_set_map_.key_comp()(ref_set, lb->first)) {
178 res = lb->second;
179 } else {
180 res = NewValueName();
181 ref_set_map_.PutBefore(lb, ref_set, res);
182 }
183 return res;
184 }
185
186 const BasicBlock* GetBasicBlock(uint16_t bb_id) const {
Vladimir Marko55fff042014-07-10 12:42:52 +0100187 return mir_graph_->GetBasicBlock(bb_id);
Vladimir Marko95a05972014-05-30 10:01:32 +0100188 }
189
190 static bool HasNullCheckLastInsn(const BasicBlock* pred_bb, BasicBlockId succ_id);
191
192 bool NullCheckedInAllPredecessors(const ScopedArenaVector<uint16_t>& merge_names) const;
193
194 CompilationUnit* GetCompilationUnit() const {
195 return cu_;
196 }
197
198 MIRGraph* GetMirGraph() const {
Vladimir Marko55fff042014-07-10 12:42:52 +0100199 return mir_graph_;
Vladimir Marko95a05972014-05-30 10:01:32 +0100200 }
201
202 ScopedArenaAllocator* Allocator() const {
203 return allocator_;
204 }
205
206 CompilationUnit* const cu_;
Vladimir Marko55fff042014-07-10 12:42:52 +0100207 MIRGraph* mir_graph_;
Vladimir Marko95a05972014-05-30 10:01:32 +0100208 ScopedArenaAllocator* const allocator_;
209
Vladimir Marko55fff042014-07-10 12:42:52 +0100210 // The number of BBs that we need to process grows exponentially with the number
211 // of nested loops. Don't allow excessive processing for too many nested loops or
212 // otherwise expensive methods.
213 static constexpr uint32_t kMaxBbsToProcessMultiplyFactor = 20u;
Vladimir Marko95a05972014-05-30 10:01:32 +0100214
Vladimir Marko55fff042014-07-10 12:42:52 +0100215 uint32_t bbs_processed_;
216 uint32_t max_bbs_to_process_;
Vladimir Marko95a05972014-05-30 10:01:32 +0100217
218 // We have 32-bit last_value_ so that we can detect when we run out of value names, see Good().
219 // We usually don't check Good() until the end of LVN unless we're about to modify code.
220 uint32_t last_value_;
221
222 // Marks whether code modifications are allowed. The initial GVN is done without code
223 // modifications to settle the value names. Afterwards, we allow modifications and rerun
224 // LVN once for each BasicBlock.
225 bool modifications_allowed_;
226
227 ValueMap global_value_map_;
228 FieldIndexMap field_index_map_;
229 ScopedArenaVector<const FieldIndexMap::value_type*> field_index_reverse_map_;
230 ArrayLocationMap array_location_map_;
231 ScopedArenaVector<const ArrayLocationMap::value_type*> array_location_reverse_map_;
232 RefSetIdMap ref_set_map_;
233
234 ScopedArenaVector<const LocalValueNumbering*> lvns_; // Owning.
235 std::unique_ptr<LocalValueNumbering> work_lvn_;
236 ScopedArenaVector<const LocalValueNumbering*> merge_lvns_; // Not owning.
237
238 friend class LocalValueNumbering;
239
240 DISALLOW_COPY_AND_ASSIGN(GlobalValueNumbering);
241};
242
243} // namespace art
244
245#endif // ART_COMPILER_DEX_GLOBAL_VALUE_NUMBERING_H_