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