blob: c1ce2ac016096aea4f9cc4f954d79f04bee43ee6 [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 Marko95a05972014-05-30 10:01:32 +010019#include "global_value_numbering.h"
Vladimir Markobe0e5462014-02-26 11:24:15 +000020#include "mir_field_info.h"
Vladimir Markof59f18b2014-02-17 15:53:57 +000021#include "mir_graph.h"
22
buzbee2502e002012-12-31 16:05:53 -080023namespace art {
24
Vladimir Marko2ac01fc2014-05-22 12:09:08 +010025namespace { // anonymous namespace
26
27// Operations used for value map keys instead of actual opcode.
Vladimir Marko95a05972014-05-30 10:01:32 +010028static constexpr uint16_t kInvokeMemoryVersionBumpOp = Instruction::INVOKE_VIRTUAL;
29static constexpr uint16_t kUnresolvedSFieldOp = Instruction::SGET;
30static constexpr uint16_t kResolvedSFieldOp = Instruction::SGET_WIDE;
31static constexpr uint16_t kUnresolvedIFieldOp = Instruction::IGET;
32static constexpr uint16_t kNonAliasingIFieldLocOp = Instruction::IGET_WIDE;
33static constexpr uint16_t kNonAliasingIFieldInitialOp = Instruction::IGET_OBJECT;
34static constexpr uint16_t kAliasingIFieldOp = Instruction::IGET_BOOLEAN;
35static constexpr uint16_t kAliasingIFieldStartVersionOp = Instruction::IGET_BYTE;
36static constexpr uint16_t kAliasingIFieldBumpVersionOp = Instruction::IGET_CHAR;
Vladimir Marko2ac01fc2014-05-22 12:09:08 +010037static constexpr uint16_t kNonAliasingArrayOp = Instruction::AGET;
38static constexpr uint16_t kNonAliasingArrayStartVersionOp = Instruction::AGET_WIDE;
Vladimir Marko95a05972014-05-30 10:01:32 +010039static constexpr uint16_t kNonAliasingArrayBumpVersionOp = Instruction::AGET_OBJECT;
40static constexpr uint16_t kAliasingArrayOp = Instruction::AGET_BOOLEAN;
41static constexpr uint16_t kAliasingArrayStartVersionOp = Instruction::AGET_BYTE;
42static constexpr uint16_t kAliasingArrayBumpVersionOp = Instruction::AGET_CHAR;
43static constexpr uint16_t kMergeBlockMemoryVersionBumpOp = Instruction::INVOKE_VIRTUAL_RANGE;
44static constexpr uint16_t kMergeBlockAliasingIFieldVersionBumpOp = Instruction::IPUT;
45static constexpr uint16_t kMergeBlockAliasingIFieldMergeLocationOp = Instruction::IPUT_WIDE;
46static constexpr uint16_t kMergeBlockNonAliasingArrayVersionBumpOp = Instruction::APUT;
47static constexpr uint16_t kMergeBlockNonAliasingArrayMergeLocationOp = Instruction::APUT_WIDE;
48static constexpr uint16_t kMergeBlockAliasingArrayVersionBumpOp = Instruction::APUT_OBJECT;
49static constexpr uint16_t kMergeBlockAliasingArrayMergeLocationOp = Instruction::APUT_BOOLEAN;
50static constexpr uint16_t kMergeBlockNonAliasingIFieldVersionBumpOp = Instruction::APUT_BYTE;
51static constexpr uint16_t kMergeBlockSFieldVersionBumpOp = Instruction::APUT_CHAR;
Vladimir Marko2ac01fc2014-05-22 12:09:08 +010052
53} // anonymous namespace
54
Vladimir Marko95a05972014-05-30 10:01:32 +010055class LocalValueNumbering::AliasingIFieldVersions {
56 public:
57 static uint16_t StartMemoryVersion(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
58 uint16_t field_id) {
59 uint16_t type = gvn->GetFieldType(field_id);
60 return gvn->LookupValue(kAliasingIFieldStartVersionOp, field_id,
61 lvn->global_memory_version_, lvn->unresolved_ifield_version_[type]);
62 }
63
64 static uint16_t BumpMemoryVersion(GlobalValueNumbering* gvn, uint16_t old_version,
65 uint16_t store_ref_set_id, uint16_t stored_value) {
66 return gvn->LookupValue(kAliasingIFieldBumpVersionOp, old_version,
67 store_ref_set_id, stored_value);
68 }
69
70 static uint16_t LookupGlobalValue(GlobalValueNumbering* gvn,
71 uint16_t field_id, uint16_t base, uint16_t memory_version) {
72 return gvn->LookupValue(kAliasingIFieldOp, field_id, base, memory_version);
73 }
74
75 static uint16_t LookupMergeValue(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
76 uint16_t field_id, uint16_t base) {
77 // If the base/field_id is non-aliasing in lvn, use the non-aliasing value.
78 uint16_t type = gvn->GetFieldType(field_id);
79 if (lvn->IsNonAliasingIField(base, field_id, type)) {
80 uint16_t loc = gvn->LookupValue(kNonAliasingIFieldLocOp, base, field_id, type);
81 auto lb = lvn->non_aliasing_ifield_value_map_.find(loc);
82 return (lb != lvn->non_aliasing_ifield_value_map_.end())
83 ? lb->second
84 : gvn->LookupValue(kNonAliasingIFieldInitialOp, loc, kNoValue, kNoValue);
85 }
86 return AliasingValuesMergeGet<AliasingIFieldVersions>(
87 gvn, lvn, &lvn->aliasing_ifield_value_map_, field_id, base);
88 }
89
90 static bool HasNewBaseVersion(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
91 uint16_t field_id) {
92 uint16_t type = gvn->GetFieldType(field_id);
93 return lvn->unresolved_ifield_version_[type] == lvn->merge_new_memory_version_ ||
94 lvn->global_memory_version_ == lvn->merge_new_memory_version_;
95 }
96
97 static uint16_t LookupMergeBlockValue(GlobalValueNumbering* gvn, uint16_t lvn_id,
98 uint16_t field_id) {
99 return gvn->LookupValue(kMergeBlockAliasingIFieldVersionBumpOp, field_id, kNoValue, lvn_id);
100 }
101
102 static uint16_t LookupMergeLocationValue(GlobalValueNumbering* gvn, uint16_t lvn_id,
103 uint16_t field_id, uint16_t base) {
104 return gvn->LookupValue(kMergeBlockAliasingIFieldMergeLocationOp, field_id, base, lvn_id);
105 }
106};
107
108class LocalValueNumbering::NonAliasingArrayVersions {
109 public:
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700110 static uint16_t StartMemoryVersion(GlobalValueNumbering* gvn,
111 const LocalValueNumbering* lvn ATTRIBUTE_UNUSED,
Vladimir Marko95a05972014-05-30 10:01:32 +0100112 uint16_t array) {
113 return gvn->LookupValue(kNonAliasingArrayStartVersionOp, array, kNoValue, kNoValue);
114 }
115
116 static uint16_t BumpMemoryVersion(GlobalValueNumbering* gvn, uint16_t old_version,
117 uint16_t store_ref_set_id, uint16_t stored_value) {
118 return gvn->LookupValue(kNonAliasingArrayBumpVersionOp, old_version,
119 store_ref_set_id, stored_value);
120 }
121
122 static uint16_t LookupGlobalValue(GlobalValueNumbering* gvn,
123 uint16_t array, uint16_t index, uint16_t memory_version) {
124 return gvn->LookupValue(kNonAliasingArrayOp, array, index, memory_version);
125 }
126
127 static uint16_t LookupMergeValue(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
128 uint16_t array, uint16_t index) {
129 return AliasingValuesMergeGet<NonAliasingArrayVersions>(
130 gvn, lvn, &lvn->non_aliasing_array_value_map_, array, index);
131 }
132
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700133 static bool HasNewBaseVersion(GlobalValueNumbering* gvn ATTRIBUTE_UNUSED,
134 const LocalValueNumbering* lvn ATTRIBUTE_UNUSED,
135 uint16_t array ATTRIBUTE_UNUSED) {
Vladimir Marko95a05972014-05-30 10:01:32 +0100136 return false; // Not affected by global_memory_version_.
137 }
138
139 static uint16_t LookupMergeBlockValue(GlobalValueNumbering* gvn, uint16_t lvn_id,
140 uint16_t array) {
141 return gvn->LookupValue(kMergeBlockNonAliasingArrayVersionBumpOp, array, kNoValue, lvn_id);
142 }
143
144 static uint16_t LookupMergeLocationValue(GlobalValueNumbering* gvn, uint16_t lvn_id,
145 uint16_t array, uint16_t index) {
146 return gvn->LookupValue(kMergeBlockNonAliasingArrayMergeLocationOp, array, index, lvn_id);
147 }
148};
149
150class LocalValueNumbering::AliasingArrayVersions {
151 public:
152 static uint16_t StartMemoryVersion(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
153 uint16_t type) {
154 return gvn->LookupValue(kAliasingArrayStartVersionOp, type, lvn->global_memory_version_,
155 kNoValue);
156 }
157
158 static uint16_t BumpMemoryVersion(GlobalValueNumbering* gvn, uint16_t old_version,
159 uint16_t store_ref_set_id, uint16_t stored_value) {
160 return gvn->LookupValue(kAliasingArrayBumpVersionOp, old_version,
161 store_ref_set_id, stored_value);
162 }
163
164 static uint16_t LookupGlobalValue(GlobalValueNumbering* gvn,
165 uint16_t type, uint16_t location, uint16_t memory_version) {
166 return gvn->LookupValue(kAliasingArrayOp, type, location, memory_version);
167 }
168
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700169 static uint16_t LookupMergeValue(GlobalValueNumbering* gvn ATTRIBUTE_UNUSED,
170 const LocalValueNumbering* lvn,
171 uint16_t type ATTRIBUTE_UNUSED, uint16_t location) {
Vladimir Marko95a05972014-05-30 10:01:32 +0100172 // If the location is non-aliasing in lvn, use the non-aliasing value.
173 uint16_t array = gvn->GetArrayLocationBase(location);
174 if (lvn->IsNonAliasingArray(array, type)) {
175 uint16_t index = gvn->GetArrayLocationIndex(location);
176 return NonAliasingArrayVersions::LookupMergeValue(gvn, lvn, array, index);
177 }
178 return AliasingValuesMergeGet<AliasingArrayVersions>(
179 gvn, lvn, &lvn->aliasing_array_value_map_, type, location);
180 }
181
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700182 static bool HasNewBaseVersion(GlobalValueNumbering* gvn ATTRIBUTE_UNUSED,
183 const LocalValueNumbering* lvn,
184 uint16_t type ATTRIBUTE_UNUSED) {
185 UNUSED(gvn);
186 UNUSED(type);
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()),
342 merge_names_(allocator->Adapter()),
343 merge_map_(std::less<ScopedArenaVector<BasicBlockId>>(), allocator->Adapter()),
Vladimir Marko95a05972014-05-30 10:01:32 +0100344 merge_new_memory_version_(kNoValue) {
345 std::fill_n(unresolved_sfield_version_, kFieldTypeCount, 0u);
346 std::fill_n(unresolved_ifield_version_, kFieldTypeCount, 0u);
347}
348
349bool LocalValueNumbering::Equals(const LocalValueNumbering& other) const {
350 DCHECK(gvn_ == other.gvn_);
351 // Compare the maps/sets and memory versions.
352 return sreg_value_map_ == other.sreg_value_map_ &&
353 sreg_wide_value_map_ == other.sreg_wide_value_map_ &&
354 sfield_value_map_ == other.sfield_value_map_ &&
355 non_aliasing_ifield_value_map_ == other.non_aliasing_ifield_value_map_ &&
356 aliasing_ifield_value_map_ == other.aliasing_ifield_value_map_ &&
357 non_aliasing_array_value_map_ == other.non_aliasing_array_value_map_ &&
358 aliasing_array_value_map_ == other.aliasing_array_value_map_ &&
359 SameMemoryVersion(other) &&
360 non_aliasing_refs_ == other.non_aliasing_refs_ &&
361 escaped_refs_ == other.escaped_refs_ &&
362 escaped_ifield_clobber_set_ == other.escaped_ifield_clobber_set_ &&
363 escaped_array_clobber_set_ == other.escaped_array_clobber_set_ &&
364 range_checked_ == other.range_checked_ &&
365 null_checked_ == other.null_checked_;
366}
367
368void LocalValueNumbering::MergeOne(const LocalValueNumbering& other, MergeType merge_type) {
Vladimir Markob19955d2014-07-29 12:04:10 +0100369 CopyLiveSregValues(&sreg_value_map_, other.sreg_value_map_);
370 CopyLiveSregValues(&sreg_wide_value_map_, other.sreg_wide_value_map_);
Vladimir Marko95a05972014-05-30 10:01:32 +0100371
372 if (merge_type == kReturnMerge) {
373 // RETURN or PHI+RETURN. We need only sreg value maps.
374 return;
375 }
376
377 non_aliasing_ifield_value_map_ = other.non_aliasing_ifield_value_map_;
Vladimir Markob19955d2014-07-29 12:04:10 +0100378 CopyAliasingValuesMap(&non_aliasing_array_value_map_, other.non_aliasing_array_value_map_);
Vladimir Marko95a05972014-05-30 10:01:32 +0100379 non_aliasing_refs_ = other.non_aliasing_refs_;
380 range_checked_ = other.range_checked_;
381 null_checked_ = other.null_checked_;
382
Vladimir Markoa4426cf2014-10-22 17:15:53 +0100383 const BasicBlock* pred_bb = gvn_->GetBasicBlock(other.Id());
384 if (GlobalValueNumbering::HasNullCheckLastInsn(pred_bb, Id())) {
385 int s_reg = pred_bb->last_mir_insn->ssa_rep->uses[0];
386 null_checked_.insert(other.GetOperandValue(s_reg));
387 }
388
Vladimir Marko95a05972014-05-30 10:01:32 +0100389 if (merge_type == kCatchMerge) {
390 // Memory is clobbered. Use new memory version and don't merge aliasing locations.
391 global_memory_version_ = NewMemoryVersion(&merge_new_memory_version_);
392 std::fill_n(unresolved_sfield_version_, kFieldTypeCount, global_memory_version_);
393 std::fill_n(unresolved_ifield_version_, kFieldTypeCount, global_memory_version_);
394 PruneNonAliasingRefsForCatch();
395 return;
396 }
397
398 DCHECK(merge_type == kNormalMerge);
399 global_memory_version_ = other.global_memory_version_;
400 std::copy_n(other.unresolved_ifield_version_, kFieldTypeCount, unresolved_ifield_version_);
401 std::copy_n(other.unresolved_sfield_version_, kFieldTypeCount, unresolved_sfield_version_);
402 sfield_value_map_ = other.sfield_value_map_;
Vladimir Markob19955d2014-07-29 12:04:10 +0100403 CopyAliasingValuesMap(&aliasing_ifield_value_map_, other.aliasing_ifield_value_map_);
404 CopyAliasingValuesMap(&aliasing_array_value_map_, other.aliasing_array_value_map_);
Vladimir Marko95a05972014-05-30 10:01:32 +0100405 escaped_refs_ = other.escaped_refs_;
406 escaped_ifield_clobber_set_ = other.escaped_ifield_clobber_set_;
407 escaped_array_clobber_set_ = other.escaped_array_clobber_set_;
408}
409
410bool LocalValueNumbering::SameMemoryVersion(const LocalValueNumbering& other) const {
411 return
412 global_memory_version_ == other.global_memory_version_ &&
413 std::equal(unresolved_ifield_version_, unresolved_ifield_version_ + kFieldTypeCount,
414 other.unresolved_ifield_version_) &&
415 std::equal(unresolved_sfield_version_, unresolved_sfield_version_ + kFieldTypeCount,
416 other.unresolved_sfield_version_);
417}
418
419uint16_t LocalValueNumbering::NewMemoryVersion(uint16_t* new_version) {
420 if (*new_version == kNoValue) {
421 *new_version = gvn_->LookupValue(kMergeBlockMemoryVersionBumpOp, 0u, 0u, id_);
422 }
423 return *new_version;
424}
425
426void LocalValueNumbering::MergeMemoryVersions(bool clobbered_catch) {
427 DCHECK_GE(gvn_->merge_lvns_.size(), 2u);
428 const LocalValueNumbering* cmp = gvn_->merge_lvns_[0];
429 // Check if the global version has changed.
430 bool new_global_version = clobbered_catch;
431 if (!new_global_version) {
432 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
433 if (lvn->global_memory_version_ != cmp->global_memory_version_) {
434 // Use a new version for everything.
435 new_global_version = true;
436 break;
437 }
438 }
439 }
440 if (new_global_version) {
441 global_memory_version_ = NewMemoryVersion(&merge_new_memory_version_);
442 std::fill_n(unresolved_sfield_version_, kFieldTypeCount, merge_new_memory_version_);
443 std::fill_n(unresolved_ifield_version_, kFieldTypeCount, merge_new_memory_version_);
444 } else {
445 // Initialize with a copy of memory versions from the comparison LVN.
446 global_memory_version_ = cmp->global_memory_version_;
447 std::copy_n(cmp->unresolved_ifield_version_, kFieldTypeCount, unresolved_ifield_version_);
448 std::copy_n(cmp->unresolved_sfield_version_, kFieldTypeCount, unresolved_sfield_version_);
449 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
450 if (lvn == cmp) {
451 continue;
452 }
453 for (size_t i = 0; i != kFieldTypeCount; ++i) {
454 if (lvn->unresolved_ifield_version_[i] != cmp->unresolved_ifield_version_[i]) {
455 unresolved_ifield_version_[i] = NewMemoryVersion(&merge_new_memory_version_);
456 }
457 if (lvn->unresolved_sfield_version_[i] != cmp->unresolved_sfield_version_[i]) {
458 unresolved_sfield_version_[i] = NewMemoryVersion(&merge_new_memory_version_);
459 }
460 }
461 }
462 }
463}
464
465void LocalValueNumbering::PruneNonAliasingRefsForCatch() {
466 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
467 const BasicBlock* bb = gvn_->GetBasicBlock(lvn->Id());
Vladimir Marko11ca6122014-07-17 20:50:07 +0100468 if (UNLIKELY(bb->taken == id_) || UNLIKELY(bb->fall_through == id_)) {
469 // Non-exceptional path to a catch handler means that the catch block was actually
470 // empty and all exceptional paths lead to the shared path after that empty block.
471 continue;
472 }
Vladimir Marko95a05972014-05-30 10:01:32 +0100473 DCHECK_EQ(bb->taken, kNullBlock);
474 DCHECK_NE(bb->fall_through, kNullBlock);
475 const BasicBlock* fall_through_bb = gvn_->GetBasicBlock(bb->fall_through);
476 const MIR* mir = fall_through_bb->first_mir_insn;
477 DCHECK(mir != nullptr);
478 // Only INVOKEs can leak and clobber non-aliasing references if they throw.
Jean Christophe Beylerfb0ea2d2014-07-29 13:20:42 -0700479 if ((mir->dalvikInsn.FlagsOf() & Instruction::kInvoke) != 0) {
Vladimir Markoa4426cf2014-10-22 17:15:53 +0100480 HandleInvokeArgs(mir, lvn);
Vladimir Marko95a05972014-05-30 10:01:32 +0100481 }
482 }
483}
484
485
486template <typename Set, Set LocalValueNumbering::* set_ptr>
487void LocalValueNumbering::IntersectSets() {
488 DCHECK_GE(gvn_->merge_lvns_.size(), 2u);
489
490 // Find the LVN with the least entries in the set.
491 const LocalValueNumbering* least_entries_lvn = gvn_->merge_lvns_[0];
492 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
493 if ((lvn->*set_ptr).size() < (least_entries_lvn->*set_ptr).size()) {
494 least_entries_lvn = lvn;
495 }
496 }
497
498 // For each key check if it's in all the LVNs.
499 for (const auto& key : least_entries_lvn->*set_ptr) {
500 bool checked = true;
501 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
502 if (lvn != least_entries_lvn && (lvn->*set_ptr).count(key) == 0u) {
503 checked = false;
504 break;
505 }
506 }
507 if (checked) {
508 (this->*set_ptr).emplace_hint((this->*set_ptr).end(), key);
509 }
510 }
511}
512
Vladimir Markob19955d2014-07-29 12:04:10 +0100513void LocalValueNumbering::CopyLiveSregValues(SregValueMap* dest, const SregValueMap& src) {
514 auto dest_end = dest->end();
515 ArenaBitVector* live_in_v = gvn_->GetMirGraph()->GetBasicBlock(id_)->data_flow_info->live_in_v;
516 DCHECK(live_in_v != nullptr);
517 for (const auto& entry : src) {
518 bool live = live_in_v->IsBitSet(gvn_->GetMirGraph()->SRegToVReg(entry.first));
519 if (live) {
520 dest->PutBefore(dest_end, entry.first, entry.second);
521 }
522 }
523}
524
525template <LocalValueNumbering::SregValueMap LocalValueNumbering::* map_ptr>
526void LocalValueNumbering::IntersectSregValueMaps() {
Vladimir Marko95a05972014-05-30 10:01:32 +0100527 DCHECK_GE(gvn_->merge_lvns_.size(), 2u);
528
529 // Find the LVN with the least entries in the set.
530 const LocalValueNumbering* least_entries_lvn = gvn_->merge_lvns_[0];
531 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
532 if ((lvn->*map_ptr).size() < (least_entries_lvn->*map_ptr).size()) {
533 least_entries_lvn = lvn;
534 }
535 }
536
537 // For each key check if it's in all the LVNs.
Vladimir Markob19955d2014-07-29 12:04:10 +0100538 ArenaBitVector* live_in_v = gvn_->GetMirGraph()->GetBasicBlock(id_)->data_flow_info->live_in_v;
539 DCHECK(live_in_v != nullptr);
Vladimir Marko95a05972014-05-30 10:01:32 +0100540 for (const auto& entry : least_entries_lvn->*map_ptr) {
Vladimir Markob19955d2014-07-29 12:04:10 +0100541 bool live_and_same = live_in_v->IsBitSet(gvn_->GetMirGraph()->SRegToVReg(entry.first));
542 if (live_and_same) {
543 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
544 if (lvn != least_entries_lvn) {
545 auto it = (lvn->*map_ptr).find(entry.first);
546 if (it == (lvn->*map_ptr).end() || !(it->second == entry.second)) {
547 live_and_same = false;
548 break;
549 }
Vladimir Marko95a05972014-05-30 10:01:32 +0100550 }
551 }
552 }
Vladimir Markob19955d2014-07-29 12:04:10 +0100553 if (live_and_same) {
Vladimir Marko95a05972014-05-30 10:01:32 +0100554 (this->*map_ptr).PutBefore((this->*map_ptr).end(), entry.first, entry.second);
555 }
556 }
557}
558
559// Intersect maps as sets. The value type must be equality-comparable.
560template <typename Map>
561void LocalValueNumbering::InPlaceIntersectMaps(Map* work_map, const Map& other_map) {
562 auto work_it = work_map->begin(), work_end = work_map->end();
563 auto cmp = work_map->value_comp();
564 for (const auto& entry : other_map) {
565 while (work_it != work_end &&
566 (cmp(*work_it, entry) ||
567 (!cmp(entry, *work_it) && !(work_it->second == entry.second)))) {
568 work_it = work_map->erase(work_it);
569 }
Vladimir Marko55fff042014-07-10 12:42:52 +0100570 if (work_it == work_end) {
571 return;
572 }
573 ++work_it;
Vladimir Marko95a05972014-05-30 10:01:32 +0100574 }
575}
576
577template <typename Set, Set LocalValueNumbering::*set_ptr, void (LocalValueNumbering::*MergeFn)(
578 const typename Set::value_type& entry, typename Set::iterator hint)>
579void LocalValueNumbering::MergeSets() {
580 auto cmp = (this->*set_ptr).value_comp();
581 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
582 auto my_it = (this->*set_ptr).begin(), my_end = (this->*set_ptr).end();
583 for (const auto& entry : lvn->*set_ptr) {
584 while (my_it != my_end && cmp(*my_it, entry)) {
585 ++my_it;
586 }
587 if (my_it != my_end && !cmp(entry, *my_it)) {
588 // Already handled.
589 ++my_it;
590 } else {
591 // Merge values for this field_id.
592 (this->*MergeFn)(entry, my_it); // my_it remains valid across inserts to std::set/SafeMap.
593 }
594 }
595 }
596}
597
598void LocalValueNumbering::IntersectAliasingValueLocations(AliasingValues* work_values,
599 const AliasingValues* values) {
600 auto cmp = work_values->load_value_map.key_comp();
601 auto work_it = work_values->load_value_map.begin(), work_end = work_values->load_value_map.end();
602 auto store_it = values->store_loc_set.begin(), store_end = values->store_loc_set.end();
603 auto load_it = values->load_value_map.begin(), load_end = values->load_value_map.end();
604 while (store_it != store_end || load_it != load_end) {
605 uint16_t loc;
606 if (store_it != store_end && (load_it == load_end || *store_it < load_it->first)) {
607 loc = *store_it;
608 ++store_it;
609 } else {
610 loc = load_it->first;
611 ++load_it;
612 DCHECK(store_it == store_end || cmp(loc, *store_it));
613 }
614 while (work_it != work_end && cmp(work_it->first, loc)) {
615 work_it = work_values->load_value_map.erase(work_it);
616 }
617 if (work_it != work_end && !cmp(loc, work_it->first)) {
618 // The location matches, keep it.
619 ++work_it;
620 }
621 }
622 while (work_it != work_end) {
623 work_it = work_values->load_value_map.erase(work_it);
624 }
625}
626
627void LocalValueNumbering::MergeEscapedRefs(const ValueNameSet::value_type& entry,
628 ValueNameSet::iterator hint) {
629 // See if the ref is either escaped or non-aliasing in each predecessor.
630 bool is_escaped = true;
631 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
632 if (lvn->non_aliasing_refs_.count(entry) == 0u &&
633 lvn->escaped_refs_.count(entry) == 0u) {
634 is_escaped = false;
635 break;
636 }
637 }
638 if (is_escaped) {
639 escaped_refs_.emplace_hint(hint, entry);
640 }
641}
642
643void LocalValueNumbering::MergeEscapedIFieldTypeClobberSets(
644 const EscapedIFieldClobberSet::value_type& entry, EscapedIFieldClobberSet::iterator hint) {
645 // Insert only type-clobber entries (field_id == kNoValue) of escaped refs.
646 if (entry.field_id == kNoValue && escaped_refs_.count(entry.base) != 0u) {
647 escaped_ifield_clobber_set_.emplace_hint(hint, entry);
648 }
649}
650
651void LocalValueNumbering::MergeEscapedIFieldClobberSets(
652 const EscapedIFieldClobberSet::value_type& entry, EscapedIFieldClobberSet::iterator hint) {
653 // Insert only those entries of escaped refs that are not overridden by a type clobber.
654 if (!(hint == escaped_ifield_clobber_set_.end() &&
655 hint->base == entry.base && hint->type == entry.type) &&
656 escaped_refs_.count(entry.base) != 0u) {
657 escaped_ifield_clobber_set_.emplace_hint(hint, entry);
658 }
659}
660
661void LocalValueNumbering::MergeEscapedArrayClobberSets(
662 const EscapedArrayClobberSet::value_type& entry, EscapedArrayClobberSet::iterator hint) {
663 if (escaped_refs_.count(entry.base) != 0u) {
664 escaped_array_clobber_set_.emplace_hint(hint, entry);
665 }
666}
667
Vladimir Marko2d2365c2014-08-19 18:08:39 +0100668void LocalValueNumbering::MergeNullChecked() {
669 DCHECK_GE(gvn_->merge_lvns_.size(), 2u);
670
671 // Find the LVN with the least entries in the set.
672 const LocalValueNumbering* least_entries_lvn = gvn_->merge_lvns_[0];
673 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
674 if (lvn->null_checked_.size() < least_entries_lvn->null_checked_.size()) {
675 least_entries_lvn = lvn;
676 }
677 }
678
679 // For each null-checked value name check if it's null-checked in all the LVNs.
680 for (const auto& value_name : least_entries_lvn->null_checked_) {
681 // Merge null_checked_ for this ref.
682 merge_names_.clear();
683 merge_names_.resize(gvn_->merge_lvns_.size(), value_name);
684 if (gvn_->NullCheckedInAllPredecessors(merge_names_)) {
685 null_checked_.insert(null_checked_.end(), value_name);
686 }
687 }
688
689 // Now check if the least_entries_lvn has a null-check as the last insn.
690 const BasicBlock* least_entries_bb = gvn_->GetBasicBlock(least_entries_lvn->Id());
691 if (gvn_->HasNullCheckLastInsn(least_entries_bb, id_)) {
692 int s_reg = least_entries_bb->last_mir_insn->ssa_rep->uses[0];
Vladimir Markoa4426cf2014-10-22 17:15:53 +0100693 uint32_t value_name = least_entries_lvn->GetOperandValue(s_reg);
Vladimir Marko2d2365c2014-08-19 18:08:39 +0100694 merge_names_.clear();
695 merge_names_.resize(gvn_->merge_lvns_.size(), value_name);
696 if (gvn_->NullCheckedInAllPredecessors(merge_names_)) {
697 null_checked_.insert(value_name);
698 }
Vladimir Marko95a05972014-05-30 10:01:32 +0100699 }
700}
701
702void LocalValueNumbering::MergeSFieldValues(const SFieldToValueMap::value_type& entry,
703 SFieldToValueMap::iterator hint) {
704 uint16_t field_id = entry.first;
705 merge_names_.clear();
706 uint16_t value_name = kNoValue;
707 bool same_values = true;
708 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
709 // Get the value name as in HandleSGet() but don't modify *lvn.
710 auto it = lvn->sfield_value_map_.find(field_id);
711 if (it != lvn->sfield_value_map_.end()) {
712 value_name = it->second;
713 } else {
714 uint16_t type = gvn_->GetFieldType(field_id);
715 value_name = gvn_->LookupValue(kResolvedSFieldOp, field_id,
716 lvn->unresolved_sfield_version_[type],
717 lvn->global_memory_version_);
718 }
719
720 same_values = same_values && (merge_names_.empty() || value_name == merge_names_.back());
721 merge_names_.push_back(value_name);
722 }
723 if (same_values) {
724 // value_name already contains the result.
725 } else {
726 auto lb = merge_map_.lower_bound(merge_names_);
727 if (lb != merge_map_.end() && !merge_map_.key_comp()(merge_names_, lb->first)) {
728 value_name = lb->second;
729 } else {
730 value_name = gvn_->LookupValue(kMergeBlockSFieldVersionBumpOp, field_id, id_, kNoValue);
731 merge_map_.PutBefore(lb, merge_names_, value_name);
732 if (gvn_->NullCheckedInAllPredecessors(merge_names_)) {
733 null_checked_.insert(value_name);
734 }
735 }
736 }
737 sfield_value_map_.PutBefore(hint, field_id, value_name);
738}
739
740void LocalValueNumbering::MergeNonAliasingIFieldValues(const IFieldLocToValueMap::value_type& entry,
741 IFieldLocToValueMap::iterator hint) {
742 uint16_t field_loc = entry.first;
743 merge_names_.clear();
744 uint16_t value_name = kNoValue;
745 bool same_values = true;
746 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
747 // Get the value name as in HandleIGet() but don't modify *lvn.
748 auto it = lvn->non_aliasing_ifield_value_map_.find(field_loc);
749 if (it != lvn->non_aliasing_ifield_value_map_.end()) {
750 value_name = it->second;
751 } else {
752 value_name = gvn_->LookupValue(kNonAliasingIFieldInitialOp, field_loc, kNoValue, kNoValue);
753 }
754
755 same_values = same_values && (merge_names_.empty() || value_name == merge_names_.back());
756 merge_names_.push_back(value_name);
757 }
758 if (same_values) {
759 // value_name already contains the result.
760 } else {
761 auto lb = merge_map_.lower_bound(merge_names_);
762 if (lb != merge_map_.end() && !merge_map_.key_comp()(merge_names_, lb->first)) {
763 value_name = lb->second;
764 } else {
765 value_name = gvn_->LookupValue(kMergeBlockNonAliasingIFieldVersionBumpOp, field_loc,
766 id_, kNoValue);
767 merge_map_.PutBefore(lb, merge_names_, value_name);
768 if (gvn_->NullCheckedInAllPredecessors(merge_names_)) {
769 null_checked_.insert(value_name);
770 }
771 }
772 }
773 non_aliasing_ifield_value_map_.PutBefore(hint, field_loc, value_name);
774}
775
776template <typename Map, Map LocalValueNumbering::*map_ptr, typename Versions>
777void LocalValueNumbering::MergeAliasingValues(const typename Map::value_type& entry,
778 typename Map::iterator hint) {
779 const typename Map::key_type& key = entry.first;
780
Vladimir Markob19955d2014-07-29 12:04:10 +0100781 auto it = (this->*map_ptr).PutBefore(hint, key, AliasingValues(this));
Vladimir Marko95a05972014-05-30 10:01:32 +0100782 AliasingValues* my_values = &it->second;
783
784 const AliasingValues* cmp_values = nullptr;
785 bool same_version = !Versions::HasNewBaseVersion(gvn_, this, key);
786 uint16_t load_memory_version_for_same_version = kNoValue;
787 if (same_version) {
788 // Find the first non-null values.
789 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800790 auto value = (lvn->*map_ptr).find(key);
791 if (value != (lvn->*map_ptr).end()) {
792 cmp_values = &value->second;
Vladimir Marko95a05972014-05-30 10:01:32 +0100793 break;
794 }
795 }
796 DCHECK(cmp_values != nullptr); // There must be at least one non-null values.
797
798 // Check if we have identical memory versions, i.e. the global memory version, unresolved
799 // field version and the values' memory_version_before_stores, last_stored_value
800 // and store_loc_set are identical.
801 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800802 auto value = (lvn->*map_ptr).find(key);
803 if (value == (lvn->*map_ptr).end()) {
Vladimir Marko95a05972014-05-30 10:01:32 +0100804 if (cmp_values->memory_version_before_stores != kNoValue) {
805 same_version = false;
806 break;
807 }
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800808 } else if (cmp_values->last_stored_value != value->second.last_stored_value ||
809 cmp_values->memory_version_before_stores != value->second.memory_version_before_stores ||
810 cmp_values->store_loc_set != value->second.store_loc_set) {
Vladimir Marko95a05972014-05-30 10:01:32 +0100811 same_version = false;
812 break;
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800813 } else if (value->second.last_load_memory_version != kNoValue) {
Vladimir Marko95a05972014-05-30 10:01:32 +0100814 DCHECK(load_memory_version_for_same_version == kNoValue ||
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800815 load_memory_version_for_same_version == value->second.last_load_memory_version);
816 load_memory_version_for_same_version = value->second.last_load_memory_version;
Vladimir Marko95a05972014-05-30 10:01:32 +0100817 }
818 }
819 }
820
821 if (same_version) {
822 // Copy the identical values.
823 my_values->memory_version_before_stores = cmp_values->memory_version_before_stores;
824 my_values->last_stored_value = cmp_values->last_stored_value;
825 my_values->store_loc_set = cmp_values->store_loc_set;
826 my_values->last_load_memory_version = load_memory_version_for_same_version;
827 // Merge load values seen in all incoming arcs (i.e. an intersection).
828 if (!cmp_values->load_value_map.empty()) {
829 my_values->load_value_map = cmp_values->load_value_map;
830 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800831 auto value = (lvn->*map_ptr).find(key);
832 if (value == (lvn->*map_ptr).end() || value->second.load_value_map.empty()) {
Vladimir Marko95a05972014-05-30 10:01:32 +0100833 my_values->load_value_map.clear();
834 break;
835 }
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800836 InPlaceIntersectMaps(&my_values->load_value_map, value->second.load_value_map);
Vladimir Marko95a05972014-05-30 10:01:32 +0100837 if (my_values->load_value_map.empty()) {
838 break;
839 }
840 }
841 }
842 } else {
843 // Bump version number for the merge.
844 my_values->memory_version_before_stores = my_values->last_load_memory_version =
845 Versions::LookupMergeBlockValue(gvn_, id_, key);
846
847 // Calculate the locations that have been either read from or written to in each incoming LVN.
848 bool first_lvn = true;
849 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800850 auto value = (lvn->*map_ptr).find(key);
851 if (value == (lvn->*map_ptr).end()) {
Vladimir Marko95a05972014-05-30 10:01:32 +0100852 my_values->load_value_map.clear();
853 break;
854 }
855 if (first_lvn) {
856 first_lvn = false;
857 // Copy the first LVN's locations. Values will be overwritten later.
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800858 my_values->load_value_map = value->second.load_value_map;
859 for (uint16_t location : value->second.store_loc_set) {
Vladimir Marko95a05972014-05-30 10:01:32 +0100860 my_values->load_value_map.Put(location, 0u);
861 }
862 } else {
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800863 IntersectAliasingValueLocations(my_values, &value->second);
Vladimir Marko95a05972014-05-30 10:01:32 +0100864 }
865 }
866 // Calculate merged values for the intersection.
867 for (auto& load_value_entry : my_values->load_value_map) {
868 uint16_t location = load_value_entry.first;
869 bool same_values = true;
870 uint16_t value_name = kNoValue;
871 merge_names_.clear();
872 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
873 value_name = Versions::LookupMergeValue(gvn_, lvn, key, location);
874 same_values = same_values && (merge_names_.empty() || value_name == merge_names_.back());
875 merge_names_.push_back(value_name);
876 }
877 if (same_values) {
878 // value_name already contains the result.
879 } else {
880 auto lb = merge_map_.lower_bound(merge_names_);
881 if (lb != merge_map_.end() && !merge_map_.key_comp()(merge_names_, lb->first)) {
882 value_name = lb->second;
883 } else {
884 // NOTE: In addition to the key and id_ which don't change on an LVN recalculation
885 // during GVN, we also add location which can actually change on recalculation, so the
886 // value_name below may change. This could lead to an infinite loop if the location
887 // value name always changed when the refereced value name changes. However, given that
888 // we assign unique value names for other merges, such as Phis, such a dependency is
889 // not possible in a well-formed SSA graph.
890 value_name = Versions::LookupMergeLocationValue(gvn_, id_, key, location);
891 merge_map_.PutBefore(lb, merge_names_, value_name);
892 if (gvn_->NullCheckedInAllPredecessors(merge_names_)) {
893 null_checked_.insert(value_name);
894 }
895 }
896 }
897 load_value_entry.second = value_name;
898 }
899 }
900}
901
902void LocalValueNumbering::Merge(MergeType merge_type) {
903 DCHECK_GE(gvn_->merge_lvns_.size(), 2u);
904
Vladimir Markob19955d2014-07-29 12:04:10 +0100905 IntersectSregValueMaps<&LocalValueNumbering::sreg_value_map_>();
906 IntersectSregValueMaps<&LocalValueNumbering::sreg_wide_value_map_>();
Vladimir Marko95a05972014-05-30 10:01:32 +0100907 if (merge_type == kReturnMerge) {
908 // RETURN or PHI+RETURN. We need only sreg value maps.
909 return;
910 }
911
912 MergeMemoryVersions(merge_type == kCatchMerge);
913
914 // Merge non-aliasing maps/sets.
Vladimir Marko95a05972014-05-30 10:01:32 +0100915 IntersectSets<ValueNameSet, &LocalValueNumbering::non_aliasing_refs_>();
Vladimir Marko55fff042014-07-10 12:42:52 +0100916 if (!non_aliasing_refs_.empty() && merge_type == kCatchMerge) {
917 PruneNonAliasingRefsForCatch();
918 }
919 if (!non_aliasing_refs_.empty()) {
920 MergeSets<IFieldLocToValueMap, &LocalValueNumbering::non_aliasing_ifield_value_map_,
921 &LocalValueNumbering::MergeNonAliasingIFieldValues>();
922 MergeSets<NonAliasingArrayValuesMap, &LocalValueNumbering::non_aliasing_array_value_map_,
923 &LocalValueNumbering::MergeAliasingValues<
924 NonAliasingArrayValuesMap, &LocalValueNumbering::non_aliasing_array_value_map_,
925 NonAliasingArrayVersions>>();
926 }
Vladimir Marko95a05972014-05-30 10:01:32 +0100927
928 // We won't do anything complicated for range checks, just calculate the intersection.
929 IntersectSets<RangeCheckSet, &LocalValueNumbering::range_checked_>();
930
931 // Merge null_checked_. We may later insert more, such as merged object field values.
Vladimir Marko2d2365c2014-08-19 18:08:39 +0100932 MergeNullChecked();
Vladimir Marko95a05972014-05-30 10:01:32 +0100933
934 if (merge_type == kCatchMerge) {
935 // Memory is clobbered. New memory version already created, don't merge aliasing locations.
Vladimir Marko95a05972014-05-30 10:01:32 +0100936 return;
937 }
938
939 DCHECK(merge_type == kNormalMerge);
940
941 // Merge escaped refs and clobber sets.
942 MergeSets<ValueNameSet, &LocalValueNumbering::escaped_refs_,
943 &LocalValueNumbering::MergeEscapedRefs>();
944 if (!escaped_refs_.empty()) {
945 MergeSets<EscapedIFieldClobberSet, &LocalValueNumbering::escaped_ifield_clobber_set_,
946 &LocalValueNumbering::MergeEscapedIFieldTypeClobberSets>();
947 MergeSets<EscapedIFieldClobberSet, &LocalValueNumbering::escaped_ifield_clobber_set_,
948 &LocalValueNumbering::MergeEscapedIFieldClobberSets>();
949 MergeSets<EscapedArrayClobberSet, &LocalValueNumbering::escaped_array_clobber_set_,
950 &LocalValueNumbering::MergeEscapedArrayClobberSets>();
951 }
952
953 MergeSets<SFieldToValueMap, &LocalValueNumbering::sfield_value_map_,
954 &LocalValueNumbering::MergeSFieldValues>();
955 MergeSets<AliasingIFieldValuesMap, &LocalValueNumbering::aliasing_ifield_value_map_,
956 &LocalValueNumbering::MergeAliasingValues<
957 AliasingIFieldValuesMap, &LocalValueNumbering::aliasing_ifield_value_map_,
958 AliasingIFieldVersions>>();
959 MergeSets<AliasingArrayValuesMap, &LocalValueNumbering::aliasing_array_value_map_,
960 &LocalValueNumbering::MergeAliasingValues<
961 AliasingArrayValuesMap, &LocalValueNumbering::aliasing_array_value_map_,
962 AliasingArrayVersions>>();
Vladimir Markof59f18b2014-02-17 15:53:57 +0000963}
964
Vladimir Markoa4426cf2014-10-22 17:15:53 +0100965void LocalValueNumbering::PrepareEntryBlock() {
966 uint32_t vreg = gvn_->GetMirGraph()->GetFirstInVR();
967 CompilationUnit* cu = gvn_->GetCompilationUnit();
968 const char* shorty = cu->shorty;
969 ++shorty; // Skip return value.
970 if ((cu->access_flags & kAccStatic) == 0) {
971 // If non-static method, mark "this" as non-null
972 uint16_t value_name = GetOperandValue(vreg);
973 ++vreg;
974 null_checked_.insert(value_name);
975 }
976 for ( ; *shorty != 0; ++shorty, ++vreg) {
977 if (*shorty == 'J' || *shorty == 'D') {
978 uint16_t value_name = GetOperandValueWide(vreg);
979 SetOperandValueWide(vreg, value_name);
980 ++vreg;
981 }
982 }
983}
984
Vladimir Markof59f18b2014-02-17 15:53:57 +0000985uint16_t LocalValueNumbering::MarkNonAliasingNonNull(MIR* mir) {
986 uint16_t res = GetOperandValue(mir->ssa_rep->defs[0]);
Vladimir Markof59f18b2014-02-17 15:53:57 +0000987 DCHECK(null_checked_.find(res) == null_checked_.end());
988 null_checked_.insert(res);
989 non_aliasing_refs_.insert(res);
990 return res;
991}
992
Vladimir Marko95a05972014-05-30 10:01:32 +0100993bool LocalValueNumbering::IsNonAliasing(uint16_t reg) const {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100994 return non_aliasing_refs_.find(reg) != non_aliasing_refs_.end();
Vladimir Markof59f18b2014-02-17 15:53:57 +0000995}
996
Vladimir Marko95a05972014-05-30 10:01:32 +0100997bool LocalValueNumbering::IsNonAliasingIField(uint16_t reg, uint16_t field_id,
998 uint16_t type) const {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100999 if (IsNonAliasing(reg)) {
1000 return true;
1001 }
Vladimir Marko95a05972014-05-30 10:01:32 +01001002 if (escaped_refs_.find(reg) == escaped_refs_.end()) {
1003 return false;
1004 }
1005 // Check for IPUTs to unresolved fields.
1006 EscapedIFieldClobberKey key1 = { reg, type, kNoValue };
1007 if (escaped_ifield_clobber_set_.find(key1) != escaped_ifield_clobber_set_.end()) {
1008 return false;
1009 }
1010 // Check for aliased IPUTs to the same field.
1011 EscapedIFieldClobberKey key2 = { reg, type, field_id };
1012 return escaped_ifield_clobber_set_.find(key2) == escaped_ifield_clobber_set_.end();
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001013}
1014
Vladimir Marko95a05972014-05-30 10:01:32 +01001015bool LocalValueNumbering::IsNonAliasingArray(uint16_t reg, uint16_t type) const {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001016 if (IsNonAliasing(reg)) {
1017 return true;
1018 }
Vladimir Marko95a05972014-05-30 10:01:32 +01001019 if (escaped_refs_.count(reg) == 0u) {
1020 return false;
1021 }
1022 // Check for aliased APUTs.
1023 EscapedArrayClobberKey key = { reg, type };
1024 return escaped_array_clobber_set_.find(key) == escaped_array_clobber_set_.end();
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001025}
1026
Vladimir Markof59f18b2014-02-17 15:53:57 +00001027void LocalValueNumbering::HandleNullCheck(MIR* mir, uint16_t reg) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001028 auto lb = null_checked_.lower_bound(reg);
1029 if (lb != null_checked_.end() && *lb == reg) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001030 if (LIKELY(gvn_->CanModify())) {
1031 if (gvn_->GetCompilationUnit()->verbose) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001032 LOG(INFO) << "Removing null check for 0x" << std::hex << mir->offset;
1033 }
1034 mir->optimization_flags |= MIR_IGNORE_NULL_CHECK;
Vladimir Markof59f18b2014-02-17 15:53:57 +00001035 }
Vladimir Markof59f18b2014-02-17 15:53:57 +00001036 } else {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001037 null_checked_.insert(lb, reg);
Vladimir Markof59f18b2014-02-17 15:53:57 +00001038 }
1039}
1040
1041void LocalValueNumbering::HandleRangeCheck(MIR* mir, uint16_t array, uint16_t index) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001042 RangeCheckKey key = { array, index };
1043 auto lb = range_checked_.lower_bound(key);
1044 if (lb != range_checked_.end() && !RangeCheckKeyComparator()(key, *lb)) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001045 if (LIKELY(gvn_->CanModify())) {
1046 if (gvn_->GetCompilationUnit()->verbose) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001047 LOG(INFO) << "Removing range check for 0x" << std::hex << mir->offset;
1048 }
1049 mir->optimization_flags |= MIR_IGNORE_RANGE_CHECK;
Vladimir Markof59f18b2014-02-17 15:53:57 +00001050 }
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001051 } else {
1052 // Mark range check completed.
1053 range_checked_.insert(lb, key);
Vladimir Markof59f18b2014-02-17 15:53:57 +00001054 }
Vladimir Markof59f18b2014-02-17 15:53:57 +00001055}
1056
1057void LocalValueNumbering::HandlePutObject(MIR* mir) {
1058 // If we're storing a non-aliasing reference, stop tracking it as non-aliasing now.
1059 uint16_t base = GetOperandValue(mir->ssa_rep->uses[0]);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001060 HandleEscapingRef(base);
1061}
1062
1063void LocalValueNumbering::HandleEscapingRef(uint16_t base) {
1064 auto it = non_aliasing_refs_.find(base);
1065 if (it != non_aliasing_refs_.end()) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001066 non_aliasing_refs_.erase(it);
Vladimir Marko95a05972014-05-30 10:01:32 +01001067 escaped_refs_.insert(base);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001068 }
1069}
1070
Vladimir Markoa4426cf2014-10-22 17:15:53 +01001071void LocalValueNumbering::HandleInvokeArgs(const MIR* mir, const LocalValueNumbering* mir_lvn) {
1072 const int32_t* uses = mir->ssa_rep->uses;
1073 const int32_t* uses_end = uses + mir->ssa_rep->num_uses;
1074 while (uses != uses_end) {
1075 uint16_t sreg = *uses;
1076 ++uses;
1077 // Avoid LookupValue() so that we don't store new values in the global value map.
1078 auto local_it = mir_lvn->sreg_value_map_.find(sreg);
1079 if (local_it != mir_lvn->sreg_value_map_.end()) {
1080 non_aliasing_refs_.erase(local_it->second);
1081 } else {
1082 uint16_t value_name = gvn_->FindValue(kNoValue, sreg, kNoValue, kNoValue);
1083 if (value_name != kNoValue) {
1084 non_aliasing_refs_.erase(value_name);
1085 }
1086 }
1087 }
1088}
1089
Vladimir Marko95a05972014-05-30 10:01:32 +01001090uint16_t LocalValueNumbering::HandlePhi(MIR* mir) {
1091 if (gvn_->merge_lvns_.empty()) {
1092 // Running LVN without a full GVN?
1093 return kNoValue;
1094 }
Vladimir Marko95a05972014-05-30 10:01:32 +01001095 int32_t* uses = mir->ssa_rep->uses;
1096 // Try to find out if this is merging wide regs.
1097 if (mir->ssa_rep->defs[0] != 0 &&
1098 sreg_wide_value_map_.count(mir->ssa_rep->defs[0] - 1) != 0u) {
1099 // This is the high part of a wide reg. Ignore the Phi.
1100 return kNoValue;
1101 }
Vladimir Markoa4426cf2014-10-22 17:15:53 +01001102 BasicBlockId* incoming = mir->meta.phi_incoming;
1103 int16_t pos = 0;
1104 // Check if we're merging a wide value based on the first merged LVN.
1105 const LocalValueNumbering* first_lvn = gvn_->merge_lvns_[0];
1106 DCHECK_LT(pos, mir->ssa_rep->num_uses);
1107 while (incoming[pos] != first_lvn->Id()) {
1108 ++pos;
1109 DCHECK_LT(pos, mir->ssa_rep->num_uses);
Vladimir Marko95a05972014-05-30 10:01:32 +01001110 }
Vladimir Markoa4426cf2014-10-22 17:15:53 +01001111 int first_s_reg = uses[pos];
1112 bool wide = (first_lvn->sreg_wide_value_map_.count(first_s_reg) != 0u);
Vladimir Marko95a05972014-05-30 10:01:32 +01001113 // Iterate over *merge_lvns_ and skip incoming sregs for BBs without associated LVN.
1114 uint16_t value_name = kNoValue;
1115 merge_names_.clear();
Vladimir Marko95a05972014-05-30 10:01:32 +01001116 bool same_values = true;
1117 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
1118 DCHECK_LT(pos, mir->ssa_rep->num_uses);
1119 while (incoming[pos] != lvn->Id()) {
1120 ++pos;
1121 DCHECK_LT(pos, mir->ssa_rep->num_uses);
1122 }
1123 int s_reg = uses[pos];
1124 ++pos;
1125 value_name = wide ? lvn->GetOperandValueWide(s_reg) : lvn->GetOperandValue(s_reg);
1126
1127 same_values = same_values && (merge_names_.empty() || value_name == merge_names_.back());
1128 merge_names_.push_back(value_name);
1129 }
1130 if (same_values) {
1131 // value_name already contains the result.
1132 } else {
1133 auto lb = merge_map_.lower_bound(merge_names_);
1134 if (lb != merge_map_.end() && !merge_map_.key_comp()(merge_names_, lb->first)) {
1135 value_name = lb->second;
1136 } else {
1137 value_name = gvn_->LookupValue(kNoValue, mir->ssa_rep->defs[0], kNoValue, kNoValue);
1138 merge_map_.PutBefore(lb, merge_names_, value_name);
1139 if (!wide && gvn_->NullCheckedInAllPredecessors(merge_names_)) {
1140 null_checked_.insert(value_name);
1141 }
1142 }
1143 }
1144 if (wide) {
1145 SetOperandValueWide(mir->ssa_rep->defs[0], value_name);
1146 } else {
1147 SetOperandValue(mir->ssa_rep->defs[0], value_name);
1148 }
1149 return value_name;
1150}
1151
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001152uint16_t LocalValueNumbering::HandleAGet(MIR* mir, uint16_t opcode) {
1153 // uint16_t type = opcode - Instruction::AGET;
1154 uint16_t array = GetOperandValue(mir->ssa_rep->uses[0]);
1155 HandleNullCheck(mir, array);
1156 uint16_t index = GetOperandValue(mir->ssa_rep->uses[1]);
1157 HandleRangeCheck(mir, array, index);
1158 uint16_t type = opcode - Instruction::AGET;
1159 // Establish value number for loaded register.
1160 uint16_t res;
1161 if (IsNonAliasingArray(array, type)) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001162 res = HandleAliasingValuesGet<NonAliasingArrayVersions>(&non_aliasing_array_value_map_,
1163 array, index);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001164 } else {
Vladimir Marko95a05972014-05-30 10:01:32 +01001165 uint16_t location = gvn_->GetArrayLocation(array, index);
1166 res = HandleAliasingValuesGet<AliasingArrayVersions>(&aliasing_array_value_map_,
1167 type, location);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001168 }
1169 if (opcode == Instruction::AGET_WIDE) {
1170 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1171 } else {
1172 SetOperandValue(mir->ssa_rep->defs[0], res);
1173 }
1174 return res;
1175}
1176
1177void LocalValueNumbering::HandleAPut(MIR* mir, uint16_t opcode) {
1178 int array_idx = (opcode == Instruction::APUT_WIDE) ? 2 : 1;
1179 int index_idx = array_idx + 1;
1180 uint16_t array = GetOperandValue(mir->ssa_rep->uses[array_idx]);
1181 HandleNullCheck(mir, array);
1182 uint16_t index = GetOperandValue(mir->ssa_rep->uses[index_idx]);
1183 HandleRangeCheck(mir, array, index);
1184
1185 uint16_t type = opcode - Instruction::APUT;
1186 uint16_t value = (opcode == Instruction::APUT_WIDE)
1187 ? GetOperandValueWide(mir->ssa_rep->uses[0])
1188 : GetOperandValue(mir->ssa_rep->uses[0]);
1189 if (IsNonAliasing(array)) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001190 bool put_is_live = HandleAliasingValuesPut<NonAliasingArrayVersions>(
1191 &non_aliasing_array_value_map_, array, index, value);
1192 if (!put_is_live) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001193 // This APUT can be eliminated, it stores the same value that's already in the field.
1194 // TODO: Eliminate the APUT.
1195 return;
1196 }
Vladimir Marko95a05972014-05-30 10:01:32 +01001197 } else {
1198 uint16_t location = gvn_->GetArrayLocation(array, index);
1199 bool put_is_live = HandleAliasingValuesPut<AliasingArrayVersions>(
1200 &aliasing_array_value_map_, type, location, value);
1201 if (!put_is_live) {
1202 // This APUT can be eliminated, it stores the same value that's already in the field.
1203 // TODO: Eliminate the APUT.
1204 return;
1205 }
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001206
Vladimir Marko95a05972014-05-30 10:01:32 +01001207 // Clobber all escaped array refs for this type.
1208 for (uint16_t escaped_array : escaped_refs_) {
1209 EscapedArrayClobberKey clobber_key = { escaped_array, type };
1210 escaped_array_clobber_set_.insert(clobber_key);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001211 }
1212 }
1213}
1214
1215uint16_t LocalValueNumbering::HandleIGet(MIR* mir, uint16_t opcode) {
1216 uint16_t base = GetOperandValue(mir->ssa_rep->uses[0]);
1217 HandleNullCheck(mir, base);
Vladimir Marko95a05972014-05-30 10:01:32 +01001218 const MirFieldInfo& field_info = gvn_->GetMirGraph()->GetIFieldLoweringInfo(mir);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001219 uint16_t res;
1220 if (!field_info.IsResolved() || field_info.IsVolatile()) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001221 // Unresolved fields may be volatile, so handle them as such to be safe.
Vladimir Markofa236452014-09-29 17:58:10 +01001222 HandleInvokeOrClInitOrAcquireOp(mir); // Volatile GETs have acquire semantics.
1223 // Volatile fields always get a new memory version; field id is irrelevant.
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001224 // Use result s_reg - will be unique.
Vladimir Marko95a05972014-05-30 10:01:32 +01001225 res = gvn_->LookupValue(kNoValue, mir->ssa_rep->defs[0], kNoValue, kNoValue);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001226 } else {
1227 uint16_t type = opcode - Instruction::IGET;
Vladimir Marko95a05972014-05-30 10:01:32 +01001228 uint16_t field_id = gvn_->GetFieldId(field_info, type);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001229 if (IsNonAliasingIField(base, field_id, type)) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001230 uint16_t loc = gvn_->LookupValue(kNonAliasingIFieldLocOp, base, field_id, type);
1231 auto lb = non_aliasing_ifield_value_map_.lower_bound(loc);
1232 if (lb != non_aliasing_ifield_value_map_.end() && lb->first == loc) {
1233 res = lb->second;
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001234 } else {
Vladimir Marko95a05972014-05-30 10:01:32 +01001235 res = gvn_->LookupValue(kNonAliasingIFieldInitialOp, loc, kNoValue, kNoValue);
1236 non_aliasing_ifield_value_map_.PutBefore(lb, loc, res);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001237 }
Vladimir Marko95a05972014-05-30 10:01:32 +01001238 } else {
1239 res = HandleAliasingValuesGet<AliasingIFieldVersions>(&aliasing_ifield_value_map_,
1240 field_id, base);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001241 }
1242 }
1243 if (opcode == Instruction::IGET_WIDE) {
1244 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1245 } else {
1246 SetOperandValue(mir->ssa_rep->defs[0], res);
1247 }
1248 return res;
1249}
1250
1251void LocalValueNumbering::HandleIPut(MIR* mir, uint16_t opcode) {
1252 uint16_t type = opcode - Instruction::IPUT;
1253 int base_reg = (opcode == Instruction::IPUT_WIDE) ? 2 : 1;
1254 uint16_t base = GetOperandValue(mir->ssa_rep->uses[base_reg]);
1255 HandleNullCheck(mir, base);
Vladimir Marko95a05972014-05-30 10:01:32 +01001256 const MirFieldInfo& field_info = gvn_->GetMirGraph()->GetIFieldLoweringInfo(mir);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001257 if (!field_info.IsResolved()) {
1258 // Unresolved fields always alias with everything of the same type.
1259 // Use mir->offset as modifier; without elaborate inlining, it will be unique.
1260 unresolved_ifield_version_[type] =
Vladimir Marko95a05972014-05-30 10:01:32 +01001261 gvn_->LookupValue(kUnresolvedIFieldOp, kNoValue, kNoValue, mir->offset);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001262
Vladimir Marko95a05972014-05-30 10:01:32 +01001263 // For simplicity, treat base as escaped now.
1264 HandleEscapingRef(base);
1265
1266 // Clobber all fields of escaped references of the same type.
1267 for (uint16_t escaped_ref : escaped_refs_) {
1268 EscapedIFieldClobberKey clobber_key = { escaped_ref, type, kNoValue };
1269 escaped_ifield_clobber_set_.insert(clobber_key);
1270 }
1271
1272 // Aliasing fields of the same type may have been overwritten.
1273 auto it = aliasing_ifield_value_map_.begin(), end = aliasing_ifield_value_map_.end();
1274 while (it != end) {
1275 if (gvn_->GetFieldType(it->first) != type) {
1276 ++it;
1277 } else {
1278 it = aliasing_ifield_value_map_.erase(it);
1279 }
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001280 }
1281 } else if (field_info.IsVolatile()) {
1282 // Nothing to do, resolved volatile fields always get a new memory version anyway and
1283 // can't alias with resolved non-volatile fields.
1284 } else {
Vladimir Marko95a05972014-05-30 10:01:32 +01001285 uint16_t field_id = gvn_->GetFieldId(field_info, type);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001286 uint16_t value = (opcode == Instruction::IPUT_WIDE)
1287 ? GetOperandValueWide(mir->ssa_rep->uses[0])
1288 : GetOperandValue(mir->ssa_rep->uses[0]);
1289 if (IsNonAliasing(base)) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001290 uint16_t loc = gvn_->LookupValue(kNonAliasingIFieldLocOp, base, field_id, type);
1291 auto lb = non_aliasing_ifield_value_map_.lower_bound(loc);
1292 if (lb != non_aliasing_ifield_value_map_.end() && lb->first == loc) {
1293 if (lb->second == value) {
1294 // This IPUT can be eliminated, it stores the same value that's already in the field.
1295 // TODO: Eliminate the IPUT.
1296 return;
1297 }
1298 lb->second = value; // Overwrite.
1299 } else {
1300 non_aliasing_ifield_value_map_.PutBefore(lb, loc, value);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001301 }
Vladimir Marko95a05972014-05-30 10:01:32 +01001302 } else {
1303 bool put_is_live = HandleAliasingValuesPut<AliasingIFieldVersions>(
1304 &aliasing_ifield_value_map_, field_id, base, value);
1305 if (!put_is_live) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001306 // This IPUT can be eliminated, it stores the same value that's already in the field.
1307 // TODO: Eliminate the IPUT.
1308 return;
1309 }
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001310
Vladimir Marko95a05972014-05-30 10:01:32 +01001311 // Clobber all fields of escaped references for this field.
1312 for (uint16_t escaped_ref : escaped_refs_) {
1313 EscapedIFieldClobberKey clobber_key = { escaped_ref, type, field_id };
1314 escaped_ifield_clobber_set_.insert(clobber_key);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001315 }
1316 }
1317 }
1318}
1319
1320uint16_t LocalValueNumbering::HandleSGet(MIR* mir, uint16_t opcode) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001321 const MirSFieldLoweringInfo& field_info = gvn_->GetMirGraph()->GetSFieldLoweringInfo(mir);
Vladimir Markofa236452014-09-29 17:58:10 +01001322 if (!field_info.IsResolved() || field_info.IsVolatile() ||
Vladimir Marko66c6d7b2014-10-16 15:41:48 +01001323 (!field_info.IsClassInitialized() &&
1324 (mir->optimization_flags & MIR_CLASS_IS_INITIALIZED) == 0)) {
Vladimir Markofa236452014-09-29 17:58:10 +01001325 // Volatile SGETs (and unresolved fields are potentially volatile) have acquire semantics
1326 // and class initialization can call arbitrary functions, we need to wipe aliasing values.
1327 HandleInvokeOrClInitOrAcquireOp(mir);
Vladimir Markof418f322014-07-09 14:45:36 +01001328 }
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001329 uint16_t res;
1330 if (!field_info.IsResolved() || field_info.IsVolatile()) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001331 // Unresolved fields may be volatile, so handle them as such to be safe.
Vladimir Markofa236452014-09-29 17:58:10 +01001332 // Volatile fields always get a new memory version; field id is irrelevant.
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001333 // Use result s_reg - will be unique.
Vladimir Marko95a05972014-05-30 10:01:32 +01001334 res = gvn_->LookupValue(kNoValue, mir->ssa_rep->defs[0], kNoValue, kNoValue);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001335 } else {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001336 uint16_t type = opcode - Instruction::SGET;
Vladimir Marko95a05972014-05-30 10:01:32 +01001337 uint16_t field_id = gvn_->GetFieldId(field_info, type);
1338 auto lb = sfield_value_map_.lower_bound(field_id);
1339 if (lb != sfield_value_map_.end() && lb->first == field_id) {
1340 res = lb->second;
1341 } else {
1342 // Resolved non-volatile static fields can alias with non-resolved fields of the same type,
1343 // so we need to use unresolved_sfield_version_[type] in addition to global_memory_version_
1344 // to determine the version of the field.
1345 res = gvn_->LookupValue(kResolvedSFieldOp, field_id,
1346 unresolved_sfield_version_[type], global_memory_version_);
1347 sfield_value_map_.PutBefore(lb, field_id, res);
1348 }
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001349 }
1350 if (opcode == Instruction::SGET_WIDE) {
1351 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1352 } else {
1353 SetOperandValue(mir->ssa_rep->defs[0], res);
1354 }
1355 return res;
1356}
1357
1358void LocalValueNumbering::HandleSPut(MIR* mir, uint16_t opcode) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001359 const MirSFieldLoweringInfo& field_info = gvn_->GetMirGraph()->GetSFieldLoweringInfo(mir);
Vladimir Marko66c6d7b2014-10-16 15:41:48 +01001360 if (!field_info.IsClassInitialized() &&
1361 (mir->optimization_flags & MIR_CLASS_IS_INITIALIZED) == 0) {
Vladimir Markof418f322014-07-09 14:45:36 +01001362 // Class initialization can call arbitrary functions, we need to wipe aliasing values.
Vladimir Markofa236452014-09-29 17:58:10 +01001363 HandleInvokeOrClInitOrAcquireOp(mir);
Vladimir Markof418f322014-07-09 14:45:36 +01001364 }
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001365 uint16_t type = opcode - Instruction::SPUT;
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001366 if (!field_info.IsResolved()) {
1367 // Unresolved fields always alias with everything of the same type.
1368 // Use mir->offset as modifier; without elaborate inlining, it will be unique.
1369 unresolved_sfield_version_[type] =
Vladimir Marko95a05972014-05-30 10:01:32 +01001370 gvn_->LookupValue(kUnresolvedSFieldOp, kNoValue, kNoValue, mir->offset);
1371 RemoveSFieldsForType(type);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001372 } else if (field_info.IsVolatile()) {
1373 // Nothing to do, resolved volatile fields always get a new memory version anyway and
1374 // can't alias with resolved non-volatile fields.
1375 } else {
Vladimir Marko95a05972014-05-30 10:01:32 +01001376 uint16_t field_id = gvn_->GetFieldId(field_info, type);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001377 uint16_t value = (opcode == Instruction::SPUT_WIDE)
1378 ? GetOperandValueWide(mir->ssa_rep->uses[0])
1379 : GetOperandValue(mir->ssa_rep->uses[0]);
1380 // Resolved non-volatile static fields can alias with non-resolved fields of the same type,
1381 // so we need to use unresolved_sfield_version_[type] in addition to global_memory_version_
1382 // to determine the version of the field.
Vladimir Marko95a05972014-05-30 10:01:32 +01001383 auto lb = sfield_value_map_.lower_bound(field_id);
1384 if (lb != sfield_value_map_.end() && lb->first == field_id) {
1385 if (lb->second == value) {
1386 // This SPUT can be eliminated, it stores the same value that's already in the field.
1387 // TODO: Eliminate the SPUT.
1388 return;
1389 }
1390 lb->second = value; // Overwrite.
1391 } else {
1392 sfield_value_map_.PutBefore(lb, field_id, value);
1393 }
1394 }
1395}
1396
1397void LocalValueNumbering::RemoveSFieldsForType(uint16_t type) {
1398 // Erase all static fields of this type from the sfield_value_map_.
1399 for (auto it = sfield_value_map_.begin(), end = sfield_value_map_.end(); it != end; ) {
1400 if (gvn_->GetFieldType(it->first) == type) {
1401 it = sfield_value_map_.erase(it);
1402 } else {
1403 ++it;
1404 }
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001405 }
Vladimir Markof59f18b2014-02-17 15:53:57 +00001406}
buzbee2502e002012-12-31 16:05:53 -08001407
Vladimir Markofa236452014-09-29 17:58:10 +01001408void LocalValueNumbering::HandleInvokeOrClInitOrAcquireOp(MIR* mir) {
Vladimir Markof418f322014-07-09 14:45:36 +01001409 // Use mir->offset as modifier; without elaborate inlining, it will be unique.
Vladimir Marko95a05972014-05-30 10:01:32 +01001410 global_memory_version_ =
1411 gvn_->LookupValue(kInvokeMemoryVersionBumpOp, 0u, 0u, mir->offset);
1412 // All static fields and instance fields and array elements of aliasing references,
1413 // including escaped references, may have been modified.
1414 sfield_value_map_.clear();
1415 aliasing_ifield_value_map_.clear();
1416 aliasing_array_value_map_.clear();
1417 escaped_refs_.clear();
1418 escaped_ifield_clobber_set_.clear();
1419 escaped_array_clobber_set_.clear();
Vladimir Markof418f322014-07-09 14:45:36 +01001420}
1421
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001422uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001423 uint16_t res = kNoValue;
buzbee2502e002012-12-31 16:05:53 -08001424 uint16_t opcode = mir->dalvikInsn.opcode;
1425 switch (opcode) {
1426 case Instruction::NOP:
1427 case Instruction::RETURN_VOID:
1428 case Instruction::RETURN:
1429 case Instruction::RETURN_OBJECT:
1430 case Instruction::RETURN_WIDE:
buzbee2502e002012-12-31 16:05:53 -08001431 case Instruction::GOTO:
1432 case Instruction::GOTO_16:
1433 case Instruction::GOTO_32:
1434 case Instruction::CHECK_CAST:
1435 case Instruction::THROW:
1436 case Instruction::FILL_ARRAY_DATA:
buzbee2502e002012-12-31 16:05:53 -08001437 case Instruction::PACKED_SWITCH:
1438 case Instruction::SPARSE_SWITCH:
1439 case Instruction::IF_EQ:
1440 case Instruction::IF_NE:
1441 case Instruction::IF_LT:
1442 case Instruction::IF_GE:
1443 case Instruction::IF_GT:
1444 case Instruction::IF_LE:
1445 case Instruction::IF_EQZ:
1446 case Instruction::IF_NEZ:
1447 case Instruction::IF_LTZ:
1448 case Instruction::IF_GEZ:
1449 case Instruction::IF_GTZ:
1450 case Instruction::IF_LEZ:
buzbee2502e002012-12-31 16:05:53 -08001451 case kMirOpFusedCmplFloat:
1452 case kMirOpFusedCmpgFloat:
1453 case kMirOpFusedCmplDouble:
1454 case kMirOpFusedCmpgDouble:
1455 case kMirOpFusedCmpLong:
1456 // Nothing defined - take no action.
1457 break;
1458
Vladimir Marko95a05972014-05-30 10:01:32 +01001459 case Instruction::MONITOR_ENTER:
1460 HandleNullCheck(mir, GetOperandValue(mir->ssa_rep->uses[0]));
Vladimir Markofa236452014-09-29 17:58:10 +01001461 HandleInvokeOrClInitOrAcquireOp(mir); // Acquire operation.
Vladimir Marko95a05972014-05-30 10:01:32 +01001462 break;
1463
1464 case Instruction::MONITOR_EXIT:
1465 HandleNullCheck(mir, GetOperandValue(mir->ssa_rep->uses[0]));
1466 // If we're running GVN and CanModify(), uneliminated null check indicates bytecode error.
Vladimir Marko415ac882014-09-30 18:09:14 +01001467 if ((mir->optimization_flags & MIR_IGNORE_NULL_CHECK) == 0 &&
1468 gvn_->work_lvn_ != nullptr && gvn_->CanModify()) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001469 LOG(WARNING) << "Bytecode error: MONITOR_EXIT is still null checked at 0x" << std::hex
1470 << mir->offset << " in " << PrettyMethod(gvn_->cu_->method_idx, *gvn_->cu_->dex_file);
1471 }
1472 break;
1473
Vladimir Markof59f18b2014-02-17 15:53:57 +00001474 case Instruction::FILLED_NEW_ARRAY:
1475 case Instruction::FILLED_NEW_ARRAY_RANGE:
1476 // Nothing defined but the result will be unique and non-null.
1477 if (mir->next != nullptr && mir->next->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001478 uint16_t array = MarkNonAliasingNonNull(mir->next);
1479 // Do not SetOperandValue(), we'll do that when we process the MOVE_RESULT_OBJECT.
1480 if (kLocalValueNumberingEnableFilledNewArrayTracking && mir->ssa_rep->num_uses != 0u) {
1481 AliasingValues* values = GetAliasingValues(&non_aliasing_array_value_map_, array);
1482 // Clear the value if we got a merged version in a loop.
Vladimir Markob19955d2014-07-29 12:04:10 +01001483 *values = AliasingValues(this);
Vladimir Marko95a05972014-05-30 10:01:32 +01001484 for (size_t i = 0u, count = mir->ssa_rep->num_uses; i != count; ++i) {
1485 DCHECK_EQ(High16Bits(i), 0u);
1486 uint16_t index = gvn_->LookupValue(Instruction::CONST, i, 0u, 0);
1487 uint16_t value = GetOperandValue(mir->ssa_rep->uses[i]);
1488 values->load_value_map.Put(index, value);
1489 RangeCheckKey key = { array, index };
1490 range_checked_.insert(key);
1491 }
1492 }
Vladimir Markof59f18b2014-02-17 15:53:57 +00001493 // The MOVE_RESULT_OBJECT will be processed next and we'll return the value name then.
1494 }
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001495 // All args escaped (if references).
1496 for (size_t i = 0u, count = mir->ssa_rep->num_uses; i != count; ++i) {
1497 uint16_t reg = GetOperandValue(mir->ssa_rep->uses[i]);
1498 HandleEscapingRef(reg);
1499 }
Vladimir Markof59f18b2014-02-17 15:53:57 +00001500 break;
1501
Vladimir Markoa78e66a2014-10-16 13:38:44 +01001502 case kMirOpNullCheck:
1503 HandleNullCheck(mir, GetOperandValue(mir->ssa_rep->uses[0]));
1504 break;
1505
Vladimir Markof59f18b2014-02-17 15:53:57 +00001506 case Instruction::INVOKE_DIRECT:
1507 case Instruction::INVOKE_DIRECT_RANGE:
1508 case Instruction::INVOKE_VIRTUAL:
1509 case Instruction::INVOKE_VIRTUAL_RANGE:
1510 case Instruction::INVOKE_SUPER:
1511 case Instruction::INVOKE_SUPER_RANGE:
1512 case Instruction::INVOKE_INTERFACE:
1513 case Instruction::INVOKE_INTERFACE_RANGE: {
1514 // Nothing defined but handle the null check.
1515 uint16_t reg = GetOperandValue(mir->ssa_rep->uses[0]);
1516 HandleNullCheck(mir, reg);
1517 }
Ian Rogersfc787ec2014-10-09 21:56:44 -07001518 FALLTHROUGH_INTENDED;
Vladimir Markof59f18b2014-02-17 15:53:57 +00001519 case Instruction::INVOKE_STATIC:
1520 case Instruction::INVOKE_STATIC_RANGE:
Vladimir Markoff0ac472014-10-02 17:24:53 +01001521 // Make ref args aliasing.
Vladimir Markoa4426cf2014-10-22 17:15:53 +01001522 HandleInvokeArgs(mir, this);
Vladimir Markoff0ac472014-10-02 17:24:53 +01001523 HandleInvokeOrClInitOrAcquireOp(mir);
Vladimir Markof59f18b2014-02-17 15:53:57 +00001524 break;
1525
buzbee2502e002012-12-31 16:05:53 -08001526 case Instruction::MOVE_RESULT:
1527 case Instruction::MOVE_RESULT_OBJECT:
1528 case Instruction::INSTANCE_OF:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001529 // 1 result, treat as unique each time, use result s_reg - will be unique.
1530 res = GetOperandValue(mir->ssa_rep->defs[0]);
1531 SetOperandValue(mir->ssa_rep->defs[0], res);
1532 break;
1533 case Instruction::MOVE_EXCEPTION:
buzbee2502e002012-12-31 16:05:53 -08001534 case Instruction::NEW_INSTANCE:
buzbee2502e002012-12-31 16:05:53 -08001535 case Instruction::CONST_CLASS:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001536 case Instruction::NEW_ARRAY:
Vladimir Markob3e527b2014-04-04 12:37:07 +01001537 // 1 result, treat as unique each time, use result s_reg - will be unique.
1538 res = MarkNonAliasingNonNull(mir);
Vladimir Marko95a05972014-05-30 10:01:32 +01001539 SetOperandValue(mir->ssa_rep->defs[0], res);
buzbee2502e002012-12-31 16:05:53 -08001540 break;
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001541 case Instruction::CONST_STRING:
1542 case Instruction::CONST_STRING_JUMBO:
1543 // These strings are internalized, so assign value based on the string pool index.
Vladimir Marko95a05972014-05-30 10:01:32 +01001544 res = gvn_->LookupValue(Instruction::CONST_STRING, Low16Bits(mir->dalvikInsn.vB),
1545 High16Bits(mir->dalvikInsn.vB), 0);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001546 SetOperandValue(mir->ssa_rep->defs[0], res);
1547 null_checked_.insert(res); // May already be there.
1548 // NOTE: Hacking the contents of an internalized string via reflection is possible
1549 // but the behavior is undefined. Therefore, we consider the string constant and
1550 // the reference non-aliasing.
1551 // TUNING: We could keep this property even if the reference "escapes".
1552 non_aliasing_refs_.insert(res); // May already be there.
1553 break;
Vladimir Markof59f18b2014-02-17 15:53:57 +00001554 case Instruction::MOVE_RESULT_WIDE:
Vladimir Markob3e527b2014-04-04 12:37:07 +01001555 // 1 wide result, treat as unique each time, use result s_reg - will be unique.
1556 res = GetOperandValueWide(mir->ssa_rep->defs[0]);
1557 SetOperandValueWide(mir->ssa_rep->defs[0], res);
buzbee2502e002012-12-31 16:05:53 -08001558 break;
1559
1560 case kMirOpPhi:
Vladimir Marko95a05972014-05-30 10:01:32 +01001561 res = HandlePhi(mir);
buzbee2502e002012-12-31 16:05:53 -08001562 break;
1563
1564 case Instruction::MOVE:
1565 case Instruction::MOVE_OBJECT:
1566 case Instruction::MOVE_16:
1567 case Instruction::MOVE_OBJECT_16:
1568 case Instruction::MOVE_FROM16:
1569 case Instruction::MOVE_OBJECT_FROM16:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001570 case kMirOpCopy:
1571 // Just copy value number of source to value number of result.
1572 res = GetOperandValue(mir->ssa_rep->uses[0]);
1573 SetOperandValue(mir->ssa_rep->defs[0], res);
buzbee2502e002012-12-31 16:05:53 -08001574 break;
1575
1576 case Instruction::MOVE_WIDE:
1577 case Instruction::MOVE_WIDE_16:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001578 case Instruction::MOVE_WIDE_FROM16:
1579 // Just copy value number of source to value number of result.
1580 res = GetOperandValueWide(mir->ssa_rep->uses[0]);
1581 SetOperandValueWide(mir->ssa_rep->defs[0], res);
buzbee2502e002012-12-31 16:05:53 -08001582 break;
1583
1584 case Instruction::CONST:
1585 case Instruction::CONST_4:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001586 case Instruction::CONST_16:
Vladimir Marko95a05972014-05-30 10:01:32 +01001587 res = gvn_->LookupValue(Instruction::CONST, Low16Bits(mir->dalvikInsn.vB),
1588 High16Bits(mir->dalvikInsn.vB), 0);
Vladimir Markof59f18b2014-02-17 15:53:57 +00001589 SetOperandValue(mir->ssa_rep->defs[0], res);
buzbee2502e002012-12-31 16:05:53 -08001590 break;
1591
Vladimir Markof59f18b2014-02-17 15:53:57 +00001592 case Instruction::CONST_HIGH16:
Vladimir Marko95a05972014-05-30 10:01:32 +01001593 res = gvn_->LookupValue(Instruction::CONST, 0, mir->dalvikInsn.vB, 0);
Vladimir Markof59f18b2014-02-17 15:53:57 +00001594 SetOperandValue(mir->ssa_rep->defs[0], res);
buzbee2502e002012-12-31 16:05:53 -08001595 break;
1596
1597 case Instruction::CONST_WIDE_16:
1598 case Instruction::CONST_WIDE_32: {
Vladimir Marko95a05972014-05-30 10:01:32 +01001599 uint16_t low_res = gvn_->LookupValue(Instruction::CONST, Low16Bits(mir->dalvikInsn.vB),
1600 High16Bits(mir->dalvikInsn.vB >> 16), 1);
buzbee2502e002012-12-31 16:05:53 -08001601 uint16_t high_res;
1602 if (mir->dalvikInsn.vB & 0x80000000) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001603 high_res = gvn_->LookupValue(Instruction::CONST, 0xffff, 0xffff, 2);
buzbee2502e002012-12-31 16:05:53 -08001604 } else {
Vladimir Marko95a05972014-05-30 10:01:32 +01001605 high_res = gvn_->LookupValue(Instruction::CONST, 0, 0, 2);
buzbee2502e002012-12-31 16:05:53 -08001606 }
Vladimir Marko95a05972014-05-30 10:01:32 +01001607 res = gvn_->LookupValue(Instruction::CONST, low_res, high_res, 3);
Vladimir Markof59f18b2014-02-17 15:53:57 +00001608 SetOperandValueWide(mir->ssa_rep->defs[0], res);
buzbee2502e002012-12-31 16:05:53 -08001609 }
1610 break;
1611
1612 case Instruction::CONST_WIDE: {
1613 uint32_t low_word = Low32Bits(mir->dalvikInsn.vB_wide);
1614 uint32_t high_word = High32Bits(mir->dalvikInsn.vB_wide);
Vladimir Marko95a05972014-05-30 10:01:32 +01001615 uint16_t low_res = gvn_->LookupValue(Instruction::CONST, Low16Bits(low_word),
1616 High16Bits(low_word), 1);
1617 uint16_t high_res = gvn_->LookupValue(Instruction::CONST, Low16Bits(high_word),
1618 High16Bits(high_word), 2);
1619 res = gvn_->LookupValue(Instruction::CONST, low_res, high_res, 3);
buzbee2502e002012-12-31 16:05:53 -08001620 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1621 }
1622 break;
1623
1624 case Instruction::CONST_WIDE_HIGH16: {
Vladimir Marko95a05972014-05-30 10:01:32 +01001625 uint16_t low_res = gvn_->LookupValue(Instruction::CONST, 0, 0, 1);
1626 uint16_t high_res = gvn_->LookupValue(Instruction::CONST, 0,
1627 Low16Bits(mir->dalvikInsn.vB), 2);
1628 res = gvn_->LookupValue(Instruction::CONST, low_res, high_res, 3);
buzbee2502e002012-12-31 16:05:53 -08001629 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1630 }
1631 break;
1632
Vladimir Marko95a05972014-05-30 10:01:32 +01001633 case Instruction::ARRAY_LENGTH: {
1634 // Handle the null check.
1635 uint16_t reg = GetOperandValue(mir->ssa_rep->uses[0]);
1636 HandleNullCheck(mir, reg);
1637 }
Ian Rogersfc787ec2014-10-09 21:56:44 -07001638 FALLTHROUGH_INTENDED;
buzbee2502e002012-12-31 16:05:53 -08001639 case Instruction::NEG_INT:
1640 case Instruction::NOT_INT:
1641 case Instruction::NEG_FLOAT:
1642 case Instruction::INT_TO_BYTE:
1643 case Instruction::INT_TO_SHORT:
1644 case Instruction::INT_TO_CHAR:
1645 case Instruction::INT_TO_FLOAT:
1646 case Instruction::FLOAT_TO_INT: {
1647 // res = op + 1 operand
1648 uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
Vladimir Marko95a05972014-05-30 10:01:32 +01001649 res = gvn_->LookupValue(opcode, operand1, kNoValue, kNoValue);
buzbee2502e002012-12-31 16:05:53 -08001650 SetOperandValue(mir->ssa_rep->defs[0], res);
1651 }
1652 break;
1653
1654 case Instruction::LONG_TO_FLOAT:
1655 case Instruction::LONG_TO_INT:
1656 case Instruction::DOUBLE_TO_FLOAT:
1657 case Instruction::DOUBLE_TO_INT: {
1658 // res = op + 1 wide operand
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001659 uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
Vladimir Marko95a05972014-05-30 10:01:32 +01001660 res = gvn_->LookupValue(opcode, operand1, kNoValue, kNoValue);
buzbee2502e002012-12-31 16:05:53 -08001661 SetOperandValue(mir->ssa_rep->defs[0], res);
1662 }
1663 break;
1664
buzbee2502e002012-12-31 16:05:53 -08001665 case Instruction::DOUBLE_TO_LONG:
1666 case Instruction::LONG_TO_DOUBLE:
1667 case Instruction::NEG_LONG:
1668 case Instruction::NOT_LONG:
1669 case Instruction::NEG_DOUBLE: {
1670 // wide res = op + 1 wide operand
1671 uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
Vladimir Marko95a05972014-05-30 10:01:32 +01001672 res = gvn_->LookupValue(opcode, operand1, kNoValue, kNoValue);
buzbee2502e002012-12-31 16:05:53 -08001673 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1674 }
1675 break;
1676
1677 case Instruction::FLOAT_TO_DOUBLE:
1678 case Instruction::FLOAT_TO_LONG:
1679 case Instruction::INT_TO_DOUBLE:
1680 case Instruction::INT_TO_LONG: {
1681 // wide res = op + 1 operand
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001682 uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
Vladimir Marko95a05972014-05-30 10:01:32 +01001683 res = gvn_->LookupValue(opcode, operand1, kNoValue, kNoValue);
buzbee2502e002012-12-31 16:05:53 -08001684 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1685 }
1686 break;
1687
1688 case Instruction::CMPL_DOUBLE:
1689 case Instruction::CMPG_DOUBLE:
1690 case Instruction::CMP_LONG: {
1691 // res = op + 2 wide operands
1692 uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
1693 uint16_t operand2 = GetOperandValueWide(mir->ssa_rep->uses[2]);
Vladimir Marko95a05972014-05-30 10:01:32 +01001694 res = gvn_->LookupValue(opcode, operand1, operand2, kNoValue);
buzbee2502e002012-12-31 16:05:53 -08001695 SetOperandValue(mir->ssa_rep->defs[0], res);
1696 }
1697 break;
1698
1699 case Instruction::CMPG_FLOAT:
1700 case Instruction::CMPL_FLOAT:
1701 case Instruction::ADD_INT:
1702 case Instruction::ADD_INT_2ADDR:
1703 case Instruction::MUL_INT:
1704 case Instruction::MUL_INT_2ADDR:
1705 case Instruction::AND_INT:
1706 case Instruction::AND_INT_2ADDR:
1707 case Instruction::OR_INT:
1708 case Instruction::OR_INT_2ADDR:
1709 case Instruction::XOR_INT:
1710 case Instruction::XOR_INT_2ADDR:
1711 case Instruction::SUB_INT:
1712 case Instruction::SUB_INT_2ADDR:
1713 case Instruction::DIV_INT:
1714 case Instruction::DIV_INT_2ADDR:
1715 case Instruction::REM_INT:
1716 case Instruction::REM_INT_2ADDR:
1717 case Instruction::SHL_INT:
1718 case Instruction::SHL_INT_2ADDR:
1719 case Instruction::SHR_INT:
1720 case Instruction::SHR_INT_2ADDR:
1721 case Instruction::USHR_INT:
1722 case Instruction::USHR_INT_2ADDR: {
1723 // res = op + 2 operands
1724 uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
1725 uint16_t operand2 = GetOperandValue(mir->ssa_rep->uses[1]);
Vladimir Marko95a05972014-05-30 10:01:32 +01001726 res = gvn_->LookupValue(opcode, operand1, operand2, kNoValue);
buzbee2502e002012-12-31 16:05:53 -08001727 SetOperandValue(mir->ssa_rep->defs[0], res);
1728 }
1729 break;
1730
1731 case Instruction::ADD_LONG:
1732 case Instruction::SUB_LONG:
1733 case Instruction::MUL_LONG:
1734 case Instruction::DIV_LONG:
1735 case Instruction::REM_LONG:
1736 case Instruction::AND_LONG:
1737 case Instruction::OR_LONG:
1738 case Instruction::XOR_LONG:
1739 case Instruction::ADD_LONG_2ADDR:
1740 case Instruction::SUB_LONG_2ADDR:
1741 case Instruction::MUL_LONG_2ADDR:
1742 case Instruction::DIV_LONG_2ADDR:
1743 case Instruction::REM_LONG_2ADDR:
1744 case Instruction::AND_LONG_2ADDR:
1745 case Instruction::OR_LONG_2ADDR:
1746 case Instruction::XOR_LONG_2ADDR:
1747 case Instruction::ADD_DOUBLE:
1748 case Instruction::SUB_DOUBLE:
1749 case Instruction::MUL_DOUBLE:
1750 case Instruction::DIV_DOUBLE:
1751 case Instruction::REM_DOUBLE:
1752 case Instruction::ADD_DOUBLE_2ADDR:
1753 case Instruction::SUB_DOUBLE_2ADDR:
1754 case Instruction::MUL_DOUBLE_2ADDR:
1755 case Instruction::DIV_DOUBLE_2ADDR:
1756 case Instruction::REM_DOUBLE_2ADDR: {
1757 // wide res = op + 2 wide operands
1758 uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
1759 uint16_t operand2 = GetOperandValueWide(mir->ssa_rep->uses[2]);
Vladimir Marko95a05972014-05-30 10:01:32 +01001760 res = gvn_->LookupValue(opcode, operand1, operand2, kNoValue);
buzbee2502e002012-12-31 16:05:53 -08001761 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1762 }
1763 break;
1764
1765 case Instruction::SHL_LONG:
1766 case Instruction::SHR_LONG:
1767 case Instruction::USHR_LONG:
1768 case Instruction::SHL_LONG_2ADDR:
1769 case Instruction::SHR_LONG_2ADDR:
1770 case Instruction::USHR_LONG_2ADDR: {
1771 // wide res = op + 1 wide operand + 1 operand
1772 uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001773 uint16_t operand2 = GetOperandValue(mir->ssa_rep->uses[2]);
Vladimir Marko95a05972014-05-30 10:01:32 +01001774 res = gvn_->LookupValue(opcode, operand1, operand2, kNoValue);
buzbee2502e002012-12-31 16:05:53 -08001775 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1776 }
1777 break;
1778
1779 case Instruction::ADD_FLOAT:
1780 case Instruction::SUB_FLOAT:
1781 case Instruction::MUL_FLOAT:
1782 case Instruction::DIV_FLOAT:
1783 case Instruction::REM_FLOAT:
1784 case Instruction::ADD_FLOAT_2ADDR:
1785 case Instruction::SUB_FLOAT_2ADDR:
1786 case Instruction::MUL_FLOAT_2ADDR:
1787 case Instruction::DIV_FLOAT_2ADDR:
1788 case Instruction::REM_FLOAT_2ADDR: {
1789 // res = op + 2 operands
1790 uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
1791 uint16_t operand2 = GetOperandValue(mir->ssa_rep->uses[1]);
Vladimir Marko95a05972014-05-30 10:01:32 +01001792 res = gvn_->LookupValue(opcode, operand1, operand2, kNoValue);
buzbee2502e002012-12-31 16:05:53 -08001793 SetOperandValue(mir->ssa_rep->defs[0], res);
1794 }
1795 break;
1796
1797 case Instruction::RSUB_INT:
1798 case Instruction::ADD_INT_LIT16:
1799 case Instruction::MUL_INT_LIT16:
1800 case Instruction::DIV_INT_LIT16:
1801 case Instruction::REM_INT_LIT16:
1802 case Instruction::AND_INT_LIT16:
1803 case Instruction::OR_INT_LIT16:
1804 case Instruction::XOR_INT_LIT16:
1805 case Instruction::ADD_INT_LIT8:
1806 case Instruction::RSUB_INT_LIT8:
1807 case Instruction::MUL_INT_LIT8:
1808 case Instruction::DIV_INT_LIT8:
1809 case Instruction::REM_INT_LIT8:
1810 case Instruction::AND_INT_LIT8:
1811 case Instruction::OR_INT_LIT8:
1812 case Instruction::XOR_INT_LIT8:
1813 case Instruction::SHL_INT_LIT8:
1814 case Instruction::SHR_INT_LIT8:
1815 case Instruction::USHR_INT_LIT8: {
nikolay serdjukee40aa42014-03-25 12:21:29 +07001816 // Same as res = op + 2 operands, except use vC as operand 2
buzbee2502e002012-12-31 16:05:53 -08001817 uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
Vladimir Marko95a05972014-05-30 10:01:32 +01001818 uint16_t operand2 = gvn_->LookupValue(Instruction::CONST, mir->dalvikInsn.vC, 0, 0);
1819 res = gvn_->LookupValue(opcode, operand1, operand2, kNoValue);
buzbee2502e002012-12-31 16:05:53 -08001820 SetOperandValue(mir->ssa_rep->defs[0], res);
1821 }
1822 break;
1823
buzbee2502e002012-12-31 16:05:53 -08001824 case Instruction::AGET_OBJECT:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001825 case Instruction::AGET:
1826 case Instruction::AGET_WIDE:
buzbee2502e002012-12-31 16:05:53 -08001827 case Instruction::AGET_BOOLEAN:
1828 case Instruction::AGET_BYTE:
1829 case Instruction::AGET_CHAR:
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001830 case Instruction::AGET_SHORT:
1831 res = HandleAGet(mir, opcode);
buzbee2502e002012-12-31 16:05:53 -08001832 break;
1833
buzbee2502e002012-12-31 16:05:53 -08001834 case Instruction::APUT_OBJECT:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001835 HandlePutObject(mir);
Ian Rogersfc787ec2014-10-09 21:56:44 -07001836 FALLTHROUGH_INTENDED;
Vladimir Markof59f18b2014-02-17 15:53:57 +00001837 case Instruction::APUT:
1838 case Instruction::APUT_WIDE:
buzbee2502e002012-12-31 16:05:53 -08001839 case Instruction::APUT_BYTE:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001840 case Instruction::APUT_BOOLEAN:
1841 case Instruction::APUT_SHORT:
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001842 case Instruction::APUT_CHAR:
1843 HandleAPut(mir, opcode);
buzbee2502e002012-12-31 16:05:53 -08001844 break;
1845
1846 case Instruction::IGET_OBJECT:
buzbee2502e002012-12-31 16:05:53 -08001847 case Instruction::IGET:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001848 case Instruction::IGET_WIDE:
buzbee2502e002012-12-31 16:05:53 -08001849 case Instruction::IGET_BOOLEAN:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001850 case Instruction::IGET_BYTE:
1851 case Instruction::IGET_CHAR:
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001852 case Instruction::IGET_SHORT:
1853 res = HandleIGet(mir, opcode);
buzbee2502e002012-12-31 16:05:53 -08001854 break;
1855
buzbee2502e002012-12-31 16:05:53 -08001856 case Instruction::IPUT_OBJECT:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001857 HandlePutObject(mir);
Ian Rogersfc787ec2014-10-09 21:56:44 -07001858 FALLTHROUGH_INTENDED;
buzbee2502e002012-12-31 16:05:53 -08001859 case Instruction::IPUT:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001860 case Instruction::IPUT_WIDE:
buzbee2502e002012-12-31 16:05:53 -08001861 case Instruction::IPUT_BOOLEAN:
1862 case Instruction::IPUT_BYTE:
1863 case Instruction::IPUT_CHAR:
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001864 case Instruction::IPUT_SHORT:
1865 HandleIPut(mir, opcode);
buzbee2502e002012-12-31 16:05:53 -08001866 break;
1867
1868 case Instruction::SGET_OBJECT:
1869 case Instruction::SGET:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001870 case Instruction::SGET_WIDE:
buzbee2502e002012-12-31 16:05:53 -08001871 case Instruction::SGET_BOOLEAN:
1872 case Instruction::SGET_BYTE:
1873 case Instruction::SGET_CHAR:
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001874 case Instruction::SGET_SHORT:
1875 res = HandleSGet(mir, opcode);
buzbee2502e002012-12-31 16:05:53 -08001876 break;
1877
1878 case Instruction::SPUT_OBJECT:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001879 HandlePutObject(mir);
Ian Rogersfc787ec2014-10-09 21:56:44 -07001880 FALLTHROUGH_INTENDED;
buzbee2502e002012-12-31 16:05:53 -08001881 case Instruction::SPUT:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001882 case Instruction::SPUT_WIDE:
buzbee2502e002012-12-31 16:05:53 -08001883 case Instruction::SPUT_BOOLEAN:
1884 case Instruction::SPUT_BYTE:
1885 case Instruction::SPUT_CHAR:
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001886 case Instruction::SPUT_SHORT:
1887 HandleSPut(mir, opcode);
buzbee2502e002012-12-31 16:05:53 -08001888 break;
buzbee2502e002012-12-31 16:05:53 -08001889 }
1890 return res;
1891}
1892
1893} // namespace art