1 /*
2 * Copyright (C) 2012 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 #include "local_value_numbering.h"
18
19 #include "global_value_numbering.h"
20 #include "mir_field_info.h"
21 #include "mir_graph.h"
22
23 namespace art {
24
25 namespace { // anonymous namespace
26
27 // Operations used for value map keys instead of actual opcode.
28 static constexpr uint16_t kInvokeMemoryVersionBumpOp = Instruction::INVOKE_VIRTUAL;
29 static constexpr uint16_t kUnresolvedSFieldOp = Instruction::SGET;
30 static constexpr uint16_t kResolvedSFieldOp = Instruction::SGET_WIDE;
31 static constexpr uint16_t kUnresolvedIFieldOp = Instruction::IGET;
32 static constexpr uint16_t kNonAliasingIFieldLocOp = Instruction::IGET_WIDE;
33 static constexpr uint16_t kNonAliasingIFieldInitialOp = Instruction::IGET_OBJECT;
34 static constexpr uint16_t kAliasingIFieldOp = Instruction::IGET_BOOLEAN;
35 static constexpr uint16_t kAliasingIFieldStartVersionOp = Instruction::IGET_BYTE;
36 static constexpr uint16_t kAliasingIFieldBumpVersionOp = Instruction::IGET_CHAR;
37 static constexpr uint16_t kNonAliasingArrayOp = Instruction::AGET;
38 static constexpr uint16_t kNonAliasingArrayStartVersionOp = Instruction::AGET_WIDE;
39 static constexpr uint16_t kNonAliasingArrayBumpVersionOp = Instruction::AGET_OBJECT;
40 static constexpr uint16_t kAliasingArrayOp = Instruction::AGET_BOOLEAN;
41 static constexpr uint16_t kAliasingArrayStartVersionOp = Instruction::AGET_BYTE;
42 static constexpr uint16_t kAliasingArrayBumpVersionOp = Instruction::AGET_CHAR;
43 static constexpr uint16_t kMergeBlockMemoryVersionBumpOp = Instruction::INVOKE_VIRTUAL_RANGE;
44 static constexpr uint16_t kMergeBlockAliasingIFieldVersionBumpOp = Instruction::IPUT;
45 static constexpr uint16_t kMergeBlockAliasingIFieldMergeLocationOp = Instruction::IPUT_WIDE;
46 static constexpr uint16_t kMergeBlockNonAliasingArrayVersionBumpOp = Instruction::APUT;
47 static constexpr uint16_t kMergeBlockNonAliasingArrayMergeLocationOp = Instruction::APUT_WIDE;
48 static constexpr uint16_t kMergeBlockAliasingArrayVersionBumpOp = Instruction::APUT_OBJECT;
49 static constexpr uint16_t kMergeBlockAliasingArrayMergeLocationOp = Instruction::APUT_BOOLEAN;
50 static constexpr uint16_t kMergeBlockNonAliasingIFieldVersionBumpOp = Instruction::APUT_BYTE;
51 static constexpr uint16_t kMergeBlockSFieldVersionBumpOp = Instruction::APUT_CHAR;
52
53 } // anonymous namespace
54
55 class LocalValueNumbering::AliasingIFieldVersions {
56 public:
StartMemoryVersion(GlobalValueNumbering * gvn,const LocalValueNumbering * lvn,uint16_t field_id)57 static uint16_t StartMemoryVersion(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
58 uint16_t field_id) {
59 uint16_t type = gvn->GetFieldType(field_id);
60 return gvn->LookupValue(kAliasingIFieldStartVersionOp, field_id,
61 lvn->global_memory_version_, lvn->unresolved_ifield_version_[type]);
62 }
63
BumpMemoryVersion(GlobalValueNumbering * gvn,uint16_t old_version,uint16_t store_ref_set_id,uint16_t stored_value)64 static uint16_t BumpMemoryVersion(GlobalValueNumbering* gvn, uint16_t old_version,
65 uint16_t store_ref_set_id, uint16_t stored_value) {
66 return gvn->LookupValue(kAliasingIFieldBumpVersionOp, old_version,
67 store_ref_set_id, stored_value);
68 }
69
LookupGlobalValue(GlobalValueNumbering * gvn,uint16_t field_id,uint16_t base,uint16_t memory_version)70 static uint16_t LookupGlobalValue(GlobalValueNumbering* gvn,
71 uint16_t field_id, uint16_t base, uint16_t memory_version) {
72 return gvn->LookupValue(kAliasingIFieldOp, field_id, base, memory_version);
73 }
74
LookupMergeValue(GlobalValueNumbering * gvn,const LocalValueNumbering * lvn,uint16_t field_id,uint16_t base)75 static uint16_t LookupMergeValue(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
76 uint16_t field_id, uint16_t base) {
77 // If the base/field_id is non-aliasing in lvn, use the non-aliasing value.
78 uint16_t type = gvn->GetFieldType(field_id);
79 if (lvn->IsNonAliasingIField(base, field_id, type)) {
80 uint16_t loc = gvn->LookupValue(kNonAliasingIFieldLocOp, base, field_id, type);
81 auto lb = lvn->non_aliasing_ifield_value_map_.find(loc);
82 return (lb != lvn->non_aliasing_ifield_value_map_.end())
83 ? lb->second
84 : gvn->LookupValue(kNonAliasingIFieldInitialOp, loc, kNoValue, kNoValue);
85 }
86 return AliasingValuesMergeGet<AliasingIFieldVersions>(
87 gvn, lvn, &lvn->aliasing_ifield_value_map_, field_id, base);
88 }
89
HasNewBaseVersion(GlobalValueNumbering * gvn,const LocalValueNumbering * lvn,uint16_t field_id)90 static bool HasNewBaseVersion(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
91 uint16_t field_id) {
92 uint16_t type = gvn->GetFieldType(field_id);
93 return lvn->unresolved_ifield_version_[type] == lvn->merge_new_memory_version_ ||
94 lvn->global_memory_version_ == lvn->merge_new_memory_version_;
95 }
96
LookupMergeBlockValue(GlobalValueNumbering * gvn,uint16_t lvn_id,uint16_t field_id)97 static uint16_t LookupMergeBlockValue(GlobalValueNumbering* gvn, uint16_t lvn_id,
98 uint16_t field_id) {
99 return gvn->LookupValue(kMergeBlockAliasingIFieldVersionBumpOp, field_id, kNoValue, lvn_id);
100 }
101
LookupMergeLocationValue(GlobalValueNumbering * gvn,uint16_t lvn_id,uint16_t field_id,uint16_t base)102 static uint16_t LookupMergeLocationValue(GlobalValueNumbering* gvn, uint16_t lvn_id,
103 uint16_t field_id, uint16_t base) {
104 return gvn->LookupValue(kMergeBlockAliasingIFieldMergeLocationOp, field_id, base, lvn_id);
105 }
106 };
107
108 class LocalValueNumbering::NonAliasingArrayVersions {
109 public:
StartMemoryVersion(GlobalValueNumbering * gvn,const LocalValueNumbering * lvn,uint16_t array)110 static uint16_t StartMemoryVersion(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
111 uint16_t array) {
112 return gvn->LookupValue(kNonAliasingArrayStartVersionOp, array, kNoValue, kNoValue);
113 }
114
BumpMemoryVersion(GlobalValueNumbering * gvn,uint16_t old_version,uint16_t store_ref_set_id,uint16_t stored_value)115 static uint16_t BumpMemoryVersion(GlobalValueNumbering* gvn, uint16_t old_version,
116 uint16_t store_ref_set_id, uint16_t stored_value) {
117 return gvn->LookupValue(kNonAliasingArrayBumpVersionOp, old_version,
118 store_ref_set_id, stored_value);
119 }
120
LookupGlobalValue(GlobalValueNumbering * gvn,uint16_t array,uint16_t index,uint16_t memory_version)121 static uint16_t LookupGlobalValue(GlobalValueNumbering* gvn,
122 uint16_t array, uint16_t index, uint16_t memory_version) {
123 return gvn->LookupValue(kNonAliasingArrayOp, array, index, memory_version);
124 }
125
LookupMergeValue(GlobalValueNumbering * gvn,const LocalValueNumbering * lvn,uint16_t array,uint16_t index)126 static uint16_t LookupMergeValue(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
127 uint16_t array, uint16_t index) {
128 return AliasingValuesMergeGet<NonAliasingArrayVersions>(
129 gvn, lvn, &lvn->non_aliasing_array_value_map_, array, index);
130 }
131
HasNewBaseVersion(GlobalValueNumbering * gvn,const LocalValueNumbering * lvn,uint16_t array)132 static bool HasNewBaseVersion(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
133 uint16_t array) {
134 return false; // Not affected by global_memory_version_.
135 }
136
LookupMergeBlockValue(GlobalValueNumbering * gvn,uint16_t lvn_id,uint16_t array)137 static uint16_t LookupMergeBlockValue(GlobalValueNumbering* gvn, uint16_t lvn_id,
138 uint16_t array) {
139 return gvn->LookupValue(kMergeBlockNonAliasingArrayVersionBumpOp, array, kNoValue, lvn_id);
140 }
141
LookupMergeLocationValue(GlobalValueNumbering * gvn,uint16_t lvn_id,uint16_t array,uint16_t index)142 static uint16_t LookupMergeLocationValue(GlobalValueNumbering* gvn, uint16_t lvn_id,
143 uint16_t array, uint16_t index) {
144 return gvn->LookupValue(kMergeBlockNonAliasingArrayMergeLocationOp, array, index, lvn_id);
145 }
146 };
147
148 class LocalValueNumbering::AliasingArrayVersions {
149 public:
StartMemoryVersion(GlobalValueNumbering * gvn,const LocalValueNumbering * lvn,uint16_t type)150 static uint16_t StartMemoryVersion(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
151 uint16_t type) {
152 return gvn->LookupValue(kAliasingArrayStartVersionOp, type, lvn->global_memory_version_,
153 kNoValue);
154 }
155
BumpMemoryVersion(GlobalValueNumbering * gvn,uint16_t old_version,uint16_t store_ref_set_id,uint16_t stored_value)156 static uint16_t BumpMemoryVersion(GlobalValueNumbering* gvn, uint16_t old_version,
157 uint16_t store_ref_set_id, uint16_t stored_value) {
158 return gvn->LookupValue(kAliasingArrayBumpVersionOp, old_version,
159 store_ref_set_id, stored_value);
160 }
161
LookupGlobalValue(GlobalValueNumbering * gvn,uint16_t type,uint16_t location,uint16_t memory_version)162 static uint16_t LookupGlobalValue(GlobalValueNumbering* gvn,
163 uint16_t type, uint16_t location, uint16_t memory_version) {
164 return gvn->LookupValue(kAliasingArrayOp, type, location, memory_version);
165 }
166
LookupMergeValue(GlobalValueNumbering * gvn,const LocalValueNumbering * lvn,uint16_t type,uint16_t location)167 static uint16_t LookupMergeValue(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
168 uint16_t type, uint16_t location) {
169 // If the location is non-aliasing in lvn, use the non-aliasing value.
170 uint16_t array = gvn->GetArrayLocationBase(location);
171 if (lvn->IsNonAliasingArray(array, type)) {
172 uint16_t index = gvn->GetArrayLocationIndex(location);
173 return NonAliasingArrayVersions::LookupMergeValue(gvn, lvn, array, index);
174 }
175 return AliasingValuesMergeGet<AliasingArrayVersions>(
176 gvn, lvn, &lvn->aliasing_array_value_map_, type, location);
177 }
178
HasNewBaseVersion(GlobalValueNumbering * gvn,const LocalValueNumbering * lvn,uint16_t type)179 static bool HasNewBaseVersion(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
180 uint16_t type) {
181 return lvn->global_memory_version_ == lvn->merge_new_memory_version_;
182 }
183
LookupMergeBlockValue(GlobalValueNumbering * gvn,uint16_t lvn_id,uint16_t type)184 static uint16_t LookupMergeBlockValue(GlobalValueNumbering* gvn, uint16_t lvn_id,
185 uint16_t type) {
186 return gvn->LookupValue(kMergeBlockAliasingArrayVersionBumpOp, type, kNoValue, lvn_id);
187 }
188
LookupMergeLocationValue(GlobalValueNumbering * gvn,uint16_t lvn_id,uint16_t type,uint16_t location)189 static uint16_t LookupMergeLocationValue(GlobalValueNumbering* gvn, uint16_t lvn_id,
190 uint16_t type, uint16_t location) {
191 return gvn->LookupValue(kMergeBlockAliasingArrayMergeLocationOp, type, location, lvn_id);
192 }
193 };
194
195 template <typename Map>
GetAliasingValues(Map * map,const typename Map::key_type & key)196 LocalValueNumbering::AliasingValues* LocalValueNumbering::GetAliasingValues(
197 Map* map, const typename Map::key_type& key) {
198 auto lb = map->lower_bound(key);
199 if (lb == map->end() || map->key_comp()(key, lb->first)) {
200 lb = map->PutBefore(lb, key, AliasingValues(this));
201 }
202 return &lb->second;
203 }
204
205 template <typename Versions, typename KeyType>
UpdateAliasingValuesLoadVersion(const KeyType & key,AliasingValues * values)206 void LocalValueNumbering::UpdateAliasingValuesLoadVersion(const KeyType& key,
207 AliasingValues* values) {
208 if (values->last_load_memory_version == kNoValue) {
209 // Get the start version that accounts for aliasing with unresolved fields of the same
210 // type and make it unique for the field by including the field_id.
211 uint16_t memory_version = values->memory_version_before_stores;
212 if (memory_version == kNoValue) {
213 memory_version = Versions::StartMemoryVersion(gvn_, this, key);
214 }
215 if (!values->store_loc_set.empty()) {
216 uint16_t ref_set_id = gvn_->GetRefSetId(values->store_loc_set);
217 memory_version = Versions::BumpMemoryVersion(gvn_, memory_version, ref_set_id,
218 values->last_stored_value);
219 }
220 values->last_load_memory_version = memory_version;
221 }
222 }
223
224 template <typename Versions, typename Map>
AliasingValuesMergeGet(GlobalValueNumbering * gvn,const LocalValueNumbering * lvn,Map * map,const typename Map::key_type & key,uint16_t location)225 uint16_t LocalValueNumbering::AliasingValuesMergeGet(GlobalValueNumbering* gvn,
226 const LocalValueNumbering* lvn,
227 Map* map, const typename Map::key_type& key,
228 uint16_t location) {
229 // Retrieve the value name that we would get from
230 // const_cast<LocalValueNumbering*>(lvn)->HandleAliasingValueGet(map. key, location)
231 // but don't modify the map.
232 uint16_t value_name;
233 auto it = map->find(key);
234 if (it == map->end()) {
235 uint16_t start_version = Versions::StartMemoryVersion(gvn, lvn, key);
236 value_name = Versions::LookupGlobalValue(gvn, key, location, start_version);
237 } else if (it->second.store_loc_set.count(location) != 0u) {
238 value_name = it->second.last_stored_value;
239 } else {
240 auto load_it = it->second.load_value_map.find(location);
241 if (load_it != it->second.load_value_map.end()) {
242 value_name = load_it->second;
243 } else {
244 value_name = Versions::LookupGlobalValue(gvn, key, location, it->second.last_load_memory_version);
245 }
246 }
247 return value_name;
248 }
249
250 template <typename Versions, typename Map>
HandleAliasingValuesGet(Map * map,const typename Map::key_type & key,uint16_t location)251 uint16_t LocalValueNumbering::HandleAliasingValuesGet(Map* map, const typename Map::key_type& key,
252 uint16_t location) {
253 // Retrieve the value name for IGET/SGET/AGET, update the map with new value if any.
254 uint16_t res;
255 AliasingValues* values = GetAliasingValues(map, key);
256 if (values->store_loc_set.count(location) != 0u) {
257 res = values->last_stored_value;
258 } else {
259 UpdateAliasingValuesLoadVersion<Versions>(key, values);
260 auto lb = values->load_value_map.lower_bound(location);
261 if (lb != values->load_value_map.end() && lb->first == location) {
262 res = lb->second;
263 } else {
264 res = Versions::LookupGlobalValue(gvn_, key, location, values->last_load_memory_version);
265 values->load_value_map.PutBefore(lb, location, res);
266 }
267 }
268 return res;
269 }
270
271 template <typename Versions, typename Map>
HandleAliasingValuesPut(Map * map,const typename Map::key_type & key,uint16_t location,uint16_t value)272 bool LocalValueNumbering::HandleAliasingValuesPut(Map* map, const typename Map::key_type& key,
273 uint16_t location, uint16_t value) {
274 AliasingValues* values = GetAliasingValues(map, key);
275 auto load_values_it = values->load_value_map.find(location);
276 if (load_values_it != values->load_value_map.end() && load_values_it->second == value) {
277 // This insn can be eliminated, it stores the same value that's already in the field.
278 return false;
279 }
280 if (value == values->last_stored_value) {
281 auto store_loc_lb = values->store_loc_set.lower_bound(location);
282 if (store_loc_lb != values->store_loc_set.end() && *store_loc_lb == location) {
283 // This insn can be eliminated, it stores the same value that's already in the field.
284 return false;
285 }
286 values->store_loc_set.emplace_hint(store_loc_lb, location);
287 } else {
288 UpdateAliasingValuesLoadVersion<Versions>(key, values);
289 values->memory_version_before_stores = values->last_load_memory_version;
290 values->last_stored_value = value;
291 values->store_loc_set.clear();
292 values->store_loc_set.insert(location);
293 }
294 // Clear the last load memory version and remove all potentially overwritten values.
295 values->last_load_memory_version = kNoValue;
296 auto it = values->load_value_map.begin(), end = values->load_value_map.end();
297 while (it != end) {
298 if (it->second == value) {
299 ++it;
300 } else {
301 it = values->load_value_map.erase(it);
302 }
303 }
304 return true;
305 }
306
307 template <typename K>
CopyAliasingValuesMap(ScopedArenaSafeMap<K,AliasingValues> * dest,const ScopedArenaSafeMap<K,AliasingValues> & src)308 void LocalValueNumbering::CopyAliasingValuesMap(ScopedArenaSafeMap<K, AliasingValues>* dest,
309 const ScopedArenaSafeMap<K, AliasingValues>& src) {
310 // We need each new AliasingValues (or rather its map members) to be constructed
311 // with our allocator, rather than the allocator of the source.
312 for (const auto& entry : src) {
313 auto it = dest->PutBefore(dest->end(), entry.first, AliasingValues(this));
314 it->second = entry.second; // Map assignments preserve current allocator.
315 }
316 }
317
LocalValueNumbering(GlobalValueNumbering * gvn,uint16_t id,ScopedArenaAllocator * allocator)318 LocalValueNumbering::LocalValueNumbering(GlobalValueNumbering* gvn, uint16_t id,
319 ScopedArenaAllocator* allocator)
320 : gvn_(gvn),
321 id_(id),
322 sreg_value_map_(std::less<uint16_t>(), allocator->Adapter()),
323 sreg_wide_value_map_(std::less<uint16_t>(), allocator->Adapter()),
324 sfield_value_map_(std::less<uint16_t>(), allocator->Adapter()),
325 non_aliasing_ifield_value_map_(std::less<uint16_t>(), allocator->Adapter()),
326 aliasing_ifield_value_map_(std::less<uint16_t>(), allocator->Adapter()),
327 non_aliasing_array_value_map_(std::less<uint16_t>(), allocator->Adapter()),
328 aliasing_array_value_map_(std::less<uint16_t>(), allocator->Adapter()),
329 global_memory_version_(0u),
330 non_aliasing_refs_(std::less<uint16_t>(), allocator->Adapter()),
331 escaped_refs_(std::less<uint16_t>(), allocator->Adapter()),
332 escaped_ifield_clobber_set_(EscapedIFieldClobberKeyComparator(), allocator->Adapter()),
333 escaped_array_clobber_set_(EscapedArrayClobberKeyComparator(), allocator->Adapter()),
334 range_checked_(RangeCheckKeyComparator() , allocator->Adapter()),
335 null_checked_(std::less<uint16_t>(), allocator->Adapter()),
336 merge_names_(allocator->Adapter()),
337 merge_map_(std::less<ScopedArenaVector<BasicBlockId>>(), allocator->Adapter()),
338 merge_new_memory_version_(kNoValue) {
339 std::fill_n(unresolved_sfield_version_, kFieldTypeCount, 0u);
340 std::fill_n(unresolved_ifield_version_, kFieldTypeCount, 0u);
341 }
342
Equals(const LocalValueNumbering & other) const343 bool LocalValueNumbering::Equals(const LocalValueNumbering& other) const {
344 DCHECK(gvn_ == other.gvn_);
345 // Compare the maps/sets and memory versions.
346 return sreg_value_map_ == other.sreg_value_map_ &&
347 sreg_wide_value_map_ == other.sreg_wide_value_map_ &&
348 sfield_value_map_ == other.sfield_value_map_ &&
349 non_aliasing_ifield_value_map_ == other.non_aliasing_ifield_value_map_ &&
350 aliasing_ifield_value_map_ == other.aliasing_ifield_value_map_ &&
351 non_aliasing_array_value_map_ == other.non_aliasing_array_value_map_ &&
352 aliasing_array_value_map_ == other.aliasing_array_value_map_ &&
353 SameMemoryVersion(other) &&
354 non_aliasing_refs_ == other.non_aliasing_refs_ &&
355 escaped_refs_ == other.escaped_refs_ &&
356 escaped_ifield_clobber_set_ == other.escaped_ifield_clobber_set_ &&
357 escaped_array_clobber_set_ == other.escaped_array_clobber_set_ &&
358 range_checked_ == other.range_checked_ &&
359 null_checked_ == other.null_checked_;
360 }
361
MergeOne(const LocalValueNumbering & other,MergeType merge_type)362 void LocalValueNumbering::MergeOne(const LocalValueNumbering& other, MergeType merge_type) {
363 CopyLiveSregValues(&sreg_value_map_, other.sreg_value_map_);
364 CopyLiveSregValues(&sreg_wide_value_map_, other.sreg_wide_value_map_);
365
366 if (merge_type == kReturnMerge) {
367 // RETURN or PHI+RETURN. We need only sreg value maps.
368 return;
369 }
370
371 non_aliasing_ifield_value_map_ = other.non_aliasing_ifield_value_map_;
372 CopyAliasingValuesMap(&non_aliasing_array_value_map_, other.non_aliasing_array_value_map_);
373 non_aliasing_refs_ = other.non_aliasing_refs_;
374 range_checked_ = other.range_checked_;
375 null_checked_ = other.null_checked_;
376
377 if (merge_type == kCatchMerge) {
378 // Memory is clobbered. Use new memory version and don't merge aliasing locations.
379 global_memory_version_ = NewMemoryVersion(&merge_new_memory_version_);
380 std::fill_n(unresolved_sfield_version_, kFieldTypeCount, global_memory_version_);
381 std::fill_n(unresolved_ifield_version_, kFieldTypeCount, global_memory_version_);
382 PruneNonAliasingRefsForCatch();
383 return;
384 }
385
386 DCHECK(merge_type == kNormalMerge);
387 global_memory_version_ = other.global_memory_version_;
388 std::copy_n(other.unresolved_ifield_version_, kFieldTypeCount, unresolved_ifield_version_);
389 std::copy_n(other.unresolved_sfield_version_, kFieldTypeCount, unresolved_sfield_version_);
390 sfield_value_map_ = other.sfield_value_map_;
391 CopyAliasingValuesMap(&aliasing_ifield_value_map_, other.aliasing_ifield_value_map_);
392 CopyAliasingValuesMap(&aliasing_array_value_map_, other.aliasing_array_value_map_);
393 escaped_refs_ = other.escaped_refs_;
394 escaped_ifield_clobber_set_ = other.escaped_ifield_clobber_set_;
395 escaped_array_clobber_set_ = other.escaped_array_clobber_set_;
396 }
397
SameMemoryVersion(const LocalValueNumbering & other) const398 bool LocalValueNumbering::SameMemoryVersion(const LocalValueNumbering& other) const {
399 return
400 global_memory_version_ == other.global_memory_version_ &&
401 std::equal(unresolved_ifield_version_, unresolved_ifield_version_ + kFieldTypeCount,
402 other.unresolved_ifield_version_) &&
403 std::equal(unresolved_sfield_version_, unresolved_sfield_version_ + kFieldTypeCount,
404 other.unresolved_sfield_version_);
405 }
406
NewMemoryVersion(uint16_t * new_version)407 uint16_t LocalValueNumbering::NewMemoryVersion(uint16_t* new_version) {
408 if (*new_version == kNoValue) {
409 *new_version = gvn_->LookupValue(kMergeBlockMemoryVersionBumpOp, 0u, 0u, id_);
410 }
411 return *new_version;
412 }
413
MergeMemoryVersions(bool clobbered_catch)414 void LocalValueNumbering::MergeMemoryVersions(bool clobbered_catch) {
415 DCHECK_GE(gvn_->merge_lvns_.size(), 2u);
416 const LocalValueNumbering* cmp = gvn_->merge_lvns_[0];
417 // Check if the global version has changed.
418 bool new_global_version = clobbered_catch;
419 if (!new_global_version) {
420 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
421 if (lvn->global_memory_version_ != cmp->global_memory_version_) {
422 // Use a new version for everything.
423 new_global_version = true;
424 break;
425 }
426 }
427 }
428 if (new_global_version) {
429 global_memory_version_ = NewMemoryVersion(&merge_new_memory_version_);
430 std::fill_n(unresolved_sfield_version_, kFieldTypeCount, merge_new_memory_version_);
431 std::fill_n(unresolved_ifield_version_, kFieldTypeCount, merge_new_memory_version_);
432 } else {
433 // Initialize with a copy of memory versions from the comparison LVN.
434 global_memory_version_ = cmp->global_memory_version_;
435 std::copy_n(cmp->unresolved_ifield_version_, kFieldTypeCount, unresolved_ifield_version_);
436 std::copy_n(cmp->unresolved_sfield_version_, kFieldTypeCount, unresolved_sfield_version_);
437 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
438 if (lvn == cmp) {
439 continue;
440 }
441 for (size_t i = 0; i != kFieldTypeCount; ++i) {
442 if (lvn->unresolved_ifield_version_[i] != cmp->unresolved_ifield_version_[i]) {
443 unresolved_ifield_version_[i] = NewMemoryVersion(&merge_new_memory_version_);
444 }
445 if (lvn->unresolved_sfield_version_[i] != cmp->unresolved_sfield_version_[i]) {
446 unresolved_sfield_version_[i] = NewMemoryVersion(&merge_new_memory_version_);
447 }
448 }
449 }
450 }
451 }
452
PruneNonAliasingRefsForCatch()453 void LocalValueNumbering::PruneNonAliasingRefsForCatch() {
454 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
455 const BasicBlock* bb = gvn_->GetBasicBlock(lvn->Id());
456 if (UNLIKELY(bb->taken == id_) || UNLIKELY(bb->fall_through == id_)) {
457 // Non-exceptional path to a catch handler means that the catch block was actually
458 // empty and all exceptional paths lead to the shared path after that empty block.
459 continue;
460 }
461 DCHECK_EQ(bb->taken, kNullBlock);
462 DCHECK_NE(bb->fall_through, kNullBlock);
463 const BasicBlock* fall_through_bb = gvn_->GetBasicBlock(bb->fall_through);
464 const MIR* mir = fall_through_bb->first_mir_insn;
465 DCHECK(mir != nullptr);
466 // Only INVOKEs can leak and clobber non-aliasing references if they throw.
467 if ((Instruction::FlagsOf(mir->dalvikInsn.opcode) & Instruction::kInvoke) != 0) {
468 for (uint16_t i = 0u; i != mir->ssa_rep->num_uses; ++i) {
469 uint16_t value_name = lvn->GetOperandValue(mir->ssa_rep->uses[i]);
470 non_aliasing_refs_.erase(value_name);
471 }
472 }
473 }
474 }
475
476
477 template <typename Set, Set LocalValueNumbering::* set_ptr>
IntersectSets()478 void LocalValueNumbering::IntersectSets() {
479 DCHECK_GE(gvn_->merge_lvns_.size(), 2u);
480
481 // Find the LVN with the least entries in the set.
482 const LocalValueNumbering* least_entries_lvn = gvn_->merge_lvns_[0];
483 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
484 if ((lvn->*set_ptr).size() < (least_entries_lvn->*set_ptr).size()) {
485 least_entries_lvn = lvn;
486 }
487 }
488
489 // For each key check if it's in all the LVNs.
490 for (const auto& key : least_entries_lvn->*set_ptr) {
491 bool checked = true;
492 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
493 if (lvn != least_entries_lvn && (lvn->*set_ptr).count(key) == 0u) {
494 checked = false;
495 break;
496 }
497 }
498 if (checked) {
499 (this->*set_ptr).emplace_hint((this->*set_ptr).end(), key);
500 }
501 }
502 }
503
CopyLiveSregValues(SregValueMap * dest,const SregValueMap & src)504 void LocalValueNumbering::CopyLiveSregValues(SregValueMap* dest, const SregValueMap& src) {
505 auto dest_end = dest->end();
506 ArenaBitVector* live_in_v = gvn_->GetMirGraph()->GetBasicBlock(id_)->data_flow_info->live_in_v;
507 DCHECK(live_in_v != nullptr);
508 for (const auto& entry : src) {
509 bool live = live_in_v->IsBitSet(gvn_->GetMirGraph()->SRegToVReg(entry.first));
510 if (live) {
511 dest->PutBefore(dest_end, entry.first, entry.second);
512 }
513 }
514 }
515
516 template <LocalValueNumbering::SregValueMap LocalValueNumbering::* map_ptr>
IntersectSregValueMaps()517 void LocalValueNumbering::IntersectSregValueMaps() {
518 DCHECK_GE(gvn_->merge_lvns_.size(), 2u);
519
520 // Find the LVN with the least entries in the set.
521 const LocalValueNumbering* least_entries_lvn = gvn_->merge_lvns_[0];
522 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
523 if ((lvn->*map_ptr).size() < (least_entries_lvn->*map_ptr).size()) {
524 least_entries_lvn = lvn;
525 }
526 }
527
528 // For each key check if it's in all the LVNs.
529 ArenaBitVector* live_in_v = gvn_->GetMirGraph()->GetBasicBlock(id_)->data_flow_info->live_in_v;
530 DCHECK(live_in_v != nullptr);
531 for (const auto& entry : least_entries_lvn->*map_ptr) {
532 bool live_and_same = live_in_v->IsBitSet(gvn_->GetMirGraph()->SRegToVReg(entry.first));
533 if (live_and_same) {
534 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
535 if (lvn != least_entries_lvn) {
536 auto it = (lvn->*map_ptr).find(entry.first);
537 if (it == (lvn->*map_ptr).end() || !(it->second == entry.second)) {
538 live_and_same = false;
539 break;
540 }
541 }
542 }
543 }
544 if (live_and_same) {
545 (this->*map_ptr).PutBefore((this->*map_ptr).end(), entry.first, entry.second);
546 }
547 }
548 }
549
550 // Intersect maps as sets. The value type must be equality-comparable.
551 template <typename Map>
InPlaceIntersectMaps(Map * work_map,const Map & other_map)552 void LocalValueNumbering::InPlaceIntersectMaps(Map* work_map, const Map& other_map) {
553 auto work_it = work_map->begin(), work_end = work_map->end();
554 auto cmp = work_map->value_comp();
555 for (const auto& entry : other_map) {
556 while (work_it != work_end &&
557 (cmp(*work_it, entry) ||
558 (!cmp(entry, *work_it) && !(work_it->second == entry.second)))) {
559 work_it = work_map->erase(work_it);
560 }
561 if (work_it == work_end) {
562 return;
563 }
564 ++work_it;
565 }
566 }
567
568 template <typename Set, Set LocalValueNumbering::*set_ptr, void (LocalValueNumbering::*MergeFn)(
569 const typename Set::value_type& entry, typename Set::iterator hint)>
MergeSets()570 void LocalValueNumbering::MergeSets() {
571 auto cmp = (this->*set_ptr).value_comp();
572 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
573 auto my_it = (this->*set_ptr).begin(), my_end = (this->*set_ptr).end();
574 for (const auto& entry : lvn->*set_ptr) {
575 while (my_it != my_end && cmp(*my_it, entry)) {
576 ++my_it;
577 }
578 if (my_it != my_end && !cmp(entry, *my_it)) {
579 // Already handled.
580 ++my_it;
581 } else {
582 // Merge values for this field_id.
583 (this->*MergeFn)(entry, my_it); // my_it remains valid across inserts to std::set/SafeMap.
584 }
585 }
586 }
587 }
588
IntersectAliasingValueLocations(AliasingValues * work_values,const AliasingValues * values)589 void LocalValueNumbering::IntersectAliasingValueLocations(AliasingValues* work_values,
590 const AliasingValues* values) {
591 auto cmp = work_values->load_value_map.key_comp();
592 auto work_it = work_values->load_value_map.begin(), work_end = work_values->load_value_map.end();
593 auto store_it = values->store_loc_set.begin(), store_end = values->store_loc_set.end();
594 auto load_it = values->load_value_map.begin(), load_end = values->load_value_map.end();
595 while (store_it != store_end || load_it != load_end) {
596 uint16_t loc;
597 if (store_it != store_end && (load_it == load_end || *store_it < load_it->first)) {
598 loc = *store_it;
599 ++store_it;
600 } else {
601 loc = load_it->first;
602 ++load_it;
603 DCHECK(store_it == store_end || cmp(loc, *store_it));
604 }
605 while (work_it != work_end && cmp(work_it->first, loc)) {
606 work_it = work_values->load_value_map.erase(work_it);
607 }
608 if (work_it != work_end && !cmp(loc, work_it->first)) {
609 // The location matches, keep it.
610 ++work_it;
611 }
612 }
613 while (work_it != work_end) {
614 work_it = work_values->load_value_map.erase(work_it);
615 }
616 }
617
MergeEscapedRefs(const ValueNameSet::value_type & entry,ValueNameSet::iterator hint)618 void LocalValueNumbering::MergeEscapedRefs(const ValueNameSet::value_type& entry,
619 ValueNameSet::iterator hint) {
620 // See if the ref is either escaped or non-aliasing in each predecessor.
621 bool is_escaped = true;
622 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
623 if (lvn->non_aliasing_refs_.count(entry) == 0u &&
624 lvn->escaped_refs_.count(entry) == 0u) {
625 is_escaped = false;
626 break;
627 }
628 }
629 if (is_escaped) {
630 escaped_refs_.emplace_hint(hint, entry);
631 }
632 }
633
MergeEscapedIFieldTypeClobberSets(const EscapedIFieldClobberSet::value_type & entry,EscapedIFieldClobberSet::iterator hint)634 void LocalValueNumbering::MergeEscapedIFieldTypeClobberSets(
635 const EscapedIFieldClobberSet::value_type& entry, EscapedIFieldClobberSet::iterator hint) {
636 // Insert only type-clobber entries (field_id == kNoValue) of escaped refs.
637 if (entry.field_id == kNoValue && escaped_refs_.count(entry.base) != 0u) {
638 escaped_ifield_clobber_set_.emplace_hint(hint, entry);
639 }
640 }
641
MergeEscapedIFieldClobberSets(const EscapedIFieldClobberSet::value_type & entry,EscapedIFieldClobberSet::iterator hint)642 void LocalValueNumbering::MergeEscapedIFieldClobberSets(
643 const EscapedIFieldClobberSet::value_type& entry, EscapedIFieldClobberSet::iterator hint) {
644 // Insert only those entries of escaped refs that are not overridden by a type clobber.
645 if (!(hint == escaped_ifield_clobber_set_.end() &&
646 hint->base == entry.base && hint->type == entry.type) &&
647 escaped_refs_.count(entry.base) != 0u) {
648 escaped_ifield_clobber_set_.emplace_hint(hint, entry);
649 }
650 }
651
MergeEscapedArrayClobberSets(const EscapedArrayClobberSet::value_type & entry,EscapedArrayClobberSet::iterator hint)652 void LocalValueNumbering::MergeEscapedArrayClobberSets(
653 const EscapedArrayClobberSet::value_type& entry, EscapedArrayClobberSet::iterator hint) {
654 if (escaped_refs_.count(entry.base) != 0u) {
655 escaped_array_clobber_set_.emplace_hint(hint, entry);
656 }
657 }
658
MergeNullChecked(const ValueNameSet::value_type & entry,ValueNameSet::iterator hint)659 void LocalValueNumbering::MergeNullChecked(const ValueNameSet::value_type& entry,
660 ValueNameSet::iterator hint) {
661 // Merge null_checked_ for this ref.
662 merge_names_.clear();
663 merge_names_.resize(gvn_->merge_lvns_.size(), entry);
664 if (gvn_->NullCheckedInAllPredecessors(merge_names_)) {
665 null_checked_.insert(hint, entry);
666 }
667 }
668
MergeSFieldValues(const SFieldToValueMap::value_type & entry,SFieldToValueMap::iterator hint)669 void LocalValueNumbering::MergeSFieldValues(const SFieldToValueMap::value_type& entry,
670 SFieldToValueMap::iterator hint) {
671 uint16_t field_id = entry.first;
672 merge_names_.clear();
673 uint16_t value_name = kNoValue;
674 bool same_values = true;
675 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
676 // Get the value name as in HandleSGet() but don't modify *lvn.
677 auto it = lvn->sfield_value_map_.find(field_id);
678 if (it != lvn->sfield_value_map_.end()) {
679 value_name = it->second;
680 } else {
681 uint16_t type = gvn_->GetFieldType(field_id);
682 value_name = gvn_->LookupValue(kResolvedSFieldOp, field_id,
683 lvn->unresolved_sfield_version_[type],
684 lvn->global_memory_version_);
685 }
686
687 same_values = same_values && (merge_names_.empty() || value_name == merge_names_.back());
688 merge_names_.push_back(value_name);
689 }
690 if (same_values) {
691 // value_name already contains the result.
692 } else {
693 auto lb = merge_map_.lower_bound(merge_names_);
694 if (lb != merge_map_.end() && !merge_map_.key_comp()(merge_names_, lb->first)) {
695 value_name = lb->second;
696 } else {
697 value_name = gvn_->LookupValue(kMergeBlockSFieldVersionBumpOp, field_id, id_, kNoValue);
698 merge_map_.PutBefore(lb, merge_names_, value_name);
699 if (gvn_->NullCheckedInAllPredecessors(merge_names_)) {
700 null_checked_.insert(value_name);
701 }
702 }
703 }
704 sfield_value_map_.PutBefore(hint, field_id, value_name);
705 }
706
MergeNonAliasingIFieldValues(const IFieldLocToValueMap::value_type & entry,IFieldLocToValueMap::iterator hint)707 void LocalValueNumbering::MergeNonAliasingIFieldValues(const IFieldLocToValueMap::value_type& entry,
708 IFieldLocToValueMap::iterator hint) {
709 uint16_t field_loc = entry.first;
710 merge_names_.clear();
711 uint16_t value_name = kNoValue;
712 bool same_values = true;
713 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
714 // Get the value name as in HandleIGet() but don't modify *lvn.
715 auto it = lvn->non_aliasing_ifield_value_map_.find(field_loc);
716 if (it != lvn->non_aliasing_ifield_value_map_.end()) {
717 value_name = it->second;
718 } else {
719 value_name = gvn_->LookupValue(kNonAliasingIFieldInitialOp, field_loc, kNoValue, kNoValue);
720 }
721
722 same_values = same_values && (merge_names_.empty() || value_name == merge_names_.back());
723 merge_names_.push_back(value_name);
724 }
725 if (same_values) {
726 // value_name already contains the result.
727 } else {
728 auto lb = merge_map_.lower_bound(merge_names_);
729 if (lb != merge_map_.end() && !merge_map_.key_comp()(merge_names_, lb->first)) {
730 value_name = lb->second;
731 } else {
732 value_name = gvn_->LookupValue(kMergeBlockNonAliasingIFieldVersionBumpOp, field_loc,
733 id_, kNoValue);
734 merge_map_.PutBefore(lb, merge_names_, value_name);
735 if (gvn_->NullCheckedInAllPredecessors(merge_names_)) {
736 null_checked_.insert(value_name);
737 }
738 }
739 }
740 non_aliasing_ifield_value_map_.PutBefore(hint, field_loc, value_name);
741 }
742
743 template <typename Map, Map LocalValueNumbering::*map_ptr, typename Versions>
MergeAliasingValues(const typename Map::value_type & entry,typename Map::iterator hint)744 void LocalValueNumbering::MergeAliasingValues(const typename Map::value_type& entry,
745 typename Map::iterator hint) {
746 const typename Map::key_type& key = entry.first;
747
748 auto it = (this->*map_ptr).PutBefore(hint, key, AliasingValues(this));
749 AliasingValues* my_values = &it->second;
750
751 const AliasingValues* cmp_values = nullptr;
752 bool same_version = !Versions::HasNewBaseVersion(gvn_, this, key);
753 uint16_t load_memory_version_for_same_version = kNoValue;
754 if (same_version) {
755 // Find the first non-null values.
756 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
757 auto it = (lvn->*map_ptr).find(key);
758 if (it != (lvn->*map_ptr).end()) {
759 cmp_values = &it->second;
760 break;
761 }
762 }
763 DCHECK(cmp_values != nullptr); // There must be at least one non-null values.
764
765 // Check if we have identical memory versions, i.e. the global memory version, unresolved
766 // field version and the values' memory_version_before_stores, last_stored_value
767 // and store_loc_set are identical.
768 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
769 auto it = (lvn->*map_ptr).find(key);
770 if (it == (lvn->*map_ptr).end()) {
771 if (cmp_values->memory_version_before_stores != kNoValue) {
772 same_version = false;
773 break;
774 }
775 } else if (cmp_values->last_stored_value != it->second.last_stored_value ||
776 cmp_values->memory_version_before_stores != it->second.memory_version_before_stores ||
777 cmp_values->store_loc_set != it->second.store_loc_set) {
778 same_version = false;
779 break;
780 } else if (it->second.last_load_memory_version != kNoValue) {
781 DCHECK(load_memory_version_for_same_version == kNoValue ||
782 load_memory_version_for_same_version == it->second.last_load_memory_version);
783 load_memory_version_for_same_version = it->second.last_load_memory_version;
784 }
785 }
786 }
787
788 if (same_version) {
789 // Copy the identical values.
790 my_values->memory_version_before_stores = cmp_values->memory_version_before_stores;
791 my_values->last_stored_value = cmp_values->last_stored_value;
792 my_values->store_loc_set = cmp_values->store_loc_set;
793 my_values->last_load_memory_version = load_memory_version_for_same_version;
794 // Merge load values seen in all incoming arcs (i.e. an intersection).
795 if (!cmp_values->load_value_map.empty()) {
796 my_values->load_value_map = cmp_values->load_value_map;
797 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
798 auto it = (lvn->*map_ptr).find(key);
799 if (it == (lvn->*map_ptr).end() || it->second.load_value_map.empty()) {
800 my_values->load_value_map.clear();
801 break;
802 }
803 InPlaceIntersectMaps(&my_values->load_value_map, it->second.load_value_map);
804 if (my_values->load_value_map.empty()) {
805 break;
806 }
807 }
808 }
809 } else {
810 // Bump version number for the merge.
811 my_values->memory_version_before_stores = my_values->last_load_memory_version =
812 Versions::LookupMergeBlockValue(gvn_, id_, key);
813
814 // Calculate the locations that have been either read from or written to in each incoming LVN.
815 bool first_lvn = true;
816 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
817 auto it = (lvn->*map_ptr).find(key);
818 if (it == (lvn->*map_ptr).end()) {
819 my_values->load_value_map.clear();
820 break;
821 }
822 if (first_lvn) {
823 first_lvn = false;
824 // Copy the first LVN's locations. Values will be overwritten later.
825 my_values->load_value_map = it->second.load_value_map;
826 for (uint16_t location : it->second.store_loc_set) {
827 my_values->load_value_map.Put(location, 0u);
828 }
829 } else {
830 IntersectAliasingValueLocations(my_values, &it->second);
831 }
832 }
833 // Calculate merged values for the intersection.
834 for (auto& load_value_entry : my_values->load_value_map) {
835 uint16_t location = load_value_entry.first;
836 bool same_values = true;
837 uint16_t value_name = kNoValue;
838 merge_names_.clear();
839 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
840 value_name = Versions::LookupMergeValue(gvn_, lvn, key, location);
841 same_values = same_values && (merge_names_.empty() || value_name == merge_names_.back());
842 merge_names_.push_back(value_name);
843 }
844 if (same_values) {
845 // value_name already contains the result.
846 } else {
847 auto lb = merge_map_.lower_bound(merge_names_);
848 if (lb != merge_map_.end() && !merge_map_.key_comp()(merge_names_, lb->first)) {
849 value_name = lb->second;
850 } else {
851 // NOTE: In addition to the key and id_ which don't change on an LVN recalculation
852 // during GVN, we also add location which can actually change on recalculation, so the
853 // value_name below may change. This could lead to an infinite loop if the location
854 // value name always changed when the refereced value name changes. However, given that
855 // we assign unique value names for other merges, such as Phis, such a dependency is
856 // not possible in a well-formed SSA graph.
857 value_name = Versions::LookupMergeLocationValue(gvn_, id_, key, location);
858 merge_map_.PutBefore(lb, merge_names_, value_name);
859 if (gvn_->NullCheckedInAllPredecessors(merge_names_)) {
860 null_checked_.insert(value_name);
861 }
862 }
863 }
864 load_value_entry.second = value_name;
865 }
866 }
867 }
868
Merge(MergeType merge_type)869 void LocalValueNumbering::Merge(MergeType merge_type) {
870 DCHECK_GE(gvn_->merge_lvns_.size(), 2u);
871
872 IntersectSregValueMaps<&LocalValueNumbering::sreg_value_map_>();
873 IntersectSregValueMaps<&LocalValueNumbering::sreg_wide_value_map_>();
874 if (merge_type == kReturnMerge) {
875 // RETURN or PHI+RETURN. We need only sreg value maps.
876 return;
877 }
878
879 MergeMemoryVersions(merge_type == kCatchMerge);
880
881 // Merge non-aliasing maps/sets.
882 IntersectSets<ValueNameSet, &LocalValueNumbering::non_aliasing_refs_>();
883 if (!non_aliasing_refs_.empty() && merge_type == kCatchMerge) {
884 PruneNonAliasingRefsForCatch();
885 }
886 if (!non_aliasing_refs_.empty()) {
887 MergeSets<IFieldLocToValueMap, &LocalValueNumbering::non_aliasing_ifield_value_map_,
888 &LocalValueNumbering::MergeNonAliasingIFieldValues>();
889 MergeSets<NonAliasingArrayValuesMap, &LocalValueNumbering::non_aliasing_array_value_map_,
890 &LocalValueNumbering::MergeAliasingValues<
891 NonAliasingArrayValuesMap, &LocalValueNumbering::non_aliasing_array_value_map_,
892 NonAliasingArrayVersions>>();
893 }
894
895 // We won't do anything complicated for range checks, just calculate the intersection.
896 IntersectSets<RangeCheckSet, &LocalValueNumbering::range_checked_>();
897
898 // Merge null_checked_. We may later insert more, such as merged object field values.
899 MergeSets<ValueNameSet, &LocalValueNumbering::null_checked_,
900 &LocalValueNumbering::MergeNullChecked>();
901
902 if (merge_type == kCatchMerge) {
903 // Memory is clobbered. New memory version already created, don't merge aliasing locations.
904 return;
905 }
906
907 DCHECK(merge_type == kNormalMerge);
908
909 // Merge escaped refs and clobber sets.
910 MergeSets<ValueNameSet, &LocalValueNumbering::escaped_refs_,
911 &LocalValueNumbering::MergeEscapedRefs>();
912 if (!escaped_refs_.empty()) {
913 MergeSets<EscapedIFieldClobberSet, &LocalValueNumbering::escaped_ifield_clobber_set_,
914 &LocalValueNumbering::MergeEscapedIFieldTypeClobberSets>();
915 MergeSets<EscapedIFieldClobberSet, &LocalValueNumbering::escaped_ifield_clobber_set_,
916 &LocalValueNumbering::MergeEscapedIFieldClobberSets>();
917 MergeSets<EscapedArrayClobberSet, &LocalValueNumbering::escaped_array_clobber_set_,
918 &LocalValueNumbering::MergeEscapedArrayClobberSets>();
919 }
920
921 MergeSets<SFieldToValueMap, &LocalValueNumbering::sfield_value_map_,
922 &LocalValueNumbering::MergeSFieldValues>();
923 MergeSets<AliasingIFieldValuesMap, &LocalValueNumbering::aliasing_ifield_value_map_,
924 &LocalValueNumbering::MergeAliasingValues<
925 AliasingIFieldValuesMap, &LocalValueNumbering::aliasing_ifield_value_map_,
926 AliasingIFieldVersions>>();
927 MergeSets<AliasingArrayValuesMap, &LocalValueNumbering::aliasing_array_value_map_,
928 &LocalValueNumbering::MergeAliasingValues<
929 AliasingArrayValuesMap, &LocalValueNumbering::aliasing_array_value_map_,
930 AliasingArrayVersions>>();
931 }
932
MarkNonAliasingNonNull(MIR * mir)933 uint16_t LocalValueNumbering::MarkNonAliasingNonNull(MIR* mir) {
934 uint16_t res = GetOperandValue(mir->ssa_rep->defs[0]);
935 DCHECK(null_checked_.find(res) == null_checked_.end());
936 null_checked_.insert(res);
937 non_aliasing_refs_.insert(res);
938 return res;
939 }
940
IsNonAliasing(uint16_t reg) const941 bool LocalValueNumbering::IsNonAliasing(uint16_t reg) const {
942 return non_aliasing_refs_.find(reg) != non_aliasing_refs_.end();
943 }
944
IsNonAliasingIField(uint16_t reg,uint16_t field_id,uint16_t type) const945 bool LocalValueNumbering::IsNonAliasingIField(uint16_t reg, uint16_t field_id,
946 uint16_t type) const {
947 if (IsNonAliasing(reg)) {
948 return true;
949 }
950 if (escaped_refs_.find(reg) == escaped_refs_.end()) {
951 return false;
952 }
953 // Check for IPUTs to unresolved fields.
954 EscapedIFieldClobberKey key1 = { reg, type, kNoValue };
955 if (escaped_ifield_clobber_set_.find(key1) != escaped_ifield_clobber_set_.end()) {
956 return false;
957 }
958 // Check for aliased IPUTs to the same field.
959 EscapedIFieldClobberKey key2 = { reg, type, field_id };
960 return escaped_ifield_clobber_set_.find(key2) == escaped_ifield_clobber_set_.end();
961 }
962
IsNonAliasingArray(uint16_t reg,uint16_t type) const963 bool LocalValueNumbering::IsNonAliasingArray(uint16_t reg, uint16_t type) const {
964 if (IsNonAliasing(reg)) {
965 return true;
966 }
967 if (escaped_refs_.count(reg) == 0u) {
968 return false;
969 }
970 // Check for aliased APUTs.
971 EscapedArrayClobberKey key = { reg, type };
972 return escaped_array_clobber_set_.find(key) == escaped_array_clobber_set_.end();
973 }
974
HandleNullCheck(MIR * mir,uint16_t reg)975 void LocalValueNumbering::HandleNullCheck(MIR* mir, uint16_t reg) {
976 auto lb = null_checked_.lower_bound(reg);
977 if (lb != null_checked_.end() && *lb == reg) {
978 if (LIKELY(gvn_->CanModify())) {
979 if (gvn_->GetCompilationUnit()->verbose) {
980 LOG(INFO) << "Removing null check for 0x" << std::hex << mir->offset;
981 }
982 mir->optimization_flags |= MIR_IGNORE_NULL_CHECK;
983 }
984 } else {
985 null_checked_.insert(lb, reg);
986 }
987 }
988
HandleRangeCheck(MIR * mir,uint16_t array,uint16_t index)989 void LocalValueNumbering::HandleRangeCheck(MIR* mir, uint16_t array, uint16_t index) {
990 RangeCheckKey key = { array, index };
991 auto lb = range_checked_.lower_bound(key);
992 if (lb != range_checked_.end() && !RangeCheckKeyComparator()(key, *lb)) {
993 if (LIKELY(gvn_->CanModify())) {
994 if (gvn_->GetCompilationUnit()->verbose) {
995 LOG(INFO) << "Removing range check for 0x" << std::hex << mir->offset;
996 }
997 mir->optimization_flags |= MIR_IGNORE_RANGE_CHECK;
998 }
999 } else {
1000 // Mark range check completed.
1001 range_checked_.insert(lb, key);
1002 }
1003 }
1004
HandlePutObject(MIR * mir)1005 void LocalValueNumbering::HandlePutObject(MIR* mir) {
1006 // If we're storing a non-aliasing reference, stop tracking it as non-aliasing now.
1007 uint16_t base = GetOperandValue(mir->ssa_rep->uses[0]);
1008 HandleEscapingRef(base);
1009 }
1010
HandleEscapingRef(uint16_t base)1011 void LocalValueNumbering::HandleEscapingRef(uint16_t base) {
1012 auto it = non_aliasing_refs_.find(base);
1013 if (it != non_aliasing_refs_.end()) {
1014 non_aliasing_refs_.erase(it);
1015 escaped_refs_.insert(base);
1016 }
1017 }
1018
HandlePhi(MIR * mir)1019 uint16_t LocalValueNumbering::HandlePhi(MIR* mir) {
1020 if (gvn_->merge_lvns_.empty()) {
1021 // Running LVN without a full GVN?
1022 return kNoValue;
1023 }
1024 int16_t num_uses = mir->ssa_rep->num_uses;
1025 int32_t* uses = mir->ssa_rep->uses;
1026 // Try to find out if this is merging wide regs.
1027 if (mir->ssa_rep->defs[0] != 0 &&
1028 sreg_wide_value_map_.count(mir->ssa_rep->defs[0] - 1) != 0u) {
1029 // This is the high part of a wide reg. Ignore the Phi.
1030 return kNoValue;
1031 }
1032 bool wide = false;
1033 for (int16_t i = 0; i != num_uses; ++i) {
1034 if (sreg_wide_value_map_.count(uses[i]) != 0u) {
1035 wide = true;
1036 break;
1037 }
1038 }
1039 // Iterate over *merge_lvns_ and skip incoming sregs for BBs without associated LVN.
1040 uint16_t value_name = kNoValue;
1041 merge_names_.clear();
1042 BasicBlockId* incoming = mir->meta.phi_incoming;
1043 int16_t pos = 0;
1044 bool same_values = true;
1045 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
1046 DCHECK_LT(pos, mir->ssa_rep->num_uses);
1047 while (incoming[pos] != lvn->Id()) {
1048 ++pos;
1049 DCHECK_LT(pos, mir->ssa_rep->num_uses);
1050 }
1051 int s_reg = uses[pos];
1052 ++pos;
1053 value_name = wide ? lvn->GetOperandValueWide(s_reg) : lvn->GetOperandValue(s_reg);
1054
1055 same_values = same_values && (merge_names_.empty() || value_name == merge_names_.back());
1056 merge_names_.push_back(value_name);
1057 }
1058 if (same_values) {
1059 // value_name already contains the result.
1060 } else {
1061 auto lb = merge_map_.lower_bound(merge_names_);
1062 if (lb != merge_map_.end() && !merge_map_.key_comp()(merge_names_, lb->first)) {
1063 value_name = lb->second;
1064 } else {
1065 value_name = gvn_->LookupValue(kNoValue, mir->ssa_rep->defs[0], kNoValue, kNoValue);
1066 merge_map_.PutBefore(lb, merge_names_, value_name);
1067 if (!wide && gvn_->NullCheckedInAllPredecessors(merge_names_)) {
1068 null_checked_.insert(value_name);
1069 }
1070 }
1071 }
1072 if (wide) {
1073 SetOperandValueWide(mir->ssa_rep->defs[0], value_name);
1074 } else {
1075 SetOperandValue(mir->ssa_rep->defs[0], value_name);
1076 }
1077 return value_name;
1078 }
1079
HandleAGet(MIR * mir,uint16_t opcode)1080 uint16_t LocalValueNumbering::HandleAGet(MIR* mir, uint16_t opcode) {
1081 // uint16_t type = opcode - Instruction::AGET;
1082 uint16_t array = GetOperandValue(mir->ssa_rep->uses[0]);
1083 HandleNullCheck(mir, array);
1084 uint16_t index = GetOperandValue(mir->ssa_rep->uses[1]);
1085 HandleRangeCheck(mir, array, index);
1086 uint16_t type = opcode - Instruction::AGET;
1087 // Establish value number for loaded register.
1088 uint16_t res;
1089 if (IsNonAliasingArray(array, type)) {
1090 res = HandleAliasingValuesGet<NonAliasingArrayVersions>(&non_aliasing_array_value_map_,
1091 array, index);
1092 } else {
1093 uint16_t location = gvn_->GetArrayLocation(array, index);
1094 res = HandleAliasingValuesGet<AliasingArrayVersions>(&aliasing_array_value_map_,
1095 type, location);
1096 }
1097 if (opcode == Instruction::AGET_WIDE) {
1098 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1099 } else {
1100 SetOperandValue(mir->ssa_rep->defs[0], res);
1101 }
1102 return res;
1103 }
1104
HandleAPut(MIR * mir,uint16_t opcode)1105 void LocalValueNumbering::HandleAPut(MIR* mir, uint16_t opcode) {
1106 int array_idx = (opcode == Instruction::APUT_WIDE) ? 2 : 1;
1107 int index_idx = array_idx + 1;
1108 uint16_t array = GetOperandValue(mir->ssa_rep->uses[array_idx]);
1109 HandleNullCheck(mir, array);
1110 uint16_t index = GetOperandValue(mir->ssa_rep->uses[index_idx]);
1111 HandleRangeCheck(mir, array, index);
1112
1113 uint16_t type = opcode - Instruction::APUT;
1114 uint16_t value = (opcode == Instruction::APUT_WIDE)
1115 ? GetOperandValueWide(mir->ssa_rep->uses[0])
1116 : GetOperandValue(mir->ssa_rep->uses[0]);
1117 if (IsNonAliasing(array)) {
1118 bool put_is_live = HandleAliasingValuesPut<NonAliasingArrayVersions>(
1119 &non_aliasing_array_value_map_, array, index, value);
1120 if (!put_is_live) {
1121 // This APUT can be eliminated, it stores the same value that's already in the field.
1122 // TODO: Eliminate the APUT.
1123 return;
1124 }
1125 } else {
1126 uint16_t location = gvn_->GetArrayLocation(array, index);
1127 bool put_is_live = HandleAliasingValuesPut<AliasingArrayVersions>(
1128 &aliasing_array_value_map_, type, location, value);
1129 if (!put_is_live) {
1130 // This APUT can be eliminated, it stores the same value that's already in the field.
1131 // TODO: Eliminate the APUT.
1132 return;
1133 }
1134
1135 // Clobber all escaped array refs for this type.
1136 for (uint16_t escaped_array : escaped_refs_) {
1137 EscapedArrayClobberKey clobber_key = { escaped_array, type };
1138 escaped_array_clobber_set_.insert(clobber_key);
1139 }
1140 }
1141 }
1142
HandleIGet(MIR * mir,uint16_t opcode)1143 uint16_t LocalValueNumbering::HandleIGet(MIR* mir, uint16_t opcode) {
1144 uint16_t base = GetOperandValue(mir->ssa_rep->uses[0]);
1145 HandleNullCheck(mir, base);
1146 const MirFieldInfo& field_info = gvn_->GetMirGraph()->GetIFieldLoweringInfo(mir);
1147 uint16_t res;
1148 if (!field_info.IsResolved() || field_info.IsVolatile()) {
1149 // Volatile fields always get a new memory version; field id is irrelevant.
1150 // Unresolved fields may be volatile, so handle them as such to be safe.
1151 // Use result s_reg - will be unique.
1152 res = gvn_->LookupValue(kNoValue, mir->ssa_rep->defs[0], kNoValue, kNoValue);
1153 } else {
1154 uint16_t type = opcode - Instruction::IGET;
1155 uint16_t field_id = gvn_->GetFieldId(field_info, type);
1156 if (IsNonAliasingIField(base, field_id, type)) {
1157 uint16_t loc = gvn_->LookupValue(kNonAliasingIFieldLocOp, base, field_id, type);
1158 auto lb = non_aliasing_ifield_value_map_.lower_bound(loc);
1159 if (lb != non_aliasing_ifield_value_map_.end() && lb->first == loc) {
1160 res = lb->second;
1161 } else {
1162 res = gvn_->LookupValue(kNonAliasingIFieldInitialOp, loc, kNoValue, kNoValue);
1163 non_aliasing_ifield_value_map_.PutBefore(lb, loc, res);
1164 }
1165 } else {
1166 res = HandleAliasingValuesGet<AliasingIFieldVersions>(&aliasing_ifield_value_map_,
1167 field_id, base);
1168 }
1169 }
1170 if (opcode == Instruction::IGET_WIDE) {
1171 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1172 } else {
1173 SetOperandValue(mir->ssa_rep->defs[0], res);
1174 }
1175 return res;
1176 }
1177
HandleIPut(MIR * mir,uint16_t opcode)1178 void LocalValueNumbering::HandleIPut(MIR* mir, uint16_t opcode) {
1179 uint16_t type = opcode - Instruction::IPUT;
1180 int base_reg = (opcode == Instruction::IPUT_WIDE) ? 2 : 1;
1181 uint16_t base = GetOperandValue(mir->ssa_rep->uses[base_reg]);
1182 HandleNullCheck(mir, base);
1183 const MirFieldInfo& field_info = gvn_->GetMirGraph()->GetIFieldLoweringInfo(mir);
1184 if (!field_info.IsResolved()) {
1185 // Unresolved fields always alias with everything of the same type.
1186 // Use mir->offset as modifier; without elaborate inlining, it will be unique.
1187 unresolved_ifield_version_[type] =
1188 gvn_->LookupValue(kUnresolvedIFieldOp, kNoValue, kNoValue, mir->offset);
1189
1190 // For simplicity, treat base as escaped now.
1191 HandleEscapingRef(base);
1192
1193 // Clobber all fields of escaped references of the same type.
1194 for (uint16_t escaped_ref : escaped_refs_) {
1195 EscapedIFieldClobberKey clobber_key = { escaped_ref, type, kNoValue };
1196 escaped_ifield_clobber_set_.insert(clobber_key);
1197 }
1198
1199 // Aliasing fields of the same type may have been overwritten.
1200 auto it = aliasing_ifield_value_map_.begin(), end = aliasing_ifield_value_map_.end();
1201 while (it != end) {
1202 if (gvn_->GetFieldType(it->first) != type) {
1203 ++it;
1204 } else {
1205 it = aliasing_ifield_value_map_.erase(it);
1206 }
1207 }
1208 } else if (field_info.IsVolatile()) {
1209 // Nothing to do, resolved volatile fields always get a new memory version anyway and
1210 // can't alias with resolved non-volatile fields.
1211 } else {
1212 uint16_t field_id = gvn_->GetFieldId(field_info, type);
1213 uint16_t value = (opcode == Instruction::IPUT_WIDE)
1214 ? GetOperandValueWide(mir->ssa_rep->uses[0])
1215 : GetOperandValue(mir->ssa_rep->uses[0]);
1216 if (IsNonAliasing(base)) {
1217 uint16_t loc = gvn_->LookupValue(kNonAliasingIFieldLocOp, base, field_id, type);
1218 auto lb = non_aliasing_ifield_value_map_.lower_bound(loc);
1219 if (lb != non_aliasing_ifield_value_map_.end() && lb->first == loc) {
1220 if (lb->second == value) {
1221 // This IPUT can be eliminated, it stores the same value that's already in the field.
1222 // TODO: Eliminate the IPUT.
1223 return;
1224 }
1225 lb->second = value; // Overwrite.
1226 } else {
1227 non_aliasing_ifield_value_map_.PutBefore(lb, loc, value);
1228 }
1229 } else {
1230 bool put_is_live = HandleAliasingValuesPut<AliasingIFieldVersions>(
1231 &aliasing_ifield_value_map_, field_id, base, value);
1232 if (!put_is_live) {
1233 // This IPUT can be eliminated, it stores the same value that's already in the field.
1234 // TODO: Eliminate the IPUT.
1235 return;
1236 }
1237
1238 // Clobber all fields of escaped references for this field.
1239 for (uint16_t escaped_ref : escaped_refs_) {
1240 EscapedIFieldClobberKey clobber_key = { escaped_ref, type, field_id };
1241 escaped_ifield_clobber_set_.insert(clobber_key);
1242 }
1243 }
1244 }
1245 }
1246
HandleSGet(MIR * mir,uint16_t opcode)1247 uint16_t LocalValueNumbering::HandleSGet(MIR* mir, uint16_t opcode) {
1248 const MirSFieldLoweringInfo& field_info = gvn_->GetMirGraph()->GetSFieldLoweringInfo(mir);
1249 if (!field_info.IsInitialized() && (mir->optimization_flags & MIR_IGNORE_CLINIT_CHECK) == 0) {
1250 // Class initialization can call arbitrary functions, we need to wipe aliasing values.
1251 HandleInvokeOrClInit(mir);
1252 }
1253 uint16_t res;
1254 if (!field_info.IsResolved() || field_info.IsVolatile()) {
1255 // Volatile fields always get a new memory version; field id is irrelevant.
1256 // Unresolved fields may be volatile, so handle them as such to be safe.
1257 // Use result s_reg - will be unique.
1258 res = gvn_->LookupValue(kNoValue, mir->ssa_rep->defs[0], kNoValue, kNoValue);
1259 } else {
1260 uint16_t type = opcode - Instruction::SGET;
1261 uint16_t field_id = gvn_->GetFieldId(field_info, type);
1262 auto lb = sfield_value_map_.lower_bound(field_id);
1263 if (lb != sfield_value_map_.end() && lb->first == field_id) {
1264 res = lb->second;
1265 } else {
1266 // Resolved non-volatile static fields can alias with non-resolved fields of the same type,
1267 // so we need to use unresolved_sfield_version_[type] in addition to global_memory_version_
1268 // to determine the version of the field.
1269 res = gvn_->LookupValue(kResolvedSFieldOp, field_id,
1270 unresolved_sfield_version_[type], global_memory_version_);
1271 sfield_value_map_.PutBefore(lb, field_id, res);
1272 }
1273 }
1274 if (opcode == Instruction::SGET_WIDE) {
1275 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1276 } else {
1277 SetOperandValue(mir->ssa_rep->defs[0], res);
1278 }
1279 return res;
1280 }
1281
HandleSPut(MIR * mir,uint16_t opcode)1282 void LocalValueNumbering::HandleSPut(MIR* mir, uint16_t opcode) {
1283 const MirSFieldLoweringInfo& field_info = gvn_->GetMirGraph()->GetSFieldLoweringInfo(mir);
1284 if (!field_info.IsInitialized() && (mir->optimization_flags & MIR_IGNORE_CLINIT_CHECK) == 0) {
1285 // Class initialization can call arbitrary functions, we need to wipe aliasing values.
1286 HandleInvokeOrClInit(mir);
1287 }
1288 uint16_t type = opcode - Instruction::SPUT;
1289 if (!field_info.IsResolved()) {
1290 // Unresolved fields always alias with everything of the same type.
1291 // Use mir->offset as modifier; without elaborate inlining, it will be unique.
1292 unresolved_sfield_version_[type] =
1293 gvn_->LookupValue(kUnresolvedSFieldOp, kNoValue, kNoValue, mir->offset);
1294 RemoveSFieldsForType(type);
1295 } else if (field_info.IsVolatile()) {
1296 // Nothing to do, resolved volatile fields always get a new memory version anyway and
1297 // can't alias with resolved non-volatile fields.
1298 } else {
1299 uint16_t field_id = gvn_->GetFieldId(field_info, type);
1300 uint16_t value = (opcode == Instruction::SPUT_WIDE)
1301 ? GetOperandValueWide(mir->ssa_rep->uses[0])
1302 : GetOperandValue(mir->ssa_rep->uses[0]);
1303 // Resolved non-volatile static fields can alias with non-resolved fields of the same type,
1304 // so we need to use unresolved_sfield_version_[type] in addition to global_memory_version_
1305 // to determine the version of the field.
1306 auto lb = sfield_value_map_.lower_bound(field_id);
1307 if (lb != sfield_value_map_.end() && lb->first == field_id) {
1308 if (lb->second == value) {
1309 // This SPUT can be eliminated, it stores the same value that's already in the field.
1310 // TODO: Eliminate the SPUT.
1311 return;
1312 }
1313 lb->second = value; // Overwrite.
1314 } else {
1315 sfield_value_map_.PutBefore(lb, field_id, value);
1316 }
1317 }
1318 }
1319
RemoveSFieldsForType(uint16_t type)1320 void LocalValueNumbering::RemoveSFieldsForType(uint16_t type) {
1321 // Erase all static fields of this type from the sfield_value_map_.
1322 for (auto it = sfield_value_map_.begin(), end = sfield_value_map_.end(); it != end; ) {
1323 if (gvn_->GetFieldType(it->first) == type) {
1324 it = sfield_value_map_.erase(it);
1325 } else {
1326 ++it;
1327 }
1328 }
1329 }
1330
HandleInvokeOrClInit(MIR * mir)1331 void LocalValueNumbering::HandleInvokeOrClInit(MIR* mir) {
1332 // Use mir->offset as modifier; without elaborate inlining, it will be unique.
1333 global_memory_version_ =
1334 gvn_->LookupValue(kInvokeMemoryVersionBumpOp, 0u, 0u, mir->offset);
1335 // All static fields and instance fields and array elements of aliasing references,
1336 // including escaped references, may have been modified.
1337 sfield_value_map_.clear();
1338 aliasing_ifield_value_map_.clear();
1339 aliasing_array_value_map_.clear();
1340 escaped_refs_.clear();
1341 escaped_ifield_clobber_set_.clear();
1342 escaped_array_clobber_set_.clear();
1343 }
1344
GetValueNumber(MIR * mir)1345 uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
1346 uint16_t res = kNoValue;
1347 uint16_t opcode = mir->dalvikInsn.opcode;
1348 switch (opcode) {
1349 case Instruction::NOP:
1350 case Instruction::RETURN_VOID:
1351 case Instruction::RETURN:
1352 case Instruction::RETURN_OBJECT:
1353 case Instruction::RETURN_WIDE:
1354 case Instruction::GOTO:
1355 case Instruction::GOTO_16:
1356 case Instruction::GOTO_32:
1357 case Instruction::CHECK_CAST:
1358 case Instruction::THROW:
1359 case Instruction::FILL_ARRAY_DATA:
1360 case Instruction::PACKED_SWITCH:
1361 case Instruction::SPARSE_SWITCH:
1362 case Instruction::IF_EQ:
1363 case Instruction::IF_NE:
1364 case Instruction::IF_LT:
1365 case Instruction::IF_GE:
1366 case Instruction::IF_GT:
1367 case Instruction::IF_LE:
1368 case Instruction::IF_EQZ:
1369 case Instruction::IF_NEZ:
1370 case Instruction::IF_LTZ:
1371 case Instruction::IF_GEZ:
1372 case Instruction::IF_GTZ:
1373 case Instruction::IF_LEZ:
1374 case kMirOpFusedCmplFloat:
1375 case kMirOpFusedCmpgFloat:
1376 case kMirOpFusedCmplDouble:
1377 case kMirOpFusedCmpgDouble:
1378 case kMirOpFusedCmpLong:
1379 // Nothing defined - take no action.
1380 break;
1381
1382 case Instruction::MONITOR_ENTER:
1383 HandleNullCheck(mir, GetOperandValue(mir->ssa_rep->uses[0]));
1384 // NOTE: Keeping all aliasing values intact. Programs that rely on loads/stores of the
1385 // same non-volatile locations outside and inside a synchronized block being different
1386 // contain races that we cannot fix.
1387 break;
1388
1389 case Instruction::MONITOR_EXIT:
1390 HandleNullCheck(mir, GetOperandValue(mir->ssa_rep->uses[0]));
1391 // If we're running GVN and CanModify(), uneliminated null check indicates bytecode error.
1392 if ((gvn_->GetCompilationUnit()->disable_opt & (1u << kGlobalValueNumbering)) == 0u &&
1393 gvn_->CanModify() && (mir->optimization_flags & MIR_IGNORE_NULL_CHECK) == 0) {
1394 LOG(WARNING) << "Bytecode error: MONITOR_EXIT is still null checked at 0x" << std::hex
1395 << mir->offset << " in " << PrettyMethod(gvn_->cu_->method_idx, *gvn_->cu_->dex_file);
1396 }
1397 break;
1398
1399 case Instruction::FILLED_NEW_ARRAY:
1400 case Instruction::FILLED_NEW_ARRAY_RANGE:
1401 // Nothing defined but the result will be unique and non-null.
1402 if (mir->next != nullptr && mir->next->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT) {
1403 uint16_t array = MarkNonAliasingNonNull(mir->next);
1404 // Do not SetOperandValue(), we'll do that when we process the MOVE_RESULT_OBJECT.
1405 if (kLocalValueNumberingEnableFilledNewArrayTracking && mir->ssa_rep->num_uses != 0u) {
1406 AliasingValues* values = GetAliasingValues(&non_aliasing_array_value_map_, array);
1407 // Clear the value if we got a merged version in a loop.
1408 *values = AliasingValues(this);
1409 for (size_t i = 0u, count = mir->ssa_rep->num_uses; i != count; ++i) {
1410 DCHECK_EQ(High16Bits(i), 0u);
1411 uint16_t index = gvn_->LookupValue(Instruction::CONST, i, 0u, 0);
1412 uint16_t value = GetOperandValue(mir->ssa_rep->uses[i]);
1413 values->load_value_map.Put(index, value);
1414 RangeCheckKey key = { array, index };
1415 range_checked_.insert(key);
1416 }
1417 }
1418 // The MOVE_RESULT_OBJECT will be processed next and we'll return the value name then.
1419 }
1420 // All args escaped (if references).
1421 for (size_t i = 0u, count = mir->ssa_rep->num_uses; i != count; ++i) {
1422 uint16_t reg = GetOperandValue(mir->ssa_rep->uses[i]);
1423 HandleEscapingRef(reg);
1424 }
1425 break;
1426
1427 case Instruction::INVOKE_DIRECT:
1428 case Instruction::INVOKE_DIRECT_RANGE:
1429 case Instruction::INVOKE_VIRTUAL:
1430 case Instruction::INVOKE_VIRTUAL_RANGE:
1431 case Instruction::INVOKE_SUPER:
1432 case Instruction::INVOKE_SUPER_RANGE:
1433 case Instruction::INVOKE_INTERFACE:
1434 case Instruction::INVOKE_INTERFACE_RANGE: {
1435 // Nothing defined but handle the null check.
1436 uint16_t reg = GetOperandValue(mir->ssa_rep->uses[0]);
1437 HandleNullCheck(mir, reg);
1438 }
1439 // Intentional fall-through.
1440 case Instruction::INVOKE_STATIC:
1441 case Instruction::INVOKE_STATIC_RANGE:
1442 if ((mir->optimization_flags & MIR_INLINED) == 0) {
1443 // Make ref args aliasing.
1444 for (size_t i = 0u, count = mir->ssa_rep->num_uses; i != count; ++i) {
1445 uint16_t reg = GetOperandValue(mir->ssa_rep->uses[i]);
1446 non_aliasing_refs_.erase(reg);
1447 }
1448 HandleInvokeOrClInit(mir);
1449 }
1450 break;
1451
1452 case Instruction::MOVE_RESULT:
1453 case Instruction::MOVE_RESULT_OBJECT:
1454 case Instruction::INSTANCE_OF:
1455 // 1 result, treat as unique each time, use result s_reg - will be unique.
1456 res = GetOperandValue(mir->ssa_rep->defs[0]);
1457 SetOperandValue(mir->ssa_rep->defs[0], res);
1458 break;
1459 case Instruction::MOVE_EXCEPTION:
1460 case Instruction::NEW_INSTANCE:
1461 case Instruction::CONST_CLASS:
1462 case Instruction::NEW_ARRAY:
1463 // 1 result, treat as unique each time, use result s_reg - will be unique.
1464 res = MarkNonAliasingNonNull(mir);
1465 SetOperandValue(mir->ssa_rep->defs[0], res);
1466 break;
1467 case Instruction::CONST_STRING:
1468 case Instruction::CONST_STRING_JUMBO:
1469 // These strings are internalized, so assign value based on the string pool index.
1470 res = gvn_->LookupValue(Instruction::CONST_STRING, Low16Bits(mir->dalvikInsn.vB),
1471 High16Bits(mir->dalvikInsn.vB), 0);
1472 SetOperandValue(mir->ssa_rep->defs[0], res);
1473 null_checked_.insert(res); // May already be there.
1474 // NOTE: Hacking the contents of an internalized string via reflection is possible
1475 // but the behavior is undefined. Therefore, we consider the string constant and
1476 // the reference non-aliasing.
1477 // TUNING: We could keep this property even if the reference "escapes".
1478 non_aliasing_refs_.insert(res); // May already be there.
1479 break;
1480 case Instruction::MOVE_RESULT_WIDE:
1481 // 1 wide result, treat as unique each time, use result s_reg - will be unique.
1482 res = GetOperandValueWide(mir->ssa_rep->defs[0]);
1483 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1484 break;
1485
1486 case kMirOpPhi:
1487 res = HandlePhi(mir);
1488 break;
1489
1490 case Instruction::MOVE:
1491 case Instruction::MOVE_OBJECT:
1492 case Instruction::MOVE_16:
1493 case Instruction::MOVE_OBJECT_16:
1494 case Instruction::MOVE_FROM16:
1495 case Instruction::MOVE_OBJECT_FROM16:
1496 case kMirOpCopy:
1497 // Just copy value number of source to value number of result.
1498 res = GetOperandValue(mir->ssa_rep->uses[0]);
1499 SetOperandValue(mir->ssa_rep->defs[0], res);
1500 break;
1501
1502 case Instruction::MOVE_WIDE:
1503 case Instruction::MOVE_WIDE_16:
1504 case Instruction::MOVE_WIDE_FROM16:
1505 // Just copy value number of source to value number of result.
1506 res = GetOperandValueWide(mir->ssa_rep->uses[0]);
1507 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1508 break;
1509
1510 case Instruction::CONST:
1511 case Instruction::CONST_4:
1512 case Instruction::CONST_16:
1513 res = gvn_->LookupValue(Instruction::CONST, Low16Bits(mir->dalvikInsn.vB),
1514 High16Bits(mir->dalvikInsn.vB), 0);
1515 SetOperandValue(mir->ssa_rep->defs[0], res);
1516 break;
1517
1518 case Instruction::CONST_HIGH16:
1519 res = gvn_->LookupValue(Instruction::CONST, 0, mir->dalvikInsn.vB, 0);
1520 SetOperandValue(mir->ssa_rep->defs[0], res);
1521 break;
1522
1523 case Instruction::CONST_WIDE_16:
1524 case Instruction::CONST_WIDE_32: {
1525 uint16_t low_res = gvn_->LookupValue(Instruction::CONST, Low16Bits(mir->dalvikInsn.vB),
1526 High16Bits(mir->dalvikInsn.vB >> 16), 1);
1527 uint16_t high_res;
1528 if (mir->dalvikInsn.vB & 0x80000000) {
1529 high_res = gvn_->LookupValue(Instruction::CONST, 0xffff, 0xffff, 2);
1530 } else {
1531 high_res = gvn_->LookupValue(Instruction::CONST, 0, 0, 2);
1532 }
1533 res = gvn_->LookupValue(Instruction::CONST, low_res, high_res, 3);
1534 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1535 }
1536 break;
1537
1538 case Instruction::CONST_WIDE: {
1539 uint32_t low_word = Low32Bits(mir->dalvikInsn.vB_wide);
1540 uint32_t high_word = High32Bits(mir->dalvikInsn.vB_wide);
1541 uint16_t low_res = gvn_->LookupValue(Instruction::CONST, Low16Bits(low_word),
1542 High16Bits(low_word), 1);
1543 uint16_t high_res = gvn_->LookupValue(Instruction::CONST, Low16Bits(high_word),
1544 High16Bits(high_word), 2);
1545 res = gvn_->LookupValue(Instruction::CONST, low_res, high_res, 3);
1546 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1547 }
1548 break;
1549
1550 case Instruction::CONST_WIDE_HIGH16: {
1551 uint16_t low_res = gvn_->LookupValue(Instruction::CONST, 0, 0, 1);
1552 uint16_t high_res = gvn_->LookupValue(Instruction::CONST, 0,
1553 Low16Bits(mir->dalvikInsn.vB), 2);
1554 res = gvn_->LookupValue(Instruction::CONST, low_res, high_res, 3);
1555 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1556 }
1557 break;
1558
1559 case Instruction::ARRAY_LENGTH: {
1560 // Handle the null check.
1561 uint16_t reg = GetOperandValue(mir->ssa_rep->uses[0]);
1562 HandleNullCheck(mir, reg);
1563 }
1564 // Intentional fall-through.
1565 case Instruction::NEG_INT:
1566 case Instruction::NOT_INT:
1567 case Instruction::NEG_FLOAT:
1568 case Instruction::INT_TO_BYTE:
1569 case Instruction::INT_TO_SHORT:
1570 case Instruction::INT_TO_CHAR:
1571 case Instruction::INT_TO_FLOAT:
1572 case Instruction::FLOAT_TO_INT: {
1573 // res = op + 1 operand
1574 uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
1575 res = gvn_->LookupValue(opcode, operand1, kNoValue, kNoValue);
1576 SetOperandValue(mir->ssa_rep->defs[0], res);
1577 }
1578 break;
1579
1580 case Instruction::LONG_TO_FLOAT:
1581 case Instruction::LONG_TO_INT:
1582 case Instruction::DOUBLE_TO_FLOAT:
1583 case Instruction::DOUBLE_TO_INT: {
1584 // res = op + 1 wide operand
1585 uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
1586 res = gvn_->LookupValue(opcode, operand1, kNoValue, kNoValue);
1587 SetOperandValue(mir->ssa_rep->defs[0], res);
1588 }
1589 break;
1590
1591
1592 case Instruction::DOUBLE_TO_LONG:
1593 case Instruction::LONG_TO_DOUBLE:
1594 case Instruction::NEG_LONG:
1595 case Instruction::NOT_LONG:
1596 case Instruction::NEG_DOUBLE: {
1597 // wide res = op + 1 wide operand
1598 uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
1599 res = gvn_->LookupValue(opcode, operand1, kNoValue, kNoValue);
1600 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1601 }
1602 break;
1603
1604 case Instruction::FLOAT_TO_DOUBLE:
1605 case Instruction::FLOAT_TO_LONG:
1606 case Instruction::INT_TO_DOUBLE:
1607 case Instruction::INT_TO_LONG: {
1608 // wide res = op + 1 operand
1609 uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
1610 res = gvn_->LookupValue(opcode, operand1, kNoValue, kNoValue);
1611 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1612 }
1613 break;
1614
1615 case Instruction::CMPL_DOUBLE:
1616 case Instruction::CMPG_DOUBLE:
1617 case Instruction::CMP_LONG: {
1618 // res = op + 2 wide operands
1619 uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
1620 uint16_t operand2 = GetOperandValueWide(mir->ssa_rep->uses[2]);
1621 res = gvn_->LookupValue(opcode, operand1, operand2, kNoValue);
1622 SetOperandValue(mir->ssa_rep->defs[0], res);
1623 }
1624 break;
1625
1626 case Instruction::CMPG_FLOAT:
1627 case Instruction::CMPL_FLOAT:
1628 case Instruction::ADD_INT:
1629 case Instruction::ADD_INT_2ADDR:
1630 case Instruction::MUL_INT:
1631 case Instruction::MUL_INT_2ADDR:
1632 case Instruction::AND_INT:
1633 case Instruction::AND_INT_2ADDR:
1634 case Instruction::OR_INT:
1635 case Instruction::OR_INT_2ADDR:
1636 case Instruction::XOR_INT:
1637 case Instruction::XOR_INT_2ADDR:
1638 case Instruction::SUB_INT:
1639 case Instruction::SUB_INT_2ADDR:
1640 case Instruction::DIV_INT:
1641 case Instruction::DIV_INT_2ADDR:
1642 case Instruction::REM_INT:
1643 case Instruction::REM_INT_2ADDR:
1644 case Instruction::SHL_INT:
1645 case Instruction::SHL_INT_2ADDR:
1646 case Instruction::SHR_INT:
1647 case Instruction::SHR_INT_2ADDR:
1648 case Instruction::USHR_INT:
1649 case Instruction::USHR_INT_2ADDR: {
1650 // res = op + 2 operands
1651 uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
1652 uint16_t operand2 = GetOperandValue(mir->ssa_rep->uses[1]);
1653 res = gvn_->LookupValue(opcode, operand1, operand2, kNoValue);
1654 SetOperandValue(mir->ssa_rep->defs[0], res);
1655 }
1656 break;
1657
1658 case Instruction::ADD_LONG:
1659 case Instruction::SUB_LONG:
1660 case Instruction::MUL_LONG:
1661 case Instruction::DIV_LONG:
1662 case Instruction::REM_LONG:
1663 case Instruction::AND_LONG:
1664 case Instruction::OR_LONG:
1665 case Instruction::XOR_LONG:
1666 case Instruction::ADD_LONG_2ADDR:
1667 case Instruction::SUB_LONG_2ADDR:
1668 case Instruction::MUL_LONG_2ADDR:
1669 case Instruction::DIV_LONG_2ADDR:
1670 case Instruction::REM_LONG_2ADDR:
1671 case Instruction::AND_LONG_2ADDR:
1672 case Instruction::OR_LONG_2ADDR:
1673 case Instruction::XOR_LONG_2ADDR:
1674 case Instruction::ADD_DOUBLE:
1675 case Instruction::SUB_DOUBLE:
1676 case Instruction::MUL_DOUBLE:
1677 case Instruction::DIV_DOUBLE:
1678 case Instruction::REM_DOUBLE:
1679 case Instruction::ADD_DOUBLE_2ADDR:
1680 case Instruction::SUB_DOUBLE_2ADDR:
1681 case Instruction::MUL_DOUBLE_2ADDR:
1682 case Instruction::DIV_DOUBLE_2ADDR:
1683 case Instruction::REM_DOUBLE_2ADDR: {
1684 // wide res = op + 2 wide operands
1685 uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
1686 uint16_t operand2 = GetOperandValueWide(mir->ssa_rep->uses[2]);
1687 res = gvn_->LookupValue(opcode, operand1, operand2, kNoValue);
1688 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1689 }
1690 break;
1691
1692 case Instruction::SHL_LONG:
1693 case Instruction::SHR_LONG:
1694 case Instruction::USHR_LONG:
1695 case Instruction::SHL_LONG_2ADDR:
1696 case Instruction::SHR_LONG_2ADDR:
1697 case Instruction::USHR_LONG_2ADDR: {
1698 // wide res = op + 1 wide operand + 1 operand
1699 uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
1700 uint16_t operand2 = GetOperandValue(mir->ssa_rep->uses[2]);
1701 res = gvn_->LookupValue(opcode, operand1, operand2, kNoValue);
1702 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1703 }
1704 break;
1705
1706 case Instruction::ADD_FLOAT:
1707 case Instruction::SUB_FLOAT:
1708 case Instruction::MUL_FLOAT:
1709 case Instruction::DIV_FLOAT:
1710 case Instruction::REM_FLOAT:
1711 case Instruction::ADD_FLOAT_2ADDR:
1712 case Instruction::SUB_FLOAT_2ADDR:
1713 case Instruction::MUL_FLOAT_2ADDR:
1714 case Instruction::DIV_FLOAT_2ADDR:
1715 case Instruction::REM_FLOAT_2ADDR: {
1716 // res = op + 2 operands
1717 uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
1718 uint16_t operand2 = GetOperandValue(mir->ssa_rep->uses[1]);
1719 res = gvn_->LookupValue(opcode, operand1, operand2, kNoValue);
1720 SetOperandValue(mir->ssa_rep->defs[0], res);
1721 }
1722 break;
1723
1724 case Instruction::RSUB_INT:
1725 case Instruction::ADD_INT_LIT16:
1726 case Instruction::MUL_INT_LIT16:
1727 case Instruction::DIV_INT_LIT16:
1728 case Instruction::REM_INT_LIT16:
1729 case Instruction::AND_INT_LIT16:
1730 case Instruction::OR_INT_LIT16:
1731 case Instruction::XOR_INT_LIT16:
1732 case Instruction::ADD_INT_LIT8:
1733 case Instruction::RSUB_INT_LIT8:
1734 case Instruction::MUL_INT_LIT8:
1735 case Instruction::DIV_INT_LIT8:
1736 case Instruction::REM_INT_LIT8:
1737 case Instruction::AND_INT_LIT8:
1738 case Instruction::OR_INT_LIT8:
1739 case Instruction::XOR_INT_LIT8:
1740 case Instruction::SHL_INT_LIT8:
1741 case Instruction::SHR_INT_LIT8:
1742 case Instruction::USHR_INT_LIT8: {
1743 // Same as res = op + 2 operands, except use vC as operand 2
1744 uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
1745 uint16_t operand2 = gvn_->LookupValue(Instruction::CONST, mir->dalvikInsn.vC, 0, 0);
1746 res = gvn_->LookupValue(opcode, operand1, operand2, kNoValue);
1747 SetOperandValue(mir->ssa_rep->defs[0], res);
1748 }
1749 break;
1750
1751 case Instruction::AGET_OBJECT:
1752 case Instruction::AGET:
1753 case Instruction::AGET_WIDE:
1754 case Instruction::AGET_BOOLEAN:
1755 case Instruction::AGET_BYTE:
1756 case Instruction::AGET_CHAR:
1757 case Instruction::AGET_SHORT:
1758 res = HandleAGet(mir, opcode);
1759 break;
1760
1761 case Instruction::APUT_OBJECT:
1762 HandlePutObject(mir);
1763 // Intentional fall-through.
1764 case Instruction::APUT:
1765 case Instruction::APUT_WIDE:
1766 case Instruction::APUT_BYTE:
1767 case Instruction::APUT_BOOLEAN:
1768 case Instruction::APUT_SHORT:
1769 case Instruction::APUT_CHAR:
1770 HandleAPut(mir, opcode);
1771 break;
1772
1773 case Instruction::IGET_OBJECT:
1774 case Instruction::IGET:
1775 case Instruction::IGET_WIDE:
1776 case Instruction::IGET_BOOLEAN:
1777 case Instruction::IGET_BYTE:
1778 case Instruction::IGET_CHAR:
1779 case Instruction::IGET_SHORT:
1780 res = HandleIGet(mir, opcode);
1781 break;
1782
1783 case Instruction::IPUT_OBJECT:
1784 HandlePutObject(mir);
1785 // Intentional fall-through.
1786 case Instruction::IPUT:
1787 case Instruction::IPUT_WIDE:
1788 case Instruction::IPUT_BOOLEAN:
1789 case Instruction::IPUT_BYTE:
1790 case Instruction::IPUT_CHAR:
1791 case Instruction::IPUT_SHORT:
1792 HandleIPut(mir, opcode);
1793 break;
1794
1795 case Instruction::SGET_OBJECT:
1796 case Instruction::SGET:
1797 case Instruction::SGET_WIDE:
1798 case Instruction::SGET_BOOLEAN:
1799 case Instruction::SGET_BYTE:
1800 case Instruction::SGET_CHAR:
1801 case Instruction::SGET_SHORT:
1802 res = HandleSGet(mir, opcode);
1803 break;
1804
1805 case Instruction::SPUT_OBJECT:
1806 HandlePutObject(mir);
1807 // Intentional fall-through.
1808 case Instruction::SPUT:
1809 case Instruction::SPUT_WIDE:
1810 case Instruction::SPUT_BOOLEAN:
1811 case Instruction::SPUT_BYTE:
1812 case Instruction::SPUT_CHAR:
1813 case Instruction::SPUT_SHORT:
1814 HandleSPut(mir, opcode);
1815 break;
1816 }
1817 return res;
1818 }
1819
1820 } // namespace art
1821