load_store_analysis.h revision 2ca10eb3f47ef3c2535c137853f7a63d10bb908b
1/*
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.
28class ReferenceInfo : public ArenaObject<kArenaAllocLSA> {
29 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    CalculateEscape(reference_,
37                    nullptr,
38                    &is_singleton_,
39                    &is_singleton_and_not_returned_,
40                    &is_singleton_and_not_deopt_visible_);
41  }
42
43  HInstruction* GetReference() const {
44    return reference_;
45  }
46
47  size_t GetPosition() const {
48    return position_;
49  }
50
51  // Returns true if reference_ is the only name that can refer to its value during
52  // the lifetime of the method. So it's guaranteed to not have any alias in
53  // the method (including its callees).
54  bool IsSingleton() const {
55    return is_singleton_;
56  }
57
58  // Returns true if reference_ is a singleton and not returned to the caller or
59  // used as an environment local of an HDeoptimize instruction.
60  // The allocation and stores into reference_ may be eliminated for such cases.
61  bool IsSingletonAndRemovable() const {
62    return is_singleton_and_not_returned_ && is_singleton_and_not_deopt_visible_;
63  }
64
65  // Returns true if reference_ is a singleton and returned to the caller or
66  // used as an environment local of an HDeoptimize instruction.
67  bool IsSingletonAndNonRemovable() const {
68    return is_singleton_ &&
69           (!is_singleton_and_not_returned_ || !is_singleton_and_not_deopt_visible_);
70  }
71
72 private:
73  HInstruction* const reference_;
74  const size_t position_;  // position in HeapLocationCollector's ref_info_array_.
75
76  // Can only be referred to by a single name in the method.
77  bool is_singleton_;
78  // Is singleton and not returned to caller.
79  bool is_singleton_and_not_returned_;
80  // Is singleton and not used as an environment local of HDeoptimize.
81  bool is_singleton_and_not_deopt_visible_;
82
83  DISALLOW_COPY_AND_ASSIGN(ReferenceInfo);
84};
85
86// A heap location is a reference-offset/index pair that a value can be loaded from
87// or stored to.
88class HeapLocation : public ArenaObject<kArenaAllocLSA> {
89 public:
90  static constexpr size_t kInvalidFieldOffset = -1;
91  // Default value for heap locations which are not vector data.
92  static constexpr size_t kScalar = 1;
93  // TODO: more fine-grained array types.
94  static constexpr int16_t kDeclaringClassDefIndexForArrays = -1;
95
96  HeapLocation(ReferenceInfo* ref_info,
97               size_t offset,
98               HInstruction* index,
99               size_t vector_length,
100               int16_t declaring_class_def_index)
101      : ref_info_(ref_info),
102        offset_(offset),
103        index_(index),
104        vector_length_(vector_length),
105        declaring_class_def_index_(declaring_class_def_index),
106        value_killed_by_loop_side_effects_(true),
107        has_aliased_locations_(false) {
108    DCHECK(ref_info != nullptr);
109    DCHECK((offset == kInvalidFieldOffset && index != nullptr) ||
110           (offset != kInvalidFieldOffset && index == nullptr));
111    if (ref_info->IsSingleton() && !IsArray()) {
112      // Assume this location's value cannot be killed by loop side effects
113      // until proven otherwise.
114      value_killed_by_loop_side_effects_ = false;
115    }
116  }
117
118  ReferenceInfo* GetReferenceInfo() const { return ref_info_; }
119  size_t GetOffset() const { return offset_; }
120  HInstruction* GetIndex() const { return index_; }
121  size_t GetVectorLength() const { return vector_length_; }
122
123  // Returns the definition of declaring class' dex index.
124  // It's kDeclaringClassDefIndexForArrays for an array element.
125  int16_t GetDeclaringClassDefIndex() const {
126    return declaring_class_def_index_;
127  }
128
129  bool IsArray() const {
130    return index_ != nullptr;
131  }
132
133  bool IsValueKilledByLoopSideEffects() const {
134    return value_killed_by_loop_side_effects_;
135  }
136
137  void SetValueKilledByLoopSideEffects(bool val) {
138    value_killed_by_loop_side_effects_ = val;
139  }
140
141  bool HasAliasedLocations() const {
142    return has_aliased_locations_;
143  }
144
145  void SetHasAliasedLocations(bool val) {
146    has_aliased_locations_ = val;
147  }
148
149 private:
150  // Reference for instance/static field, array element or vector data.
151  ReferenceInfo* const ref_info_;
152  // Offset of static/instance field.
153  // Invalid when this HeapLocation is not field.
154  const size_t offset_;
155  // Index of an array element or starting index of vector data.
156  // Invalid when this HeapLocation is not array.
157  HInstruction* const index_;
158  // Vector length of vector data.
159  // When this HeapLocation is not vector data, it's value is kScalar.
160  const size_t vector_length_;
161  // Declaring class's def's dex index.
162  // Invalid when this HeapLocation is not field access.
163  const int16_t declaring_class_def_index_;
164
165  // Value of this location may be killed by loop side effects
166  // because this location is stored into inside a loop.
167  // This gives better info on whether a singleton's location
168  // value may be killed by loop side effects.
169  bool value_killed_by_loop_side_effects_;
170
171  // Has aliased heap locations in the method, due to either the
172  // reference is aliased or the array element is aliased via different
173  // index names.
174  bool has_aliased_locations_;
175
176  DISALLOW_COPY_AND_ASSIGN(HeapLocation);
177};
178
179// A HeapLocationCollector collects all relevant heap locations and keeps
180// an aliasing matrix for all locations.
181class HeapLocationCollector : public HGraphVisitor {
182 public:
183  static constexpr size_t kHeapLocationNotFound = -1;
184  // Start with a single uint32_t word. That's enough bits for pair-wise
185  // aliasing matrix of 8 heap locations.
186  static constexpr uint32_t kInitialAliasingMatrixBitVectorSize = 32;
187
188  explicit HeapLocationCollector(HGraph* graph)
189      : HGraphVisitor(graph),
190        ref_info_array_(graph->GetAllocator()->Adapter(kArenaAllocLSA)),
191        heap_locations_(graph->GetAllocator()->Adapter(kArenaAllocLSA)),
192        aliasing_matrix_(graph->GetAllocator(),
193                         kInitialAliasingMatrixBitVectorSize,
194                         true,
195                         kArenaAllocLSA),
196        has_heap_stores_(false),
197        has_volatile_(false),
198        has_monitor_operations_(false) {}
199
200  void CleanUp() {
201    heap_locations_.clear();
202    ref_info_array_.clear();
203  }
204
205  size_t GetNumberOfHeapLocations() const {
206    return heap_locations_.size();
207  }
208
209  HeapLocation* GetHeapLocation(size_t index) const {
210    return heap_locations_[index];
211  }
212
213  HInstruction* HuntForOriginalReference(HInstruction* ref) const {
214    // An original reference can be transformed by instructions like:
215    //   i0 NewArray
216    //   i1 HInstruction(i0)  <-- NullCheck, BoundType, IntermediateAddress.
217    //   i2 ArrayGet(i1, index)
218    DCHECK(ref != nullptr);
219    while (ref->IsNullCheck() || ref->IsBoundType() || ref->IsIntermediateAddress()) {
220      ref = ref->InputAt(0);
221    }
222    return ref;
223  }
224
225  ReferenceInfo* FindReferenceInfoOf(HInstruction* ref) const {
226    for (size_t i = 0; i < ref_info_array_.size(); i++) {
227      ReferenceInfo* ref_info = ref_info_array_[i];
228      if (ref_info->GetReference() == ref) {
229        DCHECK_EQ(i, ref_info->GetPosition());
230        return ref_info;
231      }
232    }
233    return nullptr;
234  }
235
236  size_t GetFieldHeapLocation(HInstruction* object, const FieldInfo* field) const {
237    DCHECK(object != nullptr);
238    DCHECK(field != nullptr);
239    return FindHeapLocationIndex(FindReferenceInfoOf(HuntForOriginalReference(object)),
240                                 field->GetFieldOffset().SizeValue(),
241                                 nullptr,
242                                 HeapLocation::kScalar,
243                                 field->GetDeclaringClassDefIndex());
244  }
245
246  size_t GetArrayHeapLocation(HInstruction* array,
247                              HInstruction* index,
248                              size_t vector_length = HeapLocation::kScalar) const {
249    DCHECK(array != nullptr);
250    DCHECK(index != nullptr);
251    DCHECK_GE(vector_length, HeapLocation::kScalar);
252    return FindHeapLocationIndex(FindReferenceInfoOf(HuntForOriginalReference(array)),
253                                 HeapLocation::kInvalidFieldOffset,
254                                 index,
255                                 vector_length,
256                                 HeapLocation::kDeclaringClassDefIndexForArrays);
257  }
258
259  bool HasHeapStores() const {
260    return has_heap_stores_;
261  }
262
263  bool HasVolatile() const {
264    return has_volatile_;
265  }
266
267  bool HasMonitorOps() const {
268    return has_monitor_operations_;
269  }
270
271  // Find and return the heap location index in heap_locations_.
272  // NOTE: When heap locations are created, potentially aliasing/overlapping
273  // accesses are given different indexes. This find function also
274  // doesn't take aliasing/overlapping into account. For example,
275  // this function returns three different indexes for:
276  // - ref_info=array, index=i, vector_length=kScalar;
277  // - ref_info=array, index=i, vector_length=2;
278  // - ref_info=array, index=i, vector_length=4;
279  // In later analysis, ComputeMayAlias() and MayAlias() compute and tell whether
280  // these indexes alias.
281  size_t FindHeapLocationIndex(ReferenceInfo* ref_info,
282                               size_t offset,
283                               HInstruction* index,
284                               size_t vector_length,
285                               int16_t declaring_class_def_index) const {
286    for (size_t i = 0; i < heap_locations_.size(); i++) {
287      HeapLocation* loc = heap_locations_[i];
288      if (loc->GetReferenceInfo() == ref_info &&
289          loc->GetOffset() == offset &&
290          loc->GetIndex() == index &&
291          loc->GetVectorLength() == vector_length &&
292          loc->GetDeclaringClassDefIndex() == declaring_class_def_index) {
293        return i;
294      }
295    }
296    return kHeapLocationNotFound;
297  }
298
299  // Returns true if heap_locations_[index1] and heap_locations_[index2] may alias.
300  bool MayAlias(size_t index1, size_t index2) const {
301    if (index1 < index2) {
302      return aliasing_matrix_.IsBitSet(AliasingMatrixPosition(index1, index2));
303    } else if (index1 > index2) {
304      return aliasing_matrix_.IsBitSet(AliasingMatrixPosition(index2, index1));
305    } else {
306      DCHECK(false) << "index1 and index2 are expected to be different";
307      return true;
308    }
309  }
310
311  void BuildAliasingMatrix() {
312    const size_t number_of_locations = heap_locations_.size();
313    if (number_of_locations == 0) {
314      return;
315    }
316    size_t pos = 0;
317    // Compute aliasing info between every pair of different heap locations.
318    // Save the result in a matrix represented as a BitVector.
319    for (size_t i = 0; i < number_of_locations - 1; i++) {
320      for (size_t j = i + 1; j < number_of_locations; j++) {
321        if (ComputeMayAlias(i, j)) {
322          aliasing_matrix_.SetBit(CheckedAliasingMatrixPosition(i, j, pos));
323        }
324        pos++;
325      }
326    }
327  }
328
329 private:
330  // An allocation cannot alias with a name which already exists at the point
331  // of the allocation, such as a parameter or a load happening before the allocation.
332  bool MayAliasWithPreexistenceChecking(ReferenceInfo* ref_info1, ReferenceInfo* ref_info2) const {
333    if (ref_info1->GetReference()->IsNewInstance() || ref_info1->GetReference()->IsNewArray()) {
334      // Any reference that can alias with the allocation must appear after it in the block/in
335      // the block's successors. In reverse post order, those instructions will be visited after
336      // the allocation.
337      return ref_info2->GetPosition() >= ref_info1->GetPosition();
338    }
339    return true;
340  }
341
342  bool CanReferencesAlias(ReferenceInfo* ref_info1, ReferenceInfo* ref_info2) const {
343    if (ref_info1 == ref_info2) {
344      return true;
345    } else if (ref_info1->IsSingleton()) {
346      return false;
347    } else if (ref_info2->IsSingleton()) {
348      return false;
349    } else if (!MayAliasWithPreexistenceChecking(ref_info1, ref_info2) ||
350        !MayAliasWithPreexistenceChecking(ref_info2, ref_info1)) {
351      return false;
352    }
353    return true;
354  }
355
356  bool CanArrayElementsAlias(const HInstruction* idx1,
357                             const size_t vector_length1,
358                             const HInstruction* idx2,
359                             const size_t vector_length2) const;
360
361  // `index1` and `index2` are indices in the array of collected heap locations.
362  // Returns the position in the bit vector that tracks whether the two heap
363  // locations may alias.
364  size_t AliasingMatrixPosition(size_t index1, size_t index2) const {
365    DCHECK(index2 > index1);
366    const size_t number_of_locations = heap_locations_.size();
367    // It's (num_of_locations - 1) + ... + (num_of_locations - index1) + (index2 - index1 - 1).
368    return (number_of_locations * index1 - (1 + index1) * index1 / 2 + (index2 - index1 - 1));
369  }
370
371  // An additional position is passed in to make sure the calculated position is correct.
372  size_t CheckedAliasingMatrixPosition(size_t index1, size_t index2, size_t position) {
373    size_t calculated_position = AliasingMatrixPosition(index1, index2);
374    DCHECK_EQ(calculated_position, position);
375    return calculated_position;
376  }
377
378  // Compute if two locations may alias to each other.
379  bool ComputeMayAlias(size_t index1, size_t index2) const {
380    DCHECK_NE(index1, index2);
381    HeapLocation* loc1 = heap_locations_[index1];
382    HeapLocation* loc2 = heap_locations_[index2];
383    if (loc1->GetOffset() != loc2->GetOffset()) {
384      // Either two different instance fields, or one is an instance
385      // field and the other is an array data.
386      return false;
387    }
388    if (loc1->GetDeclaringClassDefIndex() != loc2->GetDeclaringClassDefIndex()) {
389      // Different types.
390      return false;
391    }
392    if (!CanReferencesAlias(loc1->GetReferenceInfo(), loc2->GetReferenceInfo())) {
393      return false;
394    }
395    if (loc1->IsArray() && loc2->IsArray()) {
396      HInstruction* idx1 = loc1->GetIndex();
397      HInstruction* idx2 = loc2->GetIndex();
398      size_t vector_length1 = loc1->GetVectorLength();
399      size_t vector_length2 = loc2->GetVectorLength();
400      if (!CanArrayElementsAlias(idx1, vector_length1, idx2, vector_length2)) {
401        return false;
402      }
403    }
404    loc1->SetHasAliasedLocations(true);
405    loc2->SetHasAliasedLocations(true);
406    return true;
407  }
408
409  ReferenceInfo* GetOrCreateReferenceInfo(HInstruction* instruction) {
410    ReferenceInfo* ref_info = FindReferenceInfoOf(instruction);
411    if (ref_info == nullptr) {
412      size_t pos = ref_info_array_.size();
413      ref_info = new (GetGraph()->GetAllocator()) ReferenceInfo(instruction, pos);
414      ref_info_array_.push_back(ref_info);
415    }
416    return ref_info;
417  }
418
419  void CreateReferenceInfoForReferenceType(HInstruction* instruction) {
420    if (instruction->GetType() != DataType::Type::kReference) {
421      return;
422    }
423    DCHECK(FindReferenceInfoOf(instruction) == nullptr);
424    GetOrCreateReferenceInfo(instruction);
425  }
426
427  HeapLocation* GetOrCreateHeapLocation(HInstruction* ref,
428                                        size_t offset,
429                                        HInstruction* index,
430                                        size_t vector_length,
431                                        int16_t declaring_class_def_index) {
432    HInstruction* original_ref = HuntForOriginalReference(ref);
433    ReferenceInfo* ref_info = GetOrCreateReferenceInfo(original_ref);
434    size_t heap_location_idx = FindHeapLocationIndex(
435        ref_info, offset, index, vector_length, declaring_class_def_index);
436    if (heap_location_idx == kHeapLocationNotFound) {
437      HeapLocation* heap_loc = new (GetGraph()->GetAllocator())
438          HeapLocation(ref_info, offset, index, vector_length, declaring_class_def_index);
439      heap_locations_.push_back(heap_loc);
440      return heap_loc;
441    }
442    return heap_locations_[heap_location_idx];
443  }
444
445  HeapLocation* VisitFieldAccess(HInstruction* ref, const FieldInfo& field_info) {
446    if (field_info.IsVolatile()) {
447      has_volatile_ = true;
448    }
449    const uint16_t declaring_class_def_index = field_info.GetDeclaringClassDefIndex();
450    const size_t offset = field_info.GetFieldOffset().SizeValue();
451    return GetOrCreateHeapLocation(ref,
452                                   offset,
453                                   nullptr,
454                                   HeapLocation::kScalar,
455                                   declaring_class_def_index);
456  }
457
458  void VisitArrayAccess(HInstruction* array, HInstruction* index, size_t vector_length) {
459    GetOrCreateHeapLocation(array,
460                            HeapLocation::kInvalidFieldOffset,
461                            index,
462                            vector_length,
463                            HeapLocation::kDeclaringClassDefIndexForArrays);
464  }
465
466  void VisitInstanceFieldGet(HInstanceFieldGet* instruction) OVERRIDE {
467    VisitFieldAccess(instruction->InputAt(0), instruction->GetFieldInfo());
468    CreateReferenceInfoForReferenceType(instruction);
469  }
470
471  void VisitInstanceFieldSet(HInstanceFieldSet* instruction) OVERRIDE {
472    HeapLocation* location = VisitFieldAccess(instruction->InputAt(0), instruction->GetFieldInfo());
473    has_heap_stores_ = true;
474    if (location->GetReferenceInfo()->IsSingleton()) {
475      // A singleton's location value may be killed by loop side effects if it's
476      // defined before that loop, and it's stored into inside that loop.
477      HLoopInformation* loop_info = instruction->GetBlock()->GetLoopInformation();
478      if (loop_info != nullptr) {
479        HInstruction* ref = location->GetReferenceInfo()->GetReference();
480        DCHECK(ref->IsNewInstance());
481        if (loop_info->IsDefinedOutOfTheLoop(ref)) {
482          // ref's location value may be killed by this loop's side effects.
483          location->SetValueKilledByLoopSideEffects(true);
484        } else {
485          // ref is defined inside this loop so this loop's side effects cannot
486          // kill its location value at the loop header since ref/its location doesn't
487          // exist yet at the loop header.
488        }
489      }
490    } else {
491      // For non-singletons, value_killed_by_loop_side_effects_ is inited to
492      // true.
493      DCHECK_EQ(location->IsValueKilledByLoopSideEffects(), true);
494    }
495  }
496
497  void VisitStaticFieldGet(HStaticFieldGet* instruction) OVERRIDE {
498    VisitFieldAccess(instruction->InputAt(0), instruction->GetFieldInfo());
499    CreateReferenceInfoForReferenceType(instruction);
500  }
501
502  void VisitStaticFieldSet(HStaticFieldSet* instruction) OVERRIDE {
503    VisitFieldAccess(instruction->InputAt(0), instruction->GetFieldInfo());
504    has_heap_stores_ = true;
505  }
506
507  // We intentionally don't collect HUnresolvedInstanceField/HUnresolvedStaticField accesses
508  // since we cannot accurately track the fields.
509
510  void VisitArrayGet(HArrayGet* instruction) OVERRIDE {
511    HInstruction* array = instruction->InputAt(0);
512    HInstruction* index = instruction->InputAt(1);
513    VisitArrayAccess(array, index, HeapLocation::kScalar);
514    CreateReferenceInfoForReferenceType(instruction);
515  }
516
517  void VisitArraySet(HArraySet* instruction) OVERRIDE {
518    HInstruction* array = instruction->InputAt(0);
519    HInstruction* index = instruction->InputAt(1);
520    VisitArrayAccess(array, index, HeapLocation::kScalar);
521    has_heap_stores_ = true;
522  }
523
524  void VisitVecLoad(HVecLoad* instruction) OVERRIDE {
525    HInstruction* array = instruction->InputAt(0);
526    HInstruction* index = instruction->InputAt(1);
527    VisitArrayAccess(array, index, instruction->GetVectorLength());
528    CreateReferenceInfoForReferenceType(instruction);
529  }
530
531  void VisitVecStore(HVecStore* instruction) OVERRIDE {
532    HInstruction* array = instruction->InputAt(0);
533    HInstruction* index = instruction->InputAt(1);
534    VisitArrayAccess(array, index, instruction->GetVectorLength());
535    has_heap_stores_ = true;
536  }
537
538  void VisitInstruction(HInstruction* instruction) OVERRIDE {
539    // Any new-instance or new-array cannot alias with references that
540    // pre-exist the new-instance/new-array. We append entries into
541    // ref_info_array_ which keeps track of the order of creation
542    // of reference values since we visit the blocks in reverse post order.
543    //
544    // By default, VisitXXX() (including VisitPhi()) calls VisitInstruction(),
545    // unless VisitXXX() is overridden. VisitInstanceFieldGet() etc. above
546    // also call CreateReferenceInfoForReferenceType() explicitly.
547    CreateReferenceInfoForReferenceType(instruction);
548  }
549
550  void VisitMonitorOperation(HMonitorOperation* monitor ATTRIBUTE_UNUSED) OVERRIDE {
551    has_monitor_operations_ = true;
552  }
553
554  ArenaVector<ReferenceInfo*> ref_info_array_;   // All references used for heap accesses.
555  ArenaVector<HeapLocation*> heap_locations_;    // All heap locations.
556  ArenaBitVector aliasing_matrix_;    // aliasing info between each pair of locations.
557  bool has_heap_stores_;    // If there is no heap stores, LSE acts as GVN with better
558                            // alias analysis and won't be as effective.
559  bool has_volatile_;       // If there are volatile field accesses.
560  bool has_monitor_operations_;    // If there are monitor operations.
561
562  DISALLOW_COPY_AND_ASSIGN(HeapLocationCollector);
563};
564
565class LoadStoreAnalysis : public HOptimization {
566 public:
567  explicit LoadStoreAnalysis(HGraph* graph, const char* name = kLoadStoreAnalysisPassName)
568    : HOptimization(graph, name),
569      heap_location_collector_(graph) {}
570
571  const HeapLocationCollector& GetHeapLocationCollector() const {
572    return heap_location_collector_;
573  }
574
575  void Run() OVERRIDE;
576
577  static constexpr const char* kLoadStoreAnalysisPassName = "load_store_analysis";
578
579 private:
580  HeapLocationCollector heap_location_collector_;
581
582  DISALLOW_COPY_AND_ASSIGN(LoadStoreAnalysis);
583};
584
585}  // namespace art
586
587#endif  // ART_COMPILER_OPTIMIZING_LOAD_STORE_ANALYSIS_H_
588