blob: 38ed98adafd1124c44582a2524ab362992a2f178 [file] [log] [blame]
xueliang.zhongc239a2b2017-04-27 15:31:37 +01001/*
2 * Copyright (C) 2017 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 "load_store_analysis.h"
18
Alex Light3a73ffb2021-01-25 14:11:05 +000019#include "base/scoped_arena_allocator.h"
20#include "optimizing/escape.h"
21
Vladimir Marko0a516052019-10-14 13:00:44 +000022namespace art {
xueliang.zhongc239a2b2017-04-27 15:31:37 +010023
24// A cap for the number of heap locations to prevent pathological time/space consumption.
25// The number of heap locations for most of the methods stays below this threshold.
26constexpr size_t kMaxNumberOfHeapLocations = 32;
27
xueliang.zhongb50b16a2017-09-19 17:43:29 +010028// Test if two integer ranges [l1,h1] and [l2,h2] overlap.
29// Note that the ranges are inclusive on both ends.
30// l1|------|h1
31// l2|------|h2
32static bool CanIntegerRangesOverlap(int64_t l1, int64_t h1, int64_t l2, int64_t h2) {
33 return std::max(l1, l2) <= std::min(h1, h2);
34}
xueliang.zhong016c0f12017-05-12 18:16:31 +010035
xueliang.zhongb50b16a2017-09-19 17:43:29 +010036static bool CanBinaryOpAndIndexAlias(const HBinaryOperation* idx1,
37 const size_t vector_length1,
38 const HInstruction* idx2,
39 const size_t vector_length2) {
40 if (!IsAddOrSub(idx1)) {
xueliang.zhong016c0f12017-05-12 18:16:31 +010041 // We currently only support Add and Sub operations.
42 return true;
43 }
xueliang.zhongb50b16a2017-09-19 17:43:29 +010044 if (idx1->AsBinaryOperation()->GetLeastConstantLeft() != idx2) {
45 // Cannot analyze [i+CONST1] and [j].
46 return true;
47 }
48 if (!idx1->GetConstantRight()->IsIntConstant()) {
xueliang.zhong016c0f12017-05-12 18:16:31 +010049 return true;
50 }
51
xueliang.zhongb50b16a2017-09-19 17:43:29 +010052 // Since 'i' are the same in [i+CONST] and [i],
53 // further compare [CONST] and [0].
54 int64_t l1 = idx1->IsAdd() ?
55 idx1->GetConstantRight()->AsIntConstant()->GetValue() :
56 -idx1->GetConstantRight()->AsIntConstant()->GetValue();
57 int64_t l2 = 0;
58 int64_t h1 = l1 + (vector_length1 - 1);
59 int64_t h2 = l2 + (vector_length2 - 1);
60 return CanIntegerRangesOverlap(l1, h1, l2, h2);
xueliang.zhong016c0f12017-05-12 18:16:31 +010061}
62
xueliang.zhongb50b16a2017-09-19 17:43:29 +010063static bool CanBinaryOpsAlias(const HBinaryOperation* idx1,
64 const size_t vector_length1,
65 const HBinaryOperation* idx2,
66 const size_t vector_length2) {
67 if (!IsAddOrSub(idx1) || !IsAddOrSub(idx2)) {
68 // We currently only support Add and Sub operations.
69 return true;
70 }
71 if (idx1->AsBinaryOperation()->GetLeastConstantLeft() !=
72 idx2->AsBinaryOperation()->GetLeastConstantLeft()) {
73 // Cannot analyze [i+CONST1] and [j+CONST2].
74 return true;
75 }
76 if (!idx1->GetConstantRight()->IsIntConstant() ||
77 !idx2->GetConstantRight()->IsIntConstant()) {
xueliang.zhong016c0f12017-05-12 18:16:31 +010078 return true;
79 }
80
xueliang.zhongb50b16a2017-09-19 17:43:29 +010081 // Since 'i' are the same in [i+CONST1] and [i+CONST2],
82 // further compare [CONST1] and [CONST2].
83 int64_t l1 = idx1->IsAdd() ?
84 idx1->GetConstantRight()->AsIntConstant()->GetValue() :
85 -idx1->GetConstantRight()->AsIntConstant()->GetValue();
86 int64_t l2 = idx2->IsAdd() ?
87 idx2->GetConstantRight()->AsIntConstant()->GetValue() :
88 -idx2->GetConstantRight()->AsIntConstant()->GetValue();
89 int64_t h1 = l1 + (vector_length1 - 1);
90 int64_t h2 = l2 + (vector_length2 - 1);
91 return CanIntegerRangesOverlap(l1, h1, l2, h2);
xueliang.zhong016c0f12017-05-12 18:16:31 +010092}
93
Alex Light86fe9b82020-11-16 16:54:01 +000094// Make sure we mark any writes/potential writes to heap-locations within partially
95// escaped values as escaping.
96void ReferenceInfo::PrunePartialEscapeWrites() {
97 if (!subgraph_.IsValid()) {
98 // All paths escape.
99 return;
100 }
101 HGraph* graph = reference_->GetBlock()->GetGraph();
102 ArenaBitVector additional_exclusions(
103 allocator_, graph->GetBlocks().size(), false, kArenaAllocLSA);
104 for (const HUseListNode<HInstruction*>& use : reference_->GetUses()) {
105 const HInstruction* user = use.GetUser();
Alex Light3a73ffb2021-01-25 14:11:05 +0000106 if (!additional_exclusions.IsBitSet(user->GetBlock()->GetBlockId()) &&
107 subgraph_.ContainsBlock(user->GetBlock()) &&
Alex Light86fe9b82020-11-16 16:54:01 +0000108 (user->IsUnresolvedInstanceFieldSet() || user->IsUnresolvedStaticFieldSet() ||
109 user->IsInstanceFieldSet() || user->IsStaticFieldSet() || user->IsArraySet()) &&
Alex Light3a73ffb2021-01-25 14:11:05 +0000110 (reference_ == user->InputAt(0)) &&
Alex Light86fe9b82020-11-16 16:54:01 +0000111 std::any_of(subgraph_.UnreachableBlocks().begin(),
112 subgraph_.UnreachableBlocks().end(),
113 [&](const HBasicBlock* excluded) -> bool {
114 return reference_->GetBlock()->GetGraph()->PathBetween(excluded,
115 user->GetBlock());
116 })) {
117 // This object had memory written to it somewhere, if it escaped along
118 // some paths prior to the current block this write also counts as an
119 // escape.
120 additional_exclusions.SetBit(user->GetBlock()->GetBlockId());
121 }
122 }
123 if (UNLIKELY(additional_exclusions.IsAnyBitSet())) {
124 for (uint32_t exc : additional_exclusions.Indexes()) {
125 subgraph_.RemoveBlock(graph->GetBlocks()[exc]);
126 }
127 }
128}
129
130bool HeapLocationCollector::InstructionEligibleForLSERemoval(HInstruction* inst) const {
131 if (inst->IsNewInstance()) {
132 return !inst->AsNewInstance()->NeedsChecks();
133 } else if (inst->IsNewArray()) {
134 HInstruction* array_length = inst->AsNewArray()->GetLength();
135 bool known_array_length =
136 array_length->IsIntConstant() && array_length->AsIntConstant()->GetValue() >= 0;
137 return known_array_length &&
138 std::all_of(inst->GetUses().cbegin(),
139 inst->GetUses().cend(),
140 [&](const HUseListNode<HInstruction*>& user) {
141 if (user.GetUser()->IsArrayGet() || user.GetUser()->IsArraySet()) {
142 return user.GetUser()->InputAt(1)->IsIntConstant();
143 }
144 return true;
145 });
146 } else {
147 return false;
148 }
149}
150
Alex Light3a73ffb2021-01-25 14:11:05 +0000151void ReferenceInfo::CollectPartialEscapes(HGraph* graph) {
152 ScopedArenaAllocator saa(graph->GetArenaStack());
153 ArenaBitVector seen_instructions(&saa, graph->GetCurrentInstructionId(), false, kArenaAllocLSA);
154 // Get regular escapes.
155 ScopedArenaVector<HInstruction*> additional_escape_vectors(saa.Adapter(kArenaAllocLSA));
156 LambdaEscapeVisitor scan_instructions([&](HInstruction* escape) -> bool {
157 HandleEscape(escape);
158 // LSE can't track heap-locations through Phi and Select instructions so we
159 // need to assume all escapes from these are escapes for the base reference.
160 if ((escape->IsPhi() || escape->IsSelect()) && !seen_instructions.IsBitSet(escape->GetId())) {
161 seen_instructions.SetBit(escape->GetId());
162 additional_escape_vectors.push_back(escape);
163 }
164 return true;
165 });
166 additional_escape_vectors.push_back(reference_);
167 while (!additional_escape_vectors.empty()) {
168 HInstruction* ref = additional_escape_vectors.back();
169 additional_escape_vectors.pop_back();
170 DCHECK(ref == reference_ || ref->IsPhi() || ref->IsSelect()) << *ref;
171 VisitEscapes(ref, scan_instructions);
172 }
173
174 // Mark irreducible loop headers as escaping since they cannot be tracked through.
175 for (HBasicBlock* blk : graph->GetActiveBlocks()) {
176 if (blk->IsLoopHeader() && blk->GetLoopInformation()->IsIrreducible()) {
177 HandleEscape(blk);
178 }
179 }
180}
181
Alex Light86fe9b82020-11-16 16:54:01 +0000182void HeapLocationCollector::DumpReferenceStats(OptimizingCompilerStats* stats) {
183 if (stats == nullptr) {
184 return;
185 }
186 std::vector<bool> seen_instructions(GetGraph()->GetCurrentInstructionId(), false);
187 for (auto hl : heap_locations_) {
188 auto ri = hl->GetReferenceInfo();
189 if (ri == nullptr || seen_instructions[ri->GetReference()->GetId()]) {
190 continue;
191 }
192 auto instruction = ri->GetReference();
193 seen_instructions[instruction->GetId()] = true;
194 if (ri->IsSingletonAndRemovable()) {
195 if (InstructionEligibleForLSERemoval(instruction)) {
196 MaybeRecordStat(stats, MethodCompilationStat::kFullLSEPossible);
197 }
198 }
199 // TODO This is an estimate of the number of allocations we will be able
200 // to (partially) remove. As additional work is done this can be refined.
201 if (ri->IsPartialSingleton() && instruction->IsNewInstance() &&
202 ri->GetNoEscapeSubgraph()->ContainsBlock(instruction->GetBlock()) &&
203 !ri->GetNoEscapeSubgraph()->GetExcludedCohorts().empty() &&
204 InstructionEligibleForLSERemoval(instruction)) {
205 MaybeRecordStat(stats, MethodCompilationStat::kPartialLSEPossible);
206 }
207 }
208}
209
xueliang.zhongb50b16a2017-09-19 17:43:29 +0100210bool HeapLocationCollector::CanArrayElementsAlias(const HInstruction* idx1,
211 const size_t vector_length1,
212 const HInstruction* idx2,
213 const size_t vector_length2) const {
xueliang.zhong016c0f12017-05-12 18:16:31 +0100214 DCHECK(idx1 != nullptr);
215 DCHECK(idx2 != nullptr);
xueliang.zhongb50b16a2017-09-19 17:43:29 +0100216 DCHECK_GE(vector_length1, HeapLocation::kScalar);
217 DCHECK_GE(vector_length2, HeapLocation::kScalar);
xueliang.zhong016c0f12017-05-12 18:16:31 +0100218
xueliang.zhongb50b16a2017-09-19 17:43:29 +0100219 // [i] and [i].
xueliang.zhong016c0f12017-05-12 18:16:31 +0100220 if (idx1 == idx2) {
xueliang.zhong016c0f12017-05-12 18:16:31 +0100221 return true;
222 }
xueliang.zhongb50b16a2017-09-19 17:43:29 +0100223
224 // [CONST1] and [CONST2].
xueliang.zhong016c0f12017-05-12 18:16:31 +0100225 if (idx1->IsIntConstant() && idx2->IsIntConstant()) {
xueliang.zhongb50b16a2017-09-19 17:43:29 +0100226 int64_t l1 = idx1->AsIntConstant()->GetValue();
227 int64_t l2 = idx2->AsIntConstant()->GetValue();
228 // To avoid any overflow in following CONST+vector_length calculation,
229 // use int64_t instead of int32_t.
230 int64_t h1 = l1 + (vector_length1 - 1);
231 int64_t h2 = l2 + (vector_length2 - 1);
232 return CanIntegerRangesOverlap(l1, h1, l2, h2);
xueliang.zhong016c0f12017-05-12 18:16:31 +0100233 }
234
xueliang.zhongb50b16a2017-09-19 17:43:29 +0100235 // [i+CONST] and [i].
236 if (idx1->IsBinaryOperation() &&
237 idx1->AsBinaryOperation()->GetConstantRight() != nullptr &&
238 idx1->AsBinaryOperation()->GetLeastConstantLeft() == idx2) {
239 return CanBinaryOpAndIndexAlias(idx1->AsBinaryOperation(),
240 vector_length1,
241 idx2,
242 vector_length2);
xueliang.zhong016c0f12017-05-12 18:16:31 +0100243 }
244
xueliang.zhongb50b16a2017-09-19 17:43:29 +0100245 // [i] and [i+CONST].
246 if (idx2->IsBinaryOperation() &&
247 idx2->AsBinaryOperation()->GetConstantRight() != nullptr &&
248 idx2->AsBinaryOperation()->GetLeastConstantLeft() == idx1) {
249 return CanBinaryOpAndIndexAlias(idx2->AsBinaryOperation(),
250 vector_length2,
251 idx1,
252 vector_length1);
253 }
254
255 // [i+CONST1] and [i+CONST2].
256 if (idx1->IsBinaryOperation() &&
257 idx1->AsBinaryOperation()->GetConstantRight() != nullptr &&
258 idx2->IsBinaryOperation() &&
259 idx2->AsBinaryOperation()->GetConstantRight() != nullptr) {
260 return CanBinaryOpsAlias(idx1->AsBinaryOperation(),
261 vector_length1,
262 idx2->AsBinaryOperation(),
263 vector_length2);
xueliang.zhong016c0f12017-05-12 18:16:31 +0100264 }
265
266 // By default, MAY alias.
267 return true;
268}
269
Aart Bik24773202018-04-26 10:28:51 -0700270bool LoadStoreAnalysis::Run() {
xueliang.zhongc239a2b2017-04-27 15:31:37 +0100271 for (HBasicBlock* block : graph_->GetReversePostOrder()) {
272 heap_location_collector_.VisitBasicBlock(block);
273 }
274
275 if (heap_location_collector_.GetNumberOfHeapLocations() > kMaxNumberOfHeapLocations) {
276 // Bail out if there are too many heap locations to deal with.
277 heap_location_collector_.CleanUp();
Aart Bik24773202018-04-26 10:28:51 -0700278 return false;
xueliang.zhongc239a2b2017-04-27 15:31:37 +0100279 }
280 if (!heap_location_collector_.HasHeapStores()) {
281 // Without heap stores, this pass would act mostly as GVN on heap accesses.
282 heap_location_collector_.CleanUp();
Aart Bik24773202018-04-26 10:28:51 -0700283 return false;
xueliang.zhongc239a2b2017-04-27 15:31:37 +0100284 }
285 if (heap_location_collector_.HasVolatile() || heap_location_collector_.HasMonitorOps()) {
286 // Don't do load/store elimination if the method has volatile field accesses or
287 // monitor operations, for now.
288 // TODO: do it right.
289 heap_location_collector_.CleanUp();
Aart Bik24773202018-04-26 10:28:51 -0700290 return false;
xueliang.zhongc239a2b2017-04-27 15:31:37 +0100291 }
292
293 heap_location_collector_.BuildAliasingMatrix();
Alex Light86fe9b82020-11-16 16:54:01 +0000294 heap_location_collector_.DumpReferenceStats(stats_);
Aart Bik24773202018-04-26 10:28:51 -0700295 return true;
xueliang.zhongc239a2b2017-04-27 15:31:37 +0100296}
297
298} // namespace art