summaryrefslogtreecommitdiff
path: root/compiler/dex/local_value_numbering.cc
diff options
context:
space:
mode:
author Nicolas Geoffray <ngeoffray@google.com> 2016-03-21 17:10:24 +0000
committer Vladimir Marko <vmarko@google.com> 2016-03-21 17:39:20 +0000
commit3c94f0945ed596ceee39783fa075f013b65e80a1 (patch)
treec10b5808a5d7157371c2750823e6a168c73aa231 /compiler/dex/local_value_numbering.cc
parent162629ee8ac0fee2df0c0cdec27dff34bc6f0062 (diff)
Remove Quick from tree.
So long, old friend. Change-Id: I0241c798a34b92bf994fed83888da67d6e7f1891
Diffstat (limited to 'compiler/dex/local_value_numbering.cc')
-rw-r--r--compiler/dex/local_value_numbering.cc2038
1 files changed, 0 insertions, 2038 deletions
diff --git a/compiler/dex/local_value_numbering.cc b/compiler/dex/local_value_numbering.cc
deleted file mode 100644
index 38f7d1e712..0000000000
--- a/compiler/dex/local_value_numbering.cc
+++ /dev/null
@@ -1,2038 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "local_value_numbering.h"
-
-#include "base/bit_utils.h"
-#include "global_value_numbering.h"
-#include "mir_field_info.h"
-#include "mir_graph.h"
-#include "utils.h"
-
-namespace art {
-
-namespace { // anonymous namespace
-
-// Operations used for value map keys instead of actual opcode.
-static constexpr uint16_t kInvokeMemoryVersionBumpOp = Instruction::INVOKE_VIRTUAL;
-static constexpr uint16_t kUnresolvedSFieldOp = Instruction::SGET;
-static constexpr uint16_t kResolvedSFieldOp = Instruction::SGET_WIDE;
-static constexpr uint16_t kUnresolvedIFieldOp = Instruction::IGET;
-static constexpr uint16_t kNonAliasingIFieldLocOp = Instruction::IGET_WIDE;
-static constexpr uint16_t kNonAliasingIFieldInitialOp = Instruction::IGET_OBJECT;
-static constexpr uint16_t kAliasingIFieldOp = Instruction::IGET_BOOLEAN;
-static constexpr uint16_t kAliasingIFieldStartVersionOp = Instruction::IGET_BYTE;
-static constexpr uint16_t kAliasingIFieldBumpVersionOp = Instruction::IGET_CHAR;
-static constexpr uint16_t kNonAliasingArrayOp = Instruction::AGET;
-static constexpr uint16_t kNonAliasingArrayStartVersionOp = Instruction::AGET_WIDE;
-static constexpr uint16_t kNonAliasingArrayBumpVersionOp = Instruction::AGET_OBJECT;
-static constexpr uint16_t kAliasingArrayOp = Instruction::AGET_BOOLEAN;
-static constexpr uint16_t kAliasingArrayStartVersionOp = Instruction::AGET_BYTE;
-static constexpr uint16_t kAliasingArrayBumpVersionOp = Instruction::AGET_CHAR;
-static constexpr uint16_t kMergeBlockMemoryVersionBumpOp = Instruction::INVOKE_VIRTUAL_RANGE;
-static constexpr uint16_t kMergeBlockAliasingIFieldVersionBumpOp = Instruction::IPUT;
-static constexpr uint16_t kMergeBlockAliasingIFieldMergeLocationOp = Instruction::IPUT_WIDE;
-static constexpr uint16_t kMergeBlockNonAliasingArrayVersionBumpOp = Instruction::APUT;
-static constexpr uint16_t kMergeBlockNonAliasingArrayMergeLocationOp = Instruction::APUT_WIDE;
-static constexpr uint16_t kMergeBlockAliasingArrayVersionBumpOp = Instruction::APUT_OBJECT;
-static constexpr uint16_t kMergeBlockAliasingArrayMergeLocationOp = Instruction::APUT_BOOLEAN;
-static constexpr uint16_t kMergeBlockNonAliasingIFieldVersionBumpOp = Instruction::APUT_BYTE;
-static constexpr uint16_t kMergeBlockSFieldVersionBumpOp = Instruction::APUT_CHAR;
-
-} // anonymous namespace
-
-class LocalValueNumbering::AliasingIFieldVersions {
- public:
- static uint16_t StartMemoryVersion(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
- uint16_t field_id) {
- uint16_t type = gvn->GetIFieldType(field_id);
- return gvn->LookupValue(kAliasingIFieldStartVersionOp, field_id,
- lvn->global_memory_version_, lvn->unresolved_ifield_version_[type]);
- }
-
- static uint16_t BumpMemoryVersion(GlobalValueNumbering* gvn, uint16_t old_version,
- uint16_t store_ref_set_id, uint16_t stored_value) {
- return gvn->LookupValue(kAliasingIFieldBumpVersionOp, old_version,
- store_ref_set_id, stored_value);
- }
-
- static uint16_t LookupGlobalValue(GlobalValueNumbering* gvn,
- uint16_t field_id, uint16_t base, uint16_t memory_version) {
- return gvn->LookupValue(kAliasingIFieldOp, field_id, base, memory_version);
- }
-
- static uint16_t LookupMergeValue(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
- uint16_t field_id, uint16_t base) {
- // If the base/field_id is non-aliasing in lvn, use the non-aliasing value.
- uint16_t type = gvn->GetIFieldType(field_id);
- if (lvn->IsNonAliasingIField(base, field_id, type)) {
- uint16_t loc = gvn->LookupValue(kNonAliasingIFieldLocOp, base, field_id, type);
- auto lb = lvn->non_aliasing_ifield_value_map_.find(loc);
- return (lb != lvn->non_aliasing_ifield_value_map_.end())
- ? lb->second
- : gvn->LookupValue(kNonAliasingIFieldInitialOp, loc, kNoValue, kNoValue);
- }
- return AliasingValuesMergeGet<AliasingIFieldVersions>(
- gvn, lvn, &lvn->aliasing_ifield_value_map_, field_id, base);
- }
-
- static bool HasNewBaseVersion(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
- uint16_t field_id) {
- uint16_t type = gvn->GetIFieldType(field_id);
- return lvn->unresolved_ifield_version_[type] == lvn->merge_new_memory_version_ ||
- lvn->global_memory_version_ == lvn->merge_new_memory_version_;
- }
-
- static uint16_t LookupMergeBlockValue(GlobalValueNumbering* gvn, uint16_t lvn_id,
- uint16_t field_id) {
- return gvn->LookupValue(kMergeBlockAliasingIFieldVersionBumpOp, field_id, kNoValue, lvn_id);
- }
-
- static uint16_t LookupMergeLocationValue(GlobalValueNumbering* gvn, uint16_t lvn_id,
- uint16_t field_id, uint16_t base) {
- return gvn->LookupValue(kMergeBlockAliasingIFieldMergeLocationOp, field_id, base, lvn_id);
- }
-};
-
-class LocalValueNumbering::NonAliasingArrayVersions {
- public:
- static uint16_t StartMemoryVersion(GlobalValueNumbering* gvn,
- const LocalValueNumbering* lvn ATTRIBUTE_UNUSED,
- uint16_t array) {
- return gvn->LookupValue(kNonAliasingArrayStartVersionOp, array, kNoValue, kNoValue);
- }
-
- static uint16_t BumpMemoryVersion(GlobalValueNumbering* gvn, uint16_t old_version,
- uint16_t store_ref_set_id, uint16_t stored_value) {
- return gvn->LookupValue(kNonAliasingArrayBumpVersionOp, old_version,
- store_ref_set_id, stored_value);
- }
-
- static uint16_t LookupGlobalValue(GlobalValueNumbering* gvn,
- uint16_t array, uint16_t index, uint16_t memory_version) {
- return gvn->LookupValue(kNonAliasingArrayOp, array, index, memory_version);
- }
-
- static uint16_t LookupMergeValue(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
- uint16_t array, uint16_t index) {
- return AliasingValuesMergeGet<NonAliasingArrayVersions>(
- gvn, lvn, &lvn->non_aliasing_array_value_map_, array, index);
- }
-
- static bool HasNewBaseVersion(GlobalValueNumbering* gvn ATTRIBUTE_UNUSED,
- const LocalValueNumbering* lvn ATTRIBUTE_UNUSED,
- uint16_t array ATTRIBUTE_UNUSED) {
- return false; // Not affected by global_memory_version_.
- }
-
- static uint16_t LookupMergeBlockValue(GlobalValueNumbering* gvn, uint16_t lvn_id,
- uint16_t array) {
- return gvn->LookupValue(kMergeBlockNonAliasingArrayVersionBumpOp, array, kNoValue, lvn_id);
- }
-
- static uint16_t LookupMergeLocationValue(GlobalValueNumbering* gvn, uint16_t lvn_id,
- uint16_t array, uint16_t index) {
- return gvn->LookupValue(kMergeBlockNonAliasingArrayMergeLocationOp, array, index, lvn_id);
- }
-};
-
-class LocalValueNumbering::AliasingArrayVersions {
- public:
- static uint16_t StartMemoryVersion(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
- uint16_t type) {
- return gvn->LookupValue(kAliasingArrayStartVersionOp, type, lvn->global_memory_version_,
- kNoValue);
- }
-
- static uint16_t BumpMemoryVersion(GlobalValueNumbering* gvn, uint16_t old_version,
- uint16_t store_ref_set_id, uint16_t stored_value) {
- return gvn->LookupValue(kAliasingArrayBumpVersionOp, old_version,
- store_ref_set_id, stored_value);
- }
-
- static uint16_t LookupGlobalValue(GlobalValueNumbering* gvn,
- uint16_t type, uint16_t location, uint16_t memory_version) {
- return gvn->LookupValue(kAliasingArrayOp, type, location, memory_version);
- }
-
- static uint16_t LookupMergeValue(GlobalValueNumbering* gvn,
- const LocalValueNumbering* lvn,
- uint16_t type, uint16_t location) {
- // If the location is non-aliasing in lvn, use the non-aliasing value.
- uint16_t array = gvn->GetArrayLocationBase(location);
- if (lvn->IsNonAliasingArray(array, type)) {
- uint16_t index = gvn->GetArrayLocationIndex(location);
- return NonAliasingArrayVersions::LookupMergeValue(gvn, lvn, array, index);
- }
- return AliasingValuesMergeGet<AliasingArrayVersions>(
- gvn, lvn, &lvn->aliasing_array_value_map_, type, location);
- }
-
- static bool HasNewBaseVersion(GlobalValueNumbering* gvn ATTRIBUTE_UNUSED,
- const LocalValueNumbering* lvn,
- uint16_t type ATTRIBUTE_UNUSED) {
- return lvn->global_memory_version_ == lvn->merge_new_memory_version_;
- }
-
- static uint16_t LookupMergeBlockValue(GlobalValueNumbering* gvn, uint16_t lvn_id,
- uint16_t type) {
- return gvn->LookupValue(kMergeBlockAliasingArrayVersionBumpOp, type, kNoValue, lvn_id);
- }
-
- static uint16_t LookupMergeLocationValue(GlobalValueNumbering* gvn, uint16_t lvn_id,
- uint16_t type, uint16_t location) {
- return gvn->LookupValue(kMergeBlockAliasingArrayMergeLocationOp, type, location, lvn_id);
- }
-};
-
-template <typename Map>
-LocalValueNumbering::AliasingValues* LocalValueNumbering::GetAliasingValues(
- Map* map, const typename Map::key_type& key) {
- auto lb = map->lower_bound(key);
- if (lb == map->end() || map->key_comp()(key, lb->first)) {
- lb = map->PutBefore(lb, key, AliasingValues(this));
- }
- return &lb->second;
-}
-
-template <typename Versions, typename KeyType>
-void LocalValueNumbering::UpdateAliasingValuesLoadVersion(const KeyType& key,
- AliasingValues* values) {
- if (values->last_load_memory_version == kNoValue) {
- // Get the start version that accounts for aliasing with unresolved fields of the same
- // type and make it unique for the field by including the field_id.
- uint16_t memory_version = values->memory_version_before_stores;
- if (memory_version == kNoValue) {
- memory_version = Versions::StartMemoryVersion(gvn_, this, key);
- }
- if (!values->store_loc_set.empty()) {
- uint16_t ref_set_id = gvn_->GetRefSetId(values->store_loc_set);
- memory_version = Versions::BumpMemoryVersion(gvn_, memory_version, ref_set_id,
- values->last_stored_value);
- }
- values->last_load_memory_version = memory_version;
- }
-}
-
-template <typename Versions, typename Map>
-uint16_t LocalValueNumbering::AliasingValuesMergeGet(GlobalValueNumbering* gvn,
- const LocalValueNumbering* lvn,
- Map* map, const typename Map::key_type& key,
- uint16_t location) {
- // Retrieve the value name that we would get from
- // const_cast<LocalValueNumbering*>(lvn)->HandleAliasingValueGet(map. key, location)
- // but don't modify the map.
- uint16_t value_name;
- auto it = map->find(key);
- if (it == map->end()) {
- uint16_t start_version = Versions::StartMemoryVersion(gvn, lvn, key);
- value_name = Versions::LookupGlobalValue(gvn, key, location, start_version);
- } else if (it->second.store_loc_set.count(location) != 0u) {
- value_name = it->second.last_stored_value;
- } else {
- auto load_it = it->second.load_value_map.find(location);
- if (load_it != it->second.load_value_map.end()) {
- value_name = load_it->second;
- } else {
- value_name = Versions::LookupGlobalValue(gvn, key, location, it->second.last_load_memory_version);
- }
- }
- return value_name;
-}
-
-template <typename Versions, typename Map>
-uint16_t LocalValueNumbering::HandleAliasingValuesGet(Map* map, const typename Map::key_type& key,
- uint16_t location) {
- // Retrieve the value name for IGET/SGET/AGET, update the map with new value if any.
- uint16_t res;
- AliasingValues* values = GetAliasingValues(map, key);
- if (values->store_loc_set.count(location) != 0u) {
- res = values->last_stored_value;
- } else {
- UpdateAliasingValuesLoadVersion<Versions>(key, values);
- auto lb = values->load_value_map.lower_bound(location);
- if (lb != values->load_value_map.end() && lb->first == location) {
- res = lb->second;
- } else {
- res = Versions::LookupGlobalValue(gvn_, key, location, values->last_load_memory_version);
- values->load_value_map.PutBefore(lb, location, res);
- }
- }
- return res;
-}
-
-template <typename Versions, typename Map>
-bool LocalValueNumbering::HandleAliasingValuesPut(Map* map, const typename Map::key_type& key,
- uint16_t location, uint16_t value) {
- AliasingValues* values = GetAliasingValues(map, key);
- auto load_values_it = values->load_value_map.find(location);
- if (load_values_it != values->load_value_map.end() && load_values_it->second == value) {
- // This insn can be eliminated, it stores the same value that's already in the field.
- return false;
- }
- if (value == values->last_stored_value) {
- auto store_loc_lb = values->store_loc_set.lower_bound(location);
- if (store_loc_lb != values->store_loc_set.end() && *store_loc_lb == location) {
- // This insn can be eliminated, it stores the same value that's already in the field.
- return false;
- }
- values->store_loc_set.emplace_hint(store_loc_lb, location);
- } else {
- UpdateAliasingValuesLoadVersion<Versions>(key, values);
- values->memory_version_before_stores = values->last_load_memory_version;
- values->last_stored_value = value;
- values->store_loc_set.clear();
- values->store_loc_set.insert(location);
- }
- // Clear the last load memory version and remove all potentially overwritten values.
- values->last_load_memory_version = kNoValue;
- auto it = values->load_value_map.begin(), end = values->load_value_map.end();
- while (it != end) {
- if (it->second == value) {
- ++it;
- } else {
- it = values->load_value_map.erase(it);
- }
- }
- return true;
-}
-
-template <typename K>
-void LocalValueNumbering::CopyAliasingValuesMap(ScopedArenaSafeMap<K, AliasingValues>* dest,
- const ScopedArenaSafeMap<K, AliasingValues>& src) {
- // We need each new AliasingValues (or rather its map members) to be constructed
- // with our allocator, rather than the allocator of the source.
- for (const auto& entry : src) {
- auto it = dest->PutBefore(dest->end(), entry.first, AliasingValues(this));
- it->second = entry.second; // Map assignments preserve current allocator.
- }
-}
-
-LocalValueNumbering::LocalValueNumbering(GlobalValueNumbering* gvn, uint16_t id,
- ScopedArenaAllocator* allocator)
- : gvn_(gvn),
- id_(id),
- sreg_value_map_(std::less<uint16_t>(), allocator->Adapter()),
- sreg_wide_value_map_(std::less<uint16_t>(), allocator->Adapter()),
- sfield_value_map_(std::less<uint16_t>(), allocator->Adapter()),
- non_aliasing_ifield_value_map_(std::less<uint16_t>(), allocator->Adapter()),
- aliasing_ifield_value_map_(std::less<uint16_t>(), allocator->Adapter()),
- non_aliasing_array_value_map_(std::less<uint16_t>(), allocator->Adapter()),
- aliasing_array_value_map_(std::less<uint16_t>(), allocator->Adapter()),
- global_memory_version_(0u),
- non_aliasing_refs_(std::less<uint16_t>(), allocator->Adapter()),
- escaped_refs_(std::less<uint16_t>(), allocator->Adapter()),
- escaped_ifield_clobber_set_(EscapedIFieldClobberKeyComparator(), allocator->Adapter()),
- escaped_array_clobber_set_(EscapedArrayClobberKeyComparator(), allocator->Adapter()),
- range_checked_(RangeCheckKeyComparator() , allocator->Adapter()),
- null_checked_(std::less<uint16_t>(), allocator->Adapter()),
- div_zero_checked_(std::less<uint16_t>(), allocator->Adapter()),
- merge_names_(allocator->Adapter()),
- merge_map_(std::less<ScopedArenaVector<BasicBlockId>>(), allocator->Adapter()),
- merge_new_memory_version_(kNoValue) {
- std::fill_n(unresolved_sfield_version_, arraysize(unresolved_sfield_version_), 0u);
- std::fill_n(unresolved_ifield_version_, arraysize(unresolved_ifield_version_), 0u);
-}
-
-bool LocalValueNumbering::Equals(const LocalValueNumbering& other) const {
- DCHECK(gvn_ == other.gvn_);
- // Compare the maps/sets and memory versions.
- return sreg_value_map_ == other.sreg_value_map_ &&
- sreg_wide_value_map_ == other.sreg_wide_value_map_ &&
- sfield_value_map_ == other.sfield_value_map_ &&
- non_aliasing_ifield_value_map_ == other.non_aliasing_ifield_value_map_ &&
- aliasing_ifield_value_map_ == other.aliasing_ifield_value_map_ &&
- non_aliasing_array_value_map_ == other.non_aliasing_array_value_map_ &&
- aliasing_array_value_map_ == other.aliasing_array_value_map_ &&
- SameMemoryVersion(other) &&
- non_aliasing_refs_ == other.non_aliasing_refs_ &&
- escaped_refs_ == other.escaped_refs_ &&
- escaped_ifield_clobber_set_ == other.escaped_ifield_clobber_set_ &&
- escaped_array_clobber_set_ == other.escaped_array_clobber_set_ &&
- range_checked_ == other.range_checked_ &&
- null_checked_ == other.null_checked_ &&
- div_zero_checked_ == other.div_zero_checked_;
-}
-
-void LocalValueNumbering::MergeOne(const LocalValueNumbering& other, MergeType merge_type) {
- CopyLiveSregValues(&sreg_value_map_, other.sreg_value_map_);
- CopyLiveSregValues(&sreg_wide_value_map_, other.sreg_wide_value_map_);
-
- if (merge_type == kReturnMerge) {
- // RETURN or PHI+RETURN. We need only sreg value maps.
- return;
- }
-
- non_aliasing_ifield_value_map_ = other.non_aliasing_ifield_value_map_;
- CopyAliasingValuesMap(&non_aliasing_array_value_map_, other.non_aliasing_array_value_map_);
- non_aliasing_refs_ = other.non_aliasing_refs_;
- range_checked_ = other.range_checked_;
- null_checked_ = other.null_checked_;
- div_zero_checked_ = other.div_zero_checked_;
-
- const BasicBlock* pred_bb = gvn_->GetBasicBlock(other.Id());
- if (GlobalValueNumbering::HasNullCheckLastInsn(pred_bb, Id())) {
- int s_reg = pred_bb->last_mir_insn->ssa_rep->uses[0];
- null_checked_.insert(other.GetOperandValue(s_reg));
- }
-
- if (merge_type == kCatchMerge) {
- // Memory is clobbered. Use new memory version and don't merge aliasing locations.
- global_memory_version_ = NewMemoryVersion(&merge_new_memory_version_);
- std::fill_n(unresolved_sfield_version_, arraysize(unresolved_sfield_version_),
- global_memory_version_);
- std::fill_n(unresolved_ifield_version_, arraysize(unresolved_ifield_version_),
- global_memory_version_);
- PruneNonAliasingRefsForCatch();
- return;
- }
-
- DCHECK(merge_type == kNormalMerge);
- global_memory_version_ = other.global_memory_version_;
- std::copy_n(other.unresolved_ifield_version_, arraysize(unresolved_sfield_version_),
- unresolved_ifield_version_);
- std::copy_n(other.unresolved_sfield_version_, arraysize(unresolved_ifield_version_),
- unresolved_sfield_version_);
- sfield_value_map_ = other.sfield_value_map_;
- CopyAliasingValuesMap(&aliasing_ifield_value_map_, other.aliasing_ifield_value_map_);
- CopyAliasingValuesMap(&aliasing_array_value_map_, other.aliasing_array_value_map_);
- escaped_refs_ = other.escaped_refs_;
- escaped_ifield_clobber_set_ = other.escaped_ifield_clobber_set_;
- escaped_array_clobber_set_ = other.escaped_array_clobber_set_;
-}
-
-bool LocalValueNumbering::SameMemoryVersion(const LocalValueNumbering& other) const {
- return
- global_memory_version_ == other.global_memory_version_ &&
- std::equal(unresolved_ifield_version_,
- unresolved_ifield_version_ + arraysize(unresolved_ifield_version_),
- other.unresolved_ifield_version_) &&
- std::equal(unresolved_sfield_version_,
- unresolved_sfield_version_ + arraysize(unresolved_sfield_version_),
- other.unresolved_sfield_version_);
-}
-
-uint16_t LocalValueNumbering::NewMemoryVersion(uint16_t* new_version) {
- if (*new_version == kNoValue) {
- *new_version = gvn_->LookupValue(kMergeBlockMemoryVersionBumpOp, 0u, 0u, id_);
- }
- return *new_version;
-}
-
-void LocalValueNumbering::MergeMemoryVersions(bool clobbered_catch) {
- DCHECK_GE(gvn_->merge_lvns_.size(), 2u);
- const LocalValueNumbering* cmp = gvn_->merge_lvns_[0];
- // Check if the global version has changed.
- bool new_global_version = clobbered_catch;
- if (!new_global_version) {
- for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
- if (lvn->global_memory_version_ != cmp->global_memory_version_) {
- // Use a new version for everything.
- new_global_version = true;
- break;
- }
- }
- }
- if (new_global_version) {
- global_memory_version_ = NewMemoryVersion(&merge_new_memory_version_);
- std::fill_n(unresolved_sfield_version_, arraysize(unresolved_sfield_version_),
- merge_new_memory_version_);
- std::fill_n(unresolved_ifield_version_, arraysize(unresolved_ifield_version_),
- merge_new_memory_version_);
- } else {
- // Initialize with a copy of memory versions from the comparison LVN.
- global_memory_version_ = cmp->global_memory_version_;
- std::copy_n(cmp->unresolved_ifield_version_, arraysize(unresolved_sfield_version_),
- unresolved_ifield_version_);
- std::copy_n(cmp->unresolved_sfield_version_, arraysize(unresolved_ifield_version_),
- unresolved_sfield_version_);
- for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
- if (lvn == cmp) {
- continue;
- }
- for (size_t i = 0; i != kDexMemAccessTypeCount; ++i) {
- if (lvn->unresolved_ifield_version_[i] != cmp->unresolved_ifield_version_[i]) {
- unresolved_ifield_version_[i] = NewMemoryVersion(&merge_new_memory_version_);
- }
- if (lvn->unresolved_sfield_version_[i] != cmp->unresolved_sfield_version_[i]) {
- unresolved_sfield_version_[i] = NewMemoryVersion(&merge_new_memory_version_);
- }
- }
- }
- }
-}
-
-void LocalValueNumbering::PruneNonAliasingRefsForCatch() {
- for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
- const BasicBlock* bb = gvn_->GetBasicBlock(lvn->Id());
- if (UNLIKELY(bb->taken == id_) || UNLIKELY(bb->fall_through == id_)) {
- // Non-exceptional path to a catch handler means that the catch block was actually
- // empty and all exceptional paths lead to the shared path after that empty block.
- continue;
- }
- DCHECK_EQ(bb->taken, kNullBlock);
- DCHECK_NE(bb->fall_through, kNullBlock);
- const BasicBlock* fall_through_bb = gvn_->GetBasicBlock(bb->fall_through);
- const MIR* mir = fall_through_bb->first_mir_insn;
- DCHECK(mir != nullptr);
- // Only INVOKEs can leak and clobber non-aliasing references if they throw.
- if ((mir->dalvikInsn.FlagsOf() & Instruction::kInvoke) != 0) {
- HandleInvokeArgs(mir, lvn);
- }
- }
-}
-
-
-template <typename Set, Set LocalValueNumbering::* set_ptr>
-void LocalValueNumbering::IntersectSets() {
- DCHECK_GE(gvn_->merge_lvns_.size(), 2u);
-
- // Find the LVN with the least entries in the set.
- const LocalValueNumbering* least_entries_lvn = gvn_->merge_lvns_[0];
- for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
- if ((lvn->*set_ptr).size() < (least_entries_lvn->*set_ptr).size()) {
- least_entries_lvn = lvn;
- }
- }
-
- // For each key check if it's in all the LVNs.
- for (const auto& key : least_entries_lvn->*set_ptr) {
- bool checked = true;
- for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
- if (lvn != least_entries_lvn && (lvn->*set_ptr).count(key) == 0u) {
- checked = false;
- break;
- }
- }
- if (checked) {
- (this->*set_ptr).emplace_hint((this->*set_ptr).end(), key);
- }
- }
-}
-
-void LocalValueNumbering::CopyLiveSregValues(SregValueMap* dest, const SregValueMap& src) {
- auto dest_end = dest->end();
- ArenaBitVector* live_in_v = gvn_->GetMirGraph()->GetBasicBlock(id_)->data_flow_info->live_in_v;
- DCHECK(live_in_v != nullptr);
- for (const auto& entry : src) {
- bool live = live_in_v->IsBitSet(gvn_->GetMirGraph()->SRegToVReg(entry.first));
- if (live) {
- dest->PutBefore(dest_end, entry.first, entry.second);
- }
- }
-}
-
-template <LocalValueNumbering::SregValueMap LocalValueNumbering::* map_ptr>
-void LocalValueNumbering::IntersectSregValueMaps() {
- DCHECK_GE(gvn_->merge_lvns_.size(), 2u);
-
- // Find the LVN with the least entries in the set.
- const LocalValueNumbering* least_entries_lvn = gvn_->merge_lvns_[0];
- for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
- if ((lvn->*map_ptr).size() < (least_entries_lvn->*map_ptr).size()) {
- least_entries_lvn = lvn;
- }
- }
-
- // For each key check if it's in all the LVNs.
- ArenaBitVector* live_in_v = gvn_->GetMirGraph()->GetBasicBlock(id_)->data_flow_info->live_in_v;
- DCHECK(live_in_v != nullptr);
- for (const auto& entry : least_entries_lvn->*map_ptr) {
- bool live_and_same = live_in_v->IsBitSet(gvn_->GetMirGraph()->SRegToVReg(entry.first));
- if (live_and_same) {
- for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
- if (lvn != least_entries_lvn) {
- auto it = (lvn->*map_ptr).find(entry.first);
- if (it == (lvn->*map_ptr).end() || !(it->second == entry.second)) {
- live_and_same = false;
- break;
- }
- }
- }
- }
- if (live_and_same) {
- (this->*map_ptr).PutBefore((this->*map_ptr).end(), entry.first, entry.second);
- }
- }
-}
-
-// Intersect maps as sets. The value type must be equality-comparable.
-template <typename Map>
-void LocalValueNumbering::InPlaceIntersectMaps(Map* work_map, const Map& other_map) {
- auto work_it = work_map->begin(), work_end = work_map->end();
- auto cmp = work_map->value_comp();
- for (const auto& entry : other_map) {
- while (work_it != work_end &&
- (cmp(*work_it, entry) ||
- (!cmp(entry, *work_it) && !(work_it->second == entry.second)))) {
- work_it = work_map->erase(work_it);
- }
- if (work_it == work_end) {
- return;
- }
- ++work_it;
- }
-}
-
-template <typename Set, Set LocalValueNumbering::*set_ptr, void (LocalValueNumbering::*MergeFn)(
- const typename Set::value_type& entry, typename Set::iterator hint)>
-void LocalValueNumbering::MergeSets() {
- auto cmp = (this->*set_ptr).value_comp();
- for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
- auto my_it = (this->*set_ptr).begin(), my_end = (this->*set_ptr).end();
- for (const auto& entry : lvn->*set_ptr) {
- while (my_it != my_end && cmp(*my_it, entry)) {
- ++my_it;
- }
- if (my_it != my_end && !cmp(entry, *my_it)) {
- // Already handled.
- ++my_it;
- } else {
- // Merge values for this field_id.
- (this->*MergeFn)(entry, my_it); // my_it remains valid across inserts to std::set/SafeMap.
- }
- }
- }
-}
-
-void LocalValueNumbering::IntersectAliasingValueLocations(AliasingValues* work_values,
- const AliasingValues* values) {
- auto cmp = work_values->load_value_map.key_comp();
- auto work_it = work_values->load_value_map.begin(), work_end = work_values->load_value_map.end();
- auto store_it = values->store_loc_set.begin(), store_end = values->store_loc_set.end();
- auto load_it = values->load_value_map.begin(), load_end = values->load_value_map.end();
- while (store_it != store_end || load_it != load_end) {
- uint16_t loc;
- if (store_it != store_end && (load_it == load_end || *store_it < load_it->first)) {
- loc = *store_it;
- ++store_it;
- } else {
- loc = load_it->first;
- ++load_it;
- DCHECK(store_it == store_end || cmp(loc, *store_it));
- }
- while (work_it != work_end && cmp(work_it->first, loc)) {
- work_it = work_values->load_value_map.erase(work_it);
- }
- if (work_it != work_end && !cmp(loc, work_it->first)) {
- // The location matches, keep it.
- ++work_it;
- }
- }
- while (work_it != work_end) {
- work_it = work_values->load_value_map.erase(work_it);
- }
-}
-
-void LocalValueNumbering::MergeEscapedRefs(const ValueNameSet::value_type& entry,
- ValueNameSet::iterator hint) {
- // See if the ref is either escaped or non-aliasing in each predecessor.
- bool is_escaped = true;
- for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
- if (lvn->non_aliasing_refs_.count(entry) == 0u &&
- lvn->escaped_refs_.count(entry) == 0u) {
- is_escaped = false;
- break;
- }
- }
- if (is_escaped) {
- escaped_refs_.emplace_hint(hint, entry);
- }
-}
-
-void LocalValueNumbering::MergeEscapedIFieldTypeClobberSets(
- const EscapedIFieldClobberSet::value_type& entry, EscapedIFieldClobberSet::iterator hint) {
- // Insert only type-clobber entries (field_id == kNoValue) of escaped refs.
- if (entry.field_id == kNoValue && escaped_refs_.count(entry.base) != 0u) {
- escaped_ifield_clobber_set_.emplace_hint(hint, entry);
- }
-}
-
-void LocalValueNumbering::MergeEscapedIFieldClobberSets(
- const EscapedIFieldClobberSet::value_type& entry, EscapedIFieldClobberSet::iterator hint) {
- // Insert only those entries of escaped refs that are not overridden by a type clobber.
- if (!(hint == escaped_ifield_clobber_set_.end() &&
- hint->base == entry.base && hint->type == entry.type) &&
- escaped_refs_.count(entry.base) != 0u) {
- escaped_ifield_clobber_set_.emplace_hint(hint, entry);
- }
-}
-
-void LocalValueNumbering::MergeEscapedArrayClobberSets(
- const EscapedArrayClobberSet::value_type& entry, EscapedArrayClobberSet::iterator hint) {
- if (escaped_refs_.count(entry.base) != 0u) {
- escaped_array_clobber_set_.emplace_hint(hint, entry);
- }
-}
-
-void LocalValueNumbering::MergeNullChecked() {
- DCHECK_GE(gvn_->merge_lvns_.size(), 2u);
-
- // Find the LVN with the least entries in the set.
- const LocalValueNumbering* least_entries_lvn = gvn_->merge_lvns_[0];
- for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
- if (lvn->null_checked_.size() < least_entries_lvn->null_checked_.size()) {
- least_entries_lvn = lvn;
- }
- }
-
- // For each null-checked value name check if it's null-checked in all the LVNs.
- for (const auto& value_name : least_entries_lvn->null_checked_) {
- // Merge null_checked_ for this ref.
- merge_names_.clear();
- merge_names_.resize(gvn_->merge_lvns_.size(), value_name);
- if (gvn_->NullCheckedInAllPredecessors(merge_names_)) {
- null_checked_.insert(null_checked_.end(), value_name);
- }
- }
-
- // Now check if the least_entries_lvn has a null-check as the last insn.
- const BasicBlock* least_entries_bb = gvn_->GetBasicBlock(least_entries_lvn->Id());
- if (gvn_->HasNullCheckLastInsn(least_entries_bb, id_)) {
- int s_reg = least_entries_bb->last_mir_insn->ssa_rep->uses[0];
- uint32_t value_name = least_entries_lvn->GetOperandValue(s_reg);
- merge_names_.clear();
- merge_names_.resize(gvn_->merge_lvns_.size(), value_name);
- if (gvn_->NullCheckedInAllPredecessors(merge_names_)) {
- null_checked_.insert(value_name);
- }
- }
-}
-
-void LocalValueNumbering::MergeDivZeroChecked() {
- DCHECK_GE(gvn_->merge_lvns_.size(), 2u);
-
- // Find the LVN with the least entries in the set.
- const LocalValueNumbering* least_entries_lvn = gvn_->merge_lvns_[0];
- for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
- if (lvn->div_zero_checked_.size() < least_entries_lvn->div_zero_checked_.size()) {
- least_entries_lvn = lvn;
- }
- }
-
- // For each div-zero value name check if it's div-zero checked in all the LVNs.
- for (const auto& value_name : least_entries_lvn->div_zero_checked_) {
- // Merge null_checked_ for this ref.
- merge_names_.clear();
- merge_names_.resize(gvn_->merge_lvns_.size(), value_name);
- if (gvn_->DivZeroCheckedInAllPredecessors(merge_names_)) {
- div_zero_checked_.insert(div_zero_checked_.end(), value_name);
- }
- }
-}
-
-void LocalValueNumbering::MergeSFieldValues(const SFieldToValueMap::value_type& entry,
- SFieldToValueMap::iterator hint) {
- uint16_t field_id = entry.first;
- merge_names_.clear();
- uint16_t value_name = kNoValue;
- bool same_values = true;
- for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
- // Get the value name as in HandleSGet() but don't modify *lvn.
- auto it = lvn->sfield_value_map_.find(field_id);
- if (it != lvn->sfield_value_map_.end()) {
- value_name = it->second;
- } else {
- uint16_t type = gvn_->GetSFieldType(field_id);
- value_name = gvn_->LookupValue(kResolvedSFieldOp, field_id,
- lvn->unresolved_sfield_version_[type],
- lvn->global_memory_version_);
- }
-
- same_values = same_values && (merge_names_.empty() || value_name == merge_names_.back());
- merge_names_.push_back(value_name);
- }
- if (same_values) {
- // value_name already contains the result.
- } else {
- auto lb = merge_map_.lower_bound(merge_names_);
- if (lb != merge_map_.end() && !merge_map_.key_comp()(merge_names_, lb->first)) {
- value_name = lb->second;
- } else {
- value_name = gvn_->LookupValue(kMergeBlockSFieldVersionBumpOp, field_id, id_, kNoValue);
- merge_map_.PutBefore(lb, merge_names_, value_name);
- if (gvn_->NullCheckedInAllPredecessors(merge_names_)) {
- null_checked_.insert(value_name);
- }
- }
- }
- sfield_value_map_.PutBefore(hint, field_id, value_name);
-}
-
-void LocalValueNumbering::MergeNonAliasingIFieldValues(const IFieldLocToValueMap::value_type& entry,
- IFieldLocToValueMap::iterator hint) {
- uint16_t field_loc = entry.first;
- merge_names_.clear();
- uint16_t value_name = kNoValue;
- bool same_values = true;
- for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
- // Get the value name as in HandleIGet() but don't modify *lvn.
- auto it = lvn->non_aliasing_ifield_value_map_.find(field_loc);
- if (it != lvn->non_aliasing_ifield_value_map_.end()) {
- value_name = it->second;
- } else {
- value_name = gvn_->LookupValue(kNonAliasingIFieldInitialOp, field_loc, kNoValue, kNoValue);
- }
-
- same_values = same_values && (merge_names_.empty() || value_name == merge_names_.back());
- merge_names_.push_back(value_name);
- }
- if (same_values) {
- // value_name already contains the result.
- } else {
- auto lb = merge_map_.lower_bound(merge_names_);
- if (lb != merge_map_.end() && !merge_map_.key_comp()(merge_names_, lb->first)) {
- value_name = lb->second;
- } else {
- value_name = gvn_->LookupValue(kMergeBlockNonAliasingIFieldVersionBumpOp, field_loc,
- id_, kNoValue);
- merge_map_.PutBefore(lb, merge_names_, value_name);
- if (gvn_->NullCheckedInAllPredecessors(merge_names_)) {
- null_checked_.insert(value_name);
- }
- }
- }
- non_aliasing_ifield_value_map_.PutBefore(hint, field_loc, value_name);
-}
-
-template <typename Map, Map LocalValueNumbering::*map_ptr, typename Versions>
-void LocalValueNumbering::MergeAliasingValues(const typename Map::value_type& entry,
- typename Map::iterator hint) {
- const typename Map::key_type& key = entry.first;
-
- auto it = (this->*map_ptr).PutBefore(hint, key, AliasingValues(this));
- AliasingValues* my_values = &it->second;
-
- const AliasingValues* cmp_values = nullptr;
- bool same_version = !Versions::HasNewBaseVersion(gvn_, this, key);
- uint16_t load_memory_version_for_same_version = kNoValue;
- if (same_version) {
- // Find the first non-null values.
- for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
- auto value = (lvn->*map_ptr).find(key);
- if (value != (lvn->*map_ptr).end()) {
- cmp_values = &value->second;
- break;
- }
- }
- DCHECK(cmp_values != nullptr); // There must be at least one non-null values.
-
- // Check if we have identical memory versions, i.e. the global memory version, unresolved
- // field version and the values' memory_version_before_stores, last_stored_value
- // and store_loc_set are identical.
- for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
- auto value = (lvn->*map_ptr).find(key);
- if (value == (lvn->*map_ptr).end()) {
- if (cmp_values->memory_version_before_stores != kNoValue) {
- same_version = false;
- break;
- }
- } else if (cmp_values->last_stored_value != value->second.last_stored_value ||
- cmp_values->memory_version_before_stores != value->second.memory_version_before_stores ||
- cmp_values->store_loc_set != value->second.store_loc_set) {
- same_version = false;
- break;
- } else if (value->second.last_load_memory_version != kNoValue) {
- DCHECK(load_memory_version_for_same_version == kNoValue ||
- load_memory_version_for_same_version == value->second.last_load_memory_version);
- load_memory_version_for_same_version = value->second.last_load_memory_version;
- }
- }
- }
-
- if (same_version) {
- // Copy the identical values.
- my_values->memory_version_before_stores = cmp_values->memory_version_before_stores;
- my_values->last_stored_value = cmp_values->last_stored_value;
- my_values->store_loc_set = cmp_values->store_loc_set;
- my_values->last_load_memory_version = load_memory_version_for_same_version;
- // Merge load values seen in all incoming arcs (i.e. an intersection).
- if (!cmp_values->load_value_map.empty()) {
- my_values->load_value_map = cmp_values->load_value_map;
- for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
- auto value = (lvn->*map_ptr).find(key);
- if (value == (lvn->*map_ptr).end() || value->second.load_value_map.empty()) {
- my_values->load_value_map.clear();
- break;
- }
- InPlaceIntersectMaps(&my_values->load_value_map, value->second.load_value_map);
- if (my_values->load_value_map.empty()) {
- break;
- }
- }
- }
- } else {
- // Bump version number for the merge.
- my_values->memory_version_before_stores = my_values->last_load_memory_version =
- Versions::LookupMergeBlockValue(gvn_, id_, key);
-
- // Calculate the locations that have been either read from or written to in each incoming LVN.
- bool first_lvn = true;
- for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
- auto value = (lvn->*map_ptr).find(key);
- if (value == (lvn->*map_ptr).end()) {
- my_values->load_value_map.clear();
- break;
- }
- if (first_lvn) {
- first_lvn = false;
- // Copy the first LVN's locations. Values will be overwritten later.
- my_values->load_value_map = value->second.load_value_map;
- for (uint16_t location : value->second.store_loc_set) {
- my_values->load_value_map.Put(location, 0u);
- }
- } else {
- IntersectAliasingValueLocations(my_values, &value->second);
- }
- }
- // Calculate merged values for the intersection.
- for (auto& load_value_entry : my_values->load_value_map) {
- uint16_t location = load_value_entry.first;
- merge_names_.clear();
- uint16_t value_name = kNoValue;
- bool same_values = true;
- for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
- value_name = Versions::LookupMergeValue(gvn_, lvn, key, location);
- same_values = same_values && (merge_names_.empty() || value_name == merge_names_.back());
- merge_names_.push_back(value_name);
- }
- if (same_values) {
- // value_name already contains the result.
- } else {
- auto lb = merge_map_.lower_bound(merge_names_);
- if (lb != merge_map_.end() && !merge_map_.key_comp()(merge_names_, lb->first)) {
- value_name = lb->second;
- } else {
- // NOTE: In addition to the key and id_ which don't change on an LVN recalculation
- // during GVN, we also add location which can actually change on recalculation, so the
- // value_name below may change. This could lead to an infinite loop if the location
- // value name always changed when the refereced value name changes. However, given that
- // we assign unique value names for other merges, such as Phis, such a dependency is
- // not possible in a well-formed SSA graph.
- value_name = Versions::LookupMergeLocationValue(gvn_, id_, key, location);
- merge_map_.PutBefore(lb, merge_names_, value_name);
- if (gvn_->NullCheckedInAllPredecessors(merge_names_)) {
- null_checked_.insert(value_name);
- }
- }
- }
- load_value_entry.second = value_name;
- }
- }
-}
-
-void LocalValueNumbering::Merge(MergeType merge_type) {
- DCHECK_GE(gvn_->merge_lvns_.size(), 2u);
-
- // Always reserve space in merge_names_. Even if we don't use it in Merge() we may need it
- // in GetStartingVregValueNumberImpl() when the merge_names_'s allocator is not the top.
- merge_names_.reserve(gvn_->merge_lvns_.size());
-
- IntersectSregValueMaps<&LocalValueNumbering::sreg_value_map_>();
- IntersectSregValueMaps<&LocalValueNumbering::sreg_wide_value_map_>();
- if (merge_type == kReturnMerge) {
- // RETURN or PHI+RETURN. We need only sreg value maps.
- return;
- }
-
- MergeMemoryVersions(merge_type == kCatchMerge);
-
- // Merge non-aliasing maps/sets.
- IntersectSets<ValueNameSet, &LocalValueNumbering::non_aliasing_refs_>();
- if (!non_aliasing_refs_.empty() && merge_type == kCatchMerge) {
- PruneNonAliasingRefsForCatch();
- }
- if (!non_aliasing_refs_.empty()) {
- MergeSets<IFieldLocToValueMap, &LocalValueNumbering::non_aliasing_ifield_value_map_,
- &LocalValueNumbering::MergeNonAliasingIFieldValues>();
- MergeSets<NonAliasingArrayValuesMap, &LocalValueNumbering::non_aliasing_array_value_map_,
- &LocalValueNumbering::MergeAliasingValues<
- NonAliasingArrayValuesMap, &LocalValueNumbering::non_aliasing_array_value_map_,
- NonAliasingArrayVersions>>();
- }
-
- // We won't do anything complicated for range checks, just calculate the intersection.
- IntersectSets<RangeCheckSet, &LocalValueNumbering::range_checked_>();
-
- // Merge null_checked_. We may later insert more, such as merged object field values.
- MergeNullChecked();
-
- // Now merge the div_zero_checked_.
- MergeDivZeroChecked();
-
- if (merge_type == kCatchMerge) {
- // Memory is clobbered. New memory version already created, don't merge aliasing locations.
- return;
- }
-
- DCHECK(merge_type == kNormalMerge);
-
- // Merge escaped refs and clobber sets.
- MergeSets<ValueNameSet, &LocalValueNumbering::escaped_refs_,
- &LocalValueNumbering::MergeEscapedRefs>();
- if (!escaped_refs_.empty()) {
- MergeSets<EscapedIFieldClobberSet, &LocalValueNumbering::escaped_ifield_clobber_set_,
- &LocalValueNumbering::MergeEscapedIFieldTypeClobberSets>();
- MergeSets<EscapedIFieldClobberSet, &LocalValueNumbering::escaped_ifield_clobber_set_,
- &LocalValueNumbering::MergeEscapedIFieldClobberSets>();
- MergeSets<EscapedArrayClobberSet, &LocalValueNumbering::escaped_array_clobber_set_,
- &LocalValueNumbering::MergeEscapedArrayClobberSets>();
- }
-
- MergeSets<SFieldToValueMap, &LocalValueNumbering::sfield_value_map_,
- &LocalValueNumbering::MergeSFieldValues>();
- MergeSets<AliasingIFieldValuesMap, &LocalValueNumbering::aliasing_ifield_value_map_,
- &LocalValueNumbering::MergeAliasingValues<
- AliasingIFieldValuesMap, &LocalValueNumbering::aliasing_ifield_value_map_,
- AliasingIFieldVersions>>();
- MergeSets<AliasingArrayValuesMap, &LocalValueNumbering::aliasing_array_value_map_,
- &LocalValueNumbering::MergeAliasingValues<
- AliasingArrayValuesMap, &LocalValueNumbering::aliasing_array_value_map_,
- AliasingArrayVersions>>();
-}
-
-void LocalValueNumbering::PrepareEntryBlock() {
- uint32_t vreg = gvn_->GetMirGraph()->GetFirstInVR();
- CompilationUnit* cu = gvn_->GetCompilationUnit();
- const char* shorty = cu->shorty;
- ++shorty; // Skip return value.
- if ((cu->access_flags & kAccStatic) == 0) {
- // If non-static method, mark "this" as non-null
- uint16_t value_name = GetOperandValue(vreg);
- ++vreg;
- null_checked_.insert(value_name);
- }
- for ( ; *shorty != 0; ++shorty, ++vreg) {
- if (*shorty == 'J' || *shorty == 'D') {
- uint16_t value_name = GetOperandValueWide(vreg);
- SetOperandValueWide(vreg, value_name);
- ++vreg;
- }
- }
-}
-
-uint16_t LocalValueNumbering::MarkNonAliasingNonNull(MIR* mir) {
- uint16_t res = GetOperandValue(mir->ssa_rep->defs[0]);
- DCHECK(null_checked_.find(res) == null_checked_.end());
- null_checked_.insert(res);
- non_aliasing_refs_.insert(res);
- return res;
-}
-
-bool LocalValueNumbering::IsNonAliasing(uint16_t reg) const {
- return non_aliasing_refs_.find(reg) != non_aliasing_refs_.end();
-}
-
-bool LocalValueNumbering::IsNonAliasingIField(uint16_t reg, uint16_t field_id,
- uint16_t type) const {
- if (IsNonAliasing(reg)) {
- return true;
- }
- if (escaped_refs_.find(reg) == escaped_refs_.end()) {
- return false;
- }
- // Check for IPUTs to unresolved fields.
- EscapedIFieldClobberKey key1 = { reg, type, kNoValue };
- if (escaped_ifield_clobber_set_.find(key1) != escaped_ifield_clobber_set_.end()) {
- return false;
- }
- // Check for aliased IPUTs to the same field.
- EscapedIFieldClobberKey key2 = { reg, type, field_id };
- return escaped_ifield_clobber_set_.find(key2) == escaped_ifield_clobber_set_.end();
-}
-
-bool LocalValueNumbering::IsNonAliasingArray(uint16_t reg, uint16_t type) const {
- if (IsNonAliasing(reg)) {
- return true;
- }
- if (escaped_refs_.count(reg) == 0u) {
- return false;
- }
- // Check for aliased APUTs.
- EscapedArrayClobberKey key = { reg, type };
- return escaped_array_clobber_set_.find(key) == escaped_array_clobber_set_.end();
-}
-
-void LocalValueNumbering::HandleNullCheck(MIR* mir, uint16_t reg) {
- auto lb = null_checked_.lower_bound(reg);
- if (lb != null_checked_.end() && *lb == reg) {
- if (LIKELY(gvn_->CanModify())) {
- if (gvn_->GetCompilationUnit()->verbose) {
- LOG(INFO) << "Removing null check for 0x" << std::hex << mir->offset;
- }
- mir->optimization_flags |= MIR_IGNORE_NULL_CHECK;
- }
- } else {
- null_checked_.insert(lb, reg);
- }
-}
-
-void LocalValueNumbering::HandleRangeCheck(MIR* mir, uint16_t array, uint16_t index) {
- RangeCheckKey key = { array, index };
- auto lb = range_checked_.lower_bound(key);
- if (lb != range_checked_.end() && !RangeCheckKeyComparator()(key, *lb)) {
- if (LIKELY(gvn_->CanModify())) {
- if (gvn_->GetCompilationUnit()->verbose) {
- LOG(INFO) << "Removing range check for 0x" << std::hex << mir->offset;
- }
- mir->optimization_flags |= MIR_IGNORE_RANGE_CHECK;
- }
- } else {
- // Mark range check completed.
- range_checked_.insert(lb, key);
- }
-}
-
-void LocalValueNumbering::HandleDivZeroCheck(MIR* mir, uint16_t reg) {
- auto lb = div_zero_checked_.lower_bound(reg);
- if (lb != div_zero_checked_.end() && *lb == reg) {
- if (LIKELY(gvn_->CanModify())) {
- if (gvn_->GetCompilationUnit()->verbose) {
- LOG(INFO) << "Removing div zero check for 0x" << std::hex << mir->offset;
- }
- mir->optimization_flags |= MIR_IGNORE_DIV_ZERO_CHECK;
- }
- } else {
- div_zero_checked_.insert(lb, reg);
- }
-}
-
-void LocalValueNumbering::HandlePutObject(MIR* mir) {
- // If we're storing a non-aliasing reference, stop tracking it as non-aliasing now.
- uint16_t base = GetOperandValue(mir->ssa_rep->uses[0]);
- HandleEscapingRef(base);
- if (gvn_->CanModify() && null_checked_.count(base) != 0u) {
- if (gvn_->GetCompilationUnit()->verbose) {
- LOG(INFO) << "Removing GC card mark value null check for 0x" << std::hex << mir->offset;
- }
- mir->optimization_flags |= MIR_STORE_NON_NULL_VALUE;
- }
-}
-
-void LocalValueNumbering::HandleEscapingRef(uint16_t base) {
- auto it = non_aliasing_refs_.find(base);
- if (it != non_aliasing_refs_.end()) {
- non_aliasing_refs_.erase(it);
- escaped_refs_.insert(base);
- }
-}
-
-void LocalValueNumbering::HandleInvokeArgs(const MIR* mir, const LocalValueNumbering* mir_lvn) {
- const int32_t* uses = mir->ssa_rep->uses;
- const int32_t* uses_end = uses + mir->ssa_rep->num_uses;
- while (uses != uses_end) {
- uint16_t sreg = *uses;
- ++uses;
- // Avoid LookupValue() so that we don't store new values in the global value map.
- auto local_it = mir_lvn->sreg_value_map_.find(sreg);
- if (local_it != mir_lvn->sreg_value_map_.end()) {
- non_aliasing_refs_.erase(local_it->second);
- } else {
- uint16_t value_name = gvn_->FindValue(kNoValue, sreg, kNoValue, kNoValue);
- if (value_name != kNoValue) {
- non_aliasing_refs_.erase(value_name);
- }
- }
- }
-}
-
-uint16_t LocalValueNumbering::HandlePhi(MIR* mir) {
- if (gvn_->merge_lvns_.empty()) {
- // Running LVN without a full GVN?
- return kNoValue;
- }
- // Determine if this Phi is merging wide regs.
- RegLocation raw_dest = gvn_->GetMirGraph()->GetRawDest(mir);
- if (raw_dest.high_word) {
- // This is the high part of a wide reg. Ignore the Phi.
- return kNoValue;
- }
- bool wide = raw_dest.wide;
- // Iterate over *merge_lvns_ and skip incoming sregs for BBs without associated LVN.
- merge_names_.clear();
- uint16_t value_name = kNoValue;
- bool same_values = true;
- BasicBlockId* incoming = mir->meta.phi_incoming;
- int32_t* uses = mir->ssa_rep->uses;
- int16_t pos = 0;
- for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
- DCHECK_LT(pos, mir->ssa_rep->num_uses);
- while (incoming[pos] != lvn->Id()) {
- ++pos;
- DCHECK_LT(pos, mir->ssa_rep->num_uses);
- }
- int s_reg = uses[pos];
- ++pos;
- value_name = wide ? lvn->GetOperandValueWide(s_reg) : lvn->GetOperandValue(s_reg);
-
- same_values = same_values && (merge_names_.empty() || value_name == merge_names_.back());
- merge_names_.push_back(value_name);
- }
- if (same_values) {
- // value_name already contains the result.
- } else {
- auto lb = merge_map_.lower_bound(merge_names_);
- if (lb != merge_map_.end() && !merge_map_.key_comp()(merge_names_, lb->first)) {
- value_name = lb->second;
- } else {
- value_name = gvn_->LookupValue(kNoValue, mir->ssa_rep->defs[0], kNoValue, kNoValue);
- merge_map_.PutBefore(lb, merge_names_, value_name);
- if (!wide && gvn_->NullCheckedInAllPredecessors(merge_names_)) {
- null_checked_.insert(value_name);
- }
- if (gvn_->DivZeroCheckedInAllPredecessors(merge_names_)) {
- div_zero_checked_.insert(value_name);
- }
- }
- }
- if (wide) {
- SetOperandValueWide(mir->ssa_rep->defs[0], value_name);
- } else {
- SetOperandValue(mir->ssa_rep->defs[0], value_name);
- }
- return value_name;
-}
-
-uint16_t LocalValueNumbering::HandleConst(MIR* mir, uint32_t value) {
- RegLocation raw_dest = gvn_->GetMirGraph()->GetRawDest(mir);
- uint16_t res;
- if (value == 0u && raw_dest.ref) {
- res = GlobalValueNumbering::kNullValue;
- } else {
- Instruction::Code op = raw_dest.fp ? Instruction::CONST_HIGH16 : Instruction::CONST;
- res = gvn_->LookupValue(op, Low16Bits(value), High16Bits(value), 0);
- }
- SetOperandValue(mir->ssa_rep->defs[0], res);
- return res;
-}
-
-uint16_t LocalValueNumbering::HandleConstWide(MIR* mir, uint64_t value) {
- RegLocation raw_dest = gvn_->GetMirGraph()->GetRawDest(mir);
- Instruction::Code op = raw_dest.fp ? Instruction::CONST_HIGH16 : Instruction::CONST;
- uint32_t low_word = Low32Bits(value);
- uint32_t high_word = High32Bits(value);
- uint16_t low_res = gvn_->LookupValue(op, Low16Bits(low_word), High16Bits(low_word), 1);
- uint16_t high_res = gvn_->LookupValue(op, Low16Bits(high_word), High16Bits(high_word), 2);
- uint16_t res = gvn_->LookupValue(op, low_res, high_res, 3);
- SetOperandValueWide(mir->ssa_rep->defs[0], res);
- return res;
-}
-
-uint16_t LocalValueNumbering::HandleAGet(MIR* mir, uint16_t opcode) {
- uint16_t array = GetOperandValue(mir->ssa_rep->uses[0]);
- HandleNullCheck(mir, array);
- uint16_t index = GetOperandValue(mir->ssa_rep->uses[1]);
- HandleRangeCheck(mir, array, index);
- uint16_t type = AGetMemAccessType(static_cast<Instruction::Code>(opcode));
- // Establish value number for loaded register.
- uint16_t res;
- if (IsNonAliasingArray(array, type)) {
- res = HandleAliasingValuesGet<NonAliasingArrayVersions>(&non_aliasing_array_value_map_,
- array, index);
- } else {
- uint16_t location = gvn_->GetArrayLocation(array, index);
- res = HandleAliasingValuesGet<AliasingArrayVersions>(&aliasing_array_value_map_,
- type, location);
- }
- if (opcode == Instruction::AGET_WIDE) {
- SetOperandValueWide(mir->ssa_rep->defs[0], res);
- } else {
- SetOperandValue(mir->ssa_rep->defs[0], res);
- }
- return res;
-}
-
-void LocalValueNumbering::HandleAPut(MIR* mir, uint16_t opcode) {
- int array_idx = (opcode == Instruction::APUT_WIDE) ? 2 : 1;
- int index_idx = array_idx + 1;
- uint16_t array = GetOperandValue(mir->ssa_rep->uses[array_idx]);
- HandleNullCheck(mir, array);
- uint16_t index = GetOperandValue(mir->ssa_rep->uses[index_idx]);
- HandleRangeCheck(mir, array, index);
-
- uint16_t type = APutMemAccessType(static_cast<Instruction::Code>(opcode));
- uint16_t value = (opcode == Instruction::APUT_WIDE)
- ? GetOperandValueWide(mir->ssa_rep->uses[0])
- : GetOperandValue(mir->ssa_rep->uses[0]);
- if (IsNonAliasing(array)) {
- bool put_is_live = HandleAliasingValuesPut<NonAliasingArrayVersions>(
- &non_aliasing_array_value_map_, array, index, value);
- if (!put_is_live) {
- // This APUT can be eliminated, it stores the same value that's already in the field.
- // TODO: Eliminate the APUT.
- return;
- }
- } else {
- uint16_t location = gvn_->GetArrayLocation(array, index);
- bool put_is_live = HandleAliasingValuesPut<AliasingArrayVersions>(
- &aliasing_array_value_map_, type, location, value);
- if (!put_is_live) {
- // This APUT can be eliminated, it stores the same value that's already in the field.
- // TODO: Eliminate the APUT.
- return;
- }
-
- // Clobber all escaped array refs for this type.
- for (uint16_t escaped_array : escaped_refs_) {
- EscapedArrayClobberKey clobber_key = { escaped_array, type };
- escaped_array_clobber_set_.insert(clobber_key);
- }
- }
-}
-
-uint16_t LocalValueNumbering::HandleIGet(MIR* mir, uint16_t opcode) {
- uint16_t base = GetOperandValue(mir->ssa_rep->uses[0]);
- HandleNullCheck(mir, base);
- const MirFieldInfo& field_info = gvn_->GetMirGraph()->GetIFieldLoweringInfo(mir);
- uint16_t res;
- if (!field_info.IsResolved() || field_info.IsVolatile()) {
- // Unresolved fields may be volatile, so handle them as such to be safe.
- HandleInvokeOrClInitOrAcquireOp(mir); // Volatile GETs have acquire semantics.
- // Volatile fields always get a new memory version; field id is irrelevant.
- // Use result s_reg - will be unique.
- res = gvn_->LookupValue(kNoValue, mir->ssa_rep->defs[0], kNoValue, kNoValue);
- } else {
- uint16_t type = IGetMemAccessType(static_cast<Instruction::Code>(opcode));
- uint16_t field_id = gvn_->GetIFieldId(mir);
- if (IsNonAliasingIField(base, field_id, type)) {
- uint16_t loc = gvn_->LookupValue(kNonAliasingIFieldLocOp, base, field_id, type);
- auto lb = non_aliasing_ifield_value_map_.lower_bound(loc);
- if (lb != non_aliasing_ifield_value_map_.end() && lb->first == loc) {
- res = lb->second;
- } else {
- res = gvn_->LookupValue(kNonAliasingIFieldInitialOp, loc, kNoValue, kNoValue);
- non_aliasing_ifield_value_map_.PutBefore(lb, loc, res);
- }
- } else {
- res = HandleAliasingValuesGet<AliasingIFieldVersions>(&aliasing_ifield_value_map_,
- field_id, base);
- }
- }
- if (opcode == Instruction::IGET_WIDE) {
- SetOperandValueWide(mir->ssa_rep->defs[0], res);
- } else {
- SetOperandValue(mir->ssa_rep->defs[0], res);
- }
- return res;
-}
-
-void LocalValueNumbering::HandleIPut(MIR* mir, uint16_t opcode) {
- int base_reg = (opcode == Instruction::IPUT_WIDE) ? 2 : 1;
- uint16_t base = GetOperandValue(mir->ssa_rep->uses[base_reg]);
- HandleNullCheck(mir, base);
- uint16_t type = IPutMemAccessType(static_cast<Instruction::Code>(opcode));
- const MirFieldInfo& field_info = gvn_->GetMirGraph()->GetIFieldLoweringInfo(mir);
- if (!field_info.IsResolved()) {
- // Unresolved fields always alias with everything of the same type.
- // Use mir->offset as modifier; without elaborate inlining, it will be unique.
- unresolved_ifield_version_[type] =
- gvn_->LookupValue(kUnresolvedIFieldOp, kNoValue, kNoValue, mir->offset);
-
- // For simplicity, treat base as escaped now.
- HandleEscapingRef(base);
-
- // Clobber all fields of escaped references of the same type.
- for (uint16_t escaped_ref : escaped_refs_) {
- EscapedIFieldClobberKey clobber_key = { escaped_ref, type, kNoValue };
- escaped_ifield_clobber_set_.insert(clobber_key);
- }
-
- // Aliasing fields of the same type may have been overwritten.
- auto it = aliasing_ifield_value_map_.begin(), end = aliasing_ifield_value_map_.end();
- while (it != end) {
- if (gvn_->GetIFieldType(it->first) != type) {
- ++it;
- } else {
- it = aliasing_ifield_value_map_.erase(it);
- }
- }
- } else if (field_info.IsVolatile()) {
- // Nothing to do, resolved volatile fields always get a new memory version anyway and
- // can't alias with resolved non-volatile fields.
- } else {
- uint16_t field_id = gvn_->GetIFieldId(mir);
- uint16_t value = (opcode == Instruction::IPUT_WIDE)
- ? GetOperandValueWide(mir->ssa_rep->uses[0])
- : GetOperandValue(mir->ssa_rep->uses[0]);
- if (IsNonAliasing(base)) {
- uint16_t loc = gvn_->LookupValue(kNonAliasingIFieldLocOp, base, field_id, type);
- auto lb = non_aliasing_ifield_value_map_.lower_bound(loc);
- if (lb != non_aliasing_ifield_value_map_.end() && lb->first == loc) {
- if (lb->second == value) {
- // This IPUT can be eliminated, it stores the same value that's already in the field.
- // TODO: Eliminate the IPUT.
- return;
- }
- lb->second = value; // Overwrite.
- } else {
- non_aliasing_ifield_value_map_.PutBefore(lb, loc, value);
- }
- } else {
- bool put_is_live = HandleAliasingValuesPut<AliasingIFieldVersions>(
- &aliasing_ifield_value_map_, field_id, base, value);
- if (!put_is_live) {
- // This IPUT can be eliminated, it stores the same value that's already in the field.
- // TODO: Eliminate the IPUT.
- return;
- }
-
- // Clobber all fields of escaped references for this field.
- for (uint16_t escaped_ref : escaped_refs_) {
- EscapedIFieldClobberKey clobber_key = { escaped_ref, type, field_id };
- escaped_ifield_clobber_set_.insert(clobber_key);
- }
- }
- }
-}
-
-uint16_t LocalValueNumbering::HandleSGet(MIR* mir, uint16_t opcode) {
- const MirSFieldLoweringInfo& field_info = gvn_->GetMirGraph()->GetSFieldLoweringInfo(mir);
- if (!field_info.IsResolved() || field_info.IsVolatile() ||
- (!field_info.IsClassInitialized() &&
- (mir->optimization_flags & MIR_CLASS_IS_INITIALIZED) == 0)) {
- // Volatile SGETs (and unresolved fields are potentially volatile) have acquire semantics
- // and class initialization can call arbitrary functions, we need to wipe aliasing values.
- HandleInvokeOrClInitOrAcquireOp(mir);
- }
- uint16_t res;
- if (!field_info.IsResolved() || field_info.IsVolatile()) {
- // Unresolved fields may be volatile, so handle them as such to be safe.
- // Volatile fields always get a new memory version; field id is irrelevant.
- // Use result s_reg - will be unique.
- res = gvn_->LookupValue(kNoValue, mir->ssa_rep->defs[0], kNoValue, kNoValue);
- } else {
- uint16_t type = SGetMemAccessType(static_cast<Instruction::Code>(opcode));
- uint16_t field_id = gvn_->GetSFieldId(mir);
- auto lb = sfield_value_map_.lower_bound(field_id);
- if (lb != sfield_value_map_.end() && lb->first == field_id) {
- res = lb->second;
- } else {
- // Resolved non-volatile static fields can alias with non-resolved fields of the same type,
- // so we need to use unresolved_sfield_version_[type] in addition to global_memory_version_
- // to determine the version of the field.
- res = gvn_->LookupValue(kResolvedSFieldOp, field_id,
- unresolved_sfield_version_[type], global_memory_version_);
- sfield_value_map_.PutBefore(lb, field_id, res);
- }
- }
- if (opcode == Instruction::SGET_WIDE) {
- SetOperandValueWide(mir->ssa_rep->defs[0], res);
- } else {
- SetOperandValue(mir->ssa_rep->defs[0], res);
- }
- return res;
-}
-
-void LocalValueNumbering::HandleSPut(MIR* mir, uint16_t opcode) {
- const MirSFieldLoweringInfo& field_info = gvn_->GetMirGraph()->GetSFieldLoweringInfo(mir);
- if (!field_info.IsClassInitialized() &&
- (mir->optimization_flags & MIR_CLASS_IS_INITIALIZED) == 0) {
- // Class initialization can call arbitrary functions, we need to wipe aliasing values.
- HandleInvokeOrClInitOrAcquireOp(mir);
- }
- uint16_t type = SPutMemAccessType(static_cast<Instruction::Code>(opcode));
- if (!field_info.IsResolved()) {
- // Unresolved fields always alias with everything of the same type.
- // Use mir->offset as modifier; without elaborate inlining, it will be unique.
- unresolved_sfield_version_[type] =
- gvn_->LookupValue(kUnresolvedSFieldOp, kNoValue, kNoValue, mir->offset);
- RemoveSFieldsForType(type);
- } else if (field_info.IsVolatile()) {
- // Nothing to do, resolved volatile fields always get a new memory version anyway and
- // can't alias with resolved non-volatile fields.
- } else {
- uint16_t field_id = gvn_->GetSFieldId(mir);
- uint16_t value = (opcode == Instruction::SPUT_WIDE)
- ? GetOperandValueWide(mir->ssa_rep->uses[0])
- : GetOperandValue(mir->ssa_rep->uses[0]);
- // Resolved non-volatile static fields can alias with non-resolved fields of the same type,
- // so we need to use unresolved_sfield_version_[type] in addition to global_memory_version_
- // to determine the version of the field.
- auto lb = sfield_value_map_.lower_bound(field_id);
- if (lb != sfield_value_map_.end() && lb->first == field_id) {
- if (lb->second == value) {
- // This SPUT can be eliminated, it stores the same value that's already in the field.
- // TODO: Eliminate the SPUT.
- return;
- }
- lb->second = value; // Overwrite.
- } else {
- sfield_value_map_.PutBefore(lb, field_id, value);
- }
- }
-}
-
-void LocalValueNumbering::RemoveSFieldsForType(uint16_t type) {
- // Erase all static fields of this type from the sfield_value_map_.
- for (auto it = sfield_value_map_.begin(), end = sfield_value_map_.end(); it != end; ) {
- if (gvn_->GetSFieldType(it->first) == type) {
- it = sfield_value_map_.erase(it);
- } else {
- ++it;
- }
- }
-}
-
-void LocalValueNumbering::HandleInvokeOrClInitOrAcquireOp(MIR* mir) {
- // Use mir->offset as modifier; without elaborate inlining, it will be unique.
- global_memory_version_ =
- gvn_->LookupValue(kInvokeMemoryVersionBumpOp, 0u, 0u, mir->offset);
- // All static fields and instance fields and array elements of aliasing references,
- // including escaped references, may have been modified.
- sfield_value_map_.clear();
- aliasing_ifield_value_map_.clear();
- aliasing_array_value_map_.clear();
- escaped_refs_.clear();
- escaped_ifield_clobber_set_.clear();
- escaped_array_clobber_set_.clear();
-}
-
-uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
- uint16_t res = kNoValue;
- uint16_t opcode = mir->dalvikInsn.opcode;
- switch (opcode) {
- case Instruction::NOP:
- case Instruction::RETURN_VOID:
- case Instruction::RETURN:
- case Instruction::RETURN_OBJECT:
- case Instruction::RETURN_WIDE:
- case Instruction::GOTO:
- case Instruction::GOTO_16:
- case Instruction::GOTO_32:
- case Instruction::THROW:
- case Instruction::FILL_ARRAY_DATA:
- case Instruction::PACKED_SWITCH:
- case Instruction::SPARSE_SWITCH:
- case Instruction::IF_EQ:
- case Instruction::IF_NE:
- case Instruction::IF_LT:
- case Instruction::IF_GE:
- case Instruction::IF_GT:
- case Instruction::IF_LE:
- case Instruction::IF_EQZ:
- case Instruction::IF_NEZ:
- case Instruction::IF_LTZ:
- case Instruction::IF_GEZ:
- case Instruction::IF_GTZ:
- case Instruction::IF_LEZ:
- case kMirOpFusedCmplFloat:
- case kMirOpFusedCmpgFloat:
- case kMirOpFusedCmplDouble:
- case kMirOpFusedCmpgDouble:
- case kMirOpFusedCmpLong:
- // Nothing defined - take no action.
- break;
-
- case Instruction::MONITOR_ENTER:
- HandleNullCheck(mir, GetOperandValue(mir->ssa_rep->uses[0]));
- HandleInvokeOrClInitOrAcquireOp(mir); // Acquire operation.
- break;
-
- case Instruction::MONITOR_EXIT:
- HandleNullCheck(mir, GetOperandValue(mir->ssa_rep->uses[0]));
- // If we're running GVN and CanModify(), uneliminated null check indicates bytecode error.
- if ((mir->optimization_flags & MIR_IGNORE_NULL_CHECK) == 0 &&
- gvn_->work_lvn_ != nullptr && gvn_->CanModify()) {
- LOG(WARNING) << "Bytecode error: MONITOR_EXIT is still null checked at 0x" << std::hex
- << mir->offset << " in " << PrettyMethod(gvn_->cu_->method_idx, *gvn_->cu_->dex_file);
- }
- break;
-
- case Instruction::FILLED_NEW_ARRAY:
- case Instruction::FILLED_NEW_ARRAY_RANGE:
- // Nothing defined but the result will be unique and non-null.
- if (mir->next != nullptr && mir->next->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT) {
- uint16_t array = MarkNonAliasingNonNull(mir->next);
- // Do not SetOperandValue(), we'll do that when we process the MOVE_RESULT_OBJECT.
- if (kLocalValueNumberingEnableFilledNewArrayTracking && mir->ssa_rep->num_uses != 0u) {
- AliasingValues* values = GetAliasingValues(&non_aliasing_array_value_map_, array);
- // Clear the value if we got a merged version in a loop.
- *values = AliasingValues(this);
- for (size_t i = 0u, count = mir->ssa_rep->num_uses; i != count; ++i) {
- DCHECK_EQ(High16Bits(i), 0u);
- uint16_t index = gvn_->LookupValue(Instruction::CONST, i, 0u, 0);
- uint16_t value = GetOperandValue(mir->ssa_rep->uses[i]);
- values->load_value_map.Put(index, value);
- RangeCheckKey key = { array, index };
- range_checked_.insert(key);
- }
- }
- // The MOVE_RESULT_OBJECT will be processed next and we'll return the value name then.
- }
- // All args escaped (if references).
- for (size_t i = 0u, count = mir->ssa_rep->num_uses; i != count; ++i) {
- uint16_t reg = GetOperandValue(mir->ssa_rep->uses[i]);
- HandleEscapingRef(reg);
- }
- break;
-
- case kMirOpNullCheck:
- HandleNullCheck(mir, GetOperandValue(mir->ssa_rep->uses[0]));
- break;
-
- case Instruction::INVOKE_DIRECT:
- case Instruction::INVOKE_DIRECT_RANGE:
- case Instruction::INVOKE_VIRTUAL:
- case Instruction::INVOKE_VIRTUAL_RANGE:
- case Instruction::INVOKE_SUPER:
- case Instruction::INVOKE_SUPER_RANGE:
- case Instruction::INVOKE_INTERFACE:
- case Instruction::INVOKE_INTERFACE_RANGE: {
- // Nothing defined but handle the null check.
- uint16_t reg = GetOperandValue(mir->ssa_rep->uses[0]);
- HandleNullCheck(mir, reg);
- }
- FALLTHROUGH_INTENDED;
- case Instruction::INVOKE_STATIC:
- case Instruction::INVOKE_STATIC_RANGE:
- // Make ref args aliasing.
- HandleInvokeArgs(mir, this);
- HandleInvokeOrClInitOrAcquireOp(mir);
- break;
-
- case Instruction::INSTANCE_OF: {
- uint16_t operand = GetOperandValue(mir->ssa_rep->uses[0]);
- uint16_t type = mir->dalvikInsn.vC;
- res = gvn_->LookupValue(Instruction::INSTANCE_OF, operand, type, kNoValue);
- SetOperandValue(mir->ssa_rep->defs[0], res);
- }
- break;
- case Instruction::CHECK_CAST:
- if (gvn_->CanModify()) {
- // Check if there was an instance-of operation on the same value and if we are
- // in a block where its result is true. If so, we can eliminate the check-cast.
- uint16_t operand = GetOperandValue(mir->ssa_rep->uses[0]);
- uint16_t type = mir->dalvikInsn.vB;
- uint16_t cond = gvn_->FindValue(Instruction::INSTANCE_OF, operand, type, kNoValue);
- if (cond != kNoValue && gvn_->IsTrueInBlock(cond, Id())) {
- if (gvn_->GetCompilationUnit()->verbose) {
- LOG(INFO) << "Removing check-cast at 0x" << std::hex << mir->offset;
- }
- // Don't use kMirOpNop. Keep the check-cast as it defines the type of the register.
- mir->optimization_flags |= MIR_IGNORE_CHECK_CAST;
- }
- }
- break;
-
- case Instruction::MOVE_RESULT:
- case Instruction::MOVE_RESULT_OBJECT:
- // 1 result, treat as unique each time, use result s_reg - will be unique.
- res = GetOperandValue(mir->ssa_rep->defs[0]);
- SetOperandValue(mir->ssa_rep->defs[0], res);
- break;
- case Instruction::MOVE_EXCEPTION:
- case Instruction::NEW_INSTANCE:
- case Instruction::NEW_ARRAY:
- // 1 result, treat as unique each time, use result s_reg - will be unique.
- res = MarkNonAliasingNonNull(mir);
- SetOperandValue(mir->ssa_rep->defs[0], res);
- break;
- case Instruction::CONST_CLASS:
- DCHECK_EQ(Low16Bits(mir->dalvikInsn.vB), mir->dalvikInsn.vB);
- res = gvn_->LookupValue(Instruction::CONST_CLASS, mir->dalvikInsn.vB, 0, 0);
- SetOperandValue(mir->ssa_rep->defs[0], res);
- null_checked_.insert(res);
- non_aliasing_refs_.insert(res);
- break;
- case Instruction::CONST_STRING:
- case Instruction::CONST_STRING_JUMBO:
- // These strings are internalized, so assign value based on the string pool index.
- res = gvn_->LookupValue(Instruction::CONST_STRING, Low16Bits(mir->dalvikInsn.vB),
- High16Bits(mir->dalvikInsn.vB), 0);
- SetOperandValue(mir->ssa_rep->defs[0], res);
- null_checked_.insert(res); // May already be there.
- // NOTE: Hacking the contents of an internalized string via reflection is possible
- // but the behavior is undefined. Therefore, we consider the string constant and
- // the reference non-aliasing.
- // TUNING: We could keep this property even if the reference "escapes".
- non_aliasing_refs_.insert(res); // May already be there.
- break;
- case Instruction::MOVE_RESULT_WIDE:
- // 1 wide result, treat as unique each time, use result s_reg - will be unique.
- res = GetOperandValueWide(mir->ssa_rep->defs[0]);
- SetOperandValueWide(mir->ssa_rep->defs[0], res);
- break;
-
- case kMirOpPhi:
- res = HandlePhi(mir);
- break;
-
- case Instruction::MOVE:
- case Instruction::MOVE_OBJECT:
- case Instruction::MOVE_16:
- case Instruction::MOVE_OBJECT_16:
- case Instruction::MOVE_FROM16:
- case Instruction::MOVE_OBJECT_FROM16:
- case kMirOpCopy:
- // Just copy value number of source to value number of result.
- res = GetOperandValue(mir->ssa_rep->uses[0]);
- SetOperandValue(mir->ssa_rep->defs[0], res);
- break;
-
- case Instruction::MOVE_WIDE:
- case Instruction::MOVE_WIDE_16:
- case Instruction::MOVE_WIDE_FROM16:
- // Just copy value number of source to value number of result.
- res = GetOperandValueWide(mir->ssa_rep->uses[0]);
- SetOperandValueWide(mir->ssa_rep->defs[0], res);
- break;
-
- case Instruction::CONST_HIGH16:
- res = HandleConst(mir, mir->dalvikInsn.vB << 16);
- break;
- case Instruction::CONST:
- case Instruction::CONST_4:
- case Instruction::CONST_16:
- res = HandleConst(mir, mir->dalvikInsn.vB);
- break;
-
- case Instruction::CONST_WIDE_16:
- case Instruction::CONST_WIDE_32:
- res = HandleConstWide(
- mir,
- mir->dalvikInsn.vB +
- ((mir->dalvikInsn.vB & 0x80000000) != 0 ? UINT64_C(0xffffffff00000000) : 0u));
- break;
-
- case Instruction::CONST_WIDE:
- res = HandleConstWide(mir, mir->dalvikInsn.vB_wide);
- break;
-
- case Instruction::CONST_WIDE_HIGH16:
- res = HandleConstWide(mir, static_cast<uint64_t>(mir->dalvikInsn.vB) << 48);
- break;
-
- case Instruction::ARRAY_LENGTH: {
- // Handle the null check.
- uint16_t reg = GetOperandValue(mir->ssa_rep->uses[0]);
- HandleNullCheck(mir, reg);
- }
- FALLTHROUGH_INTENDED;
- case Instruction::NEG_INT:
- case Instruction::NOT_INT:
- case Instruction::NEG_FLOAT:
- case Instruction::INT_TO_BYTE:
- case Instruction::INT_TO_SHORT:
- case Instruction::INT_TO_CHAR:
- case Instruction::INT_TO_FLOAT:
- case Instruction::FLOAT_TO_INT: {
- // res = op + 1 operand
- uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
- res = gvn_->LookupValue(opcode, operand1, kNoValue, kNoValue);
- SetOperandValue(mir->ssa_rep->defs[0], res);
- }
- break;
-
- case Instruction::LONG_TO_FLOAT:
- case Instruction::LONG_TO_INT:
- case Instruction::DOUBLE_TO_FLOAT:
- case Instruction::DOUBLE_TO_INT: {
- // res = op + 1 wide operand
- uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
- res = gvn_->LookupValue(opcode, operand1, kNoValue, kNoValue);
- SetOperandValue(mir->ssa_rep->defs[0], res);
- }
- break;
-
- case Instruction::DOUBLE_TO_LONG:
- case Instruction::LONG_TO_DOUBLE:
- case Instruction::NEG_LONG:
- case Instruction::NOT_LONG:
- case Instruction::NEG_DOUBLE: {
- // wide res = op + 1 wide operand
- uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
- res = gvn_->LookupValue(opcode, operand1, kNoValue, kNoValue);
- SetOperandValueWide(mir->ssa_rep->defs[0], res);
- }
- break;
-
- case Instruction::FLOAT_TO_DOUBLE:
- case Instruction::FLOAT_TO_LONG:
- case Instruction::INT_TO_DOUBLE:
- case Instruction::INT_TO_LONG: {
- // wide res = op + 1 operand
- uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
- res = gvn_->LookupValue(opcode, operand1, kNoValue, kNoValue);
- SetOperandValueWide(mir->ssa_rep->defs[0], res);
- }
- break;
-
- case Instruction::CMPL_DOUBLE:
- case Instruction::CMPG_DOUBLE:
- case Instruction::CMP_LONG: {
- // res = op + 2 wide operands
- uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
- uint16_t operand2 = GetOperandValueWide(mir->ssa_rep->uses[2]);
- res = gvn_->LookupValue(opcode, operand1, operand2, kNoValue);
- SetOperandValue(mir->ssa_rep->defs[0], res);
- }
- break;
-
- case Instruction::DIV_INT:
- case Instruction::DIV_INT_2ADDR:
- case Instruction::REM_INT:
- case Instruction::REM_INT_2ADDR:
- HandleDivZeroCheck(mir, GetOperandValue(mir->ssa_rep->uses[1]));
- FALLTHROUGH_INTENDED;
-
- case Instruction::CMPG_FLOAT:
- case Instruction::CMPL_FLOAT:
- case Instruction::ADD_INT:
- case Instruction::ADD_INT_2ADDR:
- case Instruction::MUL_INT:
- case Instruction::MUL_INT_2ADDR:
- case Instruction::AND_INT:
- case Instruction::AND_INT_2ADDR:
- case Instruction::OR_INT:
- case Instruction::OR_INT_2ADDR:
- case Instruction::XOR_INT:
- case Instruction::XOR_INT_2ADDR:
- case Instruction::SUB_INT:
- case Instruction::SUB_INT_2ADDR:
- case Instruction::SHL_INT:
- case Instruction::SHL_INT_2ADDR:
- case Instruction::SHR_INT:
- case Instruction::SHR_INT_2ADDR:
- case Instruction::USHR_INT:
- case Instruction::USHR_INT_2ADDR: {
- // res = op + 2 operands
- uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
- uint16_t operand2 = GetOperandValue(mir->ssa_rep->uses[1]);
- res = gvn_->LookupValue(opcode, operand1, operand2, kNoValue);
- SetOperandValue(mir->ssa_rep->defs[0], res);
- }
- break;
-
- case Instruction::DIV_LONG:
- case Instruction::REM_LONG:
- case Instruction::DIV_LONG_2ADDR:
- case Instruction::REM_LONG_2ADDR:
- HandleDivZeroCheck(mir, GetOperandValueWide(mir->ssa_rep->uses[2]));
- FALLTHROUGH_INTENDED;
-
- case Instruction::ADD_LONG:
- case Instruction::SUB_LONG:
- case Instruction::MUL_LONG:
- case Instruction::AND_LONG:
- case Instruction::OR_LONG:
- case Instruction::XOR_LONG:
- case Instruction::ADD_LONG_2ADDR:
- case Instruction::SUB_LONG_2ADDR:
- case Instruction::MUL_LONG_2ADDR:
- case Instruction::AND_LONG_2ADDR:
- case Instruction::OR_LONG_2ADDR:
- case Instruction::XOR_LONG_2ADDR:
- case Instruction::ADD_DOUBLE:
- case Instruction::SUB_DOUBLE:
- case Instruction::MUL_DOUBLE:
- case Instruction::DIV_DOUBLE:
- case Instruction::REM_DOUBLE:
- case Instruction::ADD_DOUBLE_2ADDR:
- case Instruction::SUB_DOUBLE_2ADDR:
- case Instruction::MUL_DOUBLE_2ADDR:
- case Instruction::DIV_DOUBLE_2ADDR:
- case Instruction::REM_DOUBLE_2ADDR: {
- // wide res = op + 2 wide operands
- uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
- uint16_t operand2 = GetOperandValueWide(mir->ssa_rep->uses[2]);
- res = gvn_->LookupValue(opcode, operand1, operand2, kNoValue);
- SetOperandValueWide(mir->ssa_rep->defs[0], res);
- }
- break;
-
- case Instruction::SHL_LONG:
- case Instruction::SHR_LONG:
- case Instruction::USHR_LONG:
- case Instruction::SHL_LONG_2ADDR:
- case Instruction::SHR_LONG_2ADDR:
- case Instruction::USHR_LONG_2ADDR: {
- // wide res = op + 1 wide operand + 1 operand
- uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
- uint16_t operand2 = GetOperandValue(mir->ssa_rep->uses[2]);
- res = gvn_->LookupValue(opcode, operand1, operand2, kNoValue);
- SetOperandValueWide(mir->ssa_rep->defs[0], res);
- }
- break;
-
- case Instruction::ADD_FLOAT:
- case Instruction::SUB_FLOAT:
- case Instruction::MUL_FLOAT:
- case Instruction::DIV_FLOAT:
- case Instruction::REM_FLOAT:
- case Instruction::ADD_FLOAT_2ADDR:
- case Instruction::SUB_FLOAT_2ADDR:
- case Instruction::MUL_FLOAT_2ADDR:
- case Instruction::DIV_FLOAT_2ADDR:
- case Instruction::REM_FLOAT_2ADDR: {
- // res = op + 2 operands
- uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
- uint16_t operand2 = GetOperandValue(mir->ssa_rep->uses[1]);
- res = gvn_->LookupValue(opcode, operand1, operand2, kNoValue);
- SetOperandValue(mir->ssa_rep->defs[0], res);
- }
- break;
-
- case Instruction::RSUB_INT:
- case Instruction::ADD_INT_LIT16:
- case Instruction::MUL_INT_LIT16:
- case Instruction::DIV_INT_LIT16:
- case Instruction::REM_INT_LIT16:
- case Instruction::AND_INT_LIT16:
- case Instruction::OR_INT_LIT16:
- case Instruction::XOR_INT_LIT16:
- case Instruction::ADD_INT_LIT8:
- case Instruction::RSUB_INT_LIT8:
- case Instruction::MUL_INT_LIT8:
- case Instruction::DIV_INT_LIT8:
- case Instruction::REM_INT_LIT8:
- case Instruction::AND_INT_LIT8:
- case Instruction::OR_INT_LIT8:
- case Instruction::XOR_INT_LIT8:
- case Instruction::SHL_INT_LIT8:
- case Instruction::SHR_INT_LIT8:
- case Instruction::USHR_INT_LIT8: {
- // Same as res = op + 2 operands, except use vC as operand 2
- uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
- uint16_t operand2 = gvn_->LookupValue(Instruction::CONST, mir->dalvikInsn.vC, 0, 0);
- res = gvn_->LookupValue(opcode, operand1, operand2, kNoValue);
- SetOperandValue(mir->ssa_rep->defs[0], res);
- }
- break;
-
- case Instruction::AGET_OBJECT:
- case Instruction::AGET:
- case Instruction::AGET_WIDE:
- case Instruction::AGET_BOOLEAN:
- case Instruction::AGET_BYTE:
- case Instruction::AGET_CHAR:
- case Instruction::AGET_SHORT:
- res = HandleAGet(mir, opcode);
- break;
-
- case Instruction::APUT_OBJECT:
- HandlePutObject(mir);
- FALLTHROUGH_INTENDED;
- case Instruction::APUT:
- case Instruction::APUT_WIDE:
- case Instruction::APUT_BYTE:
- case Instruction::APUT_BOOLEAN:
- case Instruction::APUT_SHORT:
- case Instruction::APUT_CHAR:
- HandleAPut(mir, opcode);
- break;
-
- case Instruction::IGET_OBJECT:
- case Instruction::IGET:
- case Instruction::IGET_WIDE:
- case Instruction::IGET_BOOLEAN:
- case Instruction::IGET_BYTE:
- case Instruction::IGET_CHAR:
- case Instruction::IGET_SHORT:
- res = HandleIGet(mir, opcode);
- break;
-
- case Instruction::IPUT_OBJECT:
- HandlePutObject(mir);
- FALLTHROUGH_INTENDED;
- case Instruction::IPUT:
- case Instruction::IPUT_WIDE:
- case Instruction::IPUT_BOOLEAN:
- case Instruction::IPUT_BYTE:
- case Instruction::IPUT_CHAR:
- case Instruction::IPUT_SHORT:
- HandleIPut(mir, opcode);
- break;
-
- case Instruction::SGET_OBJECT:
- case Instruction::SGET:
- case Instruction::SGET_WIDE:
- case Instruction::SGET_BOOLEAN:
- case Instruction::SGET_BYTE:
- case Instruction::SGET_CHAR:
- case Instruction::SGET_SHORT:
- res = HandleSGet(mir, opcode);
- break;
-
- case Instruction::SPUT_OBJECT:
- HandlePutObject(mir);
- FALLTHROUGH_INTENDED;
- case Instruction::SPUT:
- case Instruction::SPUT_WIDE:
- case Instruction::SPUT_BOOLEAN:
- case Instruction::SPUT_BYTE:
- case Instruction::SPUT_CHAR:
- case Instruction::SPUT_SHORT:
- HandleSPut(mir, opcode);
- break;
- }
- return res;
-}
-
-uint16_t LocalValueNumbering::GetEndingVregValueNumberImpl(int v_reg, bool wide) const {
- const BasicBlock* bb = gvn_->GetBasicBlock(Id());
- DCHECK(bb != nullptr);
- int s_reg = bb->data_flow_info->vreg_to_ssa_map_exit[v_reg];
- if (s_reg == INVALID_SREG) {
- return kNoValue;
- }
- if (gvn_->GetMirGraph()->GetRegLocation(s_reg).wide != wide) {
- return kNoValue;
- }
- if (wide) {
- int high_s_reg = bb->data_flow_info->vreg_to_ssa_map_exit[v_reg + 1];
- if (high_s_reg != s_reg + 1) {
- return kNoValue; // High word has been overwritten.
- }
- return GetSregValueWide(s_reg);
- } else {
- return GetSregValue(s_reg);
- }
-}
-
-uint16_t LocalValueNumbering::GetStartingVregValueNumberImpl(int v_reg, bool wide) const {
- DCHECK_EQ(gvn_->mode_, GlobalValueNumbering::kModeGvnPostProcessing);
- DCHECK(gvn_->CanModify());
- const BasicBlock* bb = gvn_->GetBasicBlock(Id());
- DCHECK(bb != nullptr);
- DCHECK_NE(bb->predecessors.size(), 0u);
- if (bb->predecessors.size() == 1u) {
- return gvn_->GetLvn(bb->predecessors[0])->GetEndingVregValueNumberImpl(v_reg, wide);
- }
- merge_names_.clear();
- uint16_t value_name = kNoValue;
- bool same_values = true;
- for (BasicBlockId pred_id : bb->predecessors) {
- value_name = gvn_->GetLvn(pred_id)->GetEndingVregValueNumberImpl(v_reg, wide);
- if (value_name == kNoValue) {
- return kNoValue;
- }
- same_values = same_values && (merge_names_.empty() || value_name == merge_names_.back());
- merge_names_.push_back(value_name);
- }
- if (same_values) {
- // value_name already contains the result.
- } else {
- auto lb = merge_map_.lower_bound(merge_names_);
- if (lb != merge_map_.end() && !merge_map_.key_comp()(merge_names_, lb->first)) {
- value_name = lb->second;
- } else {
- value_name = kNoValue; // We never assigned a value name to this set of merged names.
- }
- }
- return value_name;
-}
-
-} // namespace art