blob: dbe98506b74ec397b9d3a031e5d2aee5496f0876 [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"
Vladimir Marko95a05972014-05-30 10:01:32 +010018#include "local_value_numbering.h"
19
20namespace art {
21
Vladimir Marko415ac882014-09-30 18:09:14 +010022GlobalValueNumbering::GlobalValueNumbering(CompilationUnit* cu, ScopedArenaAllocator* allocator,
23 Mode mode)
Vladimir Marko95a05972014-05-30 10:01:32 +010024 : cu_(cu),
Vladimir Marko55fff042014-07-10 12:42:52 +010025 mir_graph_(cu->mir_graph.get()),
Vladimir Marko95a05972014-05-30 10:01:32 +010026 allocator_(allocator),
Vladimir Marko55fff042014-07-10 12:42:52 +010027 bbs_processed_(0u),
28 max_bbs_to_process_(kMaxBbsToProcessMultiplyFactor * mir_graph_->GetNumReachableBlocks()),
Vladimir Marko95a05972014-05-30 10:01:32 +010029 last_value_(0u),
Vladimir Marko415ac882014-09-30 18:09:14 +010030 modifications_allowed_(true),
31 mode_(mode),
Vladimir Marko95a05972014-05-30 10:01:32 +010032 global_value_map_(std::less<uint64_t>(), allocator->Adapter()),
Vladimir Marko95a05972014-05-30 10:01:32 +010033 array_location_map_(ArrayLocationComparator(), allocator->Adapter()),
34 array_location_reverse_map_(allocator->Adapter()),
35 ref_set_map_(std::less<ValueNameSet>(), allocator->Adapter()),
Vladimir Marko55fff042014-07-10 12:42:52 +010036 lvns_(mir_graph_->GetNumBlocks(), nullptr, allocator->Adapter()),
Vladimir Marko95a05972014-05-30 10:01:32 +010037 work_lvn_(nullptr),
38 merge_lvns_(allocator->Adapter()) {
Vladimir Marko95a05972014-05-30 10:01:32 +010039}
40
41GlobalValueNumbering::~GlobalValueNumbering() {
42 STLDeleteElements(&lvns_);
43}
44
Vladimir Markob19955d2014-07-29 12:04:10 +010045LocalValueNumbering* GlobalValueNumbering::PrepareBasicBlock(BasicBlock* bb,
46 ScopedArenaAllocator* allocator) {
Vladimir Marko95a05972014-05-30 10:01:32 +010047 if (UNLIKELY(!Good())) {
48 return nullptr;
49 }
Vladimir Marko415ac882014-09-30 18:09:14 +010050 if (bb->block_type != kDalvikByteCode && bb->block_type != kEntryBlock) {
Vladimir Marko95a05972014-05-30 10:01:32 +010051 DCHECK(bb->first_mir_insn == nullptr);
52 return nullptr;
53 }
Vladimir Marko415ac882014-09-30 18:09:14 +010054 if (mode_ == kModeGvn && UNLIKELY(bbs_processed_ == max_bbs_to_process_)) {
Vladimir Marko2d2365c2014-08-19 18:08:39 +010055 // If we're still trying to converge, stop now. Otherwise, proceed to apply optimizations.
Vladimir Marko415ac882014-09-30 18:09:14 +010056 last_value_ = kNoValue; // Make bad.
57 return nullptr;
58 }
59 if (mode_ == kModeGvnPostProcessing &&
60 mir_graph_->GetTopologicalSortOrderLoopHeadStack()->empty()) {
61 // Modifications outside loops are performed during the main phase.
62 return nullptr;
Vladimir Marko95a05972014-05-30 10:01:32 +010063 }
Vladimir Markob19955d2014-07-29 12:04:10 +010064 if (allocator == nullptr) {
65 allocator = allocator_;
66 }
Vladimir Marko95a05972014-05-30 10:01:32 +010067 DCHECK(work_lvn_.get() == nullptr);
Vladimir Markob19955d2014-07-29 12:04:10 +010068 work_lvn_.reset(new (allocator) LocalValueNumbering(this, bb->id, allocator));
Vladimir Marko95a05972014-05-30 10:01:32 +010069 if (bb->block_type == kEntryBlock) {
Vladimir Markoa4426cf2014-10-22 17:15:53 +010070 work_lvn_->PrepareEntryBlock();
Vladimir Marko415ac882014-09-30 18:09:14 +010071 DCHECK(bb->first_mir_insn == nullptr); // modifications_allowed_ is irrelevant.
Vladimir Marko95a05972014-05-30 10:01:32 +010072 } else {
Vladimir Marko95a05972014-05-30 10:01:32 +010073 // To avoid repeated allocation on the ArenaStack, reuse a single vector kept as a member.
74 DCHECK(merge_lvns_.empty());
Vladimir Marko55fff042014-07-10 12:42:52 +010075 // If we're running the full GVN, the RepeatingTopologicalSortIterator keeps the loop
76 // head stack in the MIRGraph up to date and for a loop head we need to check whether
77 // we're making the initial computation and need to merge only preceding blocks in the
78 // topological order, or we're recalculating a loop head and need to merge all incoming
79 // LVNs. When we're not at a loop head (including having an empty loop head stack) all
80 // predecessors should be preceding blocks and we shall merge all of them anyway.
Vladimir Marko55fff042014-07-10 12:42:52 +010081 bool use_all_predecessors = true;
82 uint16_t loop_head_idx = 0u; // Used only if !use_all_predecessors.
Vladimir Marko415ac882014-09-30 18:09:14 +010083 if (mode_ == kModeGvn && mir_graph_->GetTopologicalSortOrderLoopHeadStack()->size() != 0) {
Vladimir Marko55fff042014-07-10 12:42:52 +010084 // Full GVN inside a loop, see if we're at the loop head for the first time.
Vladimir Marko415ac882014-09-30 18:09:14 +010085 modifications_allowed_ = false;
Vladimir Markoe39c54e2014-09-22 14:50:02 +010086 auto top = mir_graph_->GetTopologicalSortOrderLoopHeadStack()->back();
Vladimir Marko55fff042014-07-10 12:42:52 +010087 loop_head_idx = top.first;
88 bool recalculating = top.second;
89 use_all_predecessors = recalculating ||
Vladimir Markoe39c54e2014-09-22 14:50:02 +010090 loop_head_idx != mir_graph_->GetTopologicalSortOrderIndexes()[bb->id];
Vladimir Marko415ac882014-09-30 18:09:14 +010091 } else {
92 modifications_allowed_ = true;
Vladimir Marko55fff042014-07-10 12:42:52 +010093 }
Vladimir Markoe39c54e2014-09-22 14:50:02 +010094 for (BasicBlockId pred_id : bb->predecessors) {
95 DCHECK_NE(pred_id, NullBasicBlockId);
96 if (lvns_[pred_id] != nullptr &&
Vladimir Marko55fff042014-07-10 12:42:52 +010097 (use_all_predecessors ||
Vladimir Markoe39c54e2014-09-22 14:50:02 +010098 mir_graph_->GetTopologicalSortOrderIndexes()[pred_id] < loop_head_idx)) {
99 merge_lvns_.push_back(lvns_[pred_id]);
Vladimir Marko95a05972014-05-30 10:01:32 +0100100 }
101 }
102 // Determine merge type.
103 LocalValueNumbering::MergeType merge_type = LocalValueNumbering::kNormalMerge;
104 if (bb->catch_entry) {
105 merge_type = LocalValueNumbering::kCatchMerge;
106 } else if (bb->last_mir_insn != nullptr &&
Vladimir Marko55fff042014-07-10 12:42:52 +0100107 (bb->last_mir_insn->dalvikInsn.opcode == Instruction::RETURN_VOID ||
108 bb->last_mir_insn->dalvikInsn.opcode == Instruction::RETURN ||
Vladimir Marko95a05972014-05-30 10:01:32 +0100109 bb->last_mir_insn->dalvikInsn.opcode == Instruction::RETURN_OBJECT ||
110 bb->last_mir_insn->dalvikInsn.opcode == Instruction::RETURN_WIDE) &&
111 (bb->first_mir_insn == bb->last_mir_insn ||
Vladimir Marko55fff042014-07-10 12:42:52 +0100112 (static_cast<int>(bb->first_mir_insn->dalvikInsn.opcode) == kMirOpPhi &&
113 (bb->first_mir_insn->next == bb->last_mir_insn ||
114 (static_cast<int>(bb->first_mir_insn->next->dalvikInsn.opcode) == kMirOpPhi &&
115 bb->first_mir_insn->next->next == bb->last_mir_insn))))) {
Vladimir Marko95a05972014-05-30 10:01:32 +0100116 merge_type = LocalValueNumbering::kReturnMerge;
117 }
118 // At least one predecessor must have been processed before this bb.
119 CHECK(!merge_lvns_.empty());
120 if (merge_lvns_.size() == 1u) {
121 work_lvn_->MergeOne(*merge_lvns_[0], merge_type);
Vladimir Marko95a05972014-05-30 10:01:32 +0100122 } else {
123 work_lvn_->Merge(merge_type);
124 }
125 }
126 return work_lvn_.get();
127}
128
129bool GlobalValueNumbering::FinishBasicBlock(BasicBlock* bb) {
130 DCHECK(work_lvn_ != nullptr);
Vladimir Marko55fff042014-07-10 12:42:52 +0100131 DCHECK_EQ(bb->id, work_lvn_->Id());
132 ++bbs_processed_;
Vladimir Marko95a05972014-05-30 10:01:32 +0100133 merge_lvns_.clear();
134
Vladimir Markob19955d2014-07-29 12:04:10 +0100135 bool change = (lvns_[bb->id] == nullptr) || !lvns_[bb->id]->Equals(*work_lvn_);
136 if (change) {
137 std::unique_ptr<const LocalValueNumbering> old_lvn(lvns_[bb->id]);
138 lvns_[bb->id] = work_lvn_.release();
139 } else {
140 work_lvn_.reset();
141 }
142 return change;
Vladimir Marko95a05972014-05-30 10:01:32 +0100143}
144
Vladimir Marko95a05972014-05-30 10:01:32 +0100145uint16_t GlobalValueNumbering::GetArrayLocation(uint16_t base, uint16_t index) {
146 auto cmp = array_location_map_.key_comp();
147 ArrayLocation key = { base, index };
148 auto lb = array_location_map_.lower_bound(key);
149 if (lb != array_location_map_.end() && !cmp(key, lb->first)) {
150 return lb->second;
151 }
152 uint16_t location = static_cast<uint16_t>(array_location_reverse_map_.size());
153 DCHECK_EQ(location, array_location_reverse_map_.size()); // No overflow.
154 auto it = array_location_map_.PutBefore(lb, key, location);
155 array_location_reverse_map_.push_back(&*it);
156 return location;
157}
158
159bool GlobalValueNumbering::HasNullCheckLastInsn(const BasicBlock* pred_bb,
160 BasicBlockId succ_id) {
161 if (pred_bb->block_type != kDalvikByteCode || pred_bb->last_mir_insn == nullptr) {
162 return false;
163 }
164 Instruction::Code last_opcode = pred_bb->last_mir_insn->dalvikInsn.opcode;
165 return ((last_opcode == Instruction::IF_EQZ && pred_bb->fall_through == succ_id) ||
166 (last_opcode == Instruction::IF_NEZ && pred_bb->taken == succ_id));
167}
168
169bool GlobalValueNumbering::NullCheckedInAllPredecessors(
170 const ScopedArenaVector<uint16_t>& merge_names) const {
171 // Implicit parameters:
172 // - *work_lvn: the LVN for which we're checking predecessors.
173 // - merge_lvns_: the predecessor LVNs.
174 DCHECK_EQ(merge_lvns_.size(), merge_names.size());
175 for (size_t i = 0, size = merge_lvns_.size(); i != size; ++i) {
176 const LocalValueNumbering* pred_lvn = merge_lvns_[i];
177 uint16_t value_name = merge_names[i];
178 if (!pred_lvn->IsValueNullChecked(value_name)) {
179 // Check if the predecessor has an IF_EQZ/IF_NEZ as the last insn.
Vladimir Marko55fff042014-07-10 12:42:52 +0100180 const BasicBlock* pred_bb = mir_graph_->GetBasicBlock(pred_lvn->Id());
Vladimir Marko95a05972014-05-30 10:01:32 +0100181 if (!HasNullCheckLastInsn(pred_bb, work_lvn_->Id())) {
182 return false;
183 }
184 // IF_EQZ/IF_NEZ checks some sreg, see if that sreg contains the value_name.
185 int s_reg = pred_bb->last_mir_insn->ssa_rep->uses[0];
186 if (!pred_lvn->IsSregValue(s_reg, value_name)) {
187 return false;
188 }
189 }
190 }
191 return true;
192}
193
194} // namespace art