blob: 25a832604ab557850f9bddae93c4b80eb6ac2116 [file] [log] [blame]
buzbee2502e002012-12-31 16:05:53 -08001/*
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
buzbee311ca162013-02-28 15:56:43 -080017#include "local_value_numbering.h"
buzbee2502e002012-12-31 16:05:53 -080018
Vladimir Marko80afd022015-05-19 18:08:00 +010019#include "base/bit_utils.h"
Vladimir Marko95a05972014-05-30 10:01:32 +010020#include "global_value_numbering.h"
Vladimir Markobe0e5462014-02-26 11:24:15 +000021#include "mir_field_info.h"
Vladimir Markof59f18b2014-02-17 15:53:57 +000022#include "mir_graph.h"
Vladimir Marko80afd022015-05-19 18:08:00 +010023#include "utils.h"
Vladimir Markof59f18b2014-02-17 15:53:57 +000024
buzbee2502e002012-12-31 16:05:53 -080025namespace art {
26
Vladimir Marko2ac01fc2014-05-22 12:09:08 +010027namespace { // anonymous namespace
28
29// Operations used for value map keys instead of actual opcode.
Vladimir Marko95a05972014-05-30 10:01:32 +010030static constexpr uint16_t kInvokeMemoryVersionBumpOp = Instruction::INVOKE_VIRTUAL;
31static constexpr uint16_t kUnresolvedSFieldOp = Instruction::SGET;
32static constexpr uint16_t kResolvedSFieldOp = Instruction::SGET_WIDE;
33static constexpr uint16_t kUnresolvedIFieldOp = Instruction::IGET;
34static constexpr uint16_t kNonAliasingIFieldLocOp = Instruction::IGET_WIDE;
35static constexpr uint16_t kNonAliasingIFieldInitialOp = Instruction::IGET_OBJECT;
36static constexpr uint16_t kAliasingIFieldOp = Instruction::IGET_BOOLEAN;
37static constexpr uint16_t kAliasingIFieldStartVersionOp = Instruction::IGET_BYTE;
38static constexpr uint16_t kAliasingIFieldBumpVersionOp = Instruction::IGET_CHAR;
Vladimir Marko2ac01fc2014-05-22 12:09:08 +010039static constexpr uint16_t kNonAliasingArrayOp = Instruction::AGET;
40static constexpr uint16_t kNonAliasingArrayStartVersionOp = Instruction::AGET_WIDE;
Vladimir Marko95a05972014-05-30 10:01:32 +010041static constexpr uint16_t kNonAliasingArrayBumpVersionOp = Instruction::AGET_OBJECT;
42static constexpr uint16_t kAliasingArrayOp = Instruction::AGET_BOOLEAN;
43static constexpr uint16_t kAliasingArrayStartVersionOp = Instruction::AGET_BYTE;
44static constexpr uint16_t kAliasingArrayBumpVersionOp = Instruction::AGET_CHAR;
45static constexpr uint16_t kMergeBlockMemoryVersionBumpOp = Instruction::INVOKE_VIRTUAL_RANGE;
46static constexpr uint16_t kMergeBlockAliasingIFieldVersionBumpOp = Instruction::IPUT;
47static constexpr uint16_t kMergeBlockAliasingIFieldMergeLocationOp = Instruction::IPUT_WIDE;
48static constexpr uint16_t kMergeBlockNonAliasingArrayVersionBumpOp = Instruction::APUT;
49static constexpr uint16_t kMergeBlockNonAliasingArrayMergeLocationOp = Instruction::APUT_WIDE;
50static constexpr uint16_t kMergeBlockAliasingArrayVersionBumpOp = Instruction::APUT_OBJECT;
51static constexpr uint16_t kMergeBlockAliasingArrayMergeLocationOp = Instruction::APUT_BOOLEAN;
52static constexpr uint16_t kMergeBlockNonAliasingIFieldVersionBumpOp = Instruction::APUT_BYTE;
53static constexpr uint16_t kMergeBlockSFieldVersionBumpOp = Instruction::APUT_CHAR;
Vladimir Marko2ac01fc2014-05-22 12:09:08 +010054
55} // anonymous namespace
56
Vladimir Marko95a05972014-05-30 10:01:32 +010057class LocalValueNumbering::AliasingIFieldVersions {
58 public:
59 static uint16_t StartMemoryVersion(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
60 uint16_t field_id) {
Vladimir Markoaf6925b2014-10-31 16:37:32 +000061 uint16_t type = gvn->GetIFieldType(field_id);
Vladimir Marko95a05972014-05-30 10:01:32 +010062 return gvn->LookupValue(kAliasingIFieldStartVersionOp, field_id,
63 lvn->global_memory_version_, lvn->unresolved_ifield_version_[type]);
64 }
65
66 static uint16_t BumpMemoryVersion(GlobalValueNumbering* gvn, uint16_t old_version,
67 uint16_t store_ref_set_id, uint16_t stored_value) {
68 return gvn->LookupValue(kAliasingIFieldBumpVersionOp, old_version,
69 store_ref_set_id, stored_value);
70 }
71
72 static uint16_t LookupGlobalValue(GlobalValueNumbering* gvn,
73 uint16_t field_id, uint16_t base, uint16_t memory_version) {
74 return gvn->LookupValue(kAliasingIFieldOp, field_id, base, memory_version);
75 }
76
77 static uint16_t LookupMergeValue(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
78 uint16_t field_id, uint16_t base) {
79 // If the base/field_id is non-aliasing in lvn, use the non-aliasing value.
Vladimir Markoaf6925b2014-10-31 16:37:32 +000080 uint16_t type = gvn->GetIFieldType(field_id);
Vladimir Marko95a05972014-05-30 10:01:32 +010081 if (lvn->IsNonAliasingIField(base, field_id, type)) {
82 uint16_t loc = gvn->LookupValue(kNonAliasingIFieldLocOp, base, field_id, type);
83 auto lb = lvn->non_aliasing_ifield_value_map_.find(loc);
84 return (lb != lvn->non_aliasing_ifield_value_map_.end())
85 ? lb->second
86 : gvn->LookupValue(kNonAliasingIFieldInitialOp, loc, kNoValue, kNoValue);
87 }
88 return AliasingValuesMergeGet<AliasingIFieldVersions>(
89 gvn, lvn, &lvn->aliasing_ifield_value_map_, field_id, base);
90 }
91
92 static bool HasNewBaseVersion(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
93 uint16_t field_id) {
Vladimir Markoaf6925b2014-10-31 16:37:32 +000094 uint16_t type = gvn->GetIFieldType(field_id);
Vladimir Marko95a05972014-05-30 10:01:32 +010095 return lvn->unresolved_ifield_version_[type] == lvn->merge_new_memory_version_ ||
96 lvn->global_memory_version_ == lvn->merge_new_memory_version_;
97 }
98
99 static uint16_t LookupMergeBlockValue(GlobalValueNumbering* gvn, uint16_t lvn_id,
100 uint16_t field_id) {
101 return gvn->LookupValue(kMergeBlockAliasingIFieldVersionBumpOp, field_id, kNoValue, lvn_id);
102 }
103
104 static uint16_t LookupMergeLocationValue(GlobalValueNumbering* gvn, uint16_t lvn_id,
105 uint16_t field_id, uint16_t base) {
106 return gvn->LookupValue(kMergeBlockAliasingIFieldMergeLocationOp, field_id, base, lvn_id);
107 }
108};
109
110class LocalValueNumbering::NonAliasingArrayVersions {
111 public:
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700112 static uint16_t StartMemoryVersion(GlobalValueNumbering* gvn,
113 const LocalValueNumbering* lvn ATTRIBUTE_UNUSED,
Vladimir Marko95a05972014-05-30 10:01:32 +0100114 uint16_t array) {
115 return gvn->LookupValue(kNonAliasingArrayStartVersionOp, array, kNoValue, kNoValue);
116 }
117
118 static uint16_t BumpMemoryVersion(GlobalValueNumbering* gvn, uint16_t old_version,
119 uint16_t store_ref_set_id, uint16_t stored_value) {
120 return gvn->LookupValue(kNonAliasingArrayBumpVersionOp, old_version,
121 store_ref_set_id, stored_value);
122 }
123
124 static uint16_t LookupGlobalValue(GlobalValueNumbering* gvn,
125 uint16_t array, uint16_t index, uint16_t memory_version) {
126 return gvn->LookupValue(kNonAliasingArrayOp, array, index, memory_version);
127 }
128
129 static uint16_t LookupMergeValue(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
130 uint16_t array, uint16_t index) {
131 return AliasingValuesMergeGet<NonAliasingArrayVersions>(
132 gvn, lvn, &lvn->non_aliasing_array_value_map_, array, index);
133 }
134
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700135 static bool HasNewBaseVersion(GlobalValueNumbering* gvn ATTRIBUTE_UNUSED,
136 const LocalValueNumbering* lvn ATTRIBUTE_UNUSED,
137 uint16_t array ATTRIBUTE_UNUSED) {
Vladimir Marko95a05972014-05-30 10:01:32 +0100138 return false; // Not affected by global_memory_version_.
139 }
140
141 static uint16_t LookupMergeBlockValue(GlobalValueNumbering* gvn, uint16_t lvn_id,
142 uint16_t array) {
143 return gvn->LookupValue(kMergeBlockNonAliasingArrayVersionBumpOp, array, kNoValue, lvn_id);
144 }
145
146 static uint16_t LookupMergeLocationValue(GlobalValueNumbering* gvn, uint16_t lvn_id,
147 uint16_t array, uint16_t index) {
148 return gvn->LookupValue(kMergeBlockNonAliasingArrayMergeLocationOp, array, index, lvn_id);
149 }
150};
151
152class LocalValueNumbering::AliasingArrayVersions {
153 public:
154 static uint16_t StartMemoryVersion(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
155 uint16_t type) {
156 return gvn->LookupValue(kAliasingArrayStartVersionOp, type, lvn->global_memory_version_,
157 kNoValue);
158 }
159
160 static uint16_t BumpMemoryVersion(GlobalValueNumbering* gvn, uint16_t old_version,
161 uint16_t store_ref_set_id, uint16_t stored_value) {
162 return gvn->LookupValue(kAliasingArrayBumpVersionOp, old_version,
163 store_ref_set_id, stored_value);
164 }
165
166 static uint16_t LookupGlobalValue(GlobalValueNumbering* gvn,
167 uint16_t type, uint16_t location, uint16_t memory_version) {
168 return gvn->LookupValue(kAliasingArrayOp, type, location, memory_version);
169 }
170
Andreas Gampeca714582015-04-03 19:41:34 -0700171 static uint16_t LookupMergeValue(GlobalValueNumbering* gvn,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700172 const LocalValueNumbering* lvn,
Andreas Gampeca714582015-04-03 19:41:34 -0700173 uint16_t type, uint16_t location) {
Vladimir Marko95a05972014-05-30 10:01:32 +0100174 // If the location is non-aliasing in lvn, use the non-aliasing value.
175 uint16_t array = gvn->GetArrayLocationBase(location);
176 if (lvn->IsNonAliasingArray(array, type)) {
177 uint16_t index = gvn->GetArrayLocationIndex(location);
178 return NonAliasingArrayVersions::LookupMergeValue(gvn, lvn, array, index);
179 }
180 return AliasingValuesMergeGet<AliasingArrayVersions>(
181 gvn, lvn, &lvn->aliasing_array_value_map_, type, location);
182 }
183
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700184 static bool HasNewBaseVersion(GlobalValueNumbering* gvn ATTRIBUTE_UNUSED,
185 const LocalValueNumbering* lvn,
186 uint16_t type ATTRIBUTE_UNUSED) {
Vladimir Marko95a05972014-05-30 10:01:32 +0100187 return lvn->global_memory_version_ == lvn->merge_new_memory_version_;
188 }
189
190 static uint16_t LookupMergeBlockValue(GlobalValueNumbering* gvn, uint16_t lvn_id,
191 uint16_t type) {
192 return gvn->LookupValue(kMergeBlockAliasingArrayVersionBumpOp, type, kNoValue, lvn_id);
193 }
194
195 static uint16_t LookupMergeLocationValue(GlobalValueNumbering* gvn, uint16_t lvn_id,
196 uint16_t type, uint16_t location) {
197 return gvn->LookupValue(kMergeBlockAliasingArrayMergeLocationOp, type, location, lvn_id);
198 }
199};
200
201template <typename Map>
202LocalValueNumbering::AliasingValues* LocalValueNumbering::GetAliasingValues(
203 Map* map, const typename Map::key_type& key) {
204 auto lb = map->lower_bound(key);
205 if (lb == map->end() || map->key_comp()(key, lb->first)) {
Vladimir Markob19955d2014-07-29 12:04:10 +0100206 lb = map->PutBefore(lb, key, AliasingValues(this));
Vladimir Marko95a05972014-05-30 10:01:32 +0100207 }
208 return &lb->second;
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100209}
210
Vladimir Marko95a05972014-05-30 10:01:32 +0100211template <typename Versions, typename KeyType>
212void LocalValueNumbering::UpdateAliasingValuesLoadVersion(const KeyType& key,
213 AliasingValues* values) {
214 if (values->last_load_memory_version == kNoValue) {
215 // Get the start version that accounts for aliasing with unresolved fields of the same
216 // type and make it unique for the field by including the field_id.
217 uint16_t memory_version = values->memory_version_before_stores;
218 if (memory_version == kNoValue) {
219 memory_version = Versions::StartMemoryVersion(gvn_, this, key);
220 }
221 if (!values->store_loc_set.empty()) {
222 uint16_t ref_set_id = gvn_->GetRefSetId(values->store_loc_set);
223 memory_version = Versions::BumpMemoryVersion(gvn_, memory_version, ref_set_id,
224 values->last_stored_value);
225 }
226 values->last_load_memory_version = memory_version;
Vladimir Markof59f18b2014-02-17 15:53:57 +0000227 }
Vladimir Marko95a05972014-05-30 10:01:32 +0100228}
229
230template <typename Versions, typename Map>
231uint16_t LocalValueNumbering::AliasingValuesMergeGet(GlobalValueNumbering* gvn,
232 const LocalValueNumbering* lvn,
233 Map* map, const typename Map::key_type& key,
234 uint16_t location) {
235 // Retrieve the value name that we would get from
236 // const_cast<LocalValueNumbering*>(lvn)->HandleAliasingValueGet(map. key, location)
237 // but don't modify the map.
238 uint16_t value_name;
239 auto it = map->find(key);
240 if (it == map->end()) {
241 uint16_t start_version = Versions::StartMemoryVersion(gvn, lvn, key);
242 value_name = Versions::LookupGlobalValue(gvn, key, location, start_version);
243 } else if (it->second.store_loc_set.count(location) != 0u) {
244 value_name = it->second.last_stored_value;
245 } else {
246 auto load_it = it->second.load_value_map.find(location);
247 if (load_it != it->second.load_value_map.end()) {
248 value_name = load_it->second;
249 } else {
250 value_name = Versions::LookupGlobalValue(gvn, key, location, it->second.last_load_memory_version);
251 }
252 }
253 return value_name;
254}
255
256template <typename Versions, typename Map>
257uint16_t LocalValueNumbering::HandleAliasingValuesGet(Map* map, const typename Map::key_type& key,
258 uint16_t location) {
259 // Retrieve the value name for IGET/SGET/AGET, update the map with new value if any.
260 uint16_t res;
261 AliasingValues* values = GetAliasingValues(map, key);
262 if (values->store_loc_set.count(location) != 0u) {
263 res = values->last_stored_value;
264 } else {
265 UpdateAliasingValuesLoadVersion<Versions>(key, values);
266 auto lb = values->load_value_map.lower_bound(location);
267 if (lb != values->load_value_map.end() && lb->first == location) {
268 res = lb->second;
269 } else {
270 res = Versions::LookupGlobalValue(gvn_, key, location, values->last_load_memory_version);
271 values->load_value_map.PutBefore(lb, location, res);
272 }
273 }
274 return res;
275}
276
277template <typename Versions, typename Map>
278bool LocalValueNumbering::HandleAliasingValuesPut(Map* map, const typename Map::key_type& key,
279 uint16_t location, uint16_t value) {
280 AliasingValues* values = GetAliasingValues(map, key);
281 auto load_values_it = values->load_value_map.find(location);
282 if (load_values_it != values->load_value_map.end() && load_values_it->second == value) {
283 // This insn can be eliminated, it stores the same value that's already in the field.
284 return false;
285 }
286 if (value == values->last_stored_value) {
287 auto store_loc_lb = values->store_loc_set.lower_bound(location);
288 if (store_loc_lb != values->store_loc_set.end() && *store_loc_lb == location) {
289 // This insn can be eliminated, it stores the same value that's already in the field.
290 return false;
291 }
292 values->store_loc_set.emplace_hint(store_loc_lb, location);
293 } else {
294 UpdateAliasingValuesLoadVersion<Versions>(key, values);
295 values->memory_version_before_stores = values->last_load_memory_version;
296 values->last_stored_value = value;
297 values->store_loc_set.clear();
298 values->store_loc_set.insert(location);
299 }
300 // Clear the last load memory version and remove all potentially overwritten values.
301 values->last_load_memory_version = kNoValue;
302 auto it = values->load_value_map.begin(), end = values->load_value_map.end();
303 while (it != end) {
304 if (it->second == value) {
305 ++it;
306 } else {
307 it = values->load_value_map.erase(it);
308 }
309 }
310 return true;
311}
312
Vladimir Markob19955d2014-07-29 12:04:10 +0100313template <typename K>
314void LocalValueNumbering::CopyAliasingValuesMap(ScopedArenaSafeMap<K, AliasingValues>* dest,
315 const ScopedArenaSafeMap<K, AliasingValues>& src) {
316 // We need each new AliasingValues (or rather its map members) to be constructed
317 // with our allocator, rather than the allocator of the source.
318 for (const auto& entry : src) {
319 auto it = dest->PutBefore(dest->end(), entry.first, AliasingValues(this));
320 it->second = entry.second; // Map assignments preserve current allocator.
321 }
322}
323
324LocalValueNumbering::LocalValueNumbering(GlobalValueNumbering* gvn, uint16_t id,
325 ScopedArenaAllocator* allocator)
Vladimir Marko95a05972014-05-30 10:01:32 +0100326 : gvn_(gvn),
327 id_(id),
Vladimir Markob19955d2014-07-29 12:04:10 +0100328 sreg_value_map_(std::less<uint16_t>(), allocator->Adapter()),
329 sreg_wide_value_map_(std::less<uint16_t>(), allocator->Adapter()),
330 sfield_value_map_(std::less<uint16_t>(), allocator->Adapter()),
331 non_aliasing_ifield_value_map_(std::less<uint16_t>(), allocator->Adapter()),
332 aliasing_ifield_value_map_(std::less<uint16_t>(), allocator->Adapter()),
333 non_aliasing_array_value_map_(std::less<uint16_t>(), allocator->Adapter()),
334 aliasing_array_value_map_(std::less<uint16_t>(), allocator->Adapter()),
Vladimir Marko95a05972014-05-30 10:01:32 +0100335 global_memory_version_(0u),
Vladimir Markob19955d2014-07-29 12:04:10 +0100336 non_aliasing_refs_(std::less<uint16_t>(), allocator->Adapter()),
337 escaped_refs_(std::less<uint16_t>(), allocator->Adapter()),
338 escaped_ifield_clobber_set_(EscapedIFieldClobberKeyComparator(), allocator->Adapter()),
339 escaped_array_clobber_set_(EscapedArrayClobberKeyComparator(), allocator->Adapter()),
340 range_checked_(RangeCheckKeyComparator() , allocator->Adapter()),
341 null_checked_(std::less<uint16_t>(), allocator->Adapter()),
Razvan A Lupusorue0951142014-11-14 14:36:55 -0800342 div_zero_checked_(std::less<uint16_t>(), allocator->Adapter()),
Vladimir Markob19955d2014-07-29 12:04:10 +0100343 merge_names_(allocator->Adapter()),
344 merge_map_(std::less<ScopedArenaVector<BasicBlockId>>(), allocator->Adapter()),
Vladimir Marko95a05972014-05-30 10:01:32 +0100345 merge_new_memory_version_(kNoValue) {
Vladimir Marko321b9872014-11-24 16:33:51 +0000346 std::fill_n(unresolved_sfield_version_, arraysize(unresolved_sfield_version_), 0u);
347 std::fill_n(unresolved_ifield_version_, arraysize(unresolved_ifield_version_), 0u);
Vladimir Marko95a05972014-05-30 10:01:32 +0100348}
349
Vladimir Markod4cf1e42015-10-07 12:03:29 +0100350LocalValueNumbering::~LocalValueNumbering() {
351 // All done by member destructors.
352}
353
Vladimir Marko95a05972014-05-30 10:01:32 +0100354bool LocalValueNumbering::Equals(const LocalValueNumbering& other) const {
355 DCHECK(gvn_ == other.gvn_);
356 // Compare the maps/sets and memory versions.
357 return sreg_value_map_ == other.sreg_value_map_ &&
358 sreg_wide_value_map_ == other.sreg_wide_value_map_ &&
359 sfield_value_map_ == other.sfield_value_map_ &&
360 non_aliasing_ifield_value_map_ == other.non_aliasing_ifield_value_map_ &&
361 aliasing_ifield_value_map_ == other.aliasing_ifield_value_map_ &&
362 non_aliasing_array_value_map_ == other.non_aliasing_array_value_map_ &&
363 aliasing_array_value_map_ == other.aliasing_array_value_map_ &&
364 SameMemoryVersion(other) &&
365 non_aliasing_refs_ == other.non_aliasing_refs_ &&
366 escaped_refs_ == other.escaped_refs_ &&
367 escaped_ifield_clobber_set_ == other.escaped_ifield_clobber_set_ &&
368 escaped_array_clobber_set_ == other.escaped_array_clobber_set_ &&
369 range_checked_ == other.range_checked_ &&
Razvan A Lupusorue0951142014-11-14 14:36:55 -0800370 null_checked_ == other.null_checked_ &&
371 div_zero_checked_ == other.div_zero_checked_;
Vladimir Marko95a05972014-05-30 10:01:32 +0100372}
373
374void LocalValueNumbering::MergeOne(const LocalValueNumbering& other, MergeType merge_type) {
Vladimir Markob19955d2014-07-29 12:04:10 +0100375 CopyLiveSregValues(&sreg_value_map_, other.sreg_value_map_);
376 CopyLiveSregValues(&sreg_wide_value_map_, other.sreg_wide_value_map_);
Vladimir Marko95a05972014-05-30 10:01:32 +0100377
378 if (merge_type == kReturnMerge) {
379 // RETURN or PHI+RETURN. We need only sreg value maps.
380 return;
381 }
382
383 non_aliasing_ifield_value_map_ = other.non_aliasing_ifield_value_map_;
Vladimir Markob19955d2014-07-29 12:04:10 +0100384 CopyAliasingValuesMap(&non_aliasing_array_value_map_, other.non_aliasing_array_value_map_);
Vladimir Marko95a05972014-05-30 10:01:32 +0100385 non_aliasing_refs_ = other.non_aliasing_refs_;
386 range_checked_ = other.range_checked_;
387 null_checked_ = other.null_checked_;
Razvan A Lupusorue0951142014-11-14 14:36:55 -0800388 div_zero_checked_ = other.div_zero_checked_;
Vladimir Marko95a05972014-05-30 10:01:32 +0100389
Vladimir Markoa4426cf2014-10-22 17:15:53 +0100390 const BasicBlock* pred_bb = gvn_->GetBasicBlock(other.Id());
391 if (GlobalValueNumbering::HasNullCheckLastInsn(pred_bb, Id())) {
392 int s_reg = pred_bb->last_mir_insn->ssa_rep->uses[0];
393 null_checked_.insert(other.GetOperandValue(s_reg));
394 }
395
Vladimir Marko95a05972014-05-30 10:01:32 +0100396 if (merge_type == kCatchMerge) {
397 // Memory is clobbered. Use new memory version and don't merge aliasing locations.
398 global_memory_version_ = NewMemoryVersion(&merge_new_memory_version_);
Vladimir Marko321b9872014-11-24 16:33:51 +0000399 std::fill_n(unresolved_sfield_version_, arraysize(unresolved_sfield_version_),
400 global_memory_version_);
401 std::fill_n(unresolved_ifield_version_, arraysize(unresolved_ifield_version_),
402 global_memory_version_);
Vladimir Marko95a05972014-05-30 10:01:32 +0100403 PruneNonAliasingRefsForCatch();
404 return;
405 }
406
407 DCHECK(merge_type == kNormalMerge);
408 global_memory_version_ = other.global_memory_version_;
Vladimir Marko321b9872014-11-24 16:33:51 +0000409 std::copy_n(other.unresolved_ifield_version_, arraysize(unresolved_sfield_version_),
410 unresolved_ifield_version_);
411 std::copy_n(other.unresolved_sfield_version_, arraysize(unresolved_ifield_version_),
412 unresolved_sfield_version_);
Vladimir Marko95a05972014-05-30 10:01:32 +0100413 sfield_value_map_ = other.sfield_value_map_;
Vladimir Markob19955d2014-07-29 12:04:10 +0100414 CopyAliasingValuesMap(&aliasing_ifield_value_map_, other.aliasing_ifield_value_map_);
415 CopyAliasingValuesMap(&aliasing_array_value_map_, other.aliasing_array_value_map_);
Vladimir Marko95a05972014-05-30 10:01:32 +0100416 escaped_refs_ = other.escaped_refs_;
417 escaped_ifield_clobber_set_ = other.escaped_ifield_clobber_set_;
418 escaped_array_clobber_set_ = other.escaped_array_clobber_set_;
419}
420
421bool LocalValueNumbering::SameMemoryVersion(const LocalValueNumbering& other) const {
422 return
423 global_memory_version_ == other.global_memory_version_ &&
Vladimir Marko321b9872014-11-24 16:33:51 +0000424 std::equal(unresolved_ifield_version_,
425 unresolved_ifield_version_ + arraysize(unresolved_ifield_version_),
Vladimir Marko95a05972014-05-30 10:01:32 +0100426 other.unresolved_ifield_version_) &&
Vladimir Marko321b9872014-11-24 16:33:51 +0000427 std::equal(unresolved_sfield_version_,
428 unresolved_sfield_version_ + arraysize(unresolved_sfield_version_),
Vladimir Marko95a05972014-05-30 10:01:32 +0100429 other.unresolved_sfield_version_);
430}
431
432uint16_t LocalValueNumbering::NewMemoryVersion(uint16_t* new_version) {
433 if (*new_version == kNoValue) {
434 *new_version = gvn_->LookupValue(kMergeBlockMemoryVersionBumpOp, 0u, 0u, id_);
435 }
436 return *new_version;
437}
438
439void LocalValueNumbering::MergeMemoryVersions(bool clobbered_catch) {
440 DCHECK_GE(gvn_->merge_lvns_.size(), 2u);
441 const LocalValueNumbering* cmp = gvn_->merge_lvns_[0];
442 // Check if the global version has changed.
443 bool new_global_version = clobbered_catch;
444 if (!new_global_version) {
445 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
446 if (lvn->global_memory_version_ != cmp->global_memory_version_) {
447 // Use a new version for everything.
448 new_global_version = true;
449 break;
450 }
451 }
452 }
453 if (new_global_version) {
454 global_memory_version_ = NewMemoryVersion(&merge_new_memory_version_);
Vladimir Marko321b9872014-11-24 16:33:51 +0000455 std::fill_n(unresolved_sfield_version_, arraysize(unresolved_sfield_version_),
456 merge_new_memory_version_);
457 std::fill_n(unresolved_ifield_version_, arraysize(unresolved_ifield_version_),
458 merge_new_memory_version_);
Vladimir Marko95a05972014-05-30 10:01:32 +0100459 } else {
460 // Initialize with a copy of memory versions from the comparison LVN.
461 global_memory_version_ = cmp->global_memory_version_;
Vladimir Marko321b9872014-11-24 16:33:51 +0000462 std::copy_n(cmp->unresolved_ifield_version_, arraysize(unresolved_sfield_version_),
463 unresolved_ifield_version_);
464 std::copy_n(cmp->unresolved_sfield_version_, arraysize(unresolved_ifield_version_),
465 unresolved_sfield_version_);
Vladimir Marko95a05972014-05-30 10:01:32 +0100466 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
467 if (lvn == cmp) {
468 continue;
469 }
Vladimir Marko321b9872014-11-24 16:33:51 +0000470 for (size_t i = 0; i != kDexMemAccessTypeCount; ++i) {
Vladimir Marko95a05972014-05-30 10:01:32 +0100471 if (lvn->unresolved_ifield_version_[i] != cmp->unresolved_ifield_version_[i]) {
472 unresolved_ifield_version_[i] = NewMemoryVersion(&merge_new_memory_version_);
473 }
474 if (lvn->unresolved_sfield_version_[i] != cmp->unresolved_sfield_version_[i]) {
475 unresolved_sfield_version_[i] = NewMemoryVersion(&merge_new_memory_version_);
476 }
477 }
478 }
479 }
480}
481
482void LocalValueNumbering::PruneNonAliasingRefsForCatch() {
483 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
484 const BasicBlock* bb = gvn_->GetBasicBlock(lvn->Id());
Vladimir Marko11ca6122014-07-17 20:50:07 +0100485 if (UNLIKELY(bb->taken == id_) || UNLIKELY(bb->fall_through == id_)) {
486 // Non-exceptional path to a catch handler means that the catch block was actually
487 // empty and all exceptional paths lead to the shared path after that empty block.
488 continue;
489 }
Vladimir Marko95a05972014-05-30 10:01:32 +0100490 DCHECK_EQ(bb->taken, kNullBlock);
491 DCHECK_NE(bb->fall_through, kNullBlock);
492 const BasicBlock* fall_through_bb = gvn_->GetBasicBlock(bb->fall_through);
493 const MIR* mir = fall_through_bb->first_mir_insn;
494 DCHECK(mir != nullptr);
495 // Only INVOKEs can leak and clobber non-aliasing references if they throw.
Jean Christophe Beylerfb0ea2d2014-07-29 13:20:42 -0700496 if ((mir->dalvikInsn.FlagsOf() & Instruction::kInvoke) != 0) {
Vladimir Markoa4426cf2014-10-22 17:15:53 +0100497 HandleInvokeArgs(mir, lvn);
Vladimir Marko95a05972014-05-30 10:01:32 +0100498 }
499 }
500}
501
502
503template <typename Set, Set LocalValueNumbering::* set_ptr>
504void LocalValueNumbering::IntersectSets() {
505 DCHECK_GE(gvn_->merge_lvns_.size(), 2u);
506
507 // Find the LVN with the least entries in the set.
508 const LocalValueNumbering* least_entries_lvn = gvn_->merge_lvns_[0];
509 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
510 if ((lvn->*set_ptr).size() < (least_entries_lvn->*set_ptr).size()) {
511 least_entries_lvn = lvn;
512 }
513 }
514
515 // For each key check if it's in all the LVNs.
516 for (const auto& key : least_entries_lvn->*set_ptr) {
517 bool checked = true;
518 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
519 if (lvn != least_entries_lvn && (lvn->*set_ptr).count(key) == 0u) {
520 checked = false;
521 break;
522 }
523 }
524 if (checked) {
525 (this->*set_ptr).emplace_hint((this->*set_ptr).end(), key);
526 }
527 }
528}
529
Vladimir Markob19955d2014-07-29 12:04:10 +0100530void LocalValueNumbering::CopyLiveSregValues(SregValueMap* dest, const SregValueMap& src) {
531 auto dest_end = dest->end();
532 ArenaBitVector* live_in_v = gvn_->GetMirGraph()->GetBasicBlock(id_)->data_flow_info->live_in_v;
533 DCHECK(live_in_v != nullptr);
534 for (const auto& entry : src) {
535 bool live = live_in_v->IsBitSet(gvn_->GetMirGraph()->SRegToVReg(entry.first));
536 if (live) {
537 dest->PutBefore(dest_end, entry.first, entry.second);
538 }
539 }
540}
541
542template <LocalValueNumbering::SregValueMap LocalValueNumbering::* map_ptr>
543void LocalValueNumbering::IntersectSregValueMaps() {
Vladimir Marko95a05972014-05-30 10:01:32 +0100544 DCHECK_GE(gvn_->merge_lvns_.size(), 2u);
545
546 // Find the LVN with the least entries in the set.
547 const LocalValueNumbering* least_entries_lvn = gvn_->merge_lvns_[0];
548 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
549 if ((lvn->*map_ptr).size() < (least_entries_lvn->*map_ptr).size()) {
550 least_entries_lvn = lvn;
551 }
552 }
553
554 // For each key check if it's in all the LVNs.
Vladimir Markob19955d2014-07-29 12:04:10 +0100555 ArenaBitVector* live_in_v = gvn_->GetMirGraph()->GetBasicBlock(id_)->data_flow_info->live_in_v;
556 DCHECK(live_in_v != nullptr);
Vladimir Marko95a05972014-05-30 10:01:32 +0100557 for (const auto& entry : least_entries_lvn->*map_ptr) {
Vladimir Markob19955d2014-07-29 12:04:10 +0100558 bool live_and_same = live_in_v->IsBitSet(gvn_->GetMirGraph()->SRegToVReg(entry.first));
559 if (live_and_same) {
560 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
561 if (lvn != least_entries_lvn) {
562 auto it = (lvn->*map_ptr).find(entry.first);
563 if (it == (lvn->*map_ptr).end() || !(it->second == entry.second)) {
564 live_and_same = false;
565 break;
566 }
Vladimir Marko95a05972014-05-30 10:01:32 +0100567 }
568 }
569 }
Vladimir Markob19955d2014-07-29 12:04:10 +0100570 if (live_and_same) {
Vladimir Marko95a05972014-05-30 10:01:32 +0100571 (this->*map_ptr).PutBefore((this->*map_ptr).end(), entry.first, entry.second);
572 }
573 }
574}
575
576// Intersect maps as sets. The value type must be equality-comparable.
577template <typename Map>
578void LocalValueNumbering::InPlaceIntersectMaps(Map* work_map, const Map& other_map) {
579 auto work_it = work_map->begin(), work_end = work_map->end();
580 auto cmp = work_map->value_comp();
581 for (const auto& entry : other_map) {
582 while (work_it != work_end &&
583 (cmp(*work_it, entry) ||
584 (!cmp(entry, *work_it) && !(work_it->second == entry.second)))) {
585 work_it = work_map->erase(work_it);
586 }
Vladimir Marko55fff042014-07-10 12:42:52 +0100587 if (work_it == work_end) {
588 return;
589 }
590 ++work_it;
Vladimir Marko95a05972014-05-30 10:01:32 +0100591 }
592}
593
594template <typename Set, Set LocalValueNumbering::*set_ptr, void (LocalValueNumbering::*MergeFn)(
595 const typename Set::value_type& entry, typename Set::iterator hint)>
596void LocalValueNumbering::MergeSets() {
597 auto cmp = (this->*set_ptr).value_comp();
598 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
599 auto my_it = (this->*set_ptr).begin(), my_end = (this->*set_ptr).end();
600 for (const auto& entry : lvn->*set_ptr) {
601 while (my_it != my_end && cmp(*my_it, entry)) {
602 ++my_it;
603 }
604 if (my_it != my_end && !cmp(entry, *my_it)) {
605 // Already handled.
606 ++my_it;
607 } else {
608 // Merge values for this field_id.
609 (this->*MergeFn)(entry, my_it); // my_it remains valid across inserts to std::set/SafeMap.
610 }
611 }
612 }
613}
614
615void LocalValueNumbering::IntersectAliasingValueLocations(AliasingValues* work_values,
616 const AliasingValues* values) {
617 auto cmp = work_values->load_value_map.key_comp();
618 auto work_it = work_values->load_value_map.begin(), work_end = work_values->load_value_map.end();
619 auto store_it = values->store_loc_set.begin(), store_end = values->store_loc_set.end();
620 auto load_it = values->load_value_map.begin(), load_end = values->load_value_map.end();
621 while (store_it != store_end || load_it != load_end) {
622 uint16_t loc;
623 if (store_it != store_end && (load_it == load_end || *store_it < load_it->first)) {
624 loc = *store_it;
625 ++store_it;
626 } else {
627 loc = load_it->first;
628 ++load_it;
629 DCHECK(store_it == store_end || cmp(loc, *store_it));
630 }
631 while (work_it != work_end && cmp(work_it->first, loc)) {
632 work_it = work_values->load_value_map.erase(work_it);
633 }
634 if (work_it != work_end && !cmp(loc, work_it->first)) {
635 // The location matches, keep it.
636 ++work_it;
637 }
638 }
639 while (work_it != work_end) {
640 work_it = work_values->load_value_map.erase(work_it);
641 }
642}
643
644void LocalValueNumbering::MergeEscapedRefs(const ValueNameSet::value_type& entry,
645 ValueNameSet::iterator hint) {
646 // See if the ref is either escaped or non-aliasing in each predecessor.
647 bool is_escaped = true;
648 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
649 if (lvn->non_aliasing_refs_.count(entry) == 0u &&
650 lvn->escaped_refs_.count(entry) == 0u) {
651 is_escaped = false;
652 break;
653 }
654 }
655 if (is_escaped) {
656 escaped_refs_.emplace_hint(hint, entry);
657 }
658}
659
660void LocalValueNumbering::MergeEscapedIFieldTypeClobberSets(
661 const EscapedIFieldClobberSet::value_type& entry, EscapedIFieldClobberSet::iterator hint) {
662 // Insert only type-clobber entries (field_id == kNoValue) of escaped refs.
663 if (entry.field_id == kNoValue && escaped_refs_.count(entry.base) != 0u) {
664 escaped_ifield_clobber_set_.emplace_hint(hint, entry);
665 }
666}
667
668void LocalValueNumbering::MergeEscapedIFieldClobberSets(
669 const EscapedIFieldClobberSet::value_type& entry, EscapedIFieldClobberSet::iterator hint) {
670 // Insert only those entries of escaped refs that are not overridden by a type clobber.
671 if (!(hint == escaped_ifield_clobber_set_.end() &&
672 hint->base == entry.base && hint->type == entry.type) &&
673 escaped_refs_.count(entry.base) != 0u) {
674 escaped_ifield_clobber_set_.emplace_hint(hint, entry);
675 }
676}
677
678void LocalValueNumbering::MergeEscapedArrayClobberSets(
679 const EscapedArrayClobberSet::value_type& entry, EscapedArrayClobberSet::iterator hint) {
680 if (escaped_refs_.count(entry.base) != 0u) {
681 escaped_array_clobber_set_.emplace_hint(hint, entry);
682 }
683}
684
Vladimir Marko2d2365c2014-08-19 18:08:39 +0100685void LocalValueNumbering::MergeNullChecked() {
686 DCHECK_GE(gvn_->merge_lvns_.size(), 2u);
687
688 // Find the LVN with the least entries in the set.
689 const LocalValueNumbering* least_entries_lvn = gvn_->merge_lvns_[0];
690 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
691 if (lvn->null_checked_.size() < least_entries_lvn->null_checked_.size()) {
692 least_entries_lvn = lvn;
693 }
694 }
695
696 // For each null-checked value name check if it's null-checked in all the LVNs.
697 for (const auto& value_name : least_entries_lvn->null_checked_) {
698 // Merge null_checked_ for this ref.
699 merge_names_.clear();
700 merge_names_.resize(gvn_->merge_lvns_.size(), value_name);
701 if (gvn_->NullCheckedInAllPredecessors(merge_names_)) {
702 null_checked_.insert(null_checked_.end(), value_name);
703 }
704 }
705
706 // Now check if the least_entries_lvn has a null-check as the last insn.
707 const BasicBlock* least_entries_bb = gvn_->GetBasicBlock(least_entries_lvn->Id());
708 if (gvn_->HasNullCheckLastInsn(least_entries_bb, id_)) {
709 int s_reg = least_entries_bb->last_mir_insn->ssa_rep->uses[0];
Vladimir Markoa4426cf2014-10-22 17:15:53 +0100710 uint32_t value_name = least_entries_lvn->GetOperandValue(s_reg);
Vladimir Marko2d2365c2014-08-19 18:08:39 +0100711 merge_names_.clear();
712 merge_names_.resize(gvn_->merge_lvns_.size(), value_name);
713 if (gvn_->NullCheckedInAllPredecessors(merge_names_)) {
714 null_checked_.insert(value_name);
715 }
Vladimir Marko95a05972014-05-30 10:01:32 +0100716 }
717}
718
Razvan A Lupusorue0951142014-11-14 14:36:55 -0800719void LocalValueNumbering::MergeDivZeroChecked() {
720 DCHECK_GE(gvn_->merge_lvns_.size(), 2u);
721
722 // Find the LVN with the least entries in the set.
723 const LocalValueNumbering* least_entries_lvn = gvn_->merge_lvns_[0];
724 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
725 if (lvn->div_zero_checked_.size() < least_entries_lvn->div_zero_checked_.size()) {
726 least_entries_lvn = lvn;
727 }
728 }
729
730 // For each div-zero value name check if it's div-zero checked in all the LVNs.
731 for (const auto& value_name : least_entries_lvn->div_zero_checked_) {
732 // Merge null_checked_ for this ref.
733 merge_names_.clear();
734 merge_names_.resize(gvn_->merge_lvns_.size(), value_name);
735 if (gvn_->DivZeroCheckedInAllPredecessors(merge_names_)) {
736 div_zero_checked_.insert(div_zero_checked_.end(), value_name);
737 }
738 }
739}
740
Vladimir Marko95a05972014-05-30 10:01:32 +0100741void LocalValueNumbering::MergeSFieldValues(const SFieldToValueMap::value_type& entry,
742 SFieldToValueMap::iterator hint) {
743 uint16_t field_id = entry.first;
744 merge_names_.clear();
745 uint16_t value_name = kNoValue;
746 bool same_values = true;
747 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
748 // Get the value name as in HandleSGet() but don't modify *lvn.
749 auto it = lvn->sfield_value_map_.find(field_id);
750 if (it != lvn->sfield_value_map_.end()) {
751 value_name = it->second;
752 } else {
Vladimir Markoaf6925b2014-10-31 16:37:32 +0000753 uint16_t type = gvn_->GetSFieldType(field_id);
Vladimir Marko95a05972014-05-30 10:01:32 +0100754 value_name = gvn_->LookupValue(kResolvedSFieldOp, field_id,
755 lvn->unresolved_sfield_version_[type],
756 lvn->global_memory_version_);
757 }
758
759 same_values = same_values && (merge_names_.empty() || value_name == merge_names_.back());
760 merge_names_.push_back(value_name);
761 }
762 if (same_values) {
763 // value_name already contains the result.
764 } else {
765 auto lb = merge_map_.lower_bound(merge_names_);
766 if (lb != merge_map_.end() && !merge_map_.key_comp()(merge_names_, lb->first)) {
767 value_name = lb->second;
768 } else {
769 value_name = gvn_->LookupValue(kMergeBlockSFieldVersionBumpOp, field_id, id_, kNoValue);
770 merge_map_.PutBefore(lb, merge_names_, value_name);
771 if (gvn_->NullCheckedInAllPredecessors(merge_names_)) {
772 null_checked_.insert(value_name);
773 }
774 }
775 }
776 sfield_value_map_.PutBefore(hint, field_id, value_name);
777}
778
779void LocalValueNumbering::MergeNonAliasingIFieldValues(const IFieldLocToValueMap::value_type& entry,
780 IFieldLocToValueMap::iterator hint) {
781 uint16_t field_loc = entry.first;
782 merge_names_.clear();
783 uint16_t value_name = kNoValue;
784 bool same_values = true;
785 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
786 // Get the value name as in HandleIGet() but don't modify *lvn.
787 auto it = lvn->non_aliasing_ifield_value_map_.find(field_loc);
788 if (it != lvn->non_aliasing_ifield_value_map_.end()) {
789 value_name = it->second;
790 } else {
791 value_name = gvn_->LookupValue(kNonAliasingIFieldInitialOp, field_loc, kNoValue, kNoValue);
792 }
793
794 same_values = same_values && (merge_names_.empty() || value_name == merge_names_.back());
795 merge_names_.push_back(value_name);
796 }
797 if (same_values) {
798 // value_name already contains the result.
799 } else {
800 auto lb = merge_map_.lower_bound(merge_names_);
801 if (lb != merge_map_.end() && !merge_map_.key_comp()(merge_names_, lb->first)) {
802 value_name = lb->second;
803 } else {
804 value_name = gvn_->LookupValue(kMergeBlockNonAliasingIFieldVersionBumpOp, field_loc,
805 id_, kNoValue);
806 merge_map_.PutBefore(lb, merge_names_, value_name);
807 if (gvn_->NullCheckedInAllPredecessors(merge_names_)) {
808 null_checked_.insert(value_name);
809 }
810 }
811 }
812 non_aliasing_ifield_value_map_.PutBefore(hint, field_loc, value_name);
813}
814
815template <typename Map, Map LocalValueNumbering::*map_ptr, typename Versions>
816void LocalValueNumbering::MergeAliasingValues(const typename Map::value_type& entry,
817 typename Map::iterator hint) {
818 const typename Map::key_type& key = entry.first;
819
Vladimir Markob19955d2014-07-29 12:04:10 +0100820 auto it = (this->*map_ptr).PutBefore(hint, key, AliasingValues(this));
Vladimir Marko95a05972014-05-30 10:01:32 +0100821 AliasingValues* my_values = &it->second;
822
823 const AliasingValues* cmp_values = nullptr;
824 bool same_version = !Versions::HasNewBaseVersion(gvn_, this, key);
825 uint16_t load_memory_version_for_same_version = kNoValue;
826 if (same_version) {
827 // Find the first non-null values.
828 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800829 auto value = (lvn->*map_ptr).find(key);
830 if (value != (lvn->*map_ptr).end()) {
831 cmp_values = &value->second;
Vladimir Marko95a05972014-05-30 10:01:32 +0100832 break;
833 }
834 }
835 DCHECK(cmp_values != nullptr); // There must be at least one non-null values.
836
837 // Check if we have identical memory versions, i.e. the global memory version, unresolved
838 // field version and the values' memory_version_before_stores, last_stored_value
839 // and store_loc_set are identical.
840 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800841 auto value = (lvn->*map_ptr).find(key);
842 if (value == (lvn->*map_ptr).end()) {
Vladimir Marko95a05972014-05-30 10:01:32 +0100843 if (cmp_values->memory_version_before_stores != kNoValue) {
844 same_version = false;
845 break;
846 }
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800847 } else if (cmp_values->last_stored_value != value->second.last_stored_value ||
848 cmp_values->memory_version_before_stores != value->second.memory_version_before_stores ||
849 cmp_values->store_loc_set != value->second.store_loc_set) {
Vladimir Marko95a05972014-05-30 10:01:32 +0100850 same_version = false;
851 break;
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800852 } else if (value->second.last_load_memory_version != kNoValue) {
Vladimir Marko95a05972014-05-30 10:01:32 +0100853 DCHECK(load_memory_version_for_same_version == kNoValue ||
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800854 load_memory_version_for_same_version == value->second.last_load_memory_version);
855 load_memory_version_for_same_version = value->second.last_load_memory_version;
Vladimir Marko95a05972014-05-30 10:01:32 +0100856 }
857 }
858 }
859
860 if (same_version) {
861 // Copy the identical values.
862 my_values->memory_version_before_stores = cmp_values->memory_version_before_stores;
863 my_values->last_stored_value = cmp_values->last_stored_value;
864 my_values->store_loc_set = cmp_values->store_loc_set;
865 my_values->last_load_memory_version = load_memory_version_for_same_version;
866 // Merge load values seen in all incoming arcs (i.e. an intersection).
867 if (!cmp_values->load_value_map.empty()) {
868 my_values->load_value_map = cmp_values->load_value_map;
869 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800870 auto value = (lvn->*map_ptr).find(key);
871 if (value == (lvn->*map_ptr).end() || value->second.load_value_map.empty()) {
Vladimir Marko95a05972014-05-30 10:01:32 +0100872 my_values->load_value_map.clear();
873 break;
874 }
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800875 InPlaceIntersectMaps(&my_values->load_value_map, value->second.load_value_map);
Vladimir Marko95a05972014-05-30 10:01:32 +0100876 if (my_values->load_value_map.empty()) {
877 break;
878 }
879 }
880 }
881 } else {
882 // Bump version number for the merge.
883 my_values->memory_version_before_stores = my_values->last_load_memory_version =
884 Versions::LookupMergeBlockValue(gvn_, id_, key);
885
886 // Calculate the locations that have been either read from or written to in each incoming LVN.
887 bool first_lvn = true;
888 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800889 auto value = (lvn->*map_ptr).find(key);
890 if (value == (lvn->*map_ptr).end()) {
Vladimir Marko95a05972014-05-30 10:01:32 +0100891 my_values->load_value_map.clear();
892 break;
893 }
894 if (first_lvn) {
895 first_lvn = false;
896 // Copy the first LVN's locations. Values will be overwritten later.
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800897 my_values->load_value_map = value->second.load_value_map;
898 for (uint16_t location : value->second.store_loc_set) {
Vladimir Marko95a05972014-05-30 10:01:32 +0100899 my_values->load_value_map.Put(location, 0u);
900 }
901 } else {
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800902 IntersectAliasingValueLocations(my_values, &value->second);
Vladimir Marko95a05972014-05-30 10:01:32 +0100903 }
904 }
905 // Calculate merged values for the intersection.
906 for (auto& load_value_entry : my_values->load_value_map) {
907 uint16_t location = load_value_entry.first;
Vladimir Marko95a05972014-05-30 10:01:32 +0100908 merge_names_.clear();
Vladimir Marko7a01dc22015-01-02 17:00:44 +0000909 uint16_t value_name = kNoValue;
910 bool same_values = true;
Vladimir Marko95a05972014-05-30 10:01:32 +0100911 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
912 value_name = Versions::LookupMergeValue(gvn_, lvn, key, location);
913 same_values = same_values && (merge_names_.empty() || value_name == merge_names_.back());
914 merge_names_.push_back(value_name);
915 }
916 if (same_values) {
917 // value_name already contains the result.
918 } else {
919 auto lb = merge_map_.lower_bound(merge_names_);
920 if (lb != merge_map_.end() && !merge_map_.key_comp()(merge_names_, lb->first)) {
921 value_name = lb->second;
922 } else {
923 // NOTE: In addition to the key and id_ which don't change on an LVN recalculation
924 // during GVN, we also add location which can actually change on recalculation, so the
925 // value_name below may change. This could lead to an infinite loop if the location
926 // value name always changed when the refereced value name changes. However, given that
927 // we assign unique value names for other merges, such as Phis, such a dependency is
928 // not possible in a well-formed SSA graph.
929 value_name = Versions::LookupMergeLocationValue(gvn_, id_, key, location);
930 merge_map_.PutBefore(lb, merge_names_, value_name);
931 if (gvn_->NullCheckedInAllPredecessors(merge_names_)) {
932 null_checked_.insert(value_name);
933 }
934 }
935 }
936 load_value_entry.second = value_name;
937 }
938 }
939}
940
941void LocalValueNumbering::Merge(MergeType merge_type) {
942 DCHECK_GE(gvn_->merge_lvns_.size(), 2u);
943
Vladimir Marko7a01dc22015-01-02 17:00:44 +0000944 // Always reserve space in merge_names_. Even if we don't use it in Merge() we may need it
945 // in GetStartingVregValueNumberImpl() when the merge_names_'s allocator is not the top.
946 merge_names_.reserve(gvn_->merge_lvns_.size());
947
Vladimir Markob19955d2014-07-29 12:04:10 +0100948 IntersectSregValueMaps<&LocalValueNumbering::sreg_value_map_>();
949 IntersectSregValueMaps<&LocalValueNumbering::sreg_wide_value_map_>();
Vladimir Marko95a05972014-05-30 10:01:32 +0100950 if (merge_type == kReturnMerge) {
951 // RETURN or PHI+RETURN. We need only sreg value maps.
952 return;
953 }
954
955 MergeMemoryVersions(merge_type == kCatchMerge);
956
957 // Merge non-aliasing maps/sets.
Vladimir Marko95a05972014-05-30 10:01:32 +0100958 IntersectSets<ValueNameSet, &LocalValueNumbering::non_aliasing_refs_>();
Vladimir Marko55fff042014-07-10 12:42:52 +0100959 if (!non_aliasing_refs_.empty() && merge_type == kCatchMerge) {
960 PruneNonAliasingRefsForCatch();
961 }
962 if (!non_aliasing_refs_.empty()) {
963 MergeSets<IFieldLocToValueMap, &LocalValueNumbering::non_aliasing_ifield_value_map_,
964 &LocalValueNumbering::MergeNonAliasingIFieldValues>();
965 MergeSets<NonAliasingArrayValuesMap, &LocalValueNumbering::non_aliasing_array_value_map_,
966 &LocalValueNumbering::MergeAliasingValues<
967 NonAliasingArrayValuesMap, &LocalValueNumbering::non_aliasing_array_value_map_,
968 NonAliasingArrayVersions>>();
969 }
Vladimir Marko95a05972014-05-30 10:01:32 +0100970
971 // We won't do anything complicated for range checks, just calculate the intersection.
972 IntersectSets<RangeCheckSet, &LocalValueNumbering::range_checked_>();
973
974 // Merge null_checked_. We may later insert more, such as merged object field values.
Vladimir Marko2d2365c2014-08-19 18:08:39 +0100975 MergeNullChecked();
Vladimir Marko95a05972014-05-30 10:01:32 +0100976
Razvan A Lupusorue0951142014-11-14 14:36:55 -0800977 // Now merge the div_zero_checked_.
978 MergeDivZeroChecked();
979
Vladimir Marko95a05972014-05-30 10:01:32 +0100980 if (merge_type == kCatchMerge) {
981 // Memory is clobbered. New memory version already created, don't merge aliasing locations.
Vladimir Marko95a05972014-05-30 10:01:32 +0100982 return;
983 }
984
985 DCHECK(merge_type == kNormalMerge);
986
987 // Merge escaped refs and clobber sets.
988 MergeSets<ValueNameSet, &LocalValueNumbering::escaped_refs_,
989 &LocalValueNumbering::MergeEscapedRefs>();
990 if (!escaped_refs_.empty()) {
991 MergeSets<EscapedIFieldClobberSet, &LocalValueNumbering::escaped_ifield_clobber_set_,
992 &LocalValueNumbering::MergeEscapedIFieldTypeClobberSets>();
993 MergeSets<EscapedIFieldClobberSet, &LocalValueNumbering::escaped_ifield_clobber_set_,
994 &LocalValueNumbering::MergeEscapedIFieldClobberSets>();
995 MergeSets<EscapedArrayClobberSet, &LocalValueNumbering::escaped_array_clobber_set_,
996 &LocalValueNumbering::MergeEscapedArrayClobberSets>();
997 }
998
999 MergeSets<SFieldToValueMap, &LocalValueNumbering::sfield_value_map_,
1000 &LocalValueNumbering::MergeSFieldValues>();
1001 MergeSets<AliasingIFieldValuesMap, &LocalValueNumbering::aliasing_ifield_value_map_,
1002 &LocalValueNumbering::MergeAliasingValues<
1003 AliasingIFieldValuesMap, &LocalValueNumbering::aliasing_ifield_value_map_,
1004 AliasingIFieldVersions>>();
1005 MergeSets<AliasingArrayValuesMap, &LocalValueNumbering::aliasing_array_value_map_,
1006 &LocalValueNumbering::MergeAliasingValues<
1007 AliasingArrayValuesMap, &LocalValueNumbering::aliasing_array_value_map_,
1008 AliasingArrayVersions>>();
Vladimir Markof59f18b2014-02-17 15:53:57 +00001009}
1010
Vladimir Markoa4426cf2014-10-22 17:15:53 +01001011void LocalValueNumbering::PrepareEntryBlock() {
1012 uint32_t vreg = gvn_->GetMirGraph()->GetFirstInVR();
1013 CompilationUnit* cu = gvn_->GetCompilationUnit();
1014 const char* shorty = cu->shorty;
1015 ++shorty; // Skip return value.
1016 if ((cu->access_flags & kAccStatic) == 0) {
1017 // If non-static method, mark "this" as non-null
1018 uint16_t value_name = GetOperandValue(vreg);
1019 ++vreg;
1020 null_checked_.insert(value_name);
1021 }
1022 for ( ; *shorty != 0; ++shorty, ++vreg) {
1023 if (*shorty == 'J' || *shorty == 'D') {
1024 uint16_t value_name = GetOperandValueWide(vreg);
1025 SetOperandValueWide(vreg, value_name);
1026 ++vreg;
1027 }
1028 }
1029}
1030
Vladimir Markof59f18b2014-02-17 15:53:57 +00001031uint16_t LocalValueNumbering::MarkNonAliasingNonNull(MIR* mir) {
1032 uint16_t res = GetOperandValue(mir->ssa_rep->defs[0]);
Vladimir Markof59f18b2014-02-17 15:53:57 +00001033 DCHECK(null_checked_.find(res) == null_checked_.end());
1034 null_checked_.insert(res);
1035 non_aliasing_refs_.insert(res);
1036 return res;
1037}
1038
Vladimir Marko95a05972014-05-30 10:01:32 +01001039bool LocalValueNumbering::IsNonAliasing(uint16_t reg) const {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001040 return non_aliasing_refs_.find(reg) != non_aliasing_refs_.end();
Vladimir Markof59f18b2014-02-17 15:53:57 +00001041}
1042
Vladimir Marko95a05972014-05-30 10:01:32 +01001043bool LocalValueNumbering::IsNonAliasingIField(uint16_t reg, uint16_t field_id,
1044 uint16_t type) const {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001045 if (IsNonAliasing(reg)) {
1046 return true;
1047 }
Vladimir Marko95a05972014-05-30 10:01:32 +01001048 if (escaped_refs_.find(reg) == escaped_refs_.end()) {
1049 return false;
1050 }
1051 // Check for IPUTs to unresolved fields.
1052 EscapedIFieldClobberKey key1 = { reg, type, kNoValue };
1053 if (escaped_ifield_clobber_set_.find(key1) != escaped_ifield_clobber_set_.end()) {
1054 return false;
1055 }
1056 // Check for aliased IPUTs to the same field.
1057 EscapedIFieldClobberKey key2 = { reg, type, field_id };
1058 return escaped_ifield_clobber_set_.find(key2) == escaped_ifield_clobber_set_.end();
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001059}
1060
Vladimir Marko95a05972014-05-30 10:01:32 +01001061bool LocalValueNumbering::IsNonAliasingArray(uint16_t reg, uint16_t type) const {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001062 if (IsNonAliasing(reg)) {
1063 return true;
1064 }
Vladimir Marko95a05972014-05-30 10:01:32 +01001065 if (escaped_refs_.count(reg) == 0u) {
1066 return false;
1067 }
1068 // Check for aliased APUTs.
1069 EscapedArrayClobberKey key = { reg, type };
1070 return escaped_array_clobber_set_.find(key) == escaped_array_clobber_set_.end();
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001071}
1072
Vladimir Markof59f18b2014-02-17 15:53:57 +00001073void LocalValueNumbering::HandleNullCheck(MIR* mir, uint16_t reg) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001074 auto lb = null_checked_.lower_bound(reg);
1075 if (lb != null_checked_.end() && *lb == reg) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001076 if (LIKELY(gvn_->CanModify())) {
1077 if (gvn_->GetCompilationUnit()->verbose) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001078 LOG(INFO) << "Removing null check for 0x" << std::hex << mir->offset;
1079 }
1080 mir->optimization_flags |= MIR_IGNORE_NULL_CHECK;
Vladimir Markof59f18b2014-02-17 15:53:57 +00001081 }
Vladimir Markof59f18b2014-02-17 15:53:57 +00001082 } else {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001083 null_checked_.insert(lb, reg);
Vladimir Markof59f18b2014-02-17 15:53:57 +00001084 }
1085}
1086
1087void LocalValueNumbering::HandleRangeCheck(MIR* mir, uint16_t array, uint16_t index) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001088 RangeCheckKey key = { array, index };
1089 auto lb = range_checked_.lower_bound(key);
1090 if (lb != range_checked_.end() && !RangeCheckKeyComparator()(key, *lb)) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001091 if (LIKELY(gvn_->CanModify())) {
1092 if (gvn_->GetCompilationUnit()->verbose) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001093 LOG(INFO) << "Removing range check for 0x" << std::hex << mir->offset;
1094 }
1095 mir->optimization_flags |= MIR_IGNORE_RANGE_CHECK;
Vladimir Markof59f18b2014-02-17 15:53:57 +00001096 }
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001097 } else {
1098 // Mark range check completed.
1099 range_checked_.insert(lb, key);
Vladimir Markof59f18b2014-02-17 15:53:57 +00001100 }
Vladimir Markof59f18b2014-02-17 15:53:57 +00001101}
1102
Razvan A Lupusorue0951142014-11-14 14:36:55 -08001103void LocalValueNumbering::HandleDivZeroCheck(MIR* mir, uint16_t reg) {
1104 auto lb = div_zero_checked_.lower_bound(reg);
1105 if (lb != div_zero_checked_.end() && *lb == reg) {
1106 if (LIKELY(gvn_->CanModify())) {
1107 if (gvn_->GetCompilationUnit()->verbose) {
1108 LOG(INFO) << "Removing div zero check for 0x" << std::hex << mir->offset;
1109 }
1110 mir->optimization_flags |= MIR_IGNORE_DIV_ZERO_CHECK;
1111 }
1112 } else {
1113 div_zero_checked_.insert(lb, reg);
1114 }
1115}
1116
Vladimir Markof59f18b2014-02-17 15:53:57 +00001117void LocalValueNumbering::HandlePutObject(MIR* mir) {
1118 // If we're storing a non-aliasing reference, stop tracking it as non-aliasing now.
1119 uint16_t base = GetOperandValue(mir->ssa_rep->uses[0]);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001120 HandleEscapingRef(base);
Vladimir Marko743b98c2014-11-24 19:45:41 +00001121 if (gvn_->CanModify() && null_checked_.count(base) != 0u) {
1122 if (gvn_->GetCompilationUnit()->verbose) {
1123 LOG(INFO) << "Removing GC card mark value null check for 0x" << std::hex << mir->offset;
1124 }
1125 mir->optimization_flags |= MIR_STORE_NON_NULL_VALUE;
1126 }
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001127}
1128
1129void LocalValueNumbering::HandleEscapingRef(uint16_t base) {
1130 auto it = non_aliasing_refs_.find(base);
1131 if (it != non_aliasing_refs_.end()) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001132 non_aliasing_refs_.erase(it);
Vladimir Marko95a05972014-05-30 10:01:32 +01001133 escaped_refs_.insert(base);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001134 }
1135}
1136
Vladimir Markoa4426cf2014-10-22 17:15:53 +01001137void LocalValueNumbering::HandleInvokeArgs(const MIR* mir, const LocalValueNumbering* mir_lvn) {
1138 const int32_t* uses = mir->ssa_rep->uses;
1139 const int32_t* uses_end = uses + mir->ssa_rep->num_uses;
1140 while (uses != uses_end) {
1141 uint16_t sreg = *uses;
1142 ++uses;
1143 // Avoid LookupValue() so that we don't store new values in the global value map.
1144 auto local_it = mir_lvn->sreg_value_map_.find(sreg);
1145 if (local_it != mir_lvn->sreg_value_map_.end()) {
1146 non_aliasing_refs_.erase(local_it->second);
1147 } else {
1148 uint16_t value_name = gvn_->FindValue(kNoValue, sreg, kNoValue, kNoValue);
1149 if (value_name != kNoValue) {
1150 non_aliasing_refs_.erase(value_name);
1151 }
1152 }
1153 }
1154}
1155
Vladimir Marko95a05972014-05-30 10:01:32 +01001156uint16_t LocalValueNumbering::HandlePhi(MIR* mir) {
1157 if (gvn_->merge_lvns_.empty()) {
1158 // Running LVN without a full GVN?
1159 return kNoValue;
1160 }
Vladimir Markoa5e69e82015-04-24 19:03:51 +01001161 // Determine if this Phi is merging wide regs.
1162 RegLocation raw_dest = gvn_->GetMirGraph()->GetRawDest(mir);
1163 if (raw_dest.high_word) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001164 // This is the high part of a wide reg. Ignore the Phi.
1165 return kNoValue;
1166 }
Vladimir Markoa5e69e82015-04-24 19:03:51 +01001167 bool wide = raw_dest.wide;
Vladimir Marko95a05972014-05-30 10:01:32 +01001168 // Iterate over *merge_lvns_ and skip incoming sregs for BBs without associated LVN.
Vladimir Marko95a05972014-05-30 10:01:32 +01001169 merge_names_.clear();
Vladimir Marko7a01dc22015-01-02 17:00:44 +00001170 uint16_t value_name = kNoValue;
Vladimir Marko95a05972014-05-30 10:01:32 +01001171 bool same_values = true;
Vladimir Markoa5e69e82015-04-24 19:03:51 +01001172 BasicBlockId* incoming = mir->meta.phi_incoming;
1173 int32_t* uses = mir->ssa_rep->uses;
1174 int16_t pos = 0;
Vladimir Marko95a05972014-05-30 10:01:32 +01001175 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
1176 DCHECK_LT(pos, mir->ssa_rep->num_uses);
1177 while (incoming[pos] != lvn->Id()) {
1178 ++pos;
1179 DCHECK_LT(pos, mir->ssa_rep->num_uses);
1180 }
1181 int s_reg = uses[pos];
1182 ++pos;
1183 value_name = wide ? lvn->GetOperandValueWide(s_reg) : lvn->GetOperandValue(s_reg);
1184
1185 same_values = same_values && (merge_names_.empty() || value_name == merge_names_.back());
1186 merge_names_.push_back(value_name);
1187 }
1188 if (same_values) {
1189 // value_name already contains the result.
1190 } else {
1191 auto lb = merge_map_.lower_bound(merge_names_);
1192 if (lb != merge_map_.end() && !merge_map_.key_comp()(merge_names_, lb->first)) {
1193 value_name = lb->second;
1194 } else {
1195 value_name = gvn_->LookupValue(kNoValue, mir->ssa_rep->defs[0], kNoValue, kNoValue);
1196 merge_map_.PutBefore(lb, merge_names_, value_name);
1197 if (!wide && gvn_->NullCheckedInAllPredecessors(merge_names_)) {
1198 null_checked_.insert(value_name);
1199 }
Razvan A Lupusorue0951142014-11-14 14:36:55 -08001200 if (gvn_->DivZeroCheckedInAllPredecessors(merge_names_)) {
1201 div_zero_checked_.insert(value_name);
1202 }
Vladimir Marko95a05972014-05-30 10:01:32 +01001203 }
1204 }
1205 if (wide) {
1206 SetOperandValueWide(mir->ssa_rep->defs[0], value_name);
1207 } else {
1208 SetOperandValue(mir->ssa_rep->defs[0], value_name);
1209 }
1210 return value_name;
1211}
1212
Vladimir Marko22c7f5b2015-02-18 17:52:39 +00001213uint16_t LocalValueNumbering::HandleConst(MIR* mir, uint32_t value) {
1214 RegLocation raw_dest = gvn_->GetMirGraph()->GetRawDest(mir);
1215 uint16_t res;
1216 if (value == 0u && raw_dest.ref) {
1217 res = GlobalValueNumbering::kNullValue;
1218 } else {
1219 Instruction::Code op = raw_dest.fp ? Instruction::CONST_HIGH16 : Instruction::CONST;
1220 res = gvn_->LookupValue(op, Low16Bits(value), High16Bits(value), 0);
1221 }
1222 SetOperandValue(mir->ssa_rep->defs[0], res);
1223 return res;
1224}
1225
1226uint16_t LocalValueNumbering::HandleConstWide(MIR* mir, uint64_t value) {
1227 RegLocation raw_dest = gvn_->GetMirGraph()->GetRawDest(mir);
1228 Instruction::Code op = raw_dest.fp ? Instruction::CONST_HIGH16 : Instruction::CONST;
1229 uint32_t low_word = Low32Bits(value);
1230 uint32_t high_word = High32Bits(value);
1231 uint16_t low_res = gvn_->LookupValue(op, Low16Bits(low_word), High16Bits(low_word), 1);
1232 uint16_t high_res = gvn_->LookupValue(op, Low16Bits(high_word), High16Bits(high_word), 2);
1233 uint16_t res = gvn_->LookupValue(op, low_res, high_res, 3);
1234 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1235 return res;
1236}
1237
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001238uint16_t LocalValueNumbering::HandleAGet(MIR* mir, uint16_t opcode) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001239 uint16_t array = GetOperandValue(mir->ssa_rep->uses[0]);
1240 HandleNullCheck(mir, array);
1241 uint16_t index = GetOperandValue(mir->ssa_rep->uses[1]);
1242 HandleRangeCheck(mir, array, index);
Vladimir Markoaf6925b2014-10-31 16:37:32 +00001243 uint16_t type = AGetMemAccessType(static_cast<Instruction::Code>(opcode));
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001244 // Establish value number for loaded register.
1245 uint16_t res;
1246 if (IsNonAliasingArray(array, type)) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001247 res = HandleAliasingValuesGet<NonAliasingArrayVersions>(&non_aliasing_array_value_map_,
1248 array, index);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001249 } else {
Vladimir Marko95a05972014-05-30 10:01:32 +01001250 uint16_t location = gvn_->GetArrayLocation(array, index);
1251 res = HandleAliasingValuesGet<AliasingArrayVersions>(&aliasing_array_value_map_,
1252 type, location);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001253 }
1254 if (opcode == Instruction::AGET_WIDE) {
1255 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1256 } else {
1257 SetOperandValue(mir->ssa_rep->defs[0], res);
1258 }
1259 return res;
1260}
1261
1262void LocalValueNumbering::HandleAPut(MIR* mir, uint16_t opcode) {
1263 int array_idx = (opcode == Instruction::APUT_WIDE) ? 2 : 1;
1264 int index_idx = array_idx + 1;
1265 uint16_t array = GetOperandValue(mir->ssa_rep->uses[array_idx]);
1266 HandleNullCheck(mir, array);
1267 uint16_t index = GetOperandValue(mir->ssa_rep->uses[index_idx]);
1268 HandleRangeCheck(mir, array, index);
1269
Vladimir Markoaf6925b2014-10-31 16:37:32 +00001270 uint16_t type = APutMemAccessType(static_cast<Instruction::Code>(opcode));
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001271 uint16_t value = (opcode == Instruction::APUT_WIDE)
1272 ? GetOperandValueWide(mir->ssa_rep->uses[0])
1273 : GetOperandValue(mir->ssa_rep->uses[0]);
1274 if (IsNonAliasing(array)) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001275 bool put_is_live = HandleAliasingValuesPut<NonAliasingArrayVersions>(
1276 &non_aliasing_array_value_map_, array, index, value);
1277 if (!put_is_live) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001278 // This APUT can be eliminated, it stores the same value that's already in the field.
1279 // TODO: Eliminate the APUT.
1280 return;
1281 }
Vladimir Marko95a05972014-05-30 10:01:32 +01001282 } else {
1283 uint16_t location = gvn_->GetArrayLocation(array, index);
1284 bool put_is_live = HandleAliasingValuesPut<AliasingArrayVersions>(
1285 &aliasing_array_value_map_, type, location, value);
1286 if (!put_is_live) {
1287 // This APUT can be eliminated, it stores the same value that's already in the field.
1288 // TODO: Eliminate the APUT.
1289 return;
1290 }
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001291
Vladimir Marko95a05972014-05-30 10:01:32 +01001292 // Clobber all escaped array refs for this type.
1293 for (uint16_t escaped_array : escaped_refs_) {
1294 EscapedArrayClobberKey clobber_key = { escaped_array, type };
1295 escaped_array_clobber_set_.insert(clobber_key);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001296 }
1297 }
1298}
1299
1300uint16_t LocalValueNumbering::HandleIGet(MIR* mir, uint16_t opcode) {
1301 uint16_t base = GetOperandValue(mir->ssa_rep->uses[0]);
1302 HandleNullCheck(mir, base);
Vladimir Marko95a05972014-05-30 10:01:32 +01001303 const MirFieldInfo& field_info = gvn_->GetMirGraph()->GetIFieldLoweringInfo(mir);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001304 uint16_t res;
1305 if (!field_info.IsResolved() || field_info.IsVolatile()) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001306 // Unresolved fields may be volatile, so handle them as such to be safe.
Vladimir Markofa236452014-09-29 17:58:10 +01001307 HandleInvokeOrClInitOrAcquireOp(mir); // Volatile GETs have acquire semantics.
1308 // Volatile fields always get a new memory version; field id is irrelevant.
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001309 // Use result s_reg - will be unique.
Vladimir Marko95a05972014-05-30 10:01:32 +01001310 res = gvn_->LookupValue(kNoValue, mir->ssa_rep->defs[0], kNoValue, kNoValue);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001311 } else {
Vladimir Markoaf6925b2014-10-31 16:37:32 +00001312 uint16_t type = IGetMemAccessType(static_cast<Instruction::Code>(opcode));
1313 uint16_t field_id = gvn_->GetIFieldId(mir);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001314 if (IsNonAliasingIField(base, field_id, type)) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001315 uint16_t loc = gvn_->LookupValue(kNonAliasingIFieldLocOp, base, field_id, type);
1316 auto lb = non_aliasing_ifield_value_map_.lower_bound(loc);
1317 if (lb != non_aliasing_ifield_value_map_.end() && lb->first == loc) {
1318 res = lb->second;
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001319 } else {
Vladimir Marko95a05972014-05-30 10:01:32 +01001320 res = gvn_->LookupValue(kNonAliasingIFieldInitialOp, loc, kNoValue, kNoValue);
1321 non_aliasing_ifield_value_map_.PutBefore(lb, loc, res);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001322 }
Vladimir Marko95a05972014-05-30 10:01:32 +01001323 } else {
1324 res = HandleAliasingValuesGet<AliasingIFieldVersions>(&aliasing_ifield_value_map_,
1325 field_id, base);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001326 }
1327 }
1328 if (opcode == Instruction::IGET_WIDE) {
1329 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1330 } else {
1331 SetOperandValue(mir->ssa_rep->defs[0], res);
1332 }
1333 return res;
1334}
1335
1336void LocalValueNumbering::HandleIPut(MIR* mir, uint16_t opcode) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001337 int base_reg = (opcode == Instruction::IPUT_WIDE) ? 2 : 1;
1338 uint16_t base = GetOperandValue(mir->ssa_rep->uses[base_reg]);
1339 HandleNullCheck(mir, base);
Vladimir Markoaf6925b2014-10-31 16:37:32 +00001340 uint16_t type = IPutMemAccessType(static_cast<Instruction::Code>(opcode));
Vladimir Marko95a05972014-05-30 10:01:32 +01001341 const MirFieldInfo& field_info = gvn_->GetMirGraph()->GetIFieldLoweringInfo(mir);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001342 if (!field_info.IsResolved()) {
1343 // Unresolved fields always alias with everything of the same type.
1344 // Use mir->offset as modifier; without elaborate inlining, it will be unique.
1345 unresolved_ifield_version_[type] =
Vladimir Marko95a05972014-05-30 10:01:32 +01001346 gvn_->LookupValue(kUnresolvedIFieldOp, kNoValue, kNoValue, mir->offset);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001347
Vladimir Marko95a05972014-05-30 10:01:32 +01001348 // For simplicity, treat base as escaped now.
1349 HandleEscapingRef(base);
1350
1351 // Clobber all fields of escaped references of the same type.
1352 for (uint16_t escaped_ref : escaped_refs_) {
1353 EscapedIFieldClobberKey clobber_key = { escaped_ref, type, kNoValue };
1354 escaped_ifield_clobber_set_.insert(clobber_key);
1355 }
1356
1357 // Aliasing fields of the same type may have been overwritten.
1358 auto it = aliasing_ifield_value_map_.begin(), end = aliasing_ifield_value_map_.end();
1359 while (it != end) {
Vladimir Markoaf6925b2014-10-31 16:37:32 +00001360 if (gvn_->GetIFieldType(it->first) != type) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001361 ++it;
1362 } else {
1363 it = aliasing_ifield_value_map_.erase(it);
1364 }
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001365 }
1366 } else if (field_info.IsVolatile()) {
1367 // Nothing to do, resolved volatile fields always get a new memory version anyway and
1368 // can't alias with resolved non-volatile fields.
1369 } else {
Vladimir Markoaf6925b2014-10-31 16:37:32 +00001370 uint16_t field_id = gvn_->GetIFieldId(mir);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001371 uint16_t value = (opcode == Instruction::IPUT_WIDE)
1372 ? GetOperandValueWide(mir->ssa_rep->uses[0])
1373 : GetOperandValue(mir->ssa_rep->uses[0]);
1374 if (IsNonAliasing(base)) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001375 uint16_t loc = gvn_->LookupValue(kNonAliasingIFieldLocOp, base, field_id, type);
1376 auto lb = non_aliasing_ifield_value_map_.lower_bound(loc);
1377 if (lb != non_aliasing_ifield_value_map_.end() && lb->first == loc) {
1378 if (lb->second == value) {
1379 // This IPUT can be eliminated, it stores the same value that's already in the field.
1380 // TODO: Eliminate the IPUT.
1381 return;
1382 }
1383 lb->second = value; // Overwrite.
1384 } else {
1385 non_aliasing_ifield_value_map_.PutBefore(lb, loc, value);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001386 }
Vladimir Marko95a05972014-05-30 10:01:32 +01001387 } else {
1388 bool put_is_live = HandleAliasingValuesPut<AliasingIFieldVersions>(
1389 &aliasing_ifield_value_map_, field_id, base, value);
1390 if (!put_is_live) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001391 // This IPUT can be eliminated, it stores the same value that's already in the field.
1392 // TODO: Eliminate the IPUT.
1393 return;
1394 }
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001395
Vladimir Marko95a05972014-05-30 10:01:32 +01001396 // Clobber all fields of escaped references for this field.
1397 for (uint16_t escaped_ref : escaped_refs_) {
1398 EscapedIFieldClobberKey clobber_key = { escaped_ref, type, field_id };
1399 escaped_ifield_clobber_set_.insert(clobber_key);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001400 }
1401 }
1402 }
1403}
1404
1405uint16_t LocalValueNumbering::HandleSGet(MIR* mir, uint16_t opcode) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001406 const MirSFieldLoweringInfo& field_info = gvn_->GetMirGraph()->GetSFieldLoweringInfo(mir);
Vladimir Markofa236452014-09-29 17:58:10 +01001407 if (!field_info.IsResolved() || field_info.IsVolatile() ||
Vladimir Marko66c6d7b2014-10-16 15:41:48 +01001408 (!field_info.IsClassInitialized() &&
1409 (mir->optimization_flags & MIR_CLASS_IS_INITIALIZED) == 0)) {
Vladimir Markofa236452014-09-29 17:58:10 +01001410 // Volatile SGETs (and unresolved fields are potentially volatile) have acquire semantics
1411 // and class initialization can call arbitrary functions, we need to wipe aliasing values.
1412 HandleInvokeOrClInitOrAcquireOp(mir);
Vladimir Markof418f322014-07-09 14:45:36 +01001413 }
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001414 uint16_t res;
1415 if (!field_info.IsResolved() || field_info.IsVolatile()) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001416 // Unresolved fields may be volatile, so handle them as such to be safe.
Vladimir Markofa236452014-09-29 17:58:10 +01001417 // Volatile fields always get a new memory version; field id is irrelevant.
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001418 // Use result s_reg - will be unique.
Vladimir Marko95a05972014-05-30 10:01:32 +01001419 res = gvn_->LookupValue(kNoValue, mir->ssa_rep->defs[0], kNoValue, kNoValue);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001420 } else {
Vladimir Markoaf6925b2014-10-31 16:37:32 +00001421 uint16_t type = SGetMemAccessType(static_cast<Instruction::Code>(opcode));
1422 uint16_t field_id = gvn_->GetSFieldId(mir);
Vladimir Marko95a05972014-05-30 10:01:32 +01001423 auto lb = sfield_value_map_.lower_bound(field_id);
1424 if (lb != sfield_value_map_.end() && lb->first == field_id) {
1425 res = lb->second;
1426 } else {
1427 // Resolved non-volatile static fields can alias with non-resolved fields of the same type,
1428 // so we need to use unresolved_sfield_version_[type] in addition to global_memory_version_
1429 // to determine the version of the field.
1430 res = gvn_->LookupValue(kResolvedSFieldOp, field_id,
1431 unresolved_sfield_version_[type], global_memory_version_);
1432 sfield_value_map_.PutBefore(lb, field_id, res);
1433 }
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001434 }
1435 if (opcode == Instruction::SGET_WIDE) {
1436 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1437 } else {
1438 SetOperandValue(mir->ssa_rep->defs[0], res);
1439 }
1440 return res;
1441}
1442
1443void LocalValueNumbering::HandleSPut(MIR* mir, uint16_t opcode) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001444 const MirSFieldLoweringInfo& field_info = gvn_->GetMirGraph()->GetSFieldLoweringInfo(mir);
Vladimir Marko66c6d7b2014-10-16 15:41:48 +01001445 if (!field_info.IsClassInitialized() &&
1446 (mir->optimization_flags & MIR_CLASS_IS_INITIALIZED) == 0) {
Vladimir Markof418f322014-07-09 14:45:36 +01001447 // Class initialization can call arbitrary functions, we need to wipe aliasing values.
Vladimir Markofa236452014-09-29 17:58:10 +01001448 HandleInvokeOrClInitOrAcquireOp(mir);
Vladimir Markof418f322014-07-09 14:45:36 +01001449 }
Vladimir Markoaf6925b2014-10-31 16:37:32 +00001450 uint16_t type = SPutMemAccessType(static_cast<Instruction::Code>(opcode));
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001451 if (!field_info.IsResolved()) {
1452 // Unresolved fields always alias with everything of the same type.
1453 // Use mir->offset as modifier; without elaborate inlining, it will be unique.
1454 unresolved_sfield_version_[type] =
Vladimir Marko95a05972014-05-30 10:01:32 +01001455 gvn_->LookupValue(kUnresolvedSFieldOp, kNoValue, kNoValue, mir->offset);
1456 RemoveSFieldsForType(type);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001457 } else if (field_info.IsVolatile()) {
1458 // Nothing to do, resolved volatile fields always get a new memory version anyway and
1459 // can't alias with resolved non-volatile fields.
1460 } else {
Vladimir Markoaf6925b2014-10-31 16:37:32 +00001461 uint16_t field_id = gvn_->GetSFieldId(mir);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001462 uint16_t value = (opcode == Instruction::SPUT_WIDE)
1463 ? GetOperandValueWide(mir->ssa_rep->uses[0])
1464 : GetOperandValue(mir->ssa_rep->uses[0]);
1465 // Resolved non-volatile static fields can alias with non-resolved fields of the same type,
1466 // so we need to use unresolved_sfield_version_[type] in addition to global_memory_version_
1467 // to determine the version of the field.
Vladimir Marko95a05972014-05-30 10:01:32 +01001468 auto lb = sfield_value_map_.lower_bound(field_id);
1469 if (lb != sfield_value_map_.end() && lb->first == field_id) {
1470 if (lb->second == value) {
1471 // This SPUT can be eliminated, it stores the same value that's already in the field.
1472 // TODO: Eliminate the SPUT.
1473 return;
1474 }
1475 lb->second = value; // Overwrite.
1476 } else {
1477 sfield_value_map_.PutBefore(lb, field_id, value);
1478 }
1479 }
1480}
1481
1482void LocalValueNumbering::RemoveSFieldsForType(uint16_t type) {
1483 // Erase all static fields of this type from the sfield_value_map_.
1484 for (auto it = sfield_value_map_.begin(), end = sfield_value_map_.end(); it != end; ) {
Vladimir Markoaf6925b2014-10-31 16:37:32 +00001485 if (gvn_->GetSFieldType(it->first) == type) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001486 it = sfield_value_map_.erase(it);
1487 } else {
1488 ++it;
1489 }
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001490 }
Vladimir Markof59f18b2014-02-17 15:53:57 +00001491}
buzbee2502e002012-12-31 16:05:53 -08001492
Vladimir Markofa236452014-09-29 17:58:10 +01001493void LocalValueNumbering::HandleInvokeOrClInitOrAcquireOp(MIR* mir) {
Vladimir Markof418f322014-07-09 14:45:36 +01001494 // Use mir->offset as modifier; without elaborate inlining, it will be unique.
Vladimir Marko95a05972014-05-30 10:01:32 +01001495 global_memory_version_ =
1496 gvn_->LookupValue(kInvokeMemoryVersionBumpOp, 0u, 0u, mir->offset);
1497 // All static fields and instance fields and array elements of aliasing references,
1498 // including escaped references, may have been modified.
1499 sfield_value_map_.clear();
1500 aliasing_ifield_value_map_.clear();
1501 aliasing_array_value_map_.clear();
1502 escaped_refs_.clear();
1503 escaped_ifield_clobber_set_.clear();
1504 escaped_array_clobber_set_.clear();
Vladimir Markof418f322014-07-09 14:45:36 +01001505}
1506
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001507uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001508 uint16_t res = kNoValue;
buzbee2502e002012-12-31 16:05:53 -08001509 uint16_t opcode = mir->dalvikInsn.opcode;
1510 switch (opcode) {
1511 case Instruction::NOP:
1512 case Instruction::RETURN_VOID:
1513 case Instruction::RETURN:
1514 case Instruction::RETURN_OBJECT:
1515 case Instruction::RETURN_WIDE:
buzbee2502e002012-12-31 16:05:53 -08001516 case Instruction::GOTO:
1517 case Instruction::GOTO_16:
1518 case Instruction::GOTO_32:
buzbee2502e002012-12-31 16:05:53 -08001519 case Instruction::THROW:
1520 case Instruction::FILL_ARRAY_DATA:
buzbee2502e002012-12-31 16:05:53 -08001521 case Instruction::PACKED_SWITCH:
1522 case Instruction::SPARSE_SWITCH:
1523 case Instruction::IF_EQ:
1524 case Instruction::IF_NE:
1525 case Instruction::IF_LT:
1526 case Instruction::IF_GE:
1527 case Instruction::IF_GT:
1528 case Instruction::IF_LE:
1529 case Instruction::IF_EQZ:
1530 case Instruction::IF_NEZ:
1531 case Instruction::IF_LTZ:
1532 case Instruction::IF_GEZ:
1533 case Instruction::IF_GTZ:
1534 case Instruction::IF_LEZ:
buzbee2502e002012-12-31 16:05:53 -08001535 case kMirOpFusedCmplFloat:
1536 case kMirOpFusedCmpgFloat:
1537 case kMirOpFusedCmplDouble:
1538 case kMirOpFusedCmpgDouble:
1539 case kMirOpFusedCmpLong:
1540 // Nothing defined - take no action.
1541 break;
1542
Vladimir Marko95a05972014-05-30 10:01:32 +01001543 case Instruction::MONITOR_ENTER:
1544 HandleNullCheck(mir, GetOperandValue(mir->ssa_rep->uses[0]));
Vladimir Markofa236452014-09-29 17:58:10 +01001545 HandleInvokeOrClInitOrAcquireOp(mir); // Acquire operation.
Vladimir Marko95a05972014-05-30 10:01:32 +01001546 break;
1547
1548 case Instruction::MONITOR_EXIT:
1549 HandleNullCheck(mir, GetOperandValue(mir->ssa_rep->uses[0]));
1550 // If we're running GVN and CanModify(), uneliminated null check indicates bytecode error.
Vladimir Marko415ac882014-09-30 18:09:14 +01001551 if ((mir->optimization_flags & MIR_IGNORE_NULL_CHECK) == 0 &&
1552 gvn_->work_lvn_ != nullptr && gvn_->CanModify()) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001553 LOG(WARNING) << "Bytecode error: MONITOR_EXIT is still null checked at 0x" << std::hex
1554 << mir->offset << " in " << PrettyMethod(gvn_->cu_->method_idx, *gvn_->cu_->dex_file);
1555 }
1556 break;
1557
Vladimir Markof59f18b2014-02-17 15:53:57 +00001558 case Instruction::FILLED_NEW_ARRAY:
1559 case Instruction::FILLED_NEW_ARRAY_RANGE:
1560 // Nothing defined but the result will be unique and non-null.
1561 if (mir->next != nullptr && mir->next->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001562 uint16_t array = MarkNonAliasingNonNull(mir->next);
1563 // Do not SetOperandValue(), we'll do that when we process the MOVE_RESULT_OBJECT.
1564 if (kLocalValueNumberingEnableFilledNewArrayTracking && mir->ssa_rep->num_uses != 0u) {
1565 AliasingValues* values = GetAliasingValues(&non_aliasing_array_value_map_, array);
1566 // Clear the value if we got a merged version in a loop.
Vladimir Markob19955d2014-07-29 12:04:10 +01001567 *values = AliasingValues(this);
Vladimir Marko95a05972014-05-30 10:01:32 +01001568 for (size_t i = 0u, count = mir->ssa_rep->num_uses; i != count; ++i) {
1569 DCHECK_EQ(High16Bits(i), 0u);
1570 uint16_t index = gvn_->LookupValue(Instruction::CONST, i, 0u, 0);
1571 uint16_t value = GetOperandValue(mir->ssa_rep->uses[i]);
1572 values->load_value_map.Put(index, value);
1573 RangeCheckKey key = { array, index };
1574 range_checked_.insert(key);
1575 }
1576 }
Vladimir Markof59f18b2014-02-17 15:53:57 +00001577 // The MOVE_RESULT_OBJECT will be processed next and we'll return the value name then.
1578 }
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001579 // All args escaped (if references).
1580 for (size_t i = 0u, count = mir->ssa_rep->num_uses; i != count; ++i) {
1581 uint16_t reg = GetOperandValue(mir->ssa_rep->uses[i]);
1582 HandleEscapingRef(reg);
1583 }
Vladimir Markof59f18b2014-02-17 15:53:57 +00001584 break;
1585
Vladimir Markoa78e66a2014-10-16 13:38:44 +01001586 case kMirOpNullCheck:
1587 HandleNullCheck(mir, GetOperandValue(mir->ssa_rep->uses[0]));
1588 break;
1589
Vladimir Markof59f18b2014-02-17 15:53:57 +00001590 case Instruction::INVOKE_DIRECT:
1591 case Instruction::INVOKE_DIRECT_RANGE:
1592 case Instruction::INVOKE_VIRTUAL:
1593 case Instruction::INVOKE_VIRTUAL_RANGE:
1594 case Instruction::INVOKE_SUPER:
1595 case Instruction::INVOKE_SUPER_RANGE:
1596 case Instruction::INVOKE_INTERFACE:
1597 case Instruction::INVOKE_INTERFACE_RANGE: {
1598 // Nothing defined but handle the null check.
1599 uint16_t reg = GetOperandValue(mir->ssa_rep->uses[0]);
1600 HandleNullCheck(mir, reg);
1601 }
Ian Rogersfc787ec2014-10-09 21:56:44 -07001602 FALLTHROUGH_INTENDED;
Vladimir Markof59f18b2014-02-17 15:53:57 +00001603 case Instruction::INVOKE_STATIC:
1604 case Instruction::INVOKE_STATIC_RANGE:
Vladimir Markoff0ac472014-10-02 17:24:53 +01001605 // Make ref args aliasing.
Vladimir Markoa4426cf2014-10-22 17:15:53 +01001606 HandleInvokeArgs(mir, this);
Vladimir Markoff0ac472014-10-02 17:24:53 +01001607 HandleInvokeOrClInitOrAcquireOp(mir);
Vladimir Markof59f18b2014-02-17 15:53:57 +00001608 break;
1609
Vladimir Marko22fe45d2015-03-18 11:33:58 +00001610 case Instruction::INSTANCE_OF: {
1611 uint16_t operand = GetOperandValue(mir->ssa_rep->uses[0]);
1612 uint16_t type = mir->dalvikInsn.vC;
1613 res = gvn_->LookupValue(Instruction::INSTANCE_OF, operand, type, kNoValue);
1614 SetOperandValue(mir->ssa_rep->defs[0], res);
1615 }
1616 break;
1617 case Instruction::CHECK_CAST:
1618 if (gvn_->CanModify()) {
1619 // Check if there was an instance-of operation on the same value and if we are
1620 // in a block where its result is true. If so, we can eliminate the check-cast.
1621 uint16_t operand = GetOperandValue(mir->ssa_rep->uses[0]);
1622 uint16_t type = mir->dalvikInsn.vB;
1623 uint16_t cond = gvn_->FindValue(Instruction::INSTANCE_OF, operand, type, kNoValue);
1624 if (cond != kNoValue && gvn_->IsTrueInBlock(cond, Id())) {
1625 if (gvn_->GetCompilationUnit()->verbose) {
1626 LOG(INFO) << "Removing check-cast at 0x" << std::hex << mir->offset;
1627 }
1628 // Don't use kMirOpNop. Keep the check-cast as it defines the type of the register.
1629 mir->optimization_flags |= MIR_IGNORE_CHECK_CAST;
1630 }
1631 }
1632 break;
1633
buzbee2502e002012-12-31 16:05:53 -08001634 case Instruction::MOVE_RESULT:
1635 case Instruction::MOVE_RESULT_OBJECT:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001636 // 1 result, treat as unique each time, use result s_reg - will be unique.
1637 res = GetOperandValue(mir->ssa_rep->defs[0]);
1638 SetOperandValue(mir->ssa_rep->defs[0], res);
1639 break;
1640 case Instruction::MOVE_EXCEPTION:
buzbee2502e002012-12-31 16:05:53 -08001641 case Instruction::NEW_INSTANCE:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001642 case Instruction::NEW_ARRAY:
Vladimir Markob3e527b2014-04-04 12:37:07 +01001643 // 1 result, treat as unique each time, use result s_reg - will be unique.
1644 res = MarkNonAliasingNonNull(mir);
Vladimir Marko95a05972014-05-30 10:01:32 +01001645 SetOperandValue(mir->ssa_rep->defs[0], res);
buzbee2502e002012-12-31 16:05:53 -08001646 break;
Vladimir Marko7a01dc22015-01-02 17:00:44 +00001647 case Instruction::CONST_CLASS:
1648 DCHECK_EQ(Low16Bits(mir->dalvikInsn.vB), mir->dalvikInsn.vB);
1649 res = gvn_->LookupValue(Instruction::CONST_CLASS, mir->dalvikInsn.vB, 0, 0);
1650 SetOperandValue(mir->ssa_rep->defs[0], res);
1651 null_checked_.insert(res);
1652 non_aliasing_refs_.insert(res);
1653 break;
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001654 case Instruction::CONST_STRING:
1655 case Instruction::CONST_STRING_JUMBO:
1656 // These strings are internalized, so assign value based on the string pool index.
Vladimir Marko95a05972014-05-30 10:01:32 +01001657 res = gvn_->LookupValue(Instruction::CONST_STRING, Low16Bits(mir->dalvikInsn.vB),
1658 High16Bits(mir->dalvikInsn.vB), 0);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001659 SetOperandValue(mir->ssa_rep->defs[0], res);
1660 null_checked_.insert(res); // May already be there.
1661 // NOTE: Hacking the contents of an internalized string via reflection is possible
1662 // but the behavior is undefined. Therefore, we consider the string constant and
1663 // the reference non-aliasing.
1664 // TUNING: We could keep this property even if the reference "escapes".
1665 non_aliasing_refs_.insert(res); // May already be there.
1666 break;
Vladimir Markof59f18b2014-02-17 15:53:57 +00001667 case Instruction::MOVE_RESULT_WIDE:
Vladimir Markob3e527b2014-04-04 12:37:07 +01001668 // 1 wide result, treat as unique each time, use result s_reg - will be unique.
1669 res = GetOperandValueWide(mir->ssa_rep->defs[0]);
1670 SetOperandValueWide(mir->ssa_rep->defs[0], res);
buzbee2502e002012-12-31 16:05:53 -08001671 break;
1672
1673 case kMirOpPhi:
Vladimir Marko95a05972014-05-30 10:01:32 +01001674 res = HandlePhi(mir);
buzbee2502e002012-12-31 16:05:53 -08001675 break;
1676
1677 case Instruction::MOVE:
1678 case Instruction::MOVE_OBJECT:
1679 case Instruction::MOVE_16:
1680 case Instruction::MOVE_OBJECT_16:
1681 case Instruction::MOVE_FROM16:
1682 case Instruction::MOVE_OBJECT_FROM16:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001683 case kMirOpCopy:
1684 // Just copy value number of source to value number of result.
1685 res = GetOperandValue(mir->ssa_rep->uses[0]);
1686 SetOperandValue(mir->ssa_rep->defs[0], res);
buzbee2502e002012-12-31 16:05:53 -08001687 break;
1688
1689 case Instruction::MOVE_WIDE:
1690 case Instruction::MOVE_WIDE_16:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001691 case Instruction::MOVE_WIDE_FROM16:
1692 // Just copy value number of source to value number of result.
1693 res = GetOperandValueWide(mir->ssa_rep->uses[0]);
1694 SetOperandValueWide(mir->ssa_rep->defs[0], res);
buzbee2502e002012-12-31 16:05:53 -08001695 break;
1696
Vladimir Marko7a01dc22015-01-02 17:00:44 +00001697 case Instruction::CONST_HIGH16:
Vladimir Marko22c7f5b2015-02-18 17:52:39 +00001698 res = HandleConst(mir, mir->dalvikInsn.vB << 16);
1699 break;
buzbee2502e002012-12-31 16:05:53 -08001700 case Instruction::CONST:
1701 case Instruction::CONST_4:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001702 case Instruction::CONST_16:
Vladimir Marko22c7f5b2015-02-18 17:52:39 +00001703 res = HandleConst(mir, mir->dalvikInsn.vB);
buzbee2502e002012-12-31 16:05:53 -08001704 break;
1705
1706 case Instruction::CONST_WIDE_16:
Vladimir Marko22c7f5b2015-02-18 17:52:39 +00001707 case Instruction::CONST_WIDE_32:
1708 res = HandleConstWide(
1709 mir,
1710 mir->dalvikInsn.vB +
1711 ((mir->dalvikInsn.vB & 0x80000000) != 0 ? UINT64_C(0xffffffff00000000) : 0u));
buzbee2502e002012-12-31 16:05:53 -08001712 break;
1713
Vladimir Marko22c7f5b2015-02-18 17:52:39 +00001714 case Instruction::CONST_WIDE:
1715 res = HandleConstWide(mir, mir->dalvikInsn.vB_wide);
buzbee2502e002012-12-31 16:05:53 -08001716 break;
1717
Vladimir Marko22c7f5b2015-02-18 17:52:39 +00001718 case Instruction::CONST_WIDE_HIGH16:
1719 res = HandleConstWide(mir, static_cast<uint64_t>(mir->dalvikInsn.vB) << 48);
buzbee2502e002012-12-31 16:05:53 -08001720 break;
1721
Vladimir Marko95a05972014-05-30 10:01:32 +01001722 case Instruction::ARRAY_LENGTH: {
1723 // Handle the null check.
1724 uint16_t reg = GetOperandValue(mir->ssa_rep->uses[0]);
1725 HandleNullCheck(mir, reg);
1726 }
Ian Rogersfc787ec2014-10-09 21:56:44 -07001727 FALLTHROUGH_INTENDED;
buzbee2502e002012-12-31 16:05:53 -08001728 case Instruction::NEG_INT:
1729 case Instruction::NOT_INT:
1730 case Instruction::NEG_FLOAT:
1731 case Instruction::INT_TO_BYTE:
1732 case Instruction::INT_TO_SHORT:
1733 case Instruction::INT_TO_CHAR:
1734 case Instruction::INT_TO_FLOAT:
1735 case Instruction::FLOAT_TO_INT: {
1736 // res = op + 1 operand
1737 uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
Vladimir Marko95a05972014-05-30 10:01:32 +01001738 res = gvn_->LookupValue(opcode, operand1, kNoValue, kNoValue);
buzbee2502e002012-12-31 16:05:53 -08001739 SetOperandValue(mir->ssa_rep->defs[0], res);
1740 }
1741 break;
1742
1743 case Instruction::LONG_TO_FLOAT:
1744 case Instruction::LONG_TO_INT:
1745 case Instruction::DOUBLE_TO_FLOAT:
1746 case Instruction::DOUBLE_TO_INT: {
1747 // res = op + 1 wide operand
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001748 uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
Vladimir Marko95a05972014-05-30 10:01:32 +01001749 res = gvn_->LookupValue(opcode, operand1, kNoValue, kNoValue);
buzbee2502e002012-12-31 16:05:53 -08001750 SetOperandValue(mir->ssa_rep->defs[0], res);
1751 }
1752 break;
1753
buzbee2502e002012-12-31 16:05:53 -08001754 case Instruction::DOUBLE_TO_LONG:
1755 case Instruction::LONG_TO_DOUBLE:
1756 case Instruction::NEG_LONG:
1757 case Instruction::NOT_LONG:
1758 case Instruction::NEG_DOUBLE: {
1759 // wide res = op + 1 wide operand
1760 uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
Vladimir Marko95a05972014-05-30 10:01:32 +01001761 res = gvn_->LookupValue(opcode, operand1, kNoValue, kNoValue);
buzbee2502e002012-12-31 16:05:53 -08001762 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1763 }
1764 break;
1765
1766 case Instruction::FLOAT_TO_DOUBLE:
1767 case Instruction::FLOAT_TO_LONG:
1768 case Instruction::INT_TO_DOUBLE:
1769 case Instruction::INT_TO_LONG: {
1770 // wide res = op + 1 operand
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001771 uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
Vladimir Marko95a05972014-05-30 10:01:32 +01001772 res = gvn_->LookupValue(opcode, operand1, kNoValue, kNoValue);
buzbee2502e002012-12-31 16:05:53 -08001773 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1774 }
1775 break;
1776
1777 case Instruction::CMPL_DOUBLE:
1778 case Instruction::CMPG_DOUBLE:
1779 case Instruction::CMP_LONG: {
1780 // res = op + 2 wide operands
1781 uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
1782 uint16_t operand2 = GetOperandValueWide(mir->ssa_rep->uses[2]);
Vladimir Marko95a05972014-05-30 10:01:32 +01001783 res = gvn_->LookupValue(opcode, operand1, operand2, kNoValue);
buzbee2502e002012-12-31 16:05:53 -08001784 SetOperandValue(mir->ssa_rep->defs[0], res);
1785 }
1786 break;
1787
Razvan A Lupusorue0951142014-11-14 14:36:55 -08001788 case Instruction::DIV_INT:
1789 case Instruction::DIV_INT_2ADDR:
1790 case Instruction::REM_INT:
1791 case Instruction::REM_INT_2ADDR:
1792 HandleDivZeroCheck(mir, GetOperandValue(mir->ssa_rep->uses[1]));
1793 FALLTHROUGH_INTENDED;
1794
buzbee2502e002012-12-31 16:05:53 -08001795 case Instruction::CMPG_FLOAT:
1796 case Instruction::CMPL_FLOAT:
1797 case Instruction::ADD_INT:
1798 case Instruction::ADD_INT_2ADDR:
1799 case Instruction::MUL_INT:
1800 case Instruction::MUL_INT_2ADDR:
1801 case Instruction::AND_INT:
1802 case Instruction::AND_INT_2ADDR:
1803 case Instruction::OR_INT:
1804 case Instruction::OR_INT_2ADDR:
1805 case Instruction::XOR_INT:
1806 case Instruction::XOR_INT_2ADDR:
1807 case Instruction::SUB_INT:
1808 case Instruction::SUB_INT_2ADDR:
buzbee2502e002012-12-31 16:05:53 -08001809 case Instruction::SHL_INT:
1810 case Instruction::SHL_INT_2ADDR:
1811 case Instruction::SHR_INT:
1812 case Instruction::SHR_INT_2ADDR:
1813 case Instruction::USHR_INT:
1814 case Instruction::USHR_INT_2ADDR: {
1815 // res = op + 2 operands
1816 uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
1817 uint16_t operand2 = GetOperandValue(mir->ssa_rep->uses[1]);
Vladimir Marko95a05972014-05-30 10:01:32 +01001818 res = gvn_->LookupValue(opcode, operand1, operand2, kNoValue);
buzbee2502e002012-12-31 16:05:53 -08001819 SetOperandValue(mir->ssa_rep->defs[0], res);
1820 }
1821 break;
1822
Razvan A Lupusorue0951142014-11-14 14:36:55 -08001823 case Instruction::DIV_LONG:
1824 case Instruction::REM_LONG:
1825 case Instruction::DIV_LONG_2ADDR:
1826 case Instruction::REM_LONG_2ADDR:
1827 HandleDivZeroCheck(mir, GetOperandValueWide(mir->ssa_rep->uses[2]));
1828 FALLTHROUGH_INTENDED;
1829
buzbee2502e002012-12-31 16:05:53 -08001830 case Instruction::ADD_LONG:
1831 case Instruction::SUB_LONG:
1832 case Instruction::MUL_LONG:
buzbee2502e002012-12-31 16:05:53 -08001833 case Instruction::AND_LONG:
1834 case Instruction::OR_LONG:
1835 case Instruction::XOR_LONG:
1836 case Instruction::ADD_LONG_2ADDR:
1837 case Instruction::SUB_LONG_2ADDR:
1838 case Instruction::MUL_LONG_2ADDR:
buzbee2502e002012-12-31 16:05:53 -08001839 case Instruction::AND_LONG_2ADDR:
1840 case Instruction::OR_LONG_2ADDR:
1841 case Instruction::XOR_LONG_2ADDR:
1842 case Instruction::ADD_DOUBLE:
1843 case Instruction::SUB_DOUBLE:
1844 case Instruction::MUL_DOUBLE:
1845 case Instruction::DIV_DOUBLE:
1846 case Instruction::REM_DOUBLE:
1847 case Instruction::ADD_DOUBLE_2ADDR:
1848 case Instruction::SUB_DOUBLE_2ADDR:
1849 case Instruction::MUL_DOUBLE_2ADDR:
1850 case Instruction::DIV_DOUBLE_2ADDR:
1851 case Instruction::REM_DOUBLE_2ADDR: {
1852 // wide res = op + 2 wide operands
1853 uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
1854 uint16_t operand2 = GetOperandValueWide(mir->ssa_rep->uses[2]);
Vladimir Marko95a05972014-05-30 10:01:32 +01001855 res = gvn_->LookupValue(opcode, operand1, operand2, kNoValue);
buzbee2502e002012-12-31 16:05:53 -08001856 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1857 }
1858 break;
1859
1860 case Instruction::SHL_LONG:
1861 case Instruction::SHR_LONG:
1862 case Instruction::USHR_LONG:
1863 case Instruction::SHL_LONG_2ADDR:
1864 case Instruction::SHR_LONG_2ADDR:
1865 case Instruction::USHR_LONG_2ADDR: {
1866 // wide res = op + 1 wide operand + 1 operand
1867 uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001868 uint16_t operand2 = GetOperandValue(mir->ssa_rep->uses[2]);
Vladimir Marko95a05972014-05-30 10:01:32 +01001869 res = gvn_->LookupValue(opcode, operand1, operand2, kNoValue);
buzbee2502e002012-12-31 16:05:53 -08001870 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1871 }
1872 break;
1873
1874 case Instruction::ADD_FLOAT:
1875 case Instruction::SUB_FLOAT:
1876 case Instruction::MUL_FLOAT:
1877 case Instruction::DIV_FLOAT:
1878 case Instruction::REM_FLOAT:
1879 case Instruction::ADD_FLOAT_2ADDR:
1880 case Instruction::SUB_FLOAT_2ADDR:
1881 case Instruction::MUL_FLOAT_2ADDR:
1882 case Instruction::DIV_FLOAT_2ADDR:
1883 case Instruction::REM_FLOAT_2ADDR: {
1884 // res = op + 2 operands
1885 uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
1886 uint16_t operand2 = GetOperandValue(mir->ssa_rep->uses[1]);
Vladimir Marko95a05972014-05-30 10:01:32 +01001887 res = gvn_->LookupValue(opcode, operand1, operand2, kNoValue);
buzbee2502e002012-12-31 16:05:53 -08001888 SetOperandValue(mir->ssa_rep->defs[0], res);
1889 }
1890 break;
1891
1892 case Instruction::RSUB_INT:
1893 case Instruction::ADD_INT_LIT16:
1894 case Instruction::MUL_INT_LIT16:
1895 case Instruction::DIV_INT_LIT16:
1896 case Instruction::REM_INT_LIT16:
1897 case Instruction::AND_INT_LIT16:
1898 case Instruction::OR_INT_LIT16:
1899 case Instruction::XOR_INT_LIT16:
1900 case Instruction::ADD_INT_LIT8:
1901 case Instruction::RSUB_INT_LIT8:
1902 case Instruction::MUL_INT_LIT8:
1903 case Instruction::DIV_INT_LIT8:
1904 case Instruction::REM_INT_LIT8:
1905 case Instruction::AND_INT_LIT8:
1906 case Instruction::OR_INT_LIT8:
1907 case Instruction::XOR_INT_LIT8:
1908 case Instruction::SHL_INT_LIT8:
1909 case Instruction::SHR_INT_LIT8:
1910 case Instruction::USHR_INT_LIT8: {
nikolay serdjukee40aa42014-03-25 12:21:29 +07001911 // Same as res = op + 2 operands, except use vC as operand 2
buzbee2502e002012-12-31 16:05:53 -08001912 uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
Vladimir Marko95a05972014-05-30 10:01:32 +01001913 uint16_t operand2 = gvn_->LookupValue(Instruction::CONST, mir->dalvikInsn.vC, 0, 0);
1914 res = gvn_->LookupValue(opcode, operand1, operand2, kNoValue);
buzbee2502e002012-12-31 16:05:53 -08001915 SetOperandValue(mir->ssa_rep->defs[0], res);
1916 }
1917 break;
1918
buzbee2502e002012-12-31 16:05:53 -08001919 case Instruction::AGET_OBJECT:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001920 case Instruction::AGET:
1921 case Instruction::AGET_WIDE:
buzbee2502e002012-12-31 16:05:53 -08001922 case Instruction::AGET_BOOLEAN:
1923 case Instruction::AGET_BYTE:
1924 case Instruction::AGET_CHAR:
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001925 case Instruction::AGET_SHORT:
1926 res = HandleAGet(mir, opcode);
buzbee2502e002012-12-31 16:05:53 -08001927 break;
1928
buzbee2502e002012-12-31 16:05:53 -08001929 case Instruction::APUT_OBJECT:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001930 HandlePutObject(mir);
Ian Rogersfc787ec2014-10-09 21:56:44 -07001931 FALLTHROUGH_INTENDED;
Vladimir Markof59f18b2014-02-17 15:53:57 +00001932 case Instruction::APUT:
1933 case Instruction::APUT_WIDE:
buzbee2502e002012-12-31 16:05:53 -08001934 case Instruction::APUT_BYTE:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001935 case Instruction::APUT_BOOLEAN:
1936 case Instruction::APUT_SHORT:
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001937 case Instruction::APUT_CHAR:
1938 HandleAPut(mir, opcode);
buzbee2502e002012-12-31 16:05:53 -08001939 break;
1940
1941 case Instruction::IGET_OBJECT:
buzbee2502e002012-12-31 16:05:53 -08001942 case Instruction::IGET:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001943 case Instruction::IGET_WIDE:
buzbee2502e002012-12-31 16:05:53 -08001944 case Instruction::IGET_BOOLEAN:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001945 case Instruction::IGET_BYTE:
1946 case Instruction::IGET_CHAR:
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001947 case Instruction::IGET_SHORT:
1948 res = HandleIGet(mir, opcode);
buzbee2502e002012-12-31 16:05:53 -08001949 break;
1950
buzbee2502e002012-12-31 16:05:53 -08001951 case Instruction::IPUT_OBJECT:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001952 HandlePutObject(mir);
Ian Rogersfc787ec2014-10-09 21:56:44 -07001953 FALLTHROUGH_INTENDED;
buzbee2502e002012-12-31 16:05:53 -08001954 case Instruction::IPUT:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001955 case Instruction::IPUT_WIDE:
buzbee2502e002012-12-31 16:05:53 -08001956 case Instruction::IPUT_BOOLEAN:
1957 case Instruction::IPUT_BYTE:
1958 case Instruction::IPUT_CHAR:
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001959 case Instruction::IPUT_SHORT:
1960 HandleIPut(mir, opcode);
buzbee2502e002012-12-31 16:05:53 -08001961 break;
1962
1963 case Instruction::SGET_OBJECT:
1964 case Instruction::SGET:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001965 case Instruction::SGET_WIDE:
buzbee2502e002012-12-31 16:05:53 -08001966 case Instruction::SGET_BOOLEAN:
1967 case Instruction::SGET_BYTE:
1968 case Instruction::SGET_CHAR:
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001969 case Instruction::SGET_SHORT:
1970 res = HandleSGet(mir, opcode);
buzbee2502e002012-12-31 16:05:53 -08001971 break;
1972
1973 case Instruction::SPUT_OBJECT:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001974 HandlePutObject(mir);
Ian Rogersfc787ec2014-10-09 21:56:44 -07001975 FALLTHROUGH_INTENDED;
buzbee2502e002012-12-31 16:05:53 -08001976 case Instruction::SPUT:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001977 case Instruction::SPUT_WIDE:
buzbee2502e002012-12-31 16:05:53 -08001978 case Instruction::SPUT_BOOLEAN:
1979 case Instruction::SPUT_BYTE:
1980 case Instruction::SPUT_CHAR:
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001981 case Instruction::SPUT_SHORT:
1982 HandleSPut(mir, opcode);
buzbee2502e002012-12-31 16:05:53 -08001983 break;
buzbee2502e002012-12-31 16:05:53 -08001984 }
1985 return res;
1986}
1987
Vladimir Marko7a01dc22015-01-02 17:00:44 +00001988uint16_t LocalValueNumbering::GetEndingVregValueNumberImpl(int v_reg, bool wide) const {
1989 const BasicBlock* bb = gvn_->GetBasicBlock(Id());
1990 DCHECK(bb != nullptr);
1991 int s_reg = bb->data_flow_info->vreg_to_ssa_map_exit[v_reg];
1992 if (s_reg == INVALID_SREG) {
1993 return kNoValue;
1994 }
Vladimir Markoa5e69e82015-04-24 19:03:51 +01001995 if (gvn_->GetMirGraph()->GetRegLocation(s_reg).wide != wide) {
1996 return kNoValue;
1997 }
Vladimir Marko7a01dc22015-01-02 17:00:44 +00001998 if (wide) {
1999 int high_s_reg = bb->data_flow_info->vreg_to_ssa_map_exit[v_reg + 1];
2000 if (high_s_reg != s_reg + 1) {
2001 return kNoValue; // High word has been overwritten.
2002 }
2003 return GetSregValueWide(s_reg);
2004 } else {
2005 return GetSregValue(s_reg);
2006 }
2007}
2008
2009uint16_t LocalValueNumbering::GetStartingVregValueNumberImpl(int v_reg, bool wide) const {
2010 DCHECK_EQ(gvn_->mode_, GlobalValueNumbering::kModeGvnPostProcessing);
2011 DCHECK(gvn_->CanModify());
2012 const BasicBlock* bb = gvn_->GetBasicBlock(Id());
2013 DCHECK(bb != nullptr);
2014 DCHECK_NE(bb->predecessors.size(), 0u);
2015 if (bb->predecessors.size() == 1u) {
2016 return gvn_->GetLvn(bb->predecessors[0])->GetEndingVregValueNumberImpl(v_reg, wide);
2017 }
2018 merge_names_.clear();
2019 uint16_t value_name = kNoValue;
2020 bool same_values = true;
2021 for (BasicBlockId pred_id : bb->predecessors) {
2022 value_name = gvn_->GetLvn(pred_id)->GetEndingVregValueNumberImpl(v_reg, wide);
2023 if (value_name == kNoValue) {
2024 return kNoValue;
2025 }
2026 same_values = same_values && (merge_names_.empty() || value_name == merge_names_.back());
2027 merge_names_.push_back(value_name);
2028 }
2029 if (same_values) {
2030 // value_name already contains the result.
2031 } else {
2032 auto lb = merge_map_.lower_bound(merge_names_);
2033 if (lb != merge_map_.end() && !merge_map_.key_comp()(merge_names_, lb->first)) {
2034 value_name = lb->second;
2035 } else {
2036 value_name = kNoValue; // We never assigned a value name to this set of merged names.
2037 }
2038 }
2039 return value_name;
2040}
2041
buzbee2502e002012-12-31 16:05:53 -08002042} // namespace art