blob: 5a1df45914442715e96643536d9994245c97f3d7 [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#ifndef ART_COMPILER_OPTIMIZING_LOAD_STORE_ANALYSIS_H_
18#define ART_COMPILER_OPTIMIZING_LOAD_STORE_ANALYSIS_H_
19
20#include "escape.h"
21#include "nodes.h"
22#include "optimization.h"
23
24namespace art {
25
26// A ReferenceInfo contains additional info about a reference such as
27// whether it's a singleton, returned, etc.
Vladimir Marko009d1662017-10-10 13:21:15 +010028class ReferenceInfo : public ArenaObject<kArenaAllocLSA> {
xueliang.zhongc239a2b2017-04-27 15:31:37 +010029 public:
30 ReferenceInfo(HInstruction* reference, size_t pos)
31 : reference_(reference),
32 position_(pos),
33 is_singleton_(true),
34 is_singleton_and_not_returned_(true),
35 is_singleton_and_not_deopt_visible_(true),
36 has_index_aliasing_(false) {
37 CalculateEscape(reference_,
38 nullptr,
39 &is_singleton_,
40 &is_singleton_and_not_returned_,
41 &is_singleton_and_not_deopt_visible_);
42 }
43
44 HInstruction* GetReference() const {
45 return reference_;
46 }
47
48 size_t GetPosition() const {
49 return position_;
50 }
51
52 // Returns true if reference_ is the only name that can refer to its value during
53 // the lifetime of the method. So it's guaranteed to not have any alias in
54 // the method (including its callees).
55 bool IsSingleton() const {
56 return is_singleton_;
57 }
58
59 // Returns true if reference_ is a singleton and not returned to the caller or
60 // used as an environment local of an HDeoptimize instruction.
61 // The allocation and stores into reference_ may be eliminated for such cases.
62 bool IsSingletonAndRemovable() const {
63 return is_singleton_and_not_returned_ && is_singleton_and_not_deopt_visible_;
64 }
65
66 // Returns true if reference_ is a singleton and returned to the caller or
67 // used as an environment local of an HDeoptimize instruction.
68 bool IsSingletonAndNonRemovable() const {
69 return is_singleton_ &&
70 (!is_singleton_and_not_returned_ || !is_singleton_and_not_deopt_visible_);
71 }
72
73 bool HasIndexAliasing() {
74 return has_index_aliasing_;
75 }
76
77 void SetHasIndexAliasing(bool has_index_aliasing) {
78 // Only allow setting to true.
79 DCHECK(has_index_aliasing);
80 has_index_aliasing_ = has_index_aliasing;
81 }
82
83 private:
84 HInstruction* const reference_;
85 const size_t position_; // position in HeapLocationCollector's ref_info_array_.
86
87 // Can only be referred to by a single name in the method.
88 bool is_singleton_;
89 // Is singleton and not returned to caller.
90 bool is_singleton_and_not_returned_;
91 // Is singleton and not used as an environment local of HDeoptimize.
92 bool is_singleton_and_not_deopt_visible_;
93 // Some heap locations with reference_ have array index aliasing,
94 // e.g. arr[i] and arr[j] may be the same location.
95 bool has_index_aliasing_;
96
97 DISALLOW_COPY_AND_ASSIGN(ReferenceInfo);
98};
99
100// A heap location is a reference-offset/index pair that a value can be loaded from
101// or stored to.
Vladimir Marko009d1662017-10-10 13:21:15 +0100102class HeapLocation : public ArenaObject<kArenaAllocLSA> {
xueliang.zhongc239a2b2017-04-27 15:31:37 +0100103 public:
104 static constexpr size_t kInvalidFieldOffset = -1;
105
106 // TODO: more fine-grained array types.
107 static constexpr int16_t kDeclaringClassDefIndexForArrays = -1;
108
109 HeapLocation(ReferenceInfo* ref_info,
110 size_t offset,
111 HInstruction* index,
112 int16_t declaring_class_def_index)
113 : ref_info_(ref_info),
114 offset_(offset),
115 index_(index),
116 declaring_class_def_index_(declaring_class_def_index),
117 value_killed_by_loop_side_effects_(true) {
118 DCHECK(ref_info != nullptr);
119 DCHECK((offset == kInvalidFieldOffset && index != nullptr) ||
120 (offset != kInvalidFieldOffset && index == nullptr));
121 if (ref_info->IsSingleton() && !IsArrayElement()) {
122 // Assume this location's value cannot be killed by loop side effects
123 // until proven otherwise.
124 value_killed_by_loop_side_effects_ = false;
125 }
126 }
127
128 ReferenceInfo* GetReferenceInfo() const { return ref_info_; }
129 size_t GetOffset() const { return offset_; }
130 HInstruction* GetIndex() const { return index_; }
131
132 // Returns the definition of declaring class' dex index.
133 // It's kDeclaringClassDefIndexForArrays for an array element.
134 int16_t GetDeclaringClassDefIndex() const {
135 return declaring_class_def_index_;
136 }
137
138 bool IsArrayElement() const {
139 return index_ != nullptr;
140 }
141
142 bool IsValueKilledByLoopSideEffects() const {
143 return value_killed_by_loop_side_effects_;
144 }
145
146 void SetValueKilledByLoopSideEffects(bool val) {
147 value_killed_by_loop_side_effects_ = val;
148 }
149
150 private:
151 ReferenceInfo* const ref_info_; // reference for instance/static field or array access.
152 const size_t offset_; // offset of static/instance field.
153 HInstruction* const index_; // index of an array element.
154 const int16_t declaring_class_def_index_; // declaring class's def's dex index.
155 bool value_killed_by_loop_side_effects_; // value of this location may be killed by loop
156 // side effects because this location is stored
157 // into inside a loop. This gives
158 // better info on whether a singleton's location
159 // value may be killed by loop side effects.
160
161 DISALLOW_COPY_AND_ASSIGN(HeapLocation);
162};
163
164// A HeapLocationCollector collects all relevant heap locations and keeps
165// an aliasing matrix for all locations.
166class HeapLocationCollector : public HGraphVisitor {
167 public:
168 static constexpr size_t kHeapLocationNotFound = -1;
169 // Start with a single uint32_t word. That's enough bits for pair-wise
170 // aliasing matrix of 8 heap locations.
171 static constexpr uint32_t kInitialAliasingMatrixBitVectorSize = 32;
172
173 explicit HeapLocationCollector(HGraph* graph)
174 : HGraphVisitor(graph),
Vladimir Marko009d1662017-10-10 13:21:15 +0100175 ref_info_array_(graph->GetAllocator()->Adapter(kArenaAllocLSA)),
176 heap_locations_(graph->GetAllocator()->Adapter(kArenaAllocLSA)),
Vladimir Markoca6fff82017-10-03 14:49:14 +0100177 aliasing_matrix_(graph->GetAllocator(),
xueliang.zhongc239a2b2017-04-27 15:31:37 +0100178 kInitialAliasingMatrixBitVectorSize,
179 true,
Vladimir Marko009d1662017-10-10 13:21:15 +0100180 kArenaAllocLSA),
xueliang.zhongc239a2b2017-04-27 15:31:37 +0100181 has_heap_stores_(false),
182 has_volatile_(false),
183 has_monitor_operations_(false) {}
184
185 void CleanUp() {
186 heap_locations_.clear();
187 ref_info_array_.clear();
188 }
189
190 size_t GetNumberOfHeapLocations() const {
191 return heap_locations_.size();
192 }
193
194 HeapLocation* GetHeapLocation(size_t index) const {
195 return heap_locations_[index];
196 }
197
198 HInstruction* HuntForOriginalReference(HInstruction* ref) const {
xueliang.zhonge0eb4832017-10-30 13:43:14 +0000199 // An original reference can be transformed by instructions like:
200 // i0 NewArray
201 // i1 HInstruction(i0) <-- NullCheck, BoundType, IntermediateAddress.
202 // i2 ArrayGet(i1, index)
xueliang.zhongc239a2b2017-04-27 15:31:37 +0100203 DCHECK(ref != nullptr);
xueliang.zhonge0eb4832017-10-30 13:43:14 +0000204 while (ref->IsNullCheck() || ref->IsBoundType() || ref->IsIntermediateAddress()) {
xueliang.zhongc239a2b2017-04-27 15:31:37 +0100205 ref = ref->InputAt(0);
206 }
207 return ref;
208 }
209
210 ReferenceInfo* FindReferenceInfoOf(HInstruction* ref) const {
211 for (size_t i = 0; i < ref_info_array_.size(); i++) {
212 ReferenceInfo* ref_info = ref_info_array_[i];
213 if (ref_info->GetReference() == ref) {
214 DCHECK_EQ(i, ref_info->GetPosition());
215 return ref_info;
216 }
217 }
218 return nullptr;
219 }
220
xueliang.zhong016c0f12017-05-12 18:16:31 +0100221 size_t GetArrayAccessHeapLocation(HInstruction* array, HInstruction* index) const {
222 DCHECK(array != nullptr);
223 DCHECK(index != nullptr);
224 HInstruction* original_ref = HuntForOriginalReference(array);
225 ReferenceInfo* ref_info = FindReferenceInfoOf(original_ref);
226 return FindHeapLocationIndex(ref_info,
227 HeapLocation::kInvalidFieldOffset,
228 index,
229 HeapLocation::kDeclaringClassDefIndexForArrays);
230 }
231
xueliang.zhongc239a2b2017-04-27 15:31:37 +0100232 bool HasHeapStores() const {
233 return has_heap_stores_;
234 }
235
236 bool HasVolatile() const {
237 return has_volatile_;
238 }
239
240 bool HasMonitorOps() const {
241 return has_monitor_operations_;
242 }
243
244 // Find and return the heap location index in heap_locations_.
245 size_t FindHeapLocationIndex(ReferenceInfo* ref_info,
246 size_t offset,
247 HInstruction* index,
248 int16_t declaring_class_def_index) const {
249 for (size_t i = 0; i < heap_locations_.size(); i++) {
250 HeapLocation* loc = heap_locations_[i];
251 if (loc->GetReferenceInfo() == ref_info &&
252 loc->GetOffset() == offset &&
253 loc->GetIndex() == index &&
254 loc->GetDeclaringClassDefIndex() == declaring_class_def_index) {
255 return i;
256 }
257 }
258 return kHeapLocationNotFound;
259 }
260
261 // Returns true if heap_locations_[index1] and heap_locations_[index2] may alias.
262 bool MayAlias(size_t index1, size_t index2) const {
263 if (index1 < index2) {
264 return aliasing_matrix_.IsBitSet(AliasingMatrixPosition(index1, index2));
265 } else if (index1 > index2) {
266 return aliasing_matrix_.IsBitSet(AliasingMatrixPosition(index2, index1));
267 } else {
268 DCHECK(false) << "index1 and index2 are expected to be different";
269 return true;
270 }
271 }
272
273 void BuildAliasingMatrix() {
274 const size_t number_of_locations = heap_locations_.size();
275 if (number_of_locations == 0) {
276 return;
277 }
278 size_t pos = 0;
279 // Compute aliasing info between every pair of different heap locations.
280 // Save the result in a matrix represented as a BitVector.
281 for (size_t i = 0; i < number_of_locations - 1; i++) {
282 for (size_t j = i + 1; j < number_of_locations; j++) {
283 if (ComputeMayAlias(i, j)) {
284 aliasing_matrix_.SetBit(CheckedAliasingMatrixPosition(i, j, pos));
285 }
286 pos++;
287 }
288 }
289 }
290
291 private:
292 // An allocation cannot alias with a name which already exists at the point
293 // of the allocation, such as a parameter or a load happening before the allocation.
294 bool MayAliasWithPreexistenceChecking(ReferenceInfo* ref_info1, ReferenceInfo* ref_info2) const {
295 if (ref_info1->GetReference()->IsNewInstance() || ref_info1->GetReference()->IsNewArray()) {
296 // Any reference that can alias with the allocation must appear after it in the block/in
297 // the block's successors. In reverse post order, those instructions will be visited after
298 // the allocation.
299 return ref_info2->GetPosition() >= ref_info1->GetPosition();
300 }
301 return true;
302 }
303
304 bool CanReferencesAlias(ReferenceInfo* ref_info1, ReferenceInfo* ref_info2) const {
305 if (ref_info1 == ref_info2) {
306 return true;
307 } else if (ref_info1->IsSingleton()) {
308 return false;
309 } else if (ref_info2->IsSingleton()) {
310 return false;
311 } else if (!MayAliasWithPreexistenceChecking(ref_info1, ref_info2) ||
312 !MayAliasWithPreexistenceChecking(ref_info2, ref_info1)) {
313 return false;
314 }
315 return true;
316 }
317
xueliang.zhong016c0f12017-05-12 18:16:31 +0100318 bool CanArrayIndicesAlias(const HInstruction* i1, const HInstruction* i2) const;
319
xueliang.zhongc239a2b2017-04-27 15:31:37 +0100320 // `index1` and `index2` are indices in the array of collected heap locations.
321 // Returns the position in the bit vector that tracks whether the two heap
322 // locations may alias.
323 size_t AliasingMatrixPosition(size_t index1, size_t index2) const {
324 DCHECK(index2 > index1);
325 const size_t number_of_locations = heap_locations_.size();
326 // It's (num_of_locations - 1) + ... + (num_of_locations - index1) + (index2 - index1 - 1).
327 return (number_of_locations * index1 - (1 + index1) * index1 / 2 + (index2 - index1 - 1));
328 }
329
330 // An additional position is passed in to make sure the calculated position is correct.
331 size_t CheckedAliasingMatrixPosition(size_t index1, size_t index2, size_t position) {
332 size_t calculated_position = AliasingMatrixPosition(index1, index2);
333 DCHECK_EQ(calculated_position, position);
334 return calculated_position;
335 }
336
337 // Compute if two locations may alias to each other.
338 bool ComputeMayAlias(size_t index1, size_t index2) const {
339 HeapLocation* loc1 = heap_locations_[index1];
340 HeapLocation* loc2 = heap_locations_[index2];
341 if (loc1->GetOffset() != loc2->GetOffset()) {
342 // Either two different instance fields, or one is an instance
343 // field and the other is an array element.
344 return false;
345 }
346 if (loc1->GetDeclaringClassDefIndex() != loc2->GetDeclaringClassDefIndex()) {
347 // Different types.
348 return false;
349 }
350 if (!CanReferencesAlias(loc1->GetReferenceInfo(), loc2->GetReferenceInfo())) {
351 return false;
352 }
353 if (loc1->IsArrayElement() && loc2->IsArrayElement()) {
354 HInstruction* array_index1 = loc1->GetIndex();
355 HInstruction* array_index2 = loc2->GetIndex();
xueliang.zhong016c0f12017-05-12 18:16:31 +0100356 if (!CanArrayIndicesAlias(array_index1, array_index2)) {
xueliang.zhongc239a2b2017-04-27 15:31:37 +0100357 return false;
358 }
359 ReferenceInfo* ref_info = loc1->GetReferenceInfo();
360 ref_info->SetHasIndexAliasing(true);
361 }
362 return true;
363 }
364
365 ReferenceInfo* GetOrCreateReferenceInfo(HInstruction* instruction) {
366 ReferenceInfo* ref_info = FindReferenceInfoOf(instruction);
367 if (ref_info == nullptr) {
368 size_t pos = ref_info_array_.size();
Vladimir Markoca6fff82017-10-03 14:49:14 +0100369 ref_info = new (GetGraph()->GetAllocator()) ReferenceInfo(instruction, pos);
xueliang.zhongc239a2b2017-04-27 15:31:37 +0100370 ref_info_array_.push_back(ref_info);
371 }
372 return ref_info;
373 }
374
375 void CreateReferenceInfoForReferenceType(HInstruction* instruction) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100376 if (instruction->GetType() != DataType::Type::kReference) {
xueliang.zhongc239a2b2017-04-27 15:31:37 +0100377 return;
378 }
379 DCHECK(FindReferenceInfoOf(instruction) == nullptr);
380 GetOrCreateReferenceInfo(instruction);
381 }
382
383 HeapLocation* GetOrCreateHeapLocation(HInstruction* ref,
384 size_t offset,
385 HInstruction* index,
386 int16_t declaring_class_def_index) {
387 HInstruction* original_ref = HuntForOriginalReference(ref);
388 ReferenceInfo* ref_info = GetOrCreateReferenceInfo(original_ref);
389 size_t heap_location_idx = FindHeapLocationIndex(
390 ref_info, offset, index, declaring_class_def_index);
391 if (heap_location_idx == kHeapLocationNotFound) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100392 HeapLocation* heap_loc = new (GetGraph()->GetAllocator())
xueliang.zhongc239a2b2017-04-27 15:31:37 +0100393 HeapLocation(ref_info, offset, index, declaring_class_def_index);
394 heap_locations_.push_back(heap_loc);
395 return heap_loc;
396 }
397 return heap_locations_[heap_location_idx];
398 }
399
400 HeapLocation* VisitFieldAccess(HInstruction* ref, const FieldInfo& field_info) {
401 if (field_info.IsVolatile()) {
402 has_volatile_ = true;
403 }
404 const uint16_t declaring_class_def_index = field_info.GetDeclaringClassDefIndex();
405 const size_t offset = field_info.GetFieldOffset().SizeValue();
406 return GetOrCreateHeapLocation(ref, offset, nullptr, declaring_class_def_index);
407 }
408
409 void VisitArrayAccess(HInstruction* array, HInstruction* index) {
410 GetOrCreateHeapLocation(array, HeapLocation::kInvalidFieldOffset,
411 index, HeapLocation::kDeclaringClassDefIndexForArrays);
412 }
413
414 void VisitInstanceFieldGet(HInstanceFieldGet* instruction) OVERRIDE {
415 VisitFieldAccess(instruction->InputAt(0), instruction->GetFieldInfo());
416 CreateReferenceInfoForReferenceType(instruction);
417 }
418
419 void VisitInstanceFieldSet(HInstanceFieldSet* instruction) OVERRIDE {
420 HeapLocation* location = VisitFieldAccess(instruction->InputAt(0), instruction->GetFieldInfo());
421 has_heap_stores_ = true;
422 if (location->GetReferenceInfo()->IsSingleton()) {
423 // A singleton's location value may be killed by loop side effects if it's
424 // defined before that loop, and it's stored into inside that loop.
425 HLoopInformation* loop_info = instruction->GetBlock()->GetLoopInformation();
426 if (loop_info != nullptr) {
427 HInstruction* ref = location->GetReferenceInfo()->GetReference();
428 DCHECK(ref->IsNewInstance());
429 if (loop_info->IsDefinedOutOfTheLoop(ref)) {
430 // ref's location value may be killed by this loop's side effects.
431 location->SetValueKilledByLoopSideEffects(true);
432 } else {
433 // ref is defined inside this loop so this loop's side effects cannot
434 // kill its location value at the loop header since ref/its location doesn't
435 // exist yet at the loop header.
436 }
437 }
438 } else {
439 // For non-singletons, value_killed_by_loop_side_effects_ is inited to
440 // true.
441 DCHECK_EQ(location->IsValueKilledByLoopSideEffects(), true);
442 }
443 }
444
445 void VisitStaticFieldGet(HStaticFieldGet* instruction) OVERRIDE {
446 VisitFieldAccess(instruction->InputAt(0), instruction->GetFieldInfo());
447 CreateReferenceInfoForReferenceType(instruction);
448 }
449
450 void VisitStaticFieldSet(HStaticFieldSet* instruction) OVERRIDE {
451 VisitFieldAccess(instruction->InputAt(0), instruction->GetFieldInfo());
452 has_heap_stores_ = true;
453 }
454
455 // We intentionally don't collect HUnresolvedInstanceField/HUnresolvedStaticField accesses
456 // since we cannot accurately track the fields.
457
458 void VisitArrayGet(HArrayGet* instruction) OVERRIDE {
459 VisitArrayAccess(instruction->InputAt(0), instruction->InputAt(1));
460 CreateReferenceInfoForReferenceType(instruction);
461 }
462
463 void VisitArraySet(HArraySet* instruction) OVERRIDE {
464 VisitArrayAccess(instruction->InputAt(0), instruction->InputAt(1));
465 has_heap_stores_ = true;
466 }
467
Mingyao Yangfef28842017-08-28 15:20:57 -0700468 void VisitInstruction(HInstruction* instruction) OVERRIDE {
469 // Any new-instance or new-array cannot alias with references that
470 // pre-exist the new-instance/new-array. We append entries into
471 // ref_info_array_ which keeps track of the order of creation
472 // of reference values since we visit the blocks in reverse post order.
473 //
474 // By default, VisitXXX() (including VisitPhi()) calls VisitInstruction(),
475 // unless VisitXXX() is overridden. VisitInstanceFieldGet() etc. above
476 // also call CreateReferenceInfoForReferenceType() explicitly.
xueliang.zhongc239a2b2017-04-27 15:31:37 +0100477 CreateReferenceInfoForReferenceType(instruction);
478 }
479
480 void VisitMonitorOperation(HMonitorOperation* monitor ATTRIBUTE_UNUSED) OVERRIDE {
481 has_monitor_operations_ = true;
482 }
483
484 ArenaVector<ReferenceInfo*> ref_info_array_; // All references used for heap accesses.
485 ArenaVector<HeapLocation*> heap_locations_; // All heap locations.
486 ArenaBitVector aliasing_matrix_; // aliasing info between each pair of locations.
487 bool has_heap_stores_; // If there is no heap stores, LSE acts as GVN with better
488 // alias analysis and won't be as effective.
489 bool has_volatile_; // If there are volatile field accesses.
490 bool has_monitor_operations_; // If there are monitor operations.
491
492 DISALLOW_COPY_AND_ASSIGN(HeapLocationCollector);
493};
494
495class LoadStoreAnalysis : public HOptimization {
496 public:
497 explicit LoadStoreAnalysis(HGraph* graph)
498 : HOptimization(graph, kLoadStoreAnalysisPassName),
499 heap_location_collector_(graph) {}
500
501 const HeapLocationCollector& GetHeapLocationCollector() const {
502 return heap_location_collector_;
503 }
504
505 void Run() OVERRIDE;
506
507 static constexpr const char* kLoadStoreAnalysisPassName = "load_store_analysis";
508
509 private:
510 HeapLocationCollector heap_location_collector_;
511
512 DISALLOW_COPY_AND_ASSIGN(LoadStoreAnalysis);
513};
514
515} // namespace art
516
517#endif // ART_COMPILER_OPTIMIZING_LOAD_STORE_ANALYSIS_H_