blob: a8fd8122ff1a37d4ba9780b510ddbb7f94bb516d [file] [log] [blame]
Vladimir Marko95a05972014-05-30 10:01:32 +01001/*
2 * Copyright (C) 2014 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
17#include "global_value_numbering.h"
Andreas Gampe0b9203e2015-01-22 20:39:27 -080018
19#include "base/stl_util.h"
Vladimir Marko95a05972014-05-30 10:01:32 +010020#include "local_value_numbering.h"
21
22namespace art {
23
Vladimir Marko415ac882014-09-30 18:09:14 +010024GlobalValueNumbering::GlobalValueNumbering(CompilationUnit* cu, ScopedArenaAllocator* allocator,
25 Mode mode)
Vladimir Marko95a05972014-05-30 10:01:32 +010026 : cu_(cu),
Vladimir Marko55fff042014-07-10 12:42:52 +010027 mir_graph_(cu->mir_graph.get()),
Vladimir Marko95a05972014-05-30 10:01:32 +010028 allocator_(allocator),
Vladimir Marko55fff042014-07-10 12:42:52 +010029 bbs_processed_(0u),
30 max_bbs_to_process_(kMaxBbsToProcessMultiplyFactor * mir_graph_->GetNumReachableBlocks()),
Vladimir Marko95a05972014-05-30 10:01:32 +010031 last_value_(0u),
Vladimir Marko415ac882014-09-30 18:09:14 +010032 modifications_allowed_(true),
33 mode_(mode),
Vladimir Marko95a05972014-05-30 10:01:32 +010034 global_value_map_(std::less<uint64_t>(), allocator->Adapter()),
Vladimir Marko95a05972014-05-30 10:01:32 +010035 array_location_map_(ArrayLocationComparator(), allocator->Adapter()),
36 array_location_reverse_map_(allocator->Adapter()),
37 ref_set_map_(std::less<ValueNameSet>(), allocator->Adapter()),
Vladimir Marko55fff042014-07-10 12:42:52 +010038 lvns_(mir_graph_->GetNumBlocks(), nullptr, allocator->Adapter()),
Vladimir Marko95a05972014-05-30 10:01:32 +010039 work_lvn_(nullptr),
40 merge_lvns_(allocator->Adapter()) {
Vladimir Marko95a05972014-05-30 10:01:32 +010041}
42
43GlobalValueNumbering::~GlobalValueNumbering() {
44 STLDeleteElements(&lvns_);
45}
46
Vladimir Markob19955d2014-07-29 12:04:10 +010047LocalValueNumbering* GlobalValueNumbering::PrepareBasicBlock(BasicBlock* bb,
48 ScopedArenaAllocator* allocator) {
Vladimir Marko95a05972014-05-30 10:01:32 +010049 if (UNLIKELY(!Good())) {
50 return nullptr;
51 }
Vladimir Marko415ac882014-09-30 18:09:14 +010052 if (bb->block_type != kDalvikByteCode && bb->block_type != kEntryBlock) {
Vladimir Marko95a05972014-05-30 10:01:32 +010053 DCHECK(bb->first_mir_insn == nullptr);
54 return nullptr;
55 }
Vladimir Marko415ac882014-09-30 18:09:14 +010056 if (mode_ == kModeGvn && UNLIKELY(bbs_processed_ == max_bbs_to_process_)) {
Vladimir Marko2d2365c2014-08-19 18:08:39 +010057 // If we're still trying to converge, stop now. Otherwise, proceed to apply optimizations.
Vladimir Marko415ac882014-09-30 18:09:14 +010058 last_value_ = kNoValue; // Make bad.
59 return nullptr;
60 }
61 if (mode_ == kModeGvnPostProcessing &&
62 mir_graph_->GetTopologicalSortOrderLoopHeadStack()->empty()) {
63 // Modifications outside loops are performed during the main phase.
64 return nullptr;
Vladimir Marko95a05972014-05-30 10:01:32 +010065 }
Vladimir Markob19955d2014-07-29 12:04:10 +010066 if (allocator == nullptr) {
67 allocator = allocator_;
68 }
Vladimir Marko95a05972014-05-30 10:01:32 +010069 DCHECK(work_lvn_.get() == nullptr);
Vladimir Markob19955d2014-07-29 12:04:10 +010070 work_lvn_.reset(new (allocator) LocalValueNumbering(this, bb->id, allocator));
Vladimir Marko95a05972014-05-30 10:01:32 +010071 if (bb->block_type == kEntryBlock) {
Vladimir Markoa4426cf2014-10-22 17:15:53 +010072 work_lvn_->PrepareEntryBlock();
Vladimir Marko415ac882014-09-30 18:09:14 +010073 DCHECK(bb->first_mir_insn == nullptr); // modifications_allowed_ is irrelevant.
Vladimir Marko95a05972014-05-30 10:01:32 +010074 } else {
Vladimir Marko95a05972014-05-30 10:01:32 +010075 // To avoid repeated allocation on the ArenaStack, reuse a single vector kept as a member.
76 DCHECK(merge_lvns_.empty());
Vladimir Marko55fff042014-07-10 12:42:52 +010077 // If we're running the full GVN, the RepeatingTopologicalSortIterator keeps the loop
78 // head stack in the MIRGraph up to date and for a loop head we need to check whether
79 // we're making the initial computation and need to merge only preceding blocks in the
80 // topological order, or we're recalculating a loop head and need to merge all incoming
81 // LVNs. When we're not at a loop head (including having an empty loop head stack) all
82 // predecessors should be preceding blocks and we shall merge all of them anyway.
Vladimir Marko55fff042014-07-10 12:42:52 +010083 bool use_all_predecessors = true;
84 uint16_t loop_head_idx = 0u; // Used only if !use_all_predecessors.
Vladimir Marko415ac882014-09-30 18:09:14 +010085 if (mode_ == kModeGvn && mir_graph_->GetTopologicalSortOrderLoopHeadStack()->size() != 0) {
Vladimir Marko55fff042014-07-10 12:42:52 +010086 // Full GVN inside a loop, see if we're at the loop head for the first time.
Vladimir Marko415ac882014-09-30 18:09:14 +010087 modifications_allowed_ = false;
Vladimir Markoe39c54e2014-09-22 14:50:02 +010088 auto top = mir_graph_->GetTopologicalSortOrderLoopHeadStack()->back();
Vladimir Marko55fff042014-07-10 12:42:52 +010089 loop_head_idx = top.first;
90 bool recalculating = top.second;
91 use_all_predecessors = recalculating ||
Vladimir Markoe39c54e2014-09-22 14:50:02 +010092 loop_head_idx != mir_graph_->GetTopologicalSortOrderIndexes()[bb->id];
Vladimir Marko415ac882014-09-30 18:09:14 +010093 } else {
94 modifications_allowed_ = true;
Vladimir Marko55fff042014-07-10 12:42:52 +010095 }
Vladimir Markoe39c54e2014-09-22 14:50:02 +010096 for (BasicBlockId pred_id : bb->predecessors) {
97 DCHECK_NE(pred_id, NullBasicBlockId);
98 if (lvns_[pred_id] != nullptr &&
Vladimir Marko55fff042014-07-10 12:42:52 +010099 (use_all_predecessors ||
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100100 mir_graph_->GetTopologicalSortOrderIndexes()[pred_id] < loop_head_idx)) {
101 merge_lvns_.push_back(lvns_[pred_id]);
Vladimir Marko95a05972014-05-30 10:01:32 +0100102 }
103 }
104 // Determine merge type.
105 LocalValueNumbering::MergeType merge_type = LocalValueNumbering::kNormalMerge;
106 if (bb->catch_entry) {
107 merge_type = LocalValueNumbering::kCatchMerge;
108 } else if (bb->last_mir_insn != nullptr &&
Vladimir Marko321b9872014-11-24 16:33:51 +0000109 IsInstructionReturn(bb->last_mir_insn->dalvikInsn.opcode) &&
Vladimir Marko26e7d452014-11-24 14:09:46 +0000110 bb->GetFirstNonPhiInsn() == bb->last_mir_insn) {
Vladimir Marko95a05972014-05-30 10:01:32 +0100111 merge_type = LocalValueNumbering::kReturnMerge;
112 }
113 // At least one predecessor must have been processed before this bb.
114 CHECK(!merge_lvns_.empty());
115 if (merge_lvns_.size() == 1u) {
116 work_lvn_->MergeOne(*merge_lvns_[0], merge_type);
Vladimir Marko95a05972014-05-30 10:01:32 +0100117 } else {
118 work_lvn_->Merge(merge_type);
119 }
120 }
121 return work_lvn_.get();
122}
123
124bool GlobalValueNumbering::FinishBasicBlock(BasicBlock* bb) {
125 DCHECK(work_lvn_ != nullptr);
Vladimir Marko55fff042014-07-10 12:42:52 +0100126 DCHECK_EQ(bb->id, work_lvn_->Id());
127 ++bbs_processed_;
Vladimir Marko95a05972014-05-30 10:01:32 +0100128 merge_lvns_.clear();
129
Vladimir Markob19955d2014-07-29 12:04:10 +0100130 bool change = (lvns_[bb->id] == nullptr) || !lvns_[bb->id]->Equals(*work_lvn_);
131 if (change) {
132 std::unique_ptr<const LocalValueNumbering> old_lvn(lvns_[bb->id]);
133 lvns_[bb->id] = work_lvn_.release();
134 } else {
135 work_lvn_.reset();
136 }
137 return change;
Vladimir Marko95a05972014-05-30 10:01:32 +0100138}
139
Vladimir Marko95a05972014-05-30 10:01:32 +0100140uint16_t GlobalValueNumbering::GetArrayLocation(uint16_t base, uint16_t index) {
141 auto cmp = array_location_map_.key_comp();
142 ArrayLocation key = { base, index };
143 auto lb = array_location_map_.lower_bound(key);
144 if (lb != array_location_map_.end() && !cmp(key, lb->first)) {
145 return lb->second;
146 }
147 uint16_t location = static_cast<uint16_t>(array_location_reverse_map_.size());
148 DCHECK_EQ(location, array_location_reverse_map_.size()); // No overflow.
149 auto it = array_location_map_.PutBefore(lb, key, location);
150 array_location_reverse_map_.push_back(&*it);
151 return location;
152}
153
154bool GlobalValueNumbering::HasNullCheckLastInsn(const BasicBlock* pred_bb,
155 BasicBlockId succ_id) {
156 if (pred_bb->block_type != kDalvikByteCode || pred_bb->last_mir_insn == nullptr) {
157 return false;
158 }
159 Instruction::Code last_opcode = pred_bb->last_mir_insn->dalvikInsn.opcode;
160 return ((last_opcode == Instruction::IF_EQZ && pred_bb->fall_through == succ_id) ||
161 (last_opcode == Instruction::IF_NEZ && pred_bb->taken == succ_id));
162}
163
164bool GlobalValueNumbering::NullCheckedInAllPredecessors(
165 const ScopedArenaVector<uint16_t>& merge_names) const {
166 // Implicit parameters:
167 // - *work_lvn: the LVN for which we're checking predecessors.
168 // - merge_lvns_: the predecessor LVNs.
169 DCHECK_EQ(merge_lvns_.size(), merge_names.size());
170 for (size_t i = 0, size = merge_lvns_.size(); i != size; ++i) {
171 const LocalValueNumbering* pred_lvn = merge_lvns_[i];
172 uint16_t value_name = merge_names[i];
173 if (!pred_lvn->IsValueNullChecked(value_name)) {
174 // Check if the predecessor has an IF_EQZ/IF_NEZ as the last insn.
Vladimir Marko55fff042014-07-10 12:42:52 +0100175 const BasicBlock* pred_bb = mir_graph_->GetBasicBlock(pred_lvn->Id());
Vladimir Marko95a05972014-05-30 10:01:32 +0100176 if (!HasNullCheckLastInsn(pred_bb, work_lvn_->Id())) {
177 return false;
178 }
179 // IF_EQZ/IF_NEZ checks some sreg, see if that sreg contains the value_name.
180 int s_reg = pred_bb->last_mir_insn->ssa_rep->uses[0];
181 if (!pred_lvn->IsSregValue(s_reg, value_name)) {
182 return false;
183 }
184 }
185 }
186 return true;
187}
188
Razvan A Lupusorue0951142014-11-14 14:36:55 -0800189bool GlobalValueNumbering::DivZeroCheckedInAllPredecessors(
190 const ScopedArenaVector<uint16_t>& merge_names) const {
191 // Implicit parameters:
192 // - *work_lvn: the LVN for which we're checking predecessors.
193 // - merge_lvns_: the predecessor LVNs.
194 DCHECK_EQ(merge_lvns_.size(), merge_names.size());
195 for (size_t i = 0, size = merge_lvns_.size(); i != size; ++i) {
196 const LocalValueNumbering* pred_lvn = merge_lvns_[i];
197 uint16_t value_name = merge_names[i];
198 if (!pred_lvn->IsValueDivZeroChecked(value_name)) {
199 return false;
200 }
201 }
202 return true;
203}
204
Vladimir Marko95a05972014-05-30 10:01:32 +0100205} // namespace art