summaryrefslogtreecommitdiff
path: root/compiler/dex/local_value_numbering.cc
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/dex/local_value_numbering.cc')
-rw-r--r--compiler/dex/local_value_numbering.cc69
1 files changed, 60 insertions, 9 deletions
diff --git a/compiler/dex/local_value_numbering.cc b/compiler/dex/local_value_numbering.cc
index c1ce2ac016..854759b430 100644
--- a/compiler/dex/local_value_numbering.cc
+++ b/compiler/dex/local_value_numbering.cc
@@ -339,6 +339,7 @@ LocalValueNumbering::LocalValueNumbering(GlobalValueNumbering* gvn, uint16_t id,
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) {
@@ -362,7 +363,8 @@ bool LocalValueNumbering::Equals(const LocalValueNumbering& other) const {
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_;
+ null_checked_ == other.null_checked_ &&
+ div_zero_checked_ == other.div_zero_checked_;
}
void LocalValueNumbering::MergeOne(const LocalValueNumbering& other, MergeType merge_type) {
@@ -379,6 +381,7 @@ void LocalValueNumbering::MergeOne(const LocalValueNumbering& other, MergeType m
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())) {
@@ -699,6 +702,28 @@ void LocalValueNumbering::MergeNullChecked() {
}
}
+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;
@@ -931,6 +956,9 @@ void LocalValueNumbering::Merge(MergeType merge_type) {
// 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;
@@ -1054,6 +1082,20 @@ void LocalValueNumbering::HandleRangeCheck(MIR* mir, uint16_t array, uint16_t in
}
}
+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]);
@@ -1139,6 +1181,9 @@ uint16_t LocalValueNumbering::HandlePhi(MIR* mir) {
if (!wide && gvn_->NullCheckedInAllPredecessors(merge_names_)) {
null_checked_.insert(value_name);
}
+ if (gvn_->DivZeroCheckedInAllPredecessors(merge_names_)) {
+ div_zero_checked_.insert(value_name);
+ }
}
}
if (wide) {
@@ -1696,6 +1741,13 @@ uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
}
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:
@@ -1710,10 +1762,6 @@ uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
case Instruction::XOR_INT_2ADDR:
case Instruction::SUB_INT:
case Instruction::SUB_INT_2ADDR:
- case Instruction::DIV_INT:
- case Instruction::DIV_INT_2ADDR:
- case Instruction::REM_INT:
- case Instruction::REM_INT_2ADDR:
case Instruction::SHL_INT:
case Instruction::SHL_INT_2ADDR:
case Instruction::SHR_INT:
@@ -1728,19 +1776,22 @@ uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
}
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::DIV_LONG:
- case Instruction::REM_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::DIV_LONG_2ADDR:
- case Instruction::REM_LONG_2ADDR:
case Instruction::AND_LONG_2ADDR:
case Instruction::OR_LONG_2ADDR:
case Instruction::XOR_LONG_2ADDR: