blob: aee94dcf4333f59832fe62396b61bf9048374ed2 [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
Vladimir Marko22fe45d2015-03-18 11:33:58 +000019#include "base/bit_vector-inl.h"
Andreas Gampe0b9203e2015-01-22 20:39:27 -080020#include "base/stl_util.h"
Vladimir Marko95a05972014-05-30 10:01:32 +010021#include "local_value_numbering.h"
22
23namespace art {
24
Vladimir Marko415ac882014-09-30 18:09:14 +010025GlobalValueNumbering::GlobalValueNumbering(CompilationUnit* cu, ScopedArenaAllocator* allocator,
26 Mode mode)
Vladimir Marko95a05972014-05-30 10:01:32 +010027 : cu_(cu),
Vladimir Marko55fff042014-07-10 12:42:52 +010028 mir_graph_(cu->mir_graph.get()),
Vladimir Marko95a05972014-05-30 10:01:32 +010029 allocator_(allocator),
Vladimir Marko55fff042014-07-10 12:42:52 +010030 bbs_processed_(0u),
31 max_bbs_to_process_(kMaxBbsToProcessMultiplyFactor * mir_graph_->GetNumReachableBlocks()),
Vladimir Marko7a01dc22015-01-02 17:00:44 +000032 last_value_(kNullValue),
Vladimir Marko415ac882014-09-30 18:09:14 +010033 modifications_allowed_(true),
34 mode_(mode),
Vladimir Marko95a05972014-05-30 10:01:32 +010035 global_value_map_(std::less<uint64_t>(), allocator->Adapter()),
Vladimir Marko95a05972014-05-30 10:01:32 +010036 array_location_map_(ArrayLocationComparator(), allocator->Adapter()),
37 array_location_reverse_map_(allocator->Adapter()),
38 ref_set_map_(std::less<ValueNameSet>(), allocator->Adapter()),
Vladimir Marko55fff042014-07-10 12:42:52 +010039 lvns_(mir_graph_->GetNumBlocks(), nullptr, allocator->Adapter()),
Vladimir Marko95a05972014-05-30 10:01:32 +010040 work_lvn_(nullptr),
41 merge_lvns_(allocator->Adapter()) {
Vladimir Marko95a05972014-05-30 10:01:32 +010042}
43
Vladimir Markod4cf1e42015-10-07 12:03:29 +010044// FIXME: Large frame size for x86_64 target. Bug: 24729377.
45#pragma GCC diagnostic push
46#pragma GCC diagnostic ignored "-Wframe-larger-than="
Vladimir Marko95a05972014-05-30 10:01:32 +010047GlobalValueNumbering::~GlobalValueNumbering() {
48 STLDeleteElements(&lvns_);
49}
Vladimir Markod4cf1e42015-10-07 12:03:29 +010050#pragma GCC diagnostic pop
Vladimir Marko95a05972014-05-30 10:01:32 +010051
Vladimir Markob19955d2014-07-29 12:04:10 +010052LocalValueNumbering* GlobalValueNumbering::PrepareBasicBlock(BasicBlock* bb,
53 ScopedArenaAllocator* allocator) {
Vladimir Marko95a05972014-05-30 10:01:32 +010054 if (UNLIKELY(!Good())) {
55 return nullptr;
56 }
Vladimir Marko415ac882014-09-30 18:09:14 +010057 if (bb->block_type != kDalvikByteCode && bb->block_type != kEntryBlock) {
Vladimir Marko95a05972014-05-30 10:01:32 +010058 DCHECK(bb->first_mir_insn == nullptr);
59 return nullptr;
60 }
Vladimir Marko415ac882014-09-30 18:09:14 +010061 if (mode_ == kModeGvn && UNLIKELY(bbs_processed_ == max_bbs_to_process_)) {
Vladimir Marko2d2365c2014-08-19 18:08:39 +010062 // If we're still trying to converge, stop now. Otherwise, proceed to apply optimizations.
Vladimir Marko415ac882014-09-30 18:09:14 +010063 last_value_ = kNoValue; // Make bad.
64 return nullptr;
65 }
66 if (mode_ == kModeGvnPostProcessing &&
67 mir_graph_->GetTopologicalSortOrderLoopHeadStack()->empty()) {
68 // Modifications outside loops are performed during the main phase.
69 return nullptr;
Vladimir Marko95a05972014-05-30 10:01:32 +010070 }
Vladimir Markob19955d2014-07-29 12:04:10 +010071 if (allocator == nullptr) {
72 allocator = allocator_;
73 }
Vladimir Marko95a05972014-05-30 10:01:32 +010074 DCHECK(work_lvn_.get() == nullptr);
Vladimir Markob19955d2014-07-29 12:04:10 +010075 work_lvn_.reset(new (allocator) LocalValueNumbering(this, bb->id, allocator));
Vladimir Marko95a05972014-05-30 10:01:32 +010076 if (bb->block_type == kEntryBlock) {
Vladimir Markoa4426cf2014-10-22 17:15:53 +010077 work_lvn_->PrepareEntryBlock();
Vladimir Marko415ac882014-09-30 18:09:14 +010078 DCHECK(bb->first_mir_insn == nullptr); // modifications_allowed_ is irrelevant.
Vladimir Marko95a05972014-05-30 10:01:32 +010079 } else {
Vladimir Marko95a05972014-05-30 10:01:32 +010080 // To avoid repeated allocation on the ArenaStack, reuse a single vector kept as a member.
81 DCHECK(merge_lvns_.empty());
Vladimir Marko55fff042014-07-10 12:42:52 +010082 // If we're running the full GVN, the RepeatingTopologicalSortIterator keeps the loop
83 // head stack in the MIRGraph up to date and for a loop head we need to check whether
84 // we're making the initial computation and need to merge only preceding blocks in the
85 // topological order, or we're recalculating a loop head and need to merge all incoming
86 // LVNs. When we're not at a loop head (including having an empty loop head stack) all
87 // predecessors should be preceding blocks and we shall merge all of them anyway.
Vladimir Marko55fff042014-07-10 12:42:52 +010088 bool use_all_predecessors = true;
89 uint16_t loop_head_idx = 0u; // Used only if !use_all_predecessors.
Vladimir Marko415ac882014-09-30 18:09:14 +010090 if (mode_ == kModeGvn && mir_graph_->GetTopologicalSortOrderLoopHeadStack()->size() != 0) {
Vladimir Marko55fff042014-07-10 12:42:52 +010091 // Full GVN inside a loop, see if we're at the loop head for the first time.
Vladimir Marko415ac882014-09-30 18:09:14 +010092 modifications_allowed_ = false;
Vladimir Markoe39c54e2014-09-22 14:50:02 +010093 auto top = mir_graph_->GetTopologicalSortOrderLoopHeadStack()->back();
Vladimir Marko55fff042014-07-10 12:42:52 +010094 loop_head_idx = top.first;
95 bool recalculating = top.second;
96 use_all_predecessors = recalculating ||
Vladimir Markoe39c54e2014-09-22 14:50:02 +010097 loop_head_idx != mir_graph_->GetTopologicalSortOrderIndexes()[bb->id];
Vladimir Marko415ac882014-09-30 18:09:14 +010098 } else {
99 modifications_allowed_ = true;
Vladimir Marko55fff042014-07-10 12:42:52 +0100100 }
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100101 for (BasicBlockId pred_id : bb->predecessors) {
102 DCHECK_NE(pred_id, NullBasicBlockId);
103 if (lvns_[pred_id] != nullptr &&
Vladimir Marko55fff042014-07-10 12:42:52 +0100104 (use_all_predecessors ||
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100105 mir_graph_->GetTopologicalSortOrderIndexes()[pred_id] < loop_head_idx)) {
106 merge_lvns_.push_back(lvns_[pred_id]);
Vladimir Marko95a05972014-05-30 10:01:32 +0100107 }
108 }
109 // Determine merge type.
110 LocalValueNumbering::MergeType merge_type = LocalValueNumbering::kNormalMerge;
111 if (bb->catch_entry) {
112 merge_type = LocalValueNumbering::kCatchMerge;
113 } else if (bb->last_mir_insn != nullptr &&
Vladimir Marko321b9872014-11-24 16:33:51 +0000114 IsInstructionReturn(bb->last_mir_insn->dalvikInsn.opcode) &&
Vladimir Marko26e7d452014-11-24 14:09:46 +0000115 bb->GetFirstNonPhiInsn() == 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 Markof7255502015-04-25 17:00:45 +0100135 bool change = false;
Vladimir Marko7a01dc22015-01-02 17:00:44 +0000136 if (mode_ == kModeGvn) {
Vladimir Markof7255502015-04-25 17:00:45 +0100137 change = (lvns_[bb->id] == nullptr) || !lvns_[bb->id]->Equals(*work_lvn_);
Vladimir Marko7a01dc22015-01-02 17:00:44 +0000138 // In GVN mode, keep the latest LVN even if Equals() indicates no change. This is
139 // to keep the correct values of fields that do not contribute to Equals() as long
140 // as they depend only on predecessor LVNs' fields that do contribute to Equals().
141 // Currently, that's LVN::merge_map_ used by LVN::GetStartingVregValueNumberImpl().
Vladimir Markob19955d2014-07-29 12:04:10 +0100142 std::unique_ptr<const LocalValueNumbering> old_lvn(lvns_[bb->id]);
143 lvns_[bb->id] = work_lvn_.release();
144 } else {
Vladimir Markof7255502015-04-25 17:00:45 +0100145 DCHECK_EQ(mode_, kModeGvnPostProcessing); // kModeLvn doesn't use FinishBasicBlock().
146 DCHECK(lvns_[bb->id] != nullptr);
147 DCHECK(lvns_[bb->id]->Equals(*work_lvn_));
Vladimir Markob19955d2014-07-29 12:04:10 +0100148 work_lvn_.reset();
149 }
150 return change;
Vladimir Marko95a05972014-05-30 10:01:32 +0100151}
152
Vladimir Marko95a05972014-05-30 10:01:32 +0100153uint16_t GlobalValueNumbering::GetArrayLocation(uint16_t base, uint16_t index) {
154 auto cmp = array_location_map_.key_comp();
155 ArrayLocation key = { base, index };
156 auto lb = array_location_map_.lower_bound(key);
157 if (lb != array_location_map_.end() && !cmp(key, lb->first)) {
158 return lb->second;
159 }
160 uint16_t location = static_cast<uint16_t>(array_location_reverse_map_.size());
161 DCHECK_EQ(location, array_location_reverse_map_.size()); // No overflow.
162 auto it = array_location_map_.PutBefore(lb, key, location);
163 array_location_reverse_map_.push_back(&*it);
164 return location;
165}
166
Vladimir Marko95a05972014-05-30 10:01:32 +0100167bool GlobalValueNumbering::NullCheckedInAllPredecessors(
168 const ScopedArenaVector<uint16_t>& merge_names) const {
169 // Implicit parameters:
Vladimir Markof11c4202015-06-19 12:58:22 +0100170 // - *work_lvn_: the LVN for which we're checking predecessors.
Vladimir Marko95a05972014-05-30 10:01:32 +0100171 // - merge_lvns_: the predecessor LVNs.
172 DCHECK_EQ(merge_lvns_.size(), merge_names.size());
173 for (size_t i = 0, size = merge_lvns_.size(); i != size; ++i) {
174 const LocalValueNumbering* pred_lvn = merge_lvns_[i];
175 uint16_t value_name = merge_names[i];
176 if (!pred_lvn->IsValueNullChecked(value_name)) {
177 // Check if the predecessor has an IF_EQZ/IF_NEZ as the last insn.
Vladimir Marko55fff042014-07-10 12:42:52 +0100178 const BasicBlock* pred_bb = mir_graph_->GetBasicBlock(pred_lvn->Id());
Vladimir Marko95a05972014-05-30 10:01:32 +0100179 if (!HasNullCheckLastInsn(pred_bb, work_lvn_->Id())) {
180 return false;
181 }
182 // IF_EQZ/IF_NEZ checks some sreg, see if that sreg contains the value_name.
183 int s_reg = pred_bb->last_mir_insn->ssa_rep->uses[0];
Vladimir Marko7a01dc22015-01-02 17:00:44 +0000184 if (pred_lvn->GetSregValue(s_reg) != value_name) {
Vladimir Marko95a05972014-05-30 10:01:32 +0100185 return false;
186 }
187 }
188 }
189 return true;
190}
191
Razvan A Lupusorue0951142014-11-14 14:36:55 -0800192bool GlobalValueNumbering::DivZeroCheckedInAllPredecessors(
193 const ScopedArenaVector<uint16_t>& merge_names) const {
194 // Implicit parameters:
Vladimir Markof11c4202015-06-19 12:58:22 +0100195 // - *work_lvn_: the LVN for which we're checking predecessors.
Razvan A Lupusorue0951142014-11-14 14:36:55 -0800196 // - merge_lvns_: the predecessor LVNs.
197 DCHECK_EQ(merge_lvns_.size(), merge_names.size());
198 for (size_t i = 0, size = merge_lvns_.size(); i != size; ++i) {
199 const LocalValueNumbering* pred_lvn = merge_lvns_[i];
200 uint16_t value_name = merge_names[i];
201 if (!pred_lvn->IsValueDivZeroChecked(value_name)) {
202 return false;
203 }
204 }
205 return true;
206}
207
Vladimir Marko22fe45d2015-03-18 11:33:58 +0000208bool GlobalValueNumbering::IsBlockEnteredOnTrue(uint16_t cond, BasicBlockId bb_id) {
209 DCHECK_NE(cond, kNoValue);
210 BasicBlock* bb = mir_graph_->GetBasicBlock(bb_id);
211 if (bb->predecessors.size() == 1u) {
212 BasicBlockId pred_id = bb->predecessors[0];
213 BasicBlock* pred_bb = mir_graph_->GetBasicBlock(pred_id);
Vladimir Markof11c4202015-06-19 12:58:22 +0100214 if (pred_bb->BranchesToSuccessorOnlyIfNotZero(bb_id)) {
215 DCHECK(lvns_[pred_id] != nullptr);
216 uint16_t operand = lvns_[pred_id]->GetSregValue(pred_bb->last_mir_insn->ssa_rep->uses[0]);
217 if (operand == cond) {
218 return true;
Vladimir Marko22fe45d2015-03-18 11:33:58 +0000219 }
220 }
221 }
222 return false;
223}
224
225bool GlobalValueNumbering::IsTrueInBlock(uint16_t cond, BasicBlockId bb_id) {
226 // We're not doing proper value propagation, so just see if the condition is used
227 // with if-nez/if-eqz to branch/fall-through to this bb or one of its dominators.
228 DCHECK_NE(cond, kNoValue);
229 if (IsBlockEnteredOnTrue(cond, bb_id)) {
230 return true;
231 }
232 BasicBlock* bb = mir_graph_->GetBasicBlock(bb_id);
233 for (uint32_t dom_id : bb->dominators->Indexes()) {
234 if (IsBlockEnteredOnTrue(cond, dom_id)) {
235 return true;
236 }
237 }
238 return false;
239}
240
Vladimir Marko95a05972014-05-30 10:01:32 +0100241} // namespace art