blob: 0e072ecb6c7964bf1c753b098abf6d6274adc6a8 [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:
110 static uint16_t StartMemoryVersion(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
111 uint16_t array) {
112 return gvn->LookupValue(kNonAliasingArrayStartVersionOp, array, kNoValue, kNoValue);
113 }
114
115 static uint16_t BumpMemoryVersion(GlobalValueNumbering* gvn, uint16_t old_version,
116 uint16_t store_ref_set_id, uint16_t stored_value) {
117 return gvn->LookupValue(kNonAliasingArrayBumpVersionOp, old_version,
118 store_ref_set_id, stored_value);
119 }
120
121 static uint16_t LookupGlobalValue(GlobalValueNumbering* gvn,
122 uint16_t array, uint16_t index, uint16_t memory_version) {
123 return gvn->LookupValue(kNonAliasingArrayOp, array, index, memory_version);
124 }
125
126 static uint16_t LookupMergeValue(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
127 uint16_t array, uint16_t index) {
128 return AliasingValuesMergeGet<NonAliasingArrayVersions>(
129 gvn, lvn, &lvn->non_aliasing_array_value_map_, array, index);
130 }
131
132 static bool HasNewBaseVersion(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
133 uint16_t array) {
134 return false; // Not affected by global_memory_version_.
135 }
136
137 static uint16_t LookupMergeBlockValue(GlobalValueNumbering* gvn, uint16_t lvn_id,
138 uint16_t array) {
139 return gvn->LookupValue(kMergeBlockNonAliasingArrayVersionBumpOp, array, kNoValue, lvn_id);
140 }
141
142 static uint16_t LookupMergeLocationValue(GlobalValueNumbering* gvn, uint16_t lvn_id,
143 uint16_t array, uint16_t index) {
144 return gvn->LookupValue(kMergeBlockNonAliasingArrayMergeLocationOp, array, index, lvn_id);
145 }
146};
147
148class LocalValueNumbering::AliasingArrayVersions {
149 public:
150 static uint16_t StartMemoryVersion(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
151 uint16_t type) {
152 return gvn->LookupValue(kAliasingArrayStartVersionOp, type, lvn->global_memory_version_,
153 kNoValue);
154 }
155
156 static uint16_t BumpMemoryVersion(GlobalValueNumbering* gvn, uint16_t old_version,
157 uint16_t store_ref_set_id, uint16_t stored_value) {
158 return gvn->LookupValue(kAliasingArrayBumpVersionOp, old_version,
159 store_ref_set_id, stored_value);
160 }
161
162 static uint16_t LookupGlobalValue(GlobalValueNumbering* gvn,
163 uint16_t type, uint16_t location, uint16_t memory_version) {
164 return gvn->LookupValue(kAliasingArrayOp, type, location, memory_version);
165 }
166
167 static uint16_t LookupMergeValue(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
168 uint16_t type, uint16_t location) {
169 // If the location is non-aliasing in lvn, use the non-aliasing value.
170 uint16_t array = gvn->GetArrayLocationBase(location);
171 if (lvn->IsNonAliasingArray(array, type)) {
172 uint16_t index = gvn->GetArrayLocationIndex(location);
173 return NonAliasingArrayVersions::LookupMergeValue(gvn, lvn, array, index);
174 }
175 return AliasingValuesMergeGet<AliasingArrayVersions>(
176 gvn, lvn, &lvn->aliasing_array_value_map_, type, location);
177 }
178
179 static bool HasNewBaseVersion(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
180 uint16_t type) {
181 return lvn->global_memory_version_ == lvn->merge_new_memory_version_;
182 }
183
184 static uint16_t LookupMergeBlockValue(GlobalValueNumbering* gvn, uint16_t lvn_id,
185 uint16_t type) {
186 return gvn->LookupValue(kMergeBlockAliasingArrayVersionBumpOp, type, kNoValue, lvn_id);
187 }
188
189 static uint16_t LookupMergeLocationValue(GlobalValueNumbering* gvn, uint16_t lvn_id,
190 uint16_t type, uint16_t location) {
191 return gvn->LookupValue(kMergeBlockAliasingArrayMergeLocationOp, type, location, lvn_id);
192 }
193};
194
195template <typename Map>
196LocalValueNumbering::AliasingValues* LocalValueNumbering::GetAliasingValues(
197 Map* map, const typename Map::key_type& key) {
198 auto lb = map->lower_bound(key);
199 if (lb == map->end() || map->key_comp()(key, lb->first)) {
200 map->PutBefore(lb, key, AliasingValues(gvn_->allocator_));
201 // The new entry was inserted before lb.
202 DCHECK(lb != map->begin());
203 --lb;
204 DCHECK(!map->key_comp()(lb->first, key) && !map->key_comp()(key, lb->first));
205 }
206 return &lb->second;
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100207}
208
Vladimir Marko95a05972014-05-30 10:01:32 +0100209template <typename Versions, typename KeyType>
210void LocalValueNumbering::UpdateAliasingValuesLoadVersion(const KeyType& key,
211 AliasingValues* values) {
212 if (values->last_load_memory_version == kNoValue) {
213 // Get the start version that accounts for aliasing with unresolved fields of the same
214 // type and make it unique for the field by including the field_id.
215 uint16_t memory_version = values->memory_version_before_stores;
216 if (memory_version == kNoValue) {
217 memory_version = Versions::StartMemoryVersion(gvn_, this, key);
218 }
219 if (!values->store_loc_set.empty()) {
220 uint16_t ref_set_id = gvn_->GetRefSetId(values->store_loc_set);
221 memory_version = Versions::BumpMemoryVersion(gvn_, memory_version, ref_set_id,
222 values->last_stored_value);
223 }
224 values->last_load_memory_version = memory_version;
Vladimir Markof59f18b2014-02-17 15:53:57 +0000225 }
Vladimir Marko95a05972014-05-30 10:01:32 +0100226}
227
228template <typename Versions, typename Map>
229uint16_t LocalValueNumbering::AliasingValuesMergeGet(GlobalValueNumbering* gvn,
230 const LocalValueNumbering* lvn,
231 Map* map, const typename Map::key_type& key,
232 uint16_t location) {
233 // Retrieve the value name that we would get from
234 // const_cast<LocalValueNumbering*>(lvn)->HandleAliasingValueGet(map. key, location)
235 // but don't modify the map.
236 uint16_t value_name;
237 auto it = map->find(key);
238 if (it == map->end()) {
239 uint16_t start_version = Versions::StartMemoryVersion(gvn, lvn, key);
240 value_name = Versions::LookupGlobalValue(gvn, key, location, start_version);
241 } else if (it->second.store_loc_set.count(location) != 0u) {
242 value_name = it->second.last_stored_value;
243 } else {
244 auto load_it = it->second.load_value_map.find(location);
245 if (load_it != it->second.load_value_map.end()) {
246 value_name = load_it->second;
247 } else {
248 value_name = Versions::LookupGlobalValue(gvn, key, location, it->second.last_load_memory_version);
249 }
250 }
251 return value_name;
252}
253
254template <typename Versions, typename Map>
255uint16_t LocalValueNumbering::HandleAliasingValuesGet(Map* map, const typename Map::key_type& key,
256 uint16_t location) {
257 // Retrieve the value name for IGET/SGET/AGET, update the map with new value if any.
258 uint16_t res;
259 AliasingValues* values = GetAliasingValues(map, key);
260 if (values->store_loc_set.count(location) != 0u) {
261 res = values->last_stored_value;
262 } else {
263 UpdateAliasingValuesLoadVersion<Versions>(key, values);
264 auto lb = values->load_value_map.lower_bound(location);
265 if (lb != values->load_value_map.end() && lb->first == location) {
266 res = lb->second;
267 } else {
268 res = Versions::LookupGlobalValue(gvn_, key, location, values->last_load_memory_version);
269 values->load_value_map.PutBefore(lb, location, res);
270 }
271 }
272 return res;
273}
274
275template <typename Versions, typename Map>
276bool LocalValueNumbering::HandleAliasingValuesPut(Map* map, const typename Map::key_type& key,
277 uint16_t location, uint16_t value) {
278 AliasingValues* values = GetAliasingValues(map, key);
279 auto load_values_it = values->load_value_map.find(location);
280 if (load_values_it != values->load_value_map.end() && load_values_it->second == value) {
281 // This insn can be eliminated, it stores the same value that's already in the field.
282 return false;
283 }
284 if (value == values->last_stored_value) {
285 auto store_loc_lb = values->store_loc_set.lower_bound(location);
286 if (store_loc_lb != values->store_loc_set.end() && *store_loc_lb == location) {
287 // This insn can be eliminated, it stores the same value that's already in the field.
288 return false;
289 }
290 values->store_loc_set.emplace_hint(store_loc_lb, location);
291 } else {
292 UpdateAliasingValuesLoadVersion<Versions>(key, values);
293 values->memory_version_before_stores = values->last_load_memory_version;
294 values->last_stored_value = value;
295 values->store_loc_set.clear();
296 values->store_loc_set.insert(location);
297 }
298 // Clear the last load memory version and remove all potentially overwritten values.
299 values->last_load_memory_version = kNoValue;
300 auto it = values->load_value_map.begin(), end = values->load_value_map.end();
301 while (it != end) {
302 if (it->second == value) {
303 ++it;
304 } else {
305 it = values->load_value_map.erase(it);
306 }
307 }
308 return true;
309}
310
311LocalValueNumbering::LocalValueNumbering(GlobalValueNumbering* gvn, uint16_t id)
312 : gvn_(gvn),
313 id_(id),
314 sreg_value_map_(std::less<uint16_t>(), gvn->Allocator()->Adapter()),
315 sreg_wide_value_map_(std::less<uint16_t>(), gvn->Allocator()->Adapter()),
316 sfield_value_map_(std::less<uint16_t>(), gvn->Allocator()->Adapter()),
317 non_aliasing_ifield_value_map_(std::less<uint16_t>(), gvn->Allocator()->Adapter()),
318 aliasing_ifield_value_map_(std::less<uint16_t>(), gvn->Allocator()->Adapter()),
319 non_aliasing_array_value_map_(std::less<uint16_t>(), gvn->Allocator()->Adapter()),
320 aliasing_array_value_map_(std::less<uint16_t>(), gvn->Allocator()->Adapter()),
321 global_memory_version_(0u),
322 non_aliasing_refs_(std::less<uint16_t>(), gvn->Allocator()->Adapter()),
323 escaped_refs_(std::less<uint16_t>(), gvn->Allocator()->Adapter()),
324 escaped_ifield_clobber_set_(EscapedIFieldClobberKeyComparator(), gvn->Allocator()->Adapter()),
325 escaped_array_clobber_set_(EscapedArrayClobberKeyComparator(), gvn->Allocator()->Adapter()),
326 range_checked_(RangeCheckKeyComparator() , gvn->Allocator()->Adapter()),
327 null_checked_(std::less<uint16_t>(), gvn->Allocator()->Adapter()),
328 merge_names_(gvn->Allocator()->Adapter()),
329 merge_map_(std::less<ScopedArenaVector<BasicBlockId>>(), gvn->Allocator()->Adapter()),
330 merge_new_memory_version_(kNoValue) {
331 std::fill_n(unresolved_sfield_version_, kFieldTypeCount, 0u);
332 std::fill_n(unresolved_ifield_version_, kFieldTypeCount, 0u);
333}
334
335bool LocalValueNumbering::Equals(const LocalValueNumbering& other) const {
336 DCHECK(gvn_ == other.gvn_);
337 // Compare the maps/sets and memory versions.
338 return sreg_value_map_ == other.sreg_value_map_ &&
339 sreg_wide_value_map_ == other.sreg_wide_value_map_ &&
340 sfield_value_map_ == other.sfield_value_map_ &&
341 non_aliasing_ifield_value_map_ == other.non_aliasing_ifield_value_map_ &&
342 aliasing_ifield_value_map_ == other.aliasing_ifield_value_map_ &&
343 non_aliasing_array_value_map_ == other.non_aliasing_array_value_map_ &&
344 aliasing_array_value_map_ == other.aliasing_array_value_map_ &&
345 SameMemoryVersion(other) &&
346 non_aliasing_refs_ == other.non_aliasing_refs_ &&
347 escaped_refs_ == other.escaped_refs_ &&
348 escaped_ifield_clobber_set_ == other.escaped_ifield_clobber_set_ &&
349 escaped_array_clobber_set_ == other.escaped_array_clobber_set_ &&
350 range_checked_ == other.range_checked_ &&
351 null_checked_ == other.null_checked_;
352}
353
354void LocalValueNumbering::MergeOne(const LocalValueNumbering& other, MergeType merge_type) {
355 sreg_value_map_ = other.sreg_value_map_;
356 sreg_wide_value_map_ = other.sreg_wide_value_map_;
357
358 if (merge_type == kReturnMerge) {
359 // RETURN or PHI+RETURN. We need only sreg value maps.
360 return;
361 }
362
363 non_aliasing_ifield_value_map_ = other.non_aliasing_ifield_value_map_;
364 non_aliasing_array_value_map_ = other.non_aliasing_array_value_map_;
365 non_aliasing_refs_ = other.non_aliasing_refs_;
366 range_checked_ = other.range_checked_;
367 null_checked_ = other.null_checked_;
368
369 if (merge_type == kCatchMerge) {
370 // Memory is clobbered. Use new memory version and don't merge aliasing locations.
371 global_memory_version_ = NewMemoryVersion(&merge_new_memory_version_);
372 std::fill_n(unresolved_sfield_version_, kFieldTypeCount, global_memory_version_);
373 std::fill_n(unresolved_ifield_version_, kFieldTypeCount, global_memory_version_);
374 PruneNonAliasingRefsForCatch();
375 return;
376 }
377
378 DCHECK(merge_type == kNormalMerge);
379 global_memory_version_ = other.global_memory_version_;
380 std::copy_n(other.unresolved_ifield_version_, kFieldTypeCount, unresolved_ifield_version_);
381 std::copy_n(other.unresolved_sfield_version_, kFieldTypeCount, unresolved_sfield_version_);
382 sfield_value_map_ = other.sfield_value_map_;
383 aliasing_ifield_value_map_ = other.aliasing_ifield_value_map_;
384 aliasing_array_value_map_ = other.aliasing_array_value_map_;
385 escaped_refs_ = other.escaped_refs_;
386 escaped_ifield_clobber_set_ = other.escaped_ifield_clobber_set_;
387 escaped_array_clobber_set_ = other.escaped_array_clobber_set_;
388}
389
390bool LocalValueNumbering::SameMemoryVersion(const LocalValueNumbering& other) const {
391 return
392 global_memory_version_ == other.global_memory_version_ &&
393 std::equal(unresolved_ifield_version_, unresolved_ifield_version_ + kFieldTypeCount,
394 other.unresolved_ifield_version_) &&
395 std::equal(unresolved_sfield_version_, unresolved_sfield_version_ + kFieldTypeCount,
396 other.unresolved_sfield_version_);
397}
398
399uint16_t LocalValueNumbering::NewMemoryVersion(uint16_t* new_version) {
400 if (*new_version == kNoValue) {
401 *new_version = gvn_->LookupValue(kMergeBlockMemoryVersionBumpOp, 0u, 0u, id_);
402 }
403 return *new_version;
404}
405
406void LocalValueNumbering::MergeMemoryVersions(bool clobbered_catch) {
407 DCHECK_GE(gvn_->merge_lvns_.size(), 2u);
408 const LocalValueNumbering* cmp = gvn_->merge_lvns_[0];
409 // Check if the global version has changed.
410 bool new_global_version = clobbered_catch;
411 if (!new_global_version) {
412 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
413 if (lvn->global_memory_version_ != cmp->global_memory_version_) {
414 // Use a new version for everything.
415 new_global_version = true;
416 break;
417 }
418 }
419 }
420 if (new_global_version) {
421 global_memory_version_ = NewMemoryVersion(&merge_new_memory_version_);
422 std::fill_n(unresolved_sfield_version_, kFieldTypeCount, merge_new_memory_version_);
423 std::fill_n(unresolved_ifield_version_, kFieldTypeCount, merge_new_memory_version_);
424 } else {
425 // Initialize with a copy of memory versions from the comparison LVN.
426 global_memory_version_ = cmp->global_memory_version_;
427 std::copy_n(cmp->unresolved_ifield_version_, kFieldTypeCount, unresolved_ifield_version_);
428 std::copy_n(cmp->unresolved_sfield_version_, kFieldTypeCount, unresolved_sfield_version_);
429 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
430 if (lvn == cmp) {
431 continue;
432 }
433 for (size_t i = 0; i != kFieldTypeCount; ++i) {
434 if (lvn->unresolved_ifield_version_[i] != cmp->unresolved_ifield_version_[i]) {
435 unresolved_ifield_version_[i] = NewMemoryVersion(&merge_new_memory_version_);
436 }
437 if (lvn->unresolved_sfield_version_[i] != cmp->unresolved_sfield_version_[i]) {
438 unresolved_sfield_version_[i] = NewMemoryVersion(&merge_new_memory_version_);
439 }
440 }
441 }
442 }
443}
444
445void LocalValueNumbering::PruneNonAliasingRefsForCatch() {
446 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
447 const BasicBlock* bb = gvn_->GetBasicBlock(lvn->Id());
Vladimir Marko11ca6122014-07-17 20:50:07 +0100448 if (UNLIKELY(bb->taken == id_) || UNLIKELY(bb->fall_through == id_)) {
449 // Non-exceptional path to a catch handler means that the catch block was actually
450 // empty and all exceptional paths lead to the shared path after that empty block.
451 continue;
452 }
Vladimir Marko95a05972014-05-30 10:01:32 +0100453 DCHECK_EQ(bb->taken, kNullBlock);
454 DCHECK_NE(bb->fall_through, kNullBlock);
455 const BasicBlock* fall_through_bb = gvn_->GetBasicBlock(bb->fall_through);
456 const MIR* mir = fall_through_bb->first_mir_insn;
457 DCHECK(mir != nullptr);
458 // Only INVOKEs can leak and clobber non-aliasing references if they throw.
459 if ((Instruction::FlagsOf(mir->dalvikInsn.opcode) & Instruction::kInvoke) != 0) {
460 for (uint16_t i = 0u; i != mir->ssa_rep->num_uses; ++i) {
461 uint16_t value_name = lvn->GetOperandValue(mir->ssa_rep->uses[i]);
462 non_aliasing_refs_.erase(value_name);
463 }
464 }
465 }
466}
467
468
469template <typename Set, Set LocalValueNumbering::* set_ptr>
470void LocalValueNumbering::IntersectSets() {
471 DCHECK_GE(gvn_->merge_lvns_.size(), 2u);
472
473 // Find the LVN with the least entries in the set.
474 const LocalValueNumbering* least_entries_lvn = gvn_->merge_lvns_[0];
475 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
476 if ((lvn->*set_ptr).size() < (least_entries_lvn->*set_ptr).size()) {
477 least_entries_lvn = lvn;
478 }
479 }
480
481 // For each key check if it's in all the LVNs.
482 for (const auto& key : least_entries_lvn->*set_ptr) {
483 bool checked = true;
484 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
485 if (lvn != least_entries_lvn && (lvn->*set_ptr).count(key) == 0u) {
486 checked = false;
487 break;
488 }
489 }
490 if (checked) {
491 (this->*set_ptr).emplace_hint((this->*set_ptr).end(), key);
492 }
493 }
494}
495
496template <typename Map, Map LocalValueNumbering::* map_ptr>
497void LocalValueNumbering::IntersectMaps() {
498 DCHECK_GE(gvn_->merge_lvns_.size(), 2u);
499
500 // Find the LVN with the least entries in the set.
501 const LocalValueNumbering* least_entries_lvn = gvn_->merge_lvns_[0];
502 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
503 if ((lvn->*map_ptr).size() < (least_entries_lvn->*map_ptr).size()) {
504 least_entries_lvn = lvn;
505 }
506 }
507
508 // For each key check if it's in all the LVNs.
509 for (const auto& entry : least_entries_lvn->*map_ptr) {
510 bool checked = true;
511 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
512 if (lvn != least_entries_lvn) {
513 auto it = (lvn->*map_ptr).find(entry.first);
514 if (it == (lvn->*map_ptr).end() || !(it->second == entry.second)) {
515 checked = false;
516 break;
517 }
518 }
519 }
520 if (checked) {
521 (this->*map_ptr).PutBefore((this->*map_ptr).end(), entry.first, entry.second);
522 }
523 }
524}
525
526// Intersect maps as sets. The value type must be equality-comparable.
527template <typename Map>
528void LocalValueNumbering::InPlaceIntersectMaps(Map* work_map, const Map& other_map) {
529 auto work_it = work_map->begin(), work_end = work_map->end();
530 auto cmp = work_map->value_comp();
531 for (const auto& entry : other_map) {
532 while (work_it != work_end &&
533 (cmp(*work_it, entry) ||
534 (!cmp(entry, *work_it) && !(work_it->second == entry.second)))) {
535 work_it = work_map->erase(work_it);
536 }
Vladimir Marko55fff042014-07-10 12:42:52 +0100537 if (work_it == work_end) {
538 return;
539 }
540 ++work_it;
Vladimir Marko95a05972014-05-30 10:01:32 +0100541 }
542}
543
544template <typename Set, Set LocalValueNumbering::*set_ptr, void (LocalValueNumbering::*MergeFn)(
545 const typename Set::value_type& entry, typename Set::iterator hint)>
546void LocalValueNumbering::MergeSets() {
547 auto cmp = (this->*set_ptr).value_comp();
548 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
549 auto my_it = (this->*set_ptr).begin(), my_end = (this->*set_ptr).end();
550 for (const auto& entry : lvn->*set_ptr) {
551 while (my_it != my_end && cmp(*my_it, entry)) {
552 ++my_it;
553 }
554 if (my_it != my_end && !cmp(entry, *my_it)) {
555 // Already handled.
556 ++my_it;
557 } else {
558 // Merge values for this field_id.
559 (this->*MergeFn)(entry, my_it); // my_it remains valid across inserts to std::set/SafeMap.
560 }
561 }
562 }
563}
564
565void LocalValueNumbering::IntersectAliasingValueLocations(AliasingValues* work_values,
566 const AliasingValues* values) {
567 auto cmp = work_values->load_value_map.key_comp();
568 auto work_it = work_values->load_value_map.begin(), work_end = work_values->load_value_map.end();
569 auto store_it = values->store_loc_set.begin(), store_end = values->store_loc_set.end();
570 auto load_it = values->load_value_map.begin(), load_end = values->load_value_map.end();
571 while (store_it != store_end || load_it != load_end) {
572 uint16_t loc;
573 if (store_it != store_end && (load_it == load_end || *store_it < load_it->first)) {
574 loc = *store_it;
575 ++store_it;
576 } else {
577 loc = load_it->first;
578 ++load_it;
579 DCHECK(store_it == store_end || cmp(loc, *store_it));
580 }
581 while (work_it != work_end && cmp(work_it->first, loc)) {
582 work_it = work_values->load_value_map.erase(work_it);
583 }
584 if (work_it != work_end && !cmp(loc, work_it->first)) {
585 // The location matches, keep it.
586 ++work_it;
587 }
588 }
589 while (work_it != work_end) {
590 work_it = work_values->load_value_map.erase(work_it);
591 }
592}
593
594void LocalValueNumbering::MergeEscapedRefs(const ValueNameSet::value_type& entry,
595 ValueNameSet::iterator hint) {
596 // See if the ref is either escaped or non-aliasing in each predecessor.
597 bool is_escaped = true;
598 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
599 if (lvn->non_aliasing_refs_.count(entry) == 0u &&
600 lvn->escaped_refs_.count(entry) == 0u) {
601 is_escaped = false;
602 break;
603 }
604 }
605 if (is_escaped) {
606 escaped_refs_.emplace_hint(hint, entry);
607 }
608}
609
610void LocalValueNumbering::MergeEscapedIFieldTypeClobberSets(
611 const EscapedIFieldClobberSet::value_type& entry, EscapedIFieldClobberSet::iterator hint) {
612 // Insert only type-clobber entries (field_id == kNoValue) of escaped refs.
613 if (entry.field_id == kNoValue && escaped_refs_.count(entry.base) != 0u) {
614 escaped_ifield_clobber_set_.emplace_hint(hint, entry);
615 }
616}
617
618void LocalValueNumbering::MergeEscapedIFieldClobberSets(
619 const EscapedIFieldClobberSet::value_type& entry, EscapedIFieldClobberSet::iterator hint) {
620 // Insert only those entries of escaped refs that are not overridden by a type clobber.
621 if (!(hint == escaped_ifield_clobber_set_.end() &&
622 hint->base == entry.base && hint->type == entry.type) &&
623 escaped_refs_.count(entry.base) != 0u) {
624 escaped_ifield_clobber_set_.emplace_hint(hint, entry);
625 }
626}
627
628void LocalValueNumbering::MergeEscapedArrayClobberSets(
629 const EscapedArrayClobberSet::value_type& entry, EscapedArrayClobberSet::iterator hint) {
630 if (escaped_refs_.count(entry.base) != 0u) {
631 escaped_array_clobber_set_.emplace_hint(hint, entry);
632 }
633}
634
635void LocalValueNumbering::MergeNullChecked(const ValueNameSet::value_type& entry,
636 ValueNameSet::iterator hint) {
637 // Merge null_checked_ for this ref.
638 merge_names_.clear();
639 merge_names_.resize(gvn_->merge_lvns_.size(), entry);
640 if (gvn_->NullCheckedInAllPredecessors(merge_names_)) {
641 null_checked_.insert(hint, entry);
642 }
643}
644
645void LocalValueNumbering::MergeSFieldValues(const SFieldToValueMap::value_type& entry,
646 SFieldToValueMap::iterator hint) {
647 uint16_t field_id = entry.first;
648 merge_names_.clear();
649 uint16_t value_name = kNoValue;
650 bool same_values = true;
651 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
652 // Get the value name as in HandleSGet() but don't modify *lvn.
653 auto it = lvn->sfield_value_map_.find(field_id);
654 if (it != lvn->sfield_value_map_.end()) {
655 value_name = it->second;
656 } else {
657 uint16_t type = gvn_->GetFieldType(field_id);
658 value_name = gvn_->LookupValue(kResolvedSFieldOp, field_id,
659 lvn->unresolved_sfield_version_[type],
660 lvn->global_memory_version_);
661 }
662
663 same_values = same_values && (merge_names_.empty() || value_name == merge_names_.back());
664 merge_names_.push_back(value_name);
665 }
666 if (same_values) {
667 // value_name already contains the result.
668 } else {
669 auto lb = merge_map_.lower_bound(merge_names_);
670 if (lb != merge_map_.end() && !merge_map_.key_comp()(merge_names_, lb->first)) {
671 value_name = lb->second;
672 } else {
673 value_name = gvn_->LookupValue(kMergeBlockSFieldVersionBumpOp, field_id, id_, kNoValue);
674 merge_map_.PutBefore(lb, merge_names_, value_name);
675 if (gvn_->NullCheckedInAllPredecessors(merge_names_)) {
676 null_checked_.insert(value_name);
677 }
678 }
679 }
680 sfield_value_map_.PutBefore(hint, field_id, value_name);
681}
682
683void LocalValueNumbering::MergeNonAliasingIFieldValues(const IFieldLocToValueMap::value_type& entry,
684 IFieldLocToValueMap::iterator hint) {
685 uint16_t field_loc = entry.first;
686 merge_names_.clear();
687 uint16_t value_name = kNoValue;
688 bool same_values = true;
689 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
690 // Get the value name as in HandleIGet() but don't modify *lvn.
691 auto it = lvn->non_aliasing_ifield_value_map_.find(field_loc);
692 if (it != lvn->non_aliasing_ifield_value_map_.end()) {
693 value_name = it->second;
694 } else {
695 value_name = gvn_->LookupValue(kNonAliasingIFieldInitialOp, field_loc, kNoValue, kNoValue);
696 }
697
698 same_values = same_values && (merge_names_.empty() || value_name == merge_names_.back());
699 merge_names_.push_back(value_name);
700 }
701 if (same_values) {
702 // value_name already contains the result.
703 } else {
704 auto lb = merge_map_.lower_bound(merge_names_);
705 if (lb != merge_map_.end() && !merge_map_.key_comp()(merge_names_, lb->first)) {
706 value_name = lb->second;
707 } else {
708 value_name = gvn_->LookupValue(kMergeBlockNonAliasingIFieldVersionBumpOp, field_loc,
709 id_, kNoValue);
710 merge_map_.PutBefore(lb, merge_names_, value_name);
711 if (gvn_->NullCheckedInAllPredecessors(merge_names_)) {
712 null_checked_.insert(value_name);
713 }
714 }
715 }
716 non_aliasing_ifield_value_map_.PutBefore(hint, field_loc, value_name);
717}
718
719template <typename Map, Map LocalValueNumbering::*map_ptr, typename Versions>
720void LocalValueNumbering::MergeAliasingValues(const typename Map::value_type& entry,
721 typename Map::iterator hint) {
722 const typename Map::key_type& key = entry.first;
723
724 (this->*map_ptr).PutBefore(hint, key, AliasingValues(gvn_->allocator_));
725 DCHECK(hint != (this->*map_ptr).begin());
726 AliasingIFieldValuesMap::iterator it = hint;
727 --it;
728 DCHECK_EQ(it->first, key);
729 AliasingValues* my_values = &it->second;
730
731 const AliasingValues* cmp_values = nullptr;
732 bool same_version = !Versions::HasNewBaseVersion(gvn_, this, key);
733 uint16_t load_memory_version_for_same_version = kNoValue;
734 if (same_version) {
735 // Find the first non-null values.
736 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
737 auto it = (lvn->*map_ptr).find(key);
738 if (it != (lvn->*map_ptr).end()) {
739 cmp_values = &it->second;
740 break;
741 }
742 }
743 DCHECK(cmp_values != nullptr); // There must be at least one non-null values.
744
745 // Check if we have identical memory versions, i.e. the global memory version, unresolved
746 // field version and the values' memory_version_before_stores, last_stored_value
747 // and store_loc_set are identical.
748 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
749 auto it = (lvn->*map_ptr).find(key);
750 if (it == (lvn->*map_ptr).end()) {
751 if (cmp_values->memory_version_before_stores != kNoValue) {
752 same_version = false;
753 break;
754 }
755 } else if (cmp_values->last_stored_value != it->second.last_stored_value ||
756 cmp_values->memory_version_before_stores != it->second.memory_version_before_stores ||
757 cmp_values->store_loc_set != it->second.store_loc_set) {
758 same_version = false;
759 break;
760 } else if (it->second.last_load_memory_version != kNoValue) {
761 DCHECK(load_memory_version_for_same_version == kNoValue ||
762 load_memory_version_for_same_version == it->second.last_load_memory_version);
763 load_memory_version_for_same_version = it->second.last_load_memory_version;
764 }
765 }
766 }
767
768 if (same_version) {
769 // Copy the identical values.
770 my_values->memory_version_before_stores = cmp_values->memory_version_before_stores;
771 my_values->last_stored_value = cmp_values->last_stored_value;
772 my_values->store_loc_set = cmp_values->store_loc_set;
773 my_values->last_load_memory_version = load_memory_version_for_same_version;
774 // Merge load values seen in all incoming arcs (i.e. an intersection).
775 if (!cmp_values->load_value_map.empty()) {
776 my_values->load_value_map = cmp_values->load_value_map;
777 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
778 auto it = (lvn->*map_ptr).find(key);
779 if (it == (lvn->*map_ptr).end() || it->second.load_value_map.empty()) {
780 my_values->load_value_map.clear();
781 break;
782 }
783 InPlaceIntersectMaps(&my_values->load_value_map, it->second.load_value_map);
784 if (my_values->load_value_map.empty()) {
785 break;
786 }
787 }
788 }
789 } else {
790 // Bump version number for the merge.
791 my_values->memory_version_before_stores = my_values->last_load_memory_version =
792 Versions::LookupMergeBlockValue(gvn_, id_, key);
793
794 // Calculate the locations that have been either read from or written to in each incoming LVN.
795 bool first_lvn = true;
796 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
797 auto it = (lvn->*map_ptr).find(key);
798 if (it == (lvn->*map_ptr).end()) {
799 my_values->load_value_map.clear();
800 break;
801 }
802 if (first_lvn) {
803 first_lvn = false;
804 // Copy the first LVN's locations. Values will be overwritten later.
805 my_values->load_value_map = it->second.load_value_map;
806 for (uint16_t location : it->second.store_loc_set) {
807 my_values->load_value_map.Put(location, 0u);
808 }
809 } else {
810 IntersectAliasingValueLocations(my_values, &it->second);
811 }
812 }
813 // Calculate merged values for the intersection.
814 for (auto& load_value_entry : my_values->load_value_map) {
815 uint16_t location = load_value_entry.first;
816 bool same_values = true;
817 uint16_t value_name = kNoValue;
818 merge_names_.clear();
819 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
820 value_name = Versions::LookupMergeValue(gvn_, lvn, key, location);
821 same_values = same_values && (merge_names_.empty() || value_name == merge_names_.back());
822 merge_names_.push_back(value_name);
823 }
824 if (same_values) {
825 // value_name already contains the result.
826 } else {
827 auto lb = merge_map_.lower_bound(merge_names_);
828 if (lb != merge_map_.end() && !merge_map_.key_comp()(merge_names_, lb->first)) {
829 value_name = lb->second;
830 } else {
831 // NOTE: In addition to the key and id_ which don't change on an LVN recalculation
832 // during GVN, we also add location which can actually change on recalculation, so the
833 // value_name below may change. This could lead to an infinite loop if the location
834 // value name always changed when the refereced value name changes. However, given that
835 // we assign unique value names for other merges, such as Phis, such a dependency is
836 // not possible in a well-formed SSA graph.
837 value_name = Versions::LookupMergeLocationValue(gvn_, id_, key, location);
838 merge_map_.PutBefore(lb, merge_names_, value_name);
839 if (gvn_->NullCheckedInAllPredecessors(merge_names_)) {
840 null_checked_.insert(value_name);
841 }
842 }
843 }
844 load_value_entry.second = value_name;
845 }
846 }
847}
848
849void LocalValueNumbering::Merge(MergeType merge_type) {
850 DCHECK_GE(gvn_->merge_lvns_.size(), 2u);
851
852 IntersectMaps<SregValueMap, &LocalValueNumbering::sreg_value_map_>();
853 IntersectMaps<SregValueMap, &LocalValueNumbering::sreg_wide_value_map_>();
854 if (merge_type == kReturnMerge) {
855 // RETURN or PHI+RETURN. We need only sreg value maps.
856 return;
857 }
858
859 MergeMemoryVersions(merge_type == kCatchMerge);
860
861 // Merge non-aliasing maps/sets.
Vladimir Marko95a05972014-05-30 10:01:32 +0100862 IntersectSets<ValueNameSet, &LocalValueNumbering::non_aliasing_refs_>();
Vladimir Marko55fff042014-07-10 12:42:52 +0100863 if (!non_aliasing_refs_.empty() && merge_type == kCatchMerge) {
864 PruneNonAliasingRefsForCatch();
865 }
866 if (!non_aliasing_refs_.empty()) {
867 MergeSets<IFieldLocToValueMap, &LocalValueNumbering::non_aliasing_ifield_value_map_,
868 &LocalValueNumbering::MergeNonAliasingIFieldValues>();
869 MergeSets<NonAliasingArrayValuesMap, &LocalValueNumbering::non_aliasing_array_value_map_,
870 &LocalValueNumbering::MergeAliasingValues<
871 NonAliasingArrayValuesMap, &LocalValueNumbering::non_aliasing_array_value_map_,
872 NonAliasingArrayVersions>>();
873 }
Vladimir Marko95a05972014-05-30 10:01:32 +0100874
875 // We won't do anything complicated for range checks, just calculate the intersection.
876 IntersectSets<RangeCheckSet, &LocalValueNumbering::range_checked_>();
877
878 // Merge null_checked_. We may later insert more, such as merged object field values.
879 MergeSets<ValueNameSet, &LocalValueNumbering::null_checked_,
880 &LocalValueNumbering::MergeNullChecked>();
881
882 if (merge_type == kCatchMerge) {
883 // Memory is clobbered. New memory version already created, don't merge aliasing locations.
Vladimir Marko95a05972014-05-30 10:01:32 +0100884 return;
885 }
886
887 DCHECK(merge_type == kNormalMerge);
888
889 // Merge escaped refs and clobber sets.
890 MergeSets<ValueNameSet, &LocalValueNumbering::escaped_refs_,
891 &LocalValueNumbering::MergeEscapedRefs>();
892 if (!escaped_refs_.empty()) {
893 MergeSets<EscapedIFieldClobberSet, &LocalValueNumbering::escaped_ifield_clobber_set_,
894 &LocalValueNumbering::MergeEscapedIFieldTypeClobberSets>();
895 MergeSets<EscapedIFieldClobberSet, &LocalValueNumbering::escaped_ifield_clobber_set_,
896 &LocalValueNumbering::MergeEscapedIFieldClobberSets>();
897 MergeSets<EscapedArrayClobberSet, &LocalValueNumbering::escaped_array_clobber_set_,
898 &LocalValueNumbering::MergeEscapedArrayClobberSets>();
899 }
900
901 MergeSets<SFieldToValueMap, &LocalValueNumbering::sfield_value_map_,
902 &LocalValueNumbering::MergeSFieldValues>();
903 MergeSets<AliasingIFieldValuesMap, &LocalValueNumbering::aliasing_ifield_value_map_,
904 &LocalValueNumbering::MergeAliasingValues<
905 AliasingIFieldValuesMap, &LocalValueNumbering::aliasing_ifield_value_map_,
906 AliasingIFieldVersions>>();
907 MergeSets<AliasingArrayValuesMap, &LocalValueNumbering::aliasing_array_value_map_,
908 &LocalValueNumbering::MergeAliasingValues<
909 AliasingArrayValuesMap, &LocalValueNumbering::aliasing_array_value_map_,
910 AliasingArrayVersions>>();
Vladimir Markof59f18b2014-02-17 15:53:57 +0000911}
912
Vladimir Markof59f18b2014-02-17 15:53:57 +0000913uint16_t LocalValueNumbering::MarkNonAliasingNonNull(MIR* mir) {
914 uint16_t res = GetOperandValue(mir->ssa_rep->defs[0]);
Vladimir Markof59f18b2014-02-17 15:53:57 +0000915 DCHECK(null_checked_.find(res) == null_checked_.end());
916 null_checked_.insert(res);
917 non_aliasing_refs_.insert(res);
918 return res;
919}
920
Vladimir Marko95a05972014-05-30 10:01:32 +0100921bool LocalValueNumbering::IsNonAliasing(uint16_t reg) const {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100922 return non_aliasing_refs_.find(reg) != non_aliasing_refs_.end();
Vladimir Markof59f18b2014-02-17 15:53:57 +0000923}
924
Vladimir Marko95a05972014-05-30 10:01:32 +0100925bool LocalValueNumbering::IsNonAliasingIField(uint16_t reg, uint16_t field_id,
926 uint16_t type) const {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100927 if (IsNonAliasing(reg)) {
928 return true;
929 }
Vladimir Marko95a05972014-05-30 10:01:32 +0100930 if (escaped_refs_.find(reg) == escaped_refs_.end()) {
931 return false;
932 }
933 // Check for IPUTs to unresolved fields.
934 EscapedIFieldClobberKey key1 = { reg, type, kNoValue };
935 if (escaped_ifield_clobber_set_.find(key1) != escaped_ifield_clobber_set_.end()) {
936 return false;
937 }
938 // Check for aliased IPUTs to the same field.
939 EscapedIFieldClobberKey key2 = { reg, type, field_id };
940 return escaped_ifield_clobber_set_.find(key2) == escaped_ifield_clobber_set_.end();
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100941}
942
Vladimir Marko95a05972014-05-30 10:01:32 +0100943bool LocalValueNumbering::IsNonAliasingArray(uint16_t reg, uint16_t type) const {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100944 if (IsNonAliasing(reg)) {
945 return true;
946 }
Vladimir Marko95a05972014-05-30 10:01:32 +0100947 if (escaped_refs_.count(reg) == 0u) {
948 return false;
949 }
950 // Check for aliased APUTs.
951 EscapedArrayClobberKey key = { reg, type };
952 return escaped_array_clobber_set_.find(key) == escaped_array_clobber_set_.end();
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100953}
954
Vladimir Markof59f18b2014-02-17 15:53:57 +0000955void LocalValueNumbering::HandleNullCheck(MIR* mir, uint16_t reg) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100956 auto lb = null_checked_.lower_bound(reg);
957 if (lb != null_checked_.end() && *lb == reg) {
Vladimir Marko95a05972014-05-30 10:01:32 +0100958 if (LIKELY(gvn_->CanModify())) {
959 if (gvn_->GetCompilationUnit()->verbose) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100960 LOG(INFO) << "Removing null check for 0x" << std::hex << mir->offset;
961 }
962 mir->optimization_flags |= MIR_IGNORE_NULL_CHECK;
Vladimir Markof59f18b2014-02-17 15:53:57 +0000963 }
Vladimir Markof59f18b2014-02-17 15:53:57 +0000964 } else {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100965 null_checked_.insert(lb, reg);
Vladimir Markof59f18b2014-02-17 15:53:57 +0000966 }
967}
968
969void LocalValueNumbering::HandleRangeCheck(MIR* mir, uint16_t array, uint16_t index) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100970 RangeCheckKey key = { array, index };
971 auto lb = range_checked_.lower_bound(key);
972 if (lb != range_checked_.end() && !RangeCheckKeyComparator()(key, *lb)) {
Vladimir Marko95a05972014-05-30 10:01:32 +0100973 if (LIKELY(gvn_->CanModify())) {
974 if (gvn_->GetCompilationUnit()->verbose) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100975 LOG(INFO) << "Removing range check for 0x" << std::hex << mir->offset;
976 }
977 mir->optimization_flags |= MIR_IGNORE_RANGE_CHECK;
Vladimir Markof59f18b2014-02-17 15:53:57 +0000978 }
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100979 } else {
980 // Mark range check completed.
981 range_checked_.insert(lb, key);
Vladimir Markof59f18b2014-02-17 15:53:57 +0000982 }
Vladimir Markof59f18b2014-02-17 15:53:57 +0000983}
984
985void LocalValueNumbering::HandlePutObject(MIR* mir) {
986 // If we're storing a non-aliasing reference, stop tracking it as non-aliasing now.
987 uint16_t base = GetOperandValue(mir->ssa_rep->uses[0]);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100988 HandleEscapingRef(base);
989}
990
991void LocalValueNumbering::HandleEscapingRef(uint16_t base) {
992 auto it = non_aliasing_refs_.find(base);
993 if (it != non_aliasing_refs_.end()) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100994 non_aliasing_refs_.erase(it);
Vladimir Marko95a05972014-05-30 10:01:32 +0100995 escaped_refs_.insert(base);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100996 }
997}
998
Vladimir Marko95a05972014-05-30 10:01:32 +0100999uint16_t LocalValueNumbering::HandlePhi(MIR* mir) {
1000 if (gvn_->merge_lvns_.empty()) {
1001 // Running LVN without a full GVN?
1002 return kNoValue;
1003 }
1004 int16_t num_uses = mir->ssa_rep->num_uses;
1005 int32_t* uses = mir->ssa_rep->uses;
1006 // Try to find out if this is merging wide regs.
1007 if (mir->ssa_rep->defs[0] != 0 &&
1008 sreg_wide_value_map_.count(mir->ssa_rep->defs[0] - 1) != 0u) {
1009 // This is the high part of a wide reg. Ignore the Phi.
1010 return kNoValue;
1011 }
1012 bool wide = false;
1013 for (int16_t i = 0; i != num_uses; ++i) {
1014 if (sreg_wide_value_map_.count(uses[i]) != 0u) {
1015 wide = true;
1016 break;
1017 }
1018 }
1019 // Iterate over *merge_lvns_ and skip incoming sregs for BBs without associated LVN.
1020 uint16_t value_name = kNoValue;
1021 merge_names_.clear();
1022 BasicBlockId* incoming = mir->meta.phi_incoming;
1023 int16_t pos = 0;
1024 bool same_values = true;
1025 for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
1026 DCHECK_LT(pos, mir->ssa_rep->num_uses);
1027 while (incoming[pos] != lvn->Id()) {
1028 ++pos;
1029 DCHECK_LT(pos, mir->ssa_rep->num_uses);
1030 }
1031 int s_reg = uses[pos];
1032 ++pos;
1033 value_name = wide ? lvn->GetOperandValueWide(s_reg) : lvn->GetOperandValue(s_reg);
1034
1035 same_values = same_values && (merge_names_.empty() || value_name == merge_names_.back());
1036 merge_names_.push_back(value_name);
1037 }
1038 if (same_values) {
1039 // value_name already contains the result.
1040 } else {
1041 auto lb = merge_map_.lower_bound(merge_names_);
1042 if (lb != merge_map_.end() && !merge_map_.key_comp()(merge_names_, lb->first)) {
1043 value_name = lb->second;
1044 } else {
1045 value_name = gvn_->LookupValue(kNoValue, mir->ssa_rep->defs[0], kNoValue, kNoValue);
1046 merge_map_.PutBefore(lb, merge_names_, value_name);
1047 if (!wide && gvn_->NullCheckedInAllPredecessors(merge_names_)) {
1048 null_checked_.insert(value_name);
1049 }
1050 }
1051 }
1052 if (wide) {
1053 SetOperandValueWide(mir->ssa_rep->defs[0], value_name);
1054 } else {
1055 SetOperandValue(mir->ssa_rep->defs[0], value_name);
1056 }
1057 return value_name;
1058}
1059
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001060uint16_t LocalValueNumbering::HandleAGet(MIR* mir, uint16_t opcode) {
1061 // uint16_t type = opcode - Instruction::AGET;
1062 uint16_t array = GetOperandValue(mir->ssa_rep->uses[0]);
1063 HandleNullCheck(mir, array);
1064 uint16_t index = GetOperandValue(mir->ssa_rep->uses[1]);
1065 HandleRangeCheck(mir, array, index);
1066 uint16_t type = opcode - Instruction::AGET;
1067 // Establish value number for loaded register.
1068 uint16_t res;
1069 if (IsNonAliasingArray(array, type)) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001070 res = HandleAliasingValuesGet<NonAliasingArrayVersions>(&non_aliasing_array_value_map_,
1071 array, index);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001072 } else {
Vladimir Marko95a05972014-05-30 10:01:32 +01001073 uint16_t location = gvn_->GetArrayLocation(array, index);
1074 res = HandleAliasingValuesGet<AliasingArrayVersions>(&aliasing_array_value_map_,
1075 type, location);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001076 }
1077 if (opcode == Instruction::AGET_WIDE) {
1078 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1079 } else {
1080 SetOperandValue(mir->ssa_rep->defs[0], res);
1081 }
1082 return res;
1083}
1084
1085void LocalValueNumbering::HandleAPut(MIR* mir, uint16_t opcode) {
1086 int array_idx = (opcode == Instruction::APUT_WIDE) ? 2 : 1;
1087 int index_idx = array_idx + 1;
1088 uint16_t array = GetOperandValue(mir->ssa_rep->uses[array_idx]);
1089 HandleNullCheck(mir, array);
1090 uint16_t index = GetOperandValue(mir->ssa_rep->uses[index_idx]);
1091 HandleRangeCheck(mir, array, index);
1092
1093 uint16_t type = opcode - Instruction::APUT;
1094 uint16_t value = (opcode == Instruction::APUT_WIDE)
1095 ? GetOperandValueWide(mir->ssa_rep->uses[0])
1096 : GetOperandValue(mir->ssa_rep->uses[0]);
1097 if (IsNonAliasing(array)) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001098 bool put_is_live = HandleAliasingValuesPut<NonAliasingArrayVersions>(
1099 &non_aliasing_array_value_map_, array, index, value);
1100 if (!put_is_live) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001101 // This APUT can be eliminated, it stores the same value that's already in the field.
1102 // TODO: Eliminate the APUT.
1103 return;
1104 }
Vladimir Marko95a05972014-05-30 10:01:32 +01001105 } else {
1106 uint16_t location = gvn_->GetArrayLocation(array, index);
1107 bool put_is_live = HandleAliasingValuesPut<AliasingArrayVersions>(
1108 &aliasing_array_value_map_, type, location, value);
1109 if (!put_is_live) {
1110 // This APUT can be eliminated, it stores the same value that's already in the field.
1111 // TODO: Eliminate the APUT.
1112 return;
1113 }
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001114
Vladimir Marko95a05972014-05-30 10:01:32 +01001115 // Clobber all escaped array refs for this type.
1116 for (uint16_t escaped_array : escaped_refs_) {
1117 EscapedArrayClobberKey clobber_key = { escaped_array, type };
1118 escaped_array_clobber_set_.insert(clobber_key);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001119 }
1120 }
1121}
1122
1123uint16_t LocalValueNumbering::HandleIGet(MIR* mir, uint16_t opcode) {
1124 uint16_t base = GetOperandValue(mir->ssa_rep->uses[0]);
1125 HandleNullCheck(mir, base);
Vladimir Marko95a05972014-05-30 10:01:32 +01001126 const MirFieldInfo& field_info = gvn_->GetMirGraph()->GetIFieldLoweringInfo(mir);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001127 uint16_t res;
1128 if (!field_info.IsResolved() || field_info.IsVolatile()) {
1129 // Volatile fields always get a new memory version; field id is irrelevant.
1130 // Unresolved fields may be volatile, so handle them as such to be safe.
1131 // Use result s_reg - will be unique.
Vladimir Marko95a05972014-05-30 10:01:32 +01001132 res = gvn_->LookupValue(kNoValue, mir->ssa_rep->defs[0], kNoValue, kNoValue);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001133 } else {
1134 uint16_t type = opcode - Instruction::IGET;
Vladimir Marko95a05972014-05-30 10:01:32 +01001135 uint16_t field_id = gvn_->GetFieldId(field_info, type);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001136 if (IsNonAliasingIField(base, field_id, type)) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001137 uint16_t loc = gvn_->LookupValue(kNonAliasingIFieldLocOp, base, field_id, type);
1138 auto lb = non_aliasing_ifield_value_map_.lower_bound(loc);
1139 if (lb != non_aliasing_ifield_value_map_.end() && lb->first == loc) {
1140 res = lb->second;
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001141 } else {
Vladimir Marko95a05972014-05-30 10:01:32 +01001142 res = gvn_->LookupValue(kNonAliasingIFieldInitialOp, loc, kNoValue, kNoValue);
1143 non_aliasing_ifield_value_map_.PutBefore(lb, loc, res);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001144 }
Vladimir Marko95a05972014-05-30 10:01:32 +01001145 } else {
1146 res = HandleAliasingValuesGet<AliasingIFieldVersions>(&aliasing_ifield_value_map_,
1147 field_id, base);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001148 }
1149 }
1150 if (opcode == Instruction::IGET_WIDE) {
1151 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1152 } else {
1153 SetOperandValue(mir->ssa_rep->defs[0], res);
1154 }
1155 return res;
1156}
1157
1158void LocalValueNumbering::HandleIPut(MIR* mir, uint16_t opcode) {
1159 uint16_t type = opcode - Instruction::IPUT;
1160 int base_reg = (opcode == Instruction::IPUT_WIDE) ? 2 : 1;
1161 uint16_t base = GetOperandValue(mir->ssa_rep->uses[base_reg]);
1162 HandleNullCheck(mir, base);
Vladimir Marko95a05972014-05-30 10:01:32 +01001163 const MirFieldInfo& field_info = gvn_->GetMirGraph()->GetIFieldLoweringInfo(mir);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001164 if (!field_info.IsResolved()) {
1165 // Unresolved fields always alias with everything of the same type.
1166 // Use mir->offset as modifier; without elaborate inlining, it will be unique.
1167 unresolved_ifield_version_[type] =
Vladimir Marko95a05972014-05-30 10:01:32 +01001168 gvn_->LookupValue(kUnresolvedIFieldOp, kNoValue, kNoValue, mir->offset);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001169
Vladimir Marko95a05972014-05-30 10:01:32 +01001170 // For simplicity, treat base as escaped now.
1171 HandleEscapingRef(base);
1172
1173 // Clobber all fields of escaped references of the same type.
1174 for (uint16_t escaped_ref : escaped_refs_) {
1175 EscapedIFieldClobberKey clobber_key = { escaped_ref, type, kNoValue };
1176 escaped_ifield_clobber_set_.insert(clobber_key);
1177 }
1178
1179 // Aliasing fields of the same type may have been overwritten.
1180 auto it = aliasing_ifield_value_map_.begin(), end = aliasing_ifield_value_map_.end();
1181 while (it != end) {
1182 if (gvn_->GetFieldType(it->first) != type) {
1183 ++it;
1184 } else {
1185 it = aliasing_ifield_value_map_.erase(it);
1186 }
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001187 }
1188 } else if (field_info.IsVolatile()) {
1189 // Nothing to do, resolved volatile fields always get a new memory version anyway and
1190 // can't alias with resolved non-volatile fields.
1191 } else {
Vladimir Marko95a05972014-05-30 10:01:32 +01001192 uint16_t field_id = gvn_->GetFieldId(field_info, type);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001193 uint16_t value = (opcode == Instruction::IPUT_WIDE)
1194 ? GetOperandValueWide(mir->ssa_rep->uses[0])
1195 : GetOperandValue(mir->ssa_rep->uses[0]);
1196 if (IsNonAliasing(base)) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001197 uint16_t loc = gvn_->LookupValue(kNonAliasingIFieldLocOp, base, field_id, type);
1198 auto lb = non_aliasing_ifield_value_map_.lower_bound(loc);
1199 if (lb != non_aliasing_ifield_value_map_.end() && lb->first == loc) {
1200 if (lb->second == value) {
1201 // This IPUT can be eliminated, it stores the same value that's already in the field.
1202 // TODO: Eliminate the IPUT.
1203 return;
1204 }
1205 lb->second = value; // Overwrite.
1206 } else {
1207 non_aliasing_ifield_value_map_.PutBefore(lb, loc, value);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001208 }
Vladimir Marko95a05972014-05-30 10:01:32 +01001209 } else {
1210 bool put_is_live = HandleAliasingValuesPut<AliasingIFieldVersions>(
1211 &aliasing_ifield_value_map_, field_id, base, value);
1212 if (!put_is_live) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001213 // This IPUT can be eliminated, it stores the same value that's already in the field.
1214 // TODO: Eliminate the IPUT.
1215 return;
1216 }
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001217
Vladimir Marko95a05972014-05-30 10:01:32 +01001218 // Clobber all fields of escaped references for this field.
1219 for (uint16_t escaped_ref : escaped_refs_) {
1220 EscapedIFieldClobberKey clobber_key = { escaped_ref, type, field_id };
1221 escaped_ifield_clobber_set_.insert(clobber_key);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001222 }
1223 }
1224 }
1225}
1226
1227uint16_t LocalValueNumbering::HandleSGet(MIR* mir, uint16_t opcode) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001228 const MirSFieldLoweringInfo& field_info = gvn_->GetMirGraph()->GetSFieldLoweringInfo(mir);
Vladimir Markof418f322014-07-09 14:45:36 +01001229 if (!field_info.IsInitialized() && (mir->optimization_flags & MIR_IGNORE_CLINIT_CHECK) == 0) {
1230 // Class initialization can call arbitrary functions, we need to wipe aliasing values.
1231 HandleInvokeOrClInit(mir);
1232 }
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001233 uint16_t res;
1234 if (!field_info.IsResolved() || field_info.IsVolatile()) {
1235 // Volatile fields always get a new memory version; field id is irrelevant.
1236 // Unresolved fields may be volatile, so handle them as such to be safe.
1237 // Use result s_reg - will be unique.
Vladimir Marko95a05972014-05-30 10:01:32 +01001238 res = gvn_->LookupValue(kNoValue, mir->ssa_rep->defs[0], kNoValue, kNoValue);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001239 } else {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001240 uint16_t type = opcode - Instruction::SGET;
Vladimir Marko95a05972014-05-30 10:01:32 +01001241 uint16_t field_id = gvn_->GetFieldId(field_info, type);
1242 auto lb = sfield_value_map_.lower_bound(field_id);
1243 if (lb != sfield_value_map_.end() && lb->first == field_id) {
1244 res = lb->second;
1245 } else {
1246 // Resolved non-volatile static fields can alias with non-resolved fields of the same type,
1247 // so we need to use unresolved_sfield_version_[type] in addition to global_memory_version_
1248 // to determine the version of the field.
1249 res = gvn_->LookupValue(kResolvedSFieldOp, field_id,
1250 unresolved_sfield_version_[type], global_memory_version_);
1251 sfield_value_map_.PutBefore(lb, field_id, res);
1252 }
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001253 }
1254 if (opcode == Instruction::SGET_WIDE) {
1255 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1256 } else {
1257 SetOperandValue(mir->ssa_rep->defs[0], res);
1258 }
1259 return res;
1260}
1261
1262void LocalValueNumbering::HandleSPut(MIR* mir, uint16_t opcode) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001263 const MirSFieldLoweringInfo& field_info = gvn_->GetMirGraph()->GetSFieldLoweringInfo(mir);
Vladimir Markof418f322014-07-09 14:45:36 +01001264 if (!field_info.IsInitialized() && (mir->optimization_flags & MIR_IGNORE_CLINIT_CHECK) == 0) {
1265 // Class initialization can call arbitrary functions, we need to wipe aliasing values.
1266 HandleInvokeOrClInit(mir);
1267 }
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001268 uint16_t type = opcode - Instruction::SPUT;
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001269 if (!field_info.IsResolved()) {
1270 // Unresolved fields always alias with everything of the same type.
1271 // Use mir->offset as modifier; without elaborate inlining, it will be unique.
1272 unresolved_sfield_version_[type] =
Vladimir Marko95a05972014-05-30 10:01:32 +01001273 gvn_->LookupValue(kUnresolvedSFieldOp, kNoValue, kNoValue, mir->offset);
1274 RemoveSFieldsForType(type);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001275 } else if (field_info.IsVolatile()) {
1276 // Nothing to do, resolved volatile fields always get a new memory version anyway and
1277 // can't alias with resolved non-volatile fields.
1278 } else {
Vladimir Marko95a05972014-05-30 10:01:32 +01001279 uint16_t field_id = gvn_->GetFieldId(field_info, type);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001280 uint16_t value = (opcode == Instruction::SPUT_WIDE)
1281 ? GetOperandValueWide(mir->ssa_rep->uses[0])
1282 : GetOperandValue(mir->ssa_rep->uses[0]);
1283 // Resolved non-volatile static fields can alias with non-resolved fields of the same type,
1284 // so we need to use unresolved_sfield_version_[type] in addition to global_memory_version_
1285 // to determine the version of the field.
Vladimir Marko95a05972014-05-30 10:01:32 +01001286 auto lb = sfield_value_map_.lower_bound(field_id);
1287 if (lb != sfield_value_map_.end() && lb->first == field_id) {
1288 if (lb->second == value) {
1289 // This SPUT can be eliminated, it stores the same value that's already in the field.
1290 // TODO: Eliminate the SPUT.
1291 return;
1292 }
1293 lb->second = value; // Overwrite.
1294 } else {
1295 sfield_value_map_.PutBefore(lb, field_id, value);
1296 }
1297 }
1298}
1299
1300void LocalValueNumbering::RemoveSFieldsForType(uint16_t type) {
1301 // Erase all static fields of this type from the sfield_value_map_.
1302 for (auto it = sfield_value_map_.begin(), end = sfield_value_map_.end(); it != end; ) {
1303 if (gvn_->GetFieldType(it->first) == type) {
1304 it = sfield_value_map_.erase(it);
1305 } else {
1306 ++it;
1307 }
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001308 }
Vladimir Markof59f18b2014-02-17 15:53:57 +00001309}
buzbee2502e002012-12-31 16:05:53 -08001310
Vladimir Markof418f322014-07-09 14:45:36 +01001311void LocalValueNumbering::HandleInvokeOrClInit(MIR* mir) {
1312 // Use mir->offset as modifier; without elaborate inlining, it will be unique.
Vladimir Marko95a05972014-05-30 10:01:32 +01001313 global_memory_version_ =
1314 gvn_->LookupValue(kInvokeMemoryVersionBumpOp, 0u, 0u, mir->offset);
1315 // All static fields and instance fields and array elements of aliasing references,
1316 // including escaped references, may have been modified.
1317 sfield_value_map_.clear();
1318 aliasing_ifield_value_map_.clear();
1319 aliasing_array_value_map_.clear();
1320 escaped_refs_.clear();
1321 escaped_ifield_clobber_set_.clear();
1322 escaped_array_clobber_set_.clear();
Vladimir Markof418f322014-07-09 14:45:36 +01001323}
1324
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001325uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001326 uint16_t res = kNoValue;
buzbee2502e002012-12-31 16:05:53 -08001327 uint16_t opcode = mir->dalvikInsn.opcode;
1328 switch (opcode) {
1329 case Instruction::NOP:
1330 case Instruction::RETURN_VOID:
1331 case Instruction::RETURN:
1332 case Instruction::RETURN_OBJECT:
1333 case Instruction::RETURN_WIDE:
buzbee2502e002012-12-31 16:05:53 -08001334 case Instruction::GOTO:
1335 case Instruction::GOTO_16:
1336 case Instruction::GOTO_32:
1337 case Instruction::CHECK_CAST:
1338 case Instruction::THROW:
1339 case Instruction::FILL_ARRAY_DATA:
buzbee2502e002012-12-31 16:05:53 -08001340 case Instruction::PACKED_SWITCH:
1341 case Instruction::SPARSE_SWITCH:
1342 case Instruction::IF_EQ:
1343 case Instruction::IF_NE:
1344 case Instruction::IF_LT:
1345 case Instruction::IF_GE:
1346 case Instruction::IF_GT:
1347 case Instruction::IF_LE:
1348 case Instruction::IF_EQZ:
1349 case Instruction::IF_NEZ:
1350 case Instruction::IF_LTZ:
1351 case Instruction::IF_GEZ:
1352 case Instruction::IF_GTZ:
1353 case Instruction::IF_LEZ:
buzbee2502e002012-12-31 16:05:53 -08001354 case kMirOpFusedCmplFloat:
1355 case kMirOpFusedCmpgFloat:
1356 case kMirOpFusedCmplDouble:
1357 case kMirOpFusedCmpgDouble:
1358 case kMirOpFusedCmpLong:
1359 // Nothing defined - take no action.
1360 break;
1361
Vladimir Marko95a05972014-05-30 10:01:32 +01001362 case Instruction::MONITOR_ENTER:
1363 HandleNullCheck(mir, GetOperandValue(mir->ssa_rep->uses[0]));
1364 // NOTE: Keeping all aliasing values intact. Programs that rely on loads/stores of the
1365 // same non-volatile locations outside and inside a synchronized block being different
1366 // contain races that we cannot fix.
1367 break;
1368
1369 case Instruction::MONITOR_EXIT:
1370 HandleNullCheck(mir, GetOperandValue(mir->ssa_rep->uses[0]));
1371 // If we're running GVN and CanModify(), uneliminated null check indicates bytecode error.
Vladimir Marko55fff042014-07-10 12:42:52 +01001372 if ((gvn_->GetCompilationUnit()->disable_opt & (1u << kGlobalValueNumbering)) == 0u &&
1373 gvn_->CanModify() && (mir->optimization_flags & MIR_IGNORE_NULL_CHECK) == 0) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001374 LOG(WARNING) << "Bytecode error: MONITOR_EXIT is still null checked at 0x" << std::hex
1375 << mir->offset << " in " << PrettyMethod(gvn_->cu_->method_idx, *gvn_->cu_->dex_file);
1376 }
1377 break;
1378
Vladimir Markof59f18b2014-02-17 15:53:57 +00001379 case Instruction::FILLED_NEW_ARRAY:
1380 case Instruction::FILLED_NEW_ARRAY_RANGE:
1381 // Nothing defined but the result will be unique and non-null.
1382 if (mir->next != nullptr && mir->next->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001383 uint16_t array = MarkNonAliasingNonNull(mir->next);
1384 // Do not SetOperandValue(), we'll do that when we process the MOVE_RESULT_OBJECT.
1385 if (kLocalValueNumberingEnableFilledNewArrayTracking && mir->ssa_rep->num_uses != 0u) {
1386 AliasingValues* values = GetAliasingValues(&non_aliasing_array_value_map_, array);
1387 // Clear the value if we got a merged version in a loop.
1388 *values = AliasingValues(gvn_->allocator_);
1389 for (size_t i = 0u, count = mir->ssa_rep->num_uses; i != count; ++i) {
1390 DCHECK_EQ(High16Bits(i), 0u);
1391 uint16_t index = gvn_->LookupValue(Instruction::CONST, i, 0u, 0);
1392 uint16_t value = GetOperandValue(mir->ssa_rep->uses[i]);
1393 values->load_value_map.Put(index, value);
1394 RangeCheckKey key = { array, index };
1395 range_checked_.insert(key);
1396 }
1397 }
Vladimir Markof59f18b2014-02-17 15:53:57 +00001398 // The MOVE_RESULT_OBJECT will be processed next and we'll return the value name then.
1399 }
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001400 // All args escaped (if references).
1401 for (size_t i = 0u, count = mir->ssa_rep->num_uses; i != count; ++i) {
1402 uint16_t reg = GetOperandValue(mir->ssa_rep->uses[i]);
1403 HandleEscapingRef(reg);
1404 }
Vladimir Markof59f18b2014-02-17 15:53:57 +00001405 break;
1406
1407 case Instruction::INVOKE_DIRECT:
1408 case Instruction::INVOKE_DIRECT_RANGE:
1409 case Instruction::INVOKE_VIRTUAL:
1410 case Instruction::INVOKE_VIRTUAL_RANGE:
1411 case Instruction::INVOKE_SUPER:
1412 case Instruction::INVOKE_SUPER_RANGE:
1413 case Instruction::INVOKE_INTERFACE:
1414 case Instruction::INVOKE_INTERFACE_RANGE: {
1415 // Nothing defined but handle the null check.
1416 uint16_t reg = GetOperandValue(mir->ssa_rep->uses[0]);
1417 HandleNullCheck(mir, reg);
1418 }
1419 // Intentional fall-through.
1420 case Instruction::INVOKE_STATIC:
1421 case Instruction::INVOKE_STATIC_RANGE:
Vladimir Marko9820b7c2014-01-02 16:40:37 +00001422 if ((mir->optimization_flags & MIR_INLINED) == 0) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001423 // Make ref args aliasing.
1424 for (size_t i = 0u, count = mir->ssa_rep->num_uses; i != count; ++i) {
1425 uint16_t reg = GetOperandValue(mir->ssa_rep->uses[i]);
1426 non_aliasing_refs_.erase(reg);
1427 }
Vladimir Markof418f322014-07-09 14:45:36 +01001428 HandleInvokeOrClInit(mir);
Vladimir Marko9820b7c2014-01-02 16:40:37 +00001429 }
Vladimir Markof59f18b2014-02-17 15:53:57 +00001430 break;
1431
buzbee2502e002012-12-31 16:05:53 -08001432 case Instruction::MOVE_RESULT:
1433 case Instruction::MOVE_RESULT_OBJECT:
1434 case Instruction::INSTANCE_OF:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001435 // 1 result, treat as unique each time, use result s_reg - will be unique.
1436 res = GetOperandValue(mir->ssa_rep->defs[0]);
1437 SetOperandValue(mir->ssa_rep->defs[0], res);
1438 break;
1439 case Instruction::MOVE_EXCEPTION:
buzbee2502e002012-12-31 16:05:53 -08001440 case Instruction::NEW_INSTANCE:
buzbee2502e002012-12-31 16:05:53 -08001441 case Instruction::CONST_CLASS:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001442 case Instruction::NEW_ARRAY:
Vladimir Markob3e527b2014-04-04 12:37:07 +01001443 // 1 result, treat as unique each time, use result s_reg - will be unique.
1444 res = MarkNonAliasingNonNull(mir);
Vladimir Marko95a05972014-05-30 10:01:32 +01001445 SetOperandValue(mir->ssa_rep->defs[0], res);
buzbee2502e002012-12-31 16:05:53 -08001446 break;
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001447 case Instruction::CONST_STRING:
1448 case Instruction::CONST_STRING_JUMBO:
1449 // These strings are internalized, so assign value based on the string pool index.
Vladimir Marko95a05972014-05-30 10:01:32 +01001450 res = gvn_->LookupValue(Instruction::CONST_STRING, Low16Bits(mir->dalvikInsn.vB),
1451 High16Bits(mir->dalvikInsn.vB), 0);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001452 SetOperandValue(mir->ssa_rep->defs[0], res);
1453 null_checked_.insert(res); // May already be there.
1454 // NOTE: Hacking the contents of an internalized string via reflection is possible
1455 // but the behavior is undefined. Therefore, we consider the string constant and
1456 // the reference non-aliasing.
1457 // TUNING: We could keep this property even if the reference "escapes".
1458 non_aliasing_refs_.insert(res); // May already be there.
1459 break;
Vladimir Markof59f18b2014-02-17 15:53:57 +00001460 case Instruction::MOVE_RESULT_WIDE:
Vladimir Markob3e527b2014-04-04 12:37:07 +01001461 // 1 wide result, treat as unique each time, use result s_reg - will be unique.
1462 res = GetOperandValueWide(mir->ssa_rep->defs[0]);
1463 SetOperandValueWide(mir->ssa_rep->defs[0], res);
buzbee2502e002012-12-31 16:05:53 -08001464 break;
1465
1466 case kMirOpPhi:
Vladimir Marko95a05972014-05-30 10:01:32 +01001467 res = HandlePhi(mir);
buzbee2502e002012-12-31 16:05:53 -08001468 break;
1469
1470 case Instruction::MOVE:
1471 case Instruction::MOVE_OBJECT:
1472 case Instruction::MOVE_16:
1473 case Instruction::MOVE_OBJECT_16:
1474 case Instruction::MOVE_FROM16:
1475 case Instruction::MOVE_OBJECT_FROM16:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001476 case kMirOpCopy:
1477 // Just copy value number of source to value number of result.
1478 res = GetOperandValue(mir->ssa_rep->uses[0]);
1479 SetOperandValue(mir->ssa_rep->defs[0], res);
buzbee2502e002012-12-31 16:05:53 -08001480 break;
1481
1482 case Instruction::MOVE_WIDE:
1483 case Instruction::MOVE_WIDE_16:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001484 case Instruction::MOVE_WIDE_FROM16:
1485 // Just copy value number of source to value number of result.
1486 res = GetOperandValueWide(mir->ssa_rep->uses[0]);
1487 SetOperandValueWide(mir->ssa_rep->defs[0], res);
buzbee2502e002012-12-31 16:05:53 -08001488 break;
1489
1490 case Instruction::CONST:
1491 case Instruction::CONST_4:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001492 case Instruction::CONST_16:
Vladimir Marko95a05972014-05-30 10:01:32 +01001493 res = gvn_->LookupValue(Instruction::CONST, Low16Bits(mir->dalvikInsn.vB),
1494 High16Bits(mir->dalvikInsn.vB), 0);
Vladimir Markof59f18b2014-02-17 15:53:57 +00001495 SetOperandValue(mir->ssa_rep->defs[0], res);
buzbee2502e002012-12-31 16:05:53 -08001496 break;
1497
Vladimir Markof59f18b2014-02-17 15:53:57 +00001498 case Instruction::CONST_HIGH16:
Vladimir Marko95a05972014-05-30 10:01:32 +01001499 res = gvn_->LookupValue(Instruction::CONST, 0, mir->dalvikInsn.vB, 0);
Vladimir Markof59f18b2014-02-17 15:53:57 +00001500 SetOperandValue(mir->ssa_rep->defs[0], res);
buzbee2502e002012-12-31 16:05:53 -08001501 break;
1502
1503 case Instruction::CONST_WIDE_16:
1504 case Instruction::CONST_WIDE_32: {
Vladimir Marko95a05972014-05-30 10:01:32 +01001505 uint16_t low_res = gvn_->LookupValue(Instruction::CONST, Low16Bits(mir->dalvikInsn.vB),
1506 High16Bits(mir->dalvikInsn.vB >> 16), 1);
buzbee2502e002012-12-31 16:05:53 -08001507 uint16_t high_res;
1508 if (mir->dalvikInsn.vB & 0x80000000) {
Vladimir Marko95a05972014-05-30 10:01:32 +01001509 high_res = gvn_->LookupValue(Instruction::CONST, 0xffff, 0xffff, 2);
buzbee2502e002012-12-31 16:05:53 -08001510 } else {
Vladimir Marko95a05972014-05-30 10:01:32 +01001511 high_res = gvn_->LookupValue(Instruction::CONST, 0, 0, 2);
buzbee2502e002012-12-31 16:05:53 -08001512 }
Vladimir Marko95a05972014-05-30 10:01:32 +01001513 res = gvn_->LookupValue(Instruction::CONST, low_res, high_res, 3);
Vladimir Markof59f18b2014-02-17 15:53:57 +00001514 SetOperandValueWide(mir->ssa_rep->defs[0], res);
buzbee2502e002012-12-31 16:05:53 -08001515 }
1516 break;
1517
1518 case Instruction::CONST_WIDE: {
1519 uint32_t low_word = Low32Bits(mir->dalvikInsn.vB_wide);
1520 uint32_t high_word = High32Bits(mir->dalvikInsn.vB_wide);
Vladimir Marko95a05972014-05-30 10:01:32 +01001521 uint16_t low_res = gvn_->LookupValue(Instruction::CONST, Low16Bits(low_word),
1522 High16Bits(low_word), 1);
1523 uint16_t high_res = gvn_->LookupValue(Instruction::CONST, Low16Bits(high_word),
1524 High16Bits(high_word), 2);
1525 res = gvn_->LookupValue(Instruction::CONST, low_res, high_res, 3);
buzbee2502e002012-12-31 16:05:53 -08001526 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1527 }
1528 break;
1529
1530 case Instruction::CONST_WIDE_HIGH16: {
Vladimir Marko95a05972014-05-30 10:01:32 +01001531 uint16_t low_res = gvn_->LookupValue(Instruction::CONST, 0, 0, 1);
1532 uint16_t high_res = gvn_->LookupValue(Instruction::CONST, 0,
1533 Low16Bits(mir->dalvikInsn.vB), 2);
1534 res = gvn_->LookupValue(Instruction::CONST, low_res, high_res, 3);
buzbee2502e002012-12-31 16:05:53 -08001535 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1536 }
1537 break;
1538
Vladimir Marko95a05972014-05-30 10:01:32 +01001539 case Instruction::ARRAY_LENGTH: {
1540 // Handle the null check.
1541 uint16_t reg = GetOperandValue(mir->ssa_rep->uses[0]);
1542 HandleNullCheck(mir, reg);
1543 }
1544 // Intentional fall-through.
buzbee2502e002012-12-31 16:05:53 -08001545 case Instruction::NEG_INT:
1546 case Instruction::NOT_INT:
1547 case Instruction::NEG_FLOAT:
1548 case Instruction::INT_TO_BYTE:
1549 case Instruction::INT_TO_SHORT:
1550 case Instruction::INT_TO_CHAR:
1551 case Instruction::INT_TO_FLOAT:
1552 case Instruction::FLOAT_TO_INT: {
1553 // res = op + 1 operand
1554 uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
Vladimir Marko95a05972014-05-30 10:01:32 +01001555 res = gvn_->LookupValue(opcode, operand1, kNoValue, kNoValue);
buzbee2502e002012-12-31 16:05:53 -08001556 SetOperandValue(mir->ssa_rep->defs[0], res);
1557 }
1558 break;
1559
1560 case Instruction::LONG_TO_FLOAT:
1561 case Instruction::LONG_TO_INT:
1562 case Instruction::DOUBLE_TO_FLOAT:
1563 case Instruction::DOUBLE_TO_INT: {
1564 // res = op + 1 wide operand
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001565 uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
Vladimir Marko95a05972014-05-30 10:01:32 +01001566 res = gvn_->LookupValue(opcode, operand1, kNoValue, kNoValue);
buzbee2502e002012-12-31 16:05:53 -08001567 SetOperandValue(mir->ssa_rep->defs[0], res);
1568 }
1569 break;
1570
1571
1572 case Instruction::DOUBLE_TO_LONG:
1573 case Instruction::LONG_TO_DOUBLE:
1574 case Instruction::NEG_LONG:
1575 case Instruction::NOT_LONG:
1576 case Instruction::NEG_DOUBLE: {
1577 // wide res = op + 1 wide operand
1578 uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
Vladimir Marko95a05972014-05-30 10:01:32 +01001579 res = gvn_->LookupValue(opcode, operand1, kNoValue, kNoValue);
buzbee2502e002012-12-31 16:05:53 -08001580 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1581 }
1582 break;
1583
1584 case Instruction::FLOAT_TO_DOUBLE:
1585 case Instruction::FLOAT_TO_LONG:
1586 case Instruction::INT_TO_DOUBLE:
1587 case Instruction::INT_TO_LONG: {
1588 // wide res = op + 1 operand
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001589 uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
Vladimir Marko95a05972014-05-30 10:01:32 +01001590 res = gvn_->LookupValue(opcode, operand1, kNoValue, kNoValue);
buzbee2502e002012-12-31 16:05:53 -08001591 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1592 }
1593 break;
1594
1595 case Instruction::CMPL_DOUBLE:
1596 case Instruction::CMPG_DOUBLE:
1597 case Instruction::CMP_LONG: {
1598 // res = op + 2 wide operands
1599 uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
1600 uint16_t operand2 = GetOperandValueWide(mir->ssa_rep->uses[2]);
Vladimir Marko95a05972014-05-30 10:01:32 +01001601 res = gvn_->LookupValue(opcode, operand1, operand2, kNoValue);
buzbee2502e002012-12-31 16:05:53 -08001602 SetOperandValue(mir->ssa_rep->defs[0], res);
1603 }
1604 break;
1605
1606 case Instruction::CMPG_FLOAT:
1607 case Instruction::CMPL_FLOAT:
1608 case Instruction::ADD_INT:
1609 case Instruction::ADD_INT_2ADDR:
1610 case Instruction::MUL_INT:
1611 case Instruction::MUL_INT_2ADDR:
1612 case Instruction::AND_INT:
1613 case Instruction::AND_INT_2ADDR:
1614 case Instruction::OR_INT:
1615 case Instruction::OR_INT_2ADDR:
1616 case Instruction::XOR_INT:
1617 case Instruction::XOR_INT_2ADDR:
1618 case Instruction::SUB_INT:
1619 case Instruction::SUB_INT_2ADDR:
1620 case Instruction::DIV_INT:
1621 case Instruction::DIV_INT_2ADDR:
1622 case Instruction::REM_INT:
1623 case Instruction::REM_INT_2ADDR:
1624 case Instruction::SHL_INT:
1625 case Instruction::SHL_INT_2ADDR:
1626 case Instruction::SHR_INT:
1627 case Instruction::SHR_INT_2ADDR:
1628 case Instruction::USHR_INT:
1629 case Instruction::USHR_INT_2ADDR: {
1630 // res = op + 2 operands
1631 uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
1632 uint16_t operand2 = GetOperandValue(mir->ssa_rep->uses[1]);
Vladimir Marko95a05972014-05-30 10:01:32 +01001633 res = gvn_->LookupValue(opcode, operand1, operand2, kNoValue);
buzbee2502e002012-12-31 16:05:53 -08001634 SetOperandValue(mir->ssa_rep->defs[0], res);
1635 }
1636 break;
1637
1638 case Instruction::ADD_LONG:
1639 case Instruction::SUB_LONG:
1640 case Instruction::MUL_LONG:
1641 case Instruction::DIV_LONG:
1642 case Instruction::REM_LONG:
1643 case Instruction::AND_LONG:
1644 case Instruction::OR_LONG:
1645 case Instruction::XOR_LONG:
1646 case Instruction::ADD_LONG_2ADDR:
1647 case Instruction::SUB_LONG_2ADDR:
1648 case Instruction::MUL_LONG_2ADDR:
1649 case Instruction::DIV_LONG_2ADDR:
1650 case Instruction::REM_LONG_2ADDR:
1651 case Instruction::AND_LONG_2ADDR:
1652 case Instruction::OR_LONG_2ADDR:
1653 case Instruction::XOR_LONG_2ADDR:
1654 case Instruction::ADD_DOUBLE:
1655 case Instruction::SUB_DOUBLE:
1656 case Instruction::MUL_DOUBLE:
1657 case Instruction::DIV_DOUBLE:
1658 case Instruction::REM_DOUBLE:
1659 case Instruction::ADD_DOUBLE_2ADDR:
1660 case Instruction::SUB_DOUBLE_2ADDR:
1661 case Instruction::MUL_DOUBLE_2ADDR:
1662 case Instruction::DIV_DOUBLE_2ADDR:
1663 case Instruction::REM_DOUBLE_2ADDR: {
1664 // wide res = op + 2 wide operands
1665 uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
1666 uint16_t operand2 = GetOperandValueWide(mir->ssa_rep->uses[2]);
Vladimir Marko95a05972014-05-30 10:01:32 +01001667 res = gvn_->LookupValue(opcode, operand1, operand2, kNoValue);
buzbee2502e002012-12-31 16:05:53 -08001668 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1669 }
1670 break;
1671
1672 case Instruction::SHL_LONG:
1673 case Instruction::SHR_LONG:
1674 case Instruction::USHR_LONG:
1675 case Instruction::SHL_LONG_2ADDR:
1676 case Instruction::SHR_LONG_2ADDR:
1677 case Instruction::USHR_LONG_2ADDR: {
1678 // wide res = op + 1 wide operand + 1 operand
1679 uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001680 uint16_t operand2 = GetOperandValue(mir->ssa_rep->uses[2]);
Vladimir Marko95a05972014-05-30 10:01:32 +01001681 res = gvn_->LookupValue(opcode, operand1, operand2, kNoValue);
buzbee2502e002012-12-31 16:05:53 -08001682 SetOperandValueWide(mir->ssa_rep->defs[0], res);
1683 }
1684 break;
1685
1686 case Instruction::ADD_FLOAT:
1687 case Instruction::SUB_FLOAT:
1688 case Instruction::MUL_FLOAT:
1689 case Instruction::DIV_FLOAT:
1690 case Instruction::REM_FLOAT:
1691 case Instruction::ADD_FLOAT_2ADDR:
1692 case Instruction::SUB_FLOAT_2ADDR:
1693 case Instruction::MUL_FLOAT_2ADDR:
1694 case Instruction::DIV_FLOAT_2ADDR:
1695 case Instruction::REM_FLOAT_2ADDR: {
1696 // res = op + 2 operands
1697 uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
1698 uint16_t operand2 = GetOperandValue(mir->ssa_rep->uses[1]);
Vladimir Marko95a05972014-05-30 10:01:32 +01001699 res = gvn_->LookupValue(opcode, operand1, operand2, kNoValue);
buzbee2502e002012-12-31 16:05:53 -08001700 SetOperandValue(mir->ssa_rep->defs[0], res);
1701 }
1702 break;
1703
1704 case Instruction::RSUB_INT:
1705 case Instruction::ADD_INT_LIT16:
1706 case Instruction::MUL_INT_LIT16:
1707 case Instruction::DIV_INT_LIT16:
1708 case Instruction::REM_INT_LIT16:
1709 case Instruction::AND_INT_LIT16:
1710 case Instruction::OR_INT_LIT16:
1711 case Instruction::XOR_INT_LIT16:
1712 case Instruction::ADD_INT_LIT8:
1713 case Instruction::RSUB_INT_LIT8:
1714 case Instruction::MUL_INT_LIT8:
1715 case Instruction::DIV_INT_LIT8:
1716 case Instruction::REM_INT_LIT8:
1717 case Instruction::AND_INT_LIT8:
1718 case Instruction::OR_INT_LIT8:
1719 case Instruction::XOR_INT_LIT8:
1720 case Instruction::SHL_INT_LIT8:
1721 case Instruction::SHR_INT_LIT8:
1722 case Instruction::USHR_INT_LIT8: {
nikolay serdjukee40aa42014-03-25 12:21:29 +07001723 // Same as res = op + 2 operands, except use vC as operand 2
buzbee2502e002012-12-31 16:05:53 -08001724 uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
Vladimir Marko95a05972014-05-30 10:01:32 +01001725 uint16_t operand2 = gvn_->LookupValue(Instruction::CONST, mir->dalvikInsn.vC, 0, 0);
1726 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
buzbee2502e002012-12-31 16:05:53 -08001731 case Instruction::AGET_OBJECT:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001732 case Instruction::AGET:
1733 case Instruction::AGET_WIDE:
buzbee2502e002012-12-31 16:05:53 -08001734 case Instruction::AGET_BOOLEAN:
1735 case Instruction::AGET_BYTE:
1736 case Instruction::AGET_CHAR:
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001737 case Instruction::AGET_SHORT:
1738 res = HandleAGet(mir, opcode);
buzbee2502e002012-12-31 16:05:53 -08001739 break;
1740
buzbee2502e002012-12-31 16:05:53 -08001741 case Instruction::APUT_OBJECT:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001742 HandlePutObject(mir);
1743 // Intentional fall-through.
1744 case Instruction::APUT:
1745 case Instruction::APUT_WIDE:
buzbee2502e002012-12-31 16:05:53 -08001746 case Instruction::APUT_BYTE:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001747 case Instruction::APUT_BOOLEAN:
1748 case Instruction::APUT_SHORT:
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001749 case Instruction::APUT_CHAR:
1750 HandleAPut(mir, opcode);
buzbee2502e002012-12-31 16:05:53 -08001751 break;
1752
1753 case Instruction::IGET_OBJECT:
buzbee2502e002012-12-31 16:05:53 -08001754 case Instruction::IGET:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001755 case Instruction::IGET_WIDE:
buzbee2502e002012-12-31 16:05:53 -08001756 case Instruction::IGET_BOOLEAN:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001757 case Instruction::IGET_BYTE:
1758 case Instruction::IGET_CHAR:
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001759 case Instruction::IGET_SHORT:
1760 res = HandleIGet(mir, opcode);
buzbee2502e002012-12-31 16:05:53 -08001761 break;
1762
buzbee2502e002012-12-31 16:05:53 -08001763 case Instruction::IPUT_OBJECT:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001764 HandlePutObject(mir);
1765 // Intentional fall-through.
buzbee2502e002012-12-31 16:05:53 -08001766 case Instruction::IPUT:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001767 case Instruction::IPUT_WIDE:
buzbee2502e002012-12-31 16:05:53 -08001768 case Instruction::IPUT_BOOLEAN:
1769 case Instruction::IPUT_BYTE:
1770 case Instruction::IPUT_CHAR:
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001771 case Instruction::IPUT_SHORT:
1772 HandleIPut(mir, opcode);
buzbee2502e002012-12-31 16:05:53 -08001773 break;
1774
1775 case Instruction::SGET_OBJECT:
1776 case Instruction::SGET:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001777 case Instruction::SGET_WIDE:
buzbee2502e002012-12-31 16:05:53 -08001778 case Instruction::SGET_BOOLEAN:
1779 case Instruction::SGET_BYTE:
1780 case Instruction::SGET_CHAR:
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001781 case Instruction::SGET_SHORT:
1782 res = HandleSGet(mir, opcode);
buzbee2502e002012-12-31 16:05:53 -08001783 break;
1784
1785 case Instruction::SPUT_OBJECT:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001786 HandlePutObject(mir);
1787 // Intentional fall-through.
buzbee2502e002012-12-31 16:05:53 -08001788 case Instruction::SPUT:
Vladimir Markof59f18b2014-02-17 15:53:57 +00001789 case Instruction::SPUT_WIDE:
buzbee2502e002012-12-31 16:05:53 -08001790 case Instruction::SPUT_BOOLEAN:
1791 case Instruction::SPUT_BYTE:
1792 case Instruction::SPUT_CHAR:
Vladimir Marko2ac01fc2014-05-22 12:09:08 +01001793 case Instruction::SPUT_SHORT:
1794 HandleSPut(mir, opcode);
buzbee2502e002012-12-31 16:05:53 -08001795 break;
buzbee2502e002012-12-31 16:05:53 -08001796 }
1797 return res;
1798}
1799
1800} // namespace art