blob: ab3c946897c0b9d92b82274ad8e68cb651cdd41c [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 Marko7a01dc22015-01-02 17:00:44 +000031 last_value_(kNullValue),
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_);
Vladimir Marko7a01dc22015-01-02 17:00:44 +0000131 if (mode_ == kModeGvn) {
132 // In GVN mode, keep the latest LVN even if Equals() indicates no change. This is
133 // to keep the correct values of fields that do not contribute to Equals() as long
134 // as they depend only on predecessor LVNs' fields that do contribute to Equals().
135 // Currently, that's LVN::merge_map_ used by LVN::GetStartingVregValueNumberImpl().
Vladimir Markob19955d2014-07-29 12:04:10 +0100136 std::unique_ptr<const LocalValueNumbering> old_lvn(lvns_[bb->id]);
137 lvns_[bb->id] = work_lvn_.release();
138 } else {
139 work_lvn_.reset();
140 }
141 return change;
Vladimir Marko95a05972014-05-30 10:01:32 +0100142}
143
Vladimir Marko95a05972014-05-30 10:01:32 +0100144uint16_t GlobalValueNumbering::GetArrayLocation(uint16_t base, uint16_t index) {
145 auto cmp = array_location_map_.key_comp();
146 ArrayLocation key = { base, index };
147 auto lb = array_location_map_.lower_bound(key);
148 if (lb != array_location_map_.end() && !cmp(key, lb->first)) {
149 return lb->second;
150 }
151 uint16_t location = static_cast<uint16_t>(array_location_reverse_map_.size());
152 DCHECK_EQ(location, array_location_reverse_map_.size()); // No overflow.
153 auto it = array_location_map_.PutBefore(lb, key, location);
154 array_location_reverse_map_.push_back(&*it);
155 return location;
156}
157
158bool GlobalValueNumbering::HasNullCheckLastInsn(const BasicBlock* pred_bb,
159 BasicBlockId succ_id) {
160 if (pred_bb->block_type != kDalvikByteCode || pred_bb->last_mir_insn == nullptr) {
161 return false;
162 }
163 Instruction::Code last_opcode = pred_bb->last_mir_insn->dalvikInsn.opcode;
164 return ((last_opcode == Instruction::IF_EQZ && pred_bb->fall_through == succ_id) ||
165 (last_opcode == Instruction::IF_NEZ && pred_bb->taken == succ_id));
166}
167
168bool GlobalValueNumbering::NullCheckedInAllPredecessors(
169 const ScopedArenaVector<uint16_t>& merge_names) const {
170 // Implicit parameters:
171 // - *work_lvn: the LVN for which we're checking predecessors.
172 // - merge_lvns_: the predecessor LVNs.
173 DCHECK_EQ(merge_lvns_.size(), merge_names.size());
174 for (size_t i = 0, size = merge_lvns_.size(); i != size; ++i) {
175 const LocalValueNumbering* pred_lvn = merge_lvns_[i];
176 uint16_t value_name = merge_names[i];
177 if (!pred_lvn->IsValueNullChecked(value_name)) {
178 // Check if the predecessor has an IF_EQZ/IF_NEZ as the last insn.
Vladimir Marko55fff042014-07-10 12:42:52 +0100179 const BasicBlock* pred_bb = mir_graph_->GetBasicBlock(pred_lvn->Id());
Vladimir Marko95a05972014-05-30 10:01:32 +0100180 if (!HasNullCheckLastInsn(pred_bb, work_lvn_->Id())) {
181 return false;
182 }
183 // IF_EQZ/IF_NEZ checks some sreg, see if that sreg contains the value_name.
184 int s_reg = pred_bb->last_mir_insn->ssa_rep->uses[0];
Vladimir Marko7a01dc22015-01-02 17:00:44 +0000185 if (pred_lvn->GetSregValue(s_reg) != value_name) {
Vladimir Marko95a05972014-05-30 10:01:32 +0100186 return false;
187 }
188 }
189 }
190 return true;
191}
192
Razvan A Lupusorue0951142014-11-14 14:36:55 -0800193bool GlobalValueNumbering::DivZeroCheckedInAllPredecessors(
194 const ScopedArenaVector<uint16_t>& merge_names) const {
195 // Implicit parameters:
196 // - *work_lvn: the LVN for which we're checking predecessors.
197 // - merge_lvns_: the predecessor LVNs.
198 DCHECK_EQ(merge_lvns_.size(), merge_names.size());
199 for (size_t i = 0, size = merge_lvns_.size(); i != size; ++i) {
200 const LocalValueNumbering* pred_lvn = merge_lvns_[i];
201 uint16_t value_name = merge_names[i];
202 if (!pred_lvn->IsValueDivZeroChecked(value_name)) {
203 return false;
204 }
205 }
206 return true;
207}
208
Vladimir Marko95a05972014-05-30 10:01:32 +0100209} // namespace art