Home | History | Annotate | Download | only in optimizing
      1 /*
      2  * Copyright (C) 2015 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_elimination.h"
     18 
     19 #include "base/array_ref.h"
     20 #include "base/scoped_arena_allocator.h"
     21 #include "base/scoped_arena_containers.h"
     22 #include "escape.h"
     23 #include "load_store_analysis.h"
     24 #include "side_effects_analysis.h"
     25 
     26 #include <iostream>
     27 
     28 /**
     29  * The general algorithm of load-store elimination (LSE).
     30  * Load-store analysis in the previous pass collects a list of heap locations
     31  * and does alias analysis of those heap locations.
     32  * LSE keeps track of a list of heap values corresponding to the heap
     33  * locations. It visits basic blocks in reverse post order and for
     34  * each basic block, visits instructions sequentially, and processes
     35  * instructions as follows:
     36  * - If the instruction is a load, and the heap location for that load has a
     37  *   valid heap value, the load can be eliminated. In order to maintain the
     38  *   validity of all heap locations during the optimization phase, the real
     39  *   elimination is delayed till the end of LSE.
     40  * - If the instruction is a store, it updates the heap value for the heap
     41  *   location of the store with the store instruction. The real heap value
     42  *   can be fetched from the store instruction. Heap values are invalidated
     43  *   for heap locations that may alias with the store instruction's heap
     44  *   location. The store instruction can be eliminated unless the value stored
     45  *   is later needed e.g. by a load from the same/aliased heap location or
     46  *   the heap location persists at method return/deoptimization.
     47  *   The store instruction is also needed if it's not used to track the heap
     48  *   value anymore, e.g. when it fails to merge with the heap values from other
     49  *   predecessors.
     50  * - A store that stores the same value as the heap value is eliminated.
     51  * - The list of heap values are merged at basic block entry from the basic
     52  *   block's predecessors. The algorithm is single-pass, so loop side-effects is
     53  *   used as best effort to decide if a heap location is stored inside the loop.
     54  * - A special type of objects called singletons are instantiated in the method
     55  *   and have a single name, i.e. no aliases. Singletons have exclusive heap
     56  *   locations since they have no aliases. Singletons are helpful in narrowing
     57  *   down the life span of a heap location such that they do not always
     58  *   need to participate in merging heap values. Allocation of a singleton
     59  *   can be eliminated if that singleton is not used and does not persist
     60  *   at method return/deoptimization.
     61  * - For newly instantiated instances, their heap values are initialized to
     62  *   language defined default values.
     63  * - Some instructions such as invokes are treated as loading and invalidating
     64  *   all the heap values, depending on the instruction's side effects.
     65  * - Finalizable objects are considered as persisting at method
     66  *   return/deoptimization.
     67  * - Currently this LSE algorithm doesn't handle SIMD graph, e.g. with VecLoad
     68  *   and VecStore instructions.
     69  * - Currently this LSE algorithm doesn't handle graph with try-catch, due to
     70  *   the special block merging structure.
     71  */
     72 
     73 namespace art {
     74 
     75 // An unknown heap value. Loads with such a value in the heap location cannot be eliminated.
     76 // A heap location can be set to kUnknownHeapValue when:
     77 // - initially set a value.
     78 // - killed due to aliasing, merging, invocation, or loop side effects.
     79 static HInstruction* const kUnknownHeapValue =
     80     reinterpret_cast<HInstruction*>(static_cast<uintptr_t>(-1));
     81 
     82 // Default heap value after an allocation.
     83 // A heap location can be set to that value right after an allocation.
     84 static HInstruction* const kDefaultHeapValue =
     85     reinterpret_cast<HInstruction*>(static_cast<uintptr_t>(-2));
     86 
     87 // Use HGraphDelegateVisitor for which all VisitInvokeXXX() delegate to VisitInvoke().
     88 class LSEVisitor : public HGraphDelegateVisitor {
     89  public:
     90   LSEVisitor(HGraph* graph,
     91              const HeapLocationCollector& heap_locations_collector,
     92              const SideEffectsAnalysis& side_effects,
     93              OptimizingCompilerStats* stats)
     94       : HGraphDelegateVisitor(graph, stats),
     95         heap_location_collector_(heap_locations_collector),
     96         side_effects_(side_effects),
     97         allocator_(graph->GetArenaStack()),
     98         heap_values_for_(graph->GetBlocks().size(),
     99                          ScopedArenaVector<HInstruction*>(heap_locations_collector.
    100                                                           GetNumberOfHeapLocations(),
    101                                                           kUnknownHeapValue,
    102                                                           allocator_.Adapter(kArenaAllocLSE)),
    103                          allocator_.Adapter(kArenaAllocLSE)),
    104         removed_loads_(allocator_.Adapter(kArenaAllocLSE)),
    105         substitute_instructions_for_loads_(allocator_.Adapter(kArenaAllocLSE)),
    106         possibly_removed_stores_(allocator_.Adapter(kArenaAllocLSE)),
    107         singleton_new_instances_(allocator_.Adapter(kArenaAllocLSE)) {
    108   }
    109 
    110   void VisitBasicBlock(HBasicBlock* block) override {
    111     // Populate the heap_values array for this block.
    112     // TODO: try to reuse the heap_values array from one predecessor if possible.
    113     if (block->IsLoopHeader()) {
    114       HandleLoopSideEffects(block);
    115     } else {
    116       MergePredecessorValues(block);
    117     }
    118     HGraphVisitor::VisitBasicBlock(block);
    119   }
    120 
    121   HTypeConversion* AddTypeConversionIfNecessary(HInstruction* instruction,
    122                                                 HInstruction* value,
    123                                                 DataType::Type expected_type) {
    124     HTypeConversion* type_conversion = nullptr;
    125     // Should never add type conversion into boolean value.
    126     if (expected_type != DataType::Type::kBool &&
    127         !DataType::IsTypeConversionImplicit(value->GetType(), expected_type)) {
    128       type_conversion = new (GetGraph()->GetAllocator()) HTypeConversion(
    129           expected_type, value, instruction->GetDexPc());
    130       instruction->GetBlock()->InsertInstructionBefore(type_conversion, instruction);
    131     }
    132     return type_conversion;
    133   }
    134 
    135   // Find an instruction's substitute if it's a removed load.
    136   // Return the same instruction if it should not be removed.
    137   HInstruction* FindSubstitute(HInstruction* instruction) {
    138     if (!IsLoad(instruction)) {
    139       return instruction;
    140     }
    141     size_t size = removed_loads_.size();
    142     for (size_t i = 0; i < size; i++) {
    143       if (removed_loads_[i] == instruction) {
    144         HInstruction* substitute = substitute_instructions_for_loads_[i];
    145         // The substitute list is a flat hierarchy.
    146         DCHECK_EQ(FindSubstitute(substitute), substitute);
    147         return substitute;
    148       }
    149     }
    150     return instruction;
    151   }
    152 
    153   void AddRemovedLoad(HInstruction* load, HInstruction* heap_value) {
    154     DCHECK(IsLoad(load));
    155     DCHECK_EQ(FindSubstitute(heap_value), heap_value) <<
    156         "Unexpected heap_value that has a substitute " << heap_value->DebugName();
    157     removed_loads_.push_back(load);
    158     substitute_instructions_for_loads_.push_back(heap_value);
    159   }
    160 
    161   // Scan the list of removed loads to see if we can reuse `type_conversion`, if
    162   // the other removed load has the same substitute and type and is dominated
    163   // by `type_conversion`.
    164   void TryToReuseTypeConversion(HInstruction* type_conversion, size_t index) {
    165     size_t size = removed_loads_.size();
    166     HInstruction* load = removed_loads_[index];
    167     HInstruction* substitute = substitute_instructions_for_loads_[index];
    168     for (size_t j = index + 1; j < size; j++) {
    169       HInstruction* load2 = removed_loads_[j];
    170       HInstruction* substitute2 = substitute_instructions_for_loads_[j];
    171       if (load2 == nullptr) {
    172         DCHECK(substitute2->IsTypeConversion());
    173         continue;
    174       }
    175       DCHECK(load2->IsInstanceFieldGet() ||
    176              load2->IsStaticFieldGet() ||
    177              load2->IsArrayGet());
    178       DCHECK(substitute2 != nullptr);
    179       if (substitute2 == substitute &&
    180           load2->GetType() == load->GetType() &&
    181           type_conversion->GetBlock()->Dominates(load2->GetBlock()) &&
    182           // Don't share across irreducible loop headers.
    183           // TODO: can be more fine-grained than this by testing each dominator.
    184           (load2->GetBlock() == type_conversion->GetBlock() ||
    185            !GetGraph()->HasIrreducibleLoops())) {
    186         // The removed_loads_ are added in reverse post order.
    187         DCHECK(type_conversion->StrictlyDominates(load2));
    188         load2->ReplaceWith(type_conversion);
    189         load2->GetBlock()->RemoveInstruction(load2);
    190         removed_loads_[j] = nullptr;
    191         substitute_instructions_for_loads_[j] = type_conversion;
    192       }
    193     }
    194   }
    195 
    196   // Remove recorded instructions that should be eliminated.
    197   void RemoveInstructions() {
    198     size_t size = removed_loads_.size();
    199     DCHECK_EQ(size, substitute_instructions_for_loads_.size());
    200     for (size_t i = 0; i < size; i++) {
    201       HInstruction* load = removed_loads_[i];
    202       if (load == nullptr) {
    203         // The load has been handled in the scan for type conversion below.
    204         DCHECK(substitute_instructions_for_loads_[i]->IsTypeConversion());
    205         continue;
    206       }
    207       DCHECK(load->IsInstanceFieldGet() ||
    208              load->IsStaticFieldGet() ||
    209              load->IsArrayGet());
    210       HInstruction* substitute = substitute_instructions_for_loads_[i];
    211       DCHECK(substitute != nullptr);
    212       // We proactively retrieve the substitute for a removed load, so
    213       // a load that has a substitute should not be observed as a heap
    214       // location value.
    215       DCHECK_EQ(FindSubstitute(substitute), substitute);
    216 
    217       // The load expects to load the heap value as type load->GetType().
    218       // However the tracked heap value may not be of that type. An explicit
    219       // type conversion may be needed.
    220       // There are actually three types involved here:
    221       // (1) tracked heap value's type (type A)
    222       // (2) heap location (field or element)'s type (type B)
    223       // (3) load's type (type C)
    224       // We guarantee that type A stored as type B and then fetched out as
    225       // type C is the same as casting from type A to type C directly, since
    226       // type B and type C will have the same size which is guarenteed in
    227       // HInstanceFieldGet/HStaticFieldGet/HArrayGet's SetType().
    228       // So we only need one type conversion from type A to type C.
    229       HTypeConversion* type_conversion = AddTypeConversionIfNecessary(
    230           load, substitute, load->GetType());
    231       if (type_conversion != nullptr) {
    232         TryToReuseTypeConversion(type_conversion, i);
    233         load->ReplaceWith(type_conversion);
    234         substitute_instructions_for_loads_[i] = type_conversion;
    235       } else {
    236         load->ReplaceWith(substitute);
    237       }
    238       load->GetBlock()->RemoveInstruction(load);
    239     }
    240 
    241     // At this point, stores in possibly_removed_stores_ can be safely removed.
    242     for (HInstruction* store : possibly_removed_stores_) {
    243       DCHECK(store->IsInstanceFieldSet() || store->IsStaticFieldSet() || store->IsArraySet());
    244       store->GetBlock()->RemoveInstruction(store);
    245     }
    246 
    247     // Eliminate singleton-classified instructions:
    248     //   * - Constructor fences (they never escape this thread).
    249     //   * - Allocations (if they are unused).
    250     for (HInstruction* new_instance : singleton_new_instances_) {
    251       size_t removed = HConstructorFence::RemoveConstructorFences(new_instance);
    252       MaybeRecordStat(stats_,
    253                       MethodCompilationStat::kConstructorFenceRemovedLSE,
    254                       removed);
    255 
    256       if (!new_instance->HasNonEnvironmentUses()) {
    257         new_instance->RemoveEnvironmentUsers();
    258         new_instance->GetBlock()->RemoveInstruction(new_instance);
    259       }
    260     }
    261   }
    262 
    263  private:
    264   static bool IsLoad(HInstruction* instruction) {
    265     if (instruction == kUnknownHeapValue || instruction == kDefaultHeapValue) {
    266       return false;
    267     }
    268     // Unresolved load is not treated as a load.
    269     return instruction->IsInstanceFieldGet() ||
    270         instruction->IsStaticFieldGet() ||
    271         instruction->IsArrayGet();
    272   }
    273 
    274   static bool IsStore(HInstruction* instruction) {
    275     if (instruction == kUnknownHeapValue || instruction == kDefaultHeapValue) {
    276       return false;
    277     }
    278     // Unresolved store is not treated as a store.
    279     return instruction->IsInstanceFieldSet() ||
    280         instruction->IsArraySet() ||
    281         instruction->IsStaticFieldSet();
    282   }
    283 
    284   // Returns the real heap value by finding its substitute or by "peeling"
    285   // a store instruction.
    286   HInstruction* GetRealHeapValue(HInstruction* heap_value) {
    287     if (IsLoad(heap_value)) {
    288       return FindSubstitute(heap_value);
    289     }
    290     if (!IsStore(heap_value)) {
    291       return heap_value;
    292     }
    293 
    294     // We keep track of store instructions as the heap values which might be
    295     // eliminated if the stores are later found not necessary. The real stored
    296     // value needs to be fetched from the store instruction.
    297     if (heap_value->IsInstanceFieldSet()) {
    298       heap_value = heap_value->AsInstanceFieldSet()->GetValue();
    299     } else if (heap_value->IsStaticFieldSet()) {
    300       heap_value = heap_value->AsStaticFieldSet()->GetValue();
    301     } else {
    302       DCHECK(heap_value->IsArraySet());
    303       heap_value = heap_value->AsArraySet()->GetValue();
    304     }
    305     // heap_value may already be a removed load.
    306     return FindSubstitute(heap_value);
    307   }
    308 
    309   // If heap_value is a store, need to keep the store.
    310   // This is necessary if a heap value is killed or replaced by another value,
    311   // so that the store is no longer used to track heap value.
    312   void KeepIfIsStore(HInstruction* heap_value) {
    313     if (!IsStore(heap_value)) {
    314       return;
    315     }
    316     auto idx = std::find(possibly_removed_stores_.begin(),
    317         possibly_removed_stores_.end(), heap_value);
    318     if (idx != possibly_removed_stores_.end()) {
    319       // Make sure the store is kept.
    320       possibly_removed_stores_.erase(idx);
    321     }
    322   }
    323 
    324   // If a heap location X may alias with heap location at `loc_index`
    325   // and heap_values of that heap location X holds a store, keep that store.
    326   // It's needed for a dependent load that's not eliminated since any store
    327   // that may put value into the load's heap location needs to be kept.
    328   void KeepStoresIfAliasedToLocation(ScopedArenaVector<HInstruction*>& heap_values,
    329                                      size_t loc_index) {
    330     for (size_t i = 0; i < heap_values.size(); i++) {
    331       if ((i == loc_index) || heap_location_collector_.MayAlias(i, loc_index)) {
    332         KeepIfIsStore(heap_values[i]);
    333       }
    334     }
    335   }
    336 
    337   void HandleLoopSideEffects(HBasicBlock* block) {
    338     DCHECK(block->IsLoopHeader());
    339     int block_id = block->GetBlockId();
    340     ScopedArenaVector<HInstruction*>& heap_values = heap_values_for_[block_id];
    341     HBasicBlock* pre_header = block->GetLoopInformation()->GetPreHeader();
    342     ScopedArenaVector<HInstruction*>& pre_header_heap_values =
    343         heap_values_for_[pre_header->GetBlockId()];
    344 
    345     // Don't eliminate loads in irreducible loops.
    346     // Also keep the stores before the loop.
    347     if (block->GetLoopInformation()->IsIrreducible()) {
    348       if (kIsDebugBuild) {
    349         for (size_t i = 0; i < heap_values.size(); i++) {
    350           DCHECK_EQ(heap_values[i], kUnknownHeapValue);
    351         }
    352       }
    353       for (size_t i = 0; i < heap_values.size(); i++) {
    354         KeepIfIsStore(pre_header_heap_values[i]);
    355       }
    356       return;
    357     }
    358 
    359     // Inherit the values from pre-header.
    360     for (size_t i = 0; i < heap_values.size(); i++) {
    361       heap_values[i] = pre_header_heap_values[i];
    362     }
    363 
    364     // We do a single pass in reverse post order. For loops, use the side effects as a hint
    365     // to see if the heap values should be killed.
    366     if (side_effects_.GetLoopEffects(block).DoesAnyWrite()) {
    367       for (size_t i = 0; i < heap_values.size(); i++) {
    368         HeapLocation* location = heap_location_collector_.GetHeapLocation(i);
    369         ReferenceInfo* ref_info = location->GetReferenceInfo();
    370         if (ref_info->IsSingleton() && !location->IsValueKilledByLoopSideEffects()) {
    371           // A singleton's field that's not stored into inside a loop is
    372           // invariant throughout the loop. Nothing to do.
    373         } else {
    374           // heap value is killed by loop side effects.
    375           KeepIfIsStore(pre_header_heap_values[i]);
    376           heap_values[i] = kUnknownHeapValue;
    377         }
    378       }
    379     } else {
    380       // The loop doesn't kill any value.
    381     }
    382   }
    383 
    384   void MergePredecessorValues(HBasicBlock* block) {
    385     ArrayRef<HBasicBlock* const> predecessors(block->GetPredecessors());
    386     if (predecessors.size() == 0) {
    387       return;
    388     }
    389     if (block->IsExitBlock()) {
    390       // Exit block doesn't really merge values since the control flow ends in
    391       // its predecessors. Each predecessor needs to make sure stores are kept
    392       // if necessary.
    393       return;
    394     }
    395 
    396     ScopedArenaVector<HInstruction*>& heap_values = heap_values_for_[block->GetBlockId()];
    397     for (size_t i = 0; i < heap_values.size(); i++) {
    398       HInstruction* merged_value = nullptr;
    399       // If we can merge the store itself from the predecessors, we keep
    400       // the store as the heap value as long as possible. In case we cannot
    401       // merge the store, we try to merge the values of the stores.
    402       HInstruction* merged_store_value = nullptr;
    403       // Whether merged_value is a result that's merged from all predecessors.
    404       bool from_all_predecessors = true;
    405       ReferenceInfo* ref_info = heap_location_collector_.GetHeapLocation(i)->GetReferenceInfo();
    406       HInstruction* ref = ref_info->GetReference();
    407       HInstruction* singleton_ref = nullptr;
    408       if (ref_info->IsSingleton()) {
    409         // We do more analysis based on singleton's liveness when merging
    410         // heap values for such cases.
    411         singleton_ref = ref;
    412       }
    413 
    414       for (HBasicBlock* predecessor : predecessors) {
    415         HInstruction* pred_value = heap_values_for_[predecessor->GetBlockId()][i];
    416         if (!IsStore(pred_value)) {
    417           pred_value = FindSubstitute(pred_value);
    418         }
    419         DCHECK(pred_value != nullptr);
    420         HInstruction* pred_store_value = GetRealHeapValue(pred_value);
    421         if ((singleton_ref != nullptr) &&
    422             !singleton_ref->GetBlock()->Dominates(predecessor)) {
    423           // singleton_ref is not live in this predecessor. No need to merge
    424           // since singleton_ref is not live at the beginning of this block.
    425           DCHECK_EQ(pred_value, kUnknownHeapValue);
    426           from_all_predecessors = false;
    427           break;
    428         }
    429         if (merged_value == nullptr) {
    430           // First seen heap value.
    431           DCHECK(pred_value != nullptr);
    432           merged_value = pred_value;
    433         } else if (pred_value != merged_value) {
    434           // There are conflicting values.
    435           merged_value = kUnknownHeapValue;
    436           // We may still be able to merge store values.
    437         }
    438 
    439         // Conflicting stores may be storing the same value. We do another merge
    440         // of real stored values.
    441         if (merged_store_value == nullptr) {
    442           // First seen store value.
    443           DCHECK(pred_store_value != nullptr);
    444           merged_store_value = pred_store_value;
    445         } else if (pred_store_value != merged_store_value) {
    446           // There are conflicting store values.
    447           merged_store_value = kUnknownHeapValue;
    448           // There must be conflicting stores also.
    449           DCHECK_EQ(merged_value, kUnknownHeapValue);
    450           // No need to merge anymore.
    451           break;
    452         }
    453       }
    454 
    455       if (merged_value == nullptr) {
    456         DCHECK(!from_all_predecessors);
    457         DCHECK(singleton_ref != nullptr);
    458       }
    459       if (from_all_predecessors) {
    460         if (ref_info->IsSingletonAndRemovable() &&
    461             (block->IsSingleReturnOrReturnVoidAllowingPhis() ||
    462              (block->EndsWithReturn() && (merged_value != kUnknownHeapValue ||
    463                                           merged_store_value != kUnknownHeapValue)))) {
    464           // Values in the singleton are not needed anymore:
    465           // (1) if this block consists of a sole return, or
    466           // (2) if this block returns and a usable merged value is obtained
    467           //     (loads prior to the return will always use that value).
    468         } else if (!IsStore(merged_value)) {
    469           // We don't track merged value as a store anymore. We have to
    470           // hold the stores in predecessors live here.
    471           for (HBasicBlock* predecessor : predecessors) {
    472             ScopedArenaVector<HInstruction*>& pred_values =
    473                 heap_values_for_[predecessor->GetBlockId()];
    474             KeepIfIsStore(pred_values[i]);
    475           }
    476         }
    477       } else {
    478         DCHECK(singleton_ref != nullptr);
    479         // singleton_ref is non-existing at the beginning of the block. There is
    480         // no need to keep the stores.
    481       }
    482 
    483       if (!from_all_predecessors) {
    484         DCHECK(singleton_ref != nullptr);
    485         DCHECK((singleton_ref->GetBlock() == block) ||
    486                !singleton_ref->GetBlock()->Dominates(block))
    487             << "method: " << GetGraph()->GetMethodName();
    488         // singleton_ref is not defined before block or defined only in some of its
    489         // predecessors, so block doesn't really have the location at its entry.
    490         heap_values[i] = kUnknownHeapValue;
    491       } else if (predecessors.size() == 1) {
    492         // Inherit heap value from the single predecessor.
    493         DCHECK_EQ(heap_values_for_[predecessors[0]->GetBlockId()][i], merged_value);
    494         heap_values[i] = merged_value;
    495       } else {
    496         DCHECK(merged_value == kUnknownHeapValue ||
    497                merged_value == kDefaultHeapValue ||
    498                merged_value->GetBlock()->Dominates(block));
    499         if (merged_value != kUnknownHeapValue) {
    500           heap_values[i] = merged_value;
    501         } else {
    502           // Stores in different predecessors may be storing the same value.
    503           heap_values[i] = merged_store_value;
    504         }
    505       }
    506     }
    507   }
    508 
    509   // `instruction` is being removed. Try to see if the null check on it
    510   // can be removed. This can happen if the same value is set in two branches
    511   // but not in dominators. Such as:
    512   //   int[] a = foo();
    513   //   if () {
    514   //     a[0] = 2;
    515   //   } else {
    516   //     a[0] = 2;
    517   //   }
    518   //   // a[0] can now be replaced with constant 2, and the null check on it can be removed.
    519   void TryRemovingNullCheck(HInstruction* instruction) {
    520     HInstruction* prev = instruction->GetPrevious();
    521     if ((prev != nullptr) && prev->IsNullCheck() && (prev == instruction->InputAt(0))) {
    522       // Previous instruction is a null check for this instruction. Remove the null check.
    523       prev->ReplaceWith(prev->InputAt(0));
    524       prev->GetBlock()->RemoveInstruction(prev);
    525     }
    526   }
    527 
    528   HInstruction* GetDefaultValue(DataType::Type type) {
    529     switch (type) {
    530       case DataType::Type::kReference:
    531         return GetGraph()->GetNullConstant();
    532       case DataType::Type::kBool:
    533       case DataType::Type::kUint8:
    534       case DataType::Type::kInt8:
    535       case DataType::Type::kUint16:
    536       case DataType::Type::kInt16:
    537       case DataType::Type::kInt32:
    538         return GetGraph()->GetIntConstant(0);
    539       case DataType::Type::kInt64:
    540         return GetGraph()->GetLongConstant(0);
    541       case DataType::Type::kFloat32:
    542         return GetGraph()->GetFloatConstant(0);
    543       case DataType::Type::kFloat64:
    544         return GetGraph()->GetDoubleConstant(0);
    545       default:
    546         UNREACHABLE();
    547     }
    548   }
    549 
    550   void VisitGetLocation(HInstruction* instruction, size_t idx) {
    551     DCHECK_NE(idx, HeapLocationCollector::kHeapLocationNotFound);
    552     ScopedArenaVector<HInstruction*>& heap_values =
    553         heap_values_for_[instruction->GetBlock()->GetBlockId()];
    554     HInstruction* heap_value = heap_values[idx];
    555     if (heap_value == kDefaultHeapValue) {
    556       HInstruction* constant = GetDefaultValue(instruction->GetType());
    557       AddRemovedLoad(instruction, constant);
    558       heap_values[idx] = constant;
    559       return;
    560     }
    561     heap_value = GetRealHeapValue(heap_value);
    562     if (heap_value == kUnknownHeapValue) {
    563       // Load isn't eliminated. Put the load as the value into the HeapLocation.
    564       // This acts like GVN but with better aliasing analysis.
    565       heap_values[idx] = instruction;
    566       KeepStoresIfAliasedToLocation(heap_values, idx);
    567     } else {
    568       // Load is eliminated.
    569       AddRemovedLoad(instruction, heap_value);
    570       TryRemovingNullCheck(instruction);
    571     }
    572   }
    573 
    574   bool Equal(HInstruction* heap_value, HInstruction* value) {
    575     DCHECK(!IsStore(value)) << value->DebugName();
    576     if (heap_value == kUnknownHeapValue) {
    577       // Don't compare kUnknownHeapValue with other values.
    578       return false;
    579     }
    580     if (heap_value == value) {
    581       return true;
    582     }
    583     if (heap_value == kDefaultHeapValue && GetDefaultValue(value->GetType()) == value) {
    584       return true;
    585     }
    586     HInstruction* real_heap_value = GetRealHeapValue(heap_value);
    587     if (real_heap_value != heap_value) {
    588       return Equal(real_heap_value, value);
    589     }
    590     return false;
    591   }
    592 
    593   void VisitSetLocation(HInstruction* instruction, size_t idx, HInstruction* value) {
    594     DCHECK_NE(idx, HeapLocationCollector::kHeapLocationNotFound);
    595     DCHECK(!IsStore(value)) << value->DebugName();
    596     // value may already have a substitute.
    597     value = FindSubstitute(value);
    598     ScopedArenaVector<HInstruction*>& heap_values =
    599         heap_values_for_[instruction->GetBlock()->GetBlockId()];
    600     HInstruction* heap_value = heap_values[idx];
    601     bool possibly_redundant = false;
    602 
    603     if (Equal(heap_value, value)) {
    604       // Store into the heap location with the same value.
    605       // This store can be eliminated right away.
    606       instruction->GetBlock()->RemoveInstruction(instruction);
    607       return;
    608     } else {
    609       HLoopInformation* loop_info = instruction->GetBlock()->GetLoopInformation();
    610       if (loop_info == nullptr) {
    611         // Store is not in a loop. We try to precisely track the heap value by
    612         // the store.
    613         possibly_redundant = true;
    614       } else if (!loop_info->IsIrreducible()) {
    615         // instruction is a store in the loop so the loop must do write.
    616         DCHECK(side_effects_.GetLoopEffects(loop_info->GetHeader()).DoesAnyWrite());
    617         ReferenceInfo* ref_info = heap_location_collector_.GetHeapLocation(idx)->GetReferenceInfo();
    618         if (ref_info->IsSingleton() && !loop_info->IsDefinedOutOfTheLoop(ref_info->GetReference())) {
    619           // original_ref is created inside the loop. Value stored to it isn't needed at
    620           // the loop header. This is true for outer loops also.
    621           possibly_redundant = true;
    622         } else {
    623           // Keep the store since its value may be needed at the loop header.
    624         }
    625       } else {
    626         // Keep the store inside irreducible loops.
    627       }
    628     }
    629     if (possibly_redundant) {
    630       possibly_removed_stores_.push_back(instruction);
    631     }
    632 
    633     // Put the store as the heap value. If the value is loaded or needed after
    634     // return/deoptimization later, this store isn't really redundant.
    635     heap_values[idx] = instruction;
    636 
    637     // This store may kill values in other heap locations due to aliasing.
    638     for (size_t i = 0; i < heap_values.size(); i++) {
    639       if (i == idx) {
    640         continue;
    641       }
    642       if (Equal(heap_values[i], value)) {
    643         // Same value should be kept even if aliasing happens.
    644         continue;
    645       }
    646       if (heap_values[i] == kUnknownHeapValue) {
    647         // Value is already unknown, no need for aliasing check.
    648         continue;
    649       }
    650       if (heap_location_collector_.MayAlias(i, idx)) {
    651         // Kill heap locations that may alias and as a result if the heap value
    652         // is a store, the store needs to be kept.
    653         KeepIfIsStore(heap_values[i]);
    654         heap_values[i] = kUnknownHeapValue;
    655       }
    656     }
    657   }
    658 
    659   void VisitInstanceFieldGet(HInstanceFieldGet* instruction) override {
    660     HInstruction* object = instruction->InputAt(0);
    661     const FieldInfo& field = instruction->GetFieldInfo();
    662     VisitGetLocation(instruction, heap_location_collector_.GetFieldHeapLocation(object, &field));
    663   }
    664 
    665   void VisitInstanceFieldSet(HInstanceFieldSet* instruction) override {
    666     HInstruction* object = instruction->InputAt(0);
    667     const FieldInfo& field = instruction->GetFieldInfo();
    668     HInstruction* value = instruction->InputAt(1);
    669     size_t idx = heap_location_collector_.GetFieldHeapLocation(object, &field);
    670     VisitSetLocation(instruction, idx, value);
    671   }
    672 
    673   void VisitStaticFieldGet(HStaticFieldGet* instruction) override {
    674     HInstruction* cls = instruction->InputAt(0);
    675     const FieldInfo& field = instruction->GetFieldInfo();
    676     VisitGetLocation(instruction, heap_location_collector_.GetFieldHeapLocation(cls, &field));
    677   }
    678 
    679   void VisitStaticFieldSet(HStaticFieldSet* instruction) override {
    680     HInstruction* cls = instruction->InputAt(0);
    681     const FieldInfo& field = instruction->GetFieldInfo();
    682     size_t idx = heap_location_collector_.GetFieldHeapLocation(cls, &field);
    683     VisitSetLocation(instruction, idx, instruction->InputAt(1));
    684   }
    685 
    686   void VisitArrayGet(HArrayGet* instruction) override {
    687     VisitGetLocation(instruction, heap_location_collector_.GetArrayHeapLocation(instruction));
    688   }
    689 
    690   void VisitArraySet(HArraySet* instruction) override {
    691     size_t idx = heap_location_collector_.GetArrayHeapLocation(instruction);
    692     VisitSetLocation(instruction, idx, instruction->InputAt(2));
    693   }
    694 
    695   void VisitDeoptimize(HDeoptimize* instruction) override {
    696     const ScopedArenaVector<HInstruction*>& heap_values =
    697         heap_values_for_[instruction->GetBlock()->GetBlockId()];
    698     for (HInstruction* heap_value : heap_values) {
    699       // A store is kept as the heap value for possibly removed stores.
    700       // That value stored is generally observeable after deoptimization, except
    701       // for singletons that don't escape after deoptimization.
    702       if (IsStore(heap_value)) {
    703         if (heap_value->IsStaticFieldSet()) {
    704           KeepIfIsStore(heap_value);
    705           continue;
    706         }
    707         HInstruction* reference = heap_value->InputAt(0);
    708         if (heap_location_collector_.FindReferenceInfoOf(reference)->IsSingleton()) {
    709           if (reference->IsNewInstance() && reference->AsNewInstance()->IsFinalizable()) {
    710             // Finalizable objects alway escape.
    711             KeepIfIsStore(heap_value);
    712             continue;
    713           }
    714           // Check whether the reference for a store is used by an environment local of
    715           // HDeoptimize. If not, the singleton is not observed after
    716           // deoptimizion.
    717           for (const HUseListNode<HEnvironment*>& use : reference->GetEnvUses()) {
    718             HEnvironment* user = use.GetUser();
    719             if (user->GetHolder() == instruction) {
    720               // The singleton for the store is visible at this deoptimization
    721               // point. Need to keep the store so that the heap value is
    722               // seen by the interpreter.
    723               KeepIfIsStore(heap_value);
    724             }
    725           }
    726         } else {
    727           KeepIfIsStore(heap_value);
    728         }
    729       }
    730     }
    731   }
    732 
    733   // Keep necessary stores before exiting a method via return/throw.
    734   void HandleExit(HBasicBlock* block) {
    735     const ScopedArenaVector<HInstruction*>& heap_values =
    736         heap_values_for_[block->GetBlockId()];
    737     for (size_t i = 0; i < heap_values.size(); i++) {
    738       HInstruction* heap_value = heap_values[i];
    739       ReferenceInfo* ref_info = heap_location_collector_.GetHeapLocation(i)->GetReferenceInfo();
    740       if (!ref_info->IsSingletonAndRemovable()) {
    741         KeepIfIsStore(heap_value);
    742       }
    743     }
    744   }
    745 
    746   void VisitReturn(HReturn* instruction) override {
    747     HandleExit(instruction->GetBlock());
    748   }
    749 
    750   void VisitReturnVoid(HReturnVoid* return_void) override {
    751     HandleExit(return_void->GetBlock());
    752   }
    753 
    754   void VisitThrow(HThrow* throw_instruction) override {
    755     HandleExit(throw_instruction->GetBlock());
    756   }
    757 
    758   void HandleInvoke(HInstruction* instruction) {
    759     SideEffects side_effects = instruction->GetSideEffects();
    760     ScopedArenaVector<HInstruction*>& heap_values =
    761         heap_values_for_[instruction->GetBlock()->GetBlockId()];
    762     for (size_t i = 0; i < heap_values.size(); i++) {
    763       ReferenceInfo* ref_info = heap_location_collector_.GetHeapLocation(i)->GetReferenceInfo();
    764       if (ref_info->IsSingleton()) {
    765         // Singleton references cannot be seen by the callee.
    766       } else {
    767         if (side_effects.DoesAnyRead()) {
    768           // Invocation may read the heap value.
    769           KeepIfIsStore(heap_values[i]);
    770         }
    771         if (side_effects.DoesAnyWrite()) {
    772           // Keep the store since it's not used to track the heap value anymore.
    773           KeepIfIsStore(heap_values[i]);
    774           heap_values[i] = kUnknownHeapValue;
    775         }
    776       }
    777     }
    778   }
    779 
    780   void VisitInvoke(HInvoke* invoke) override {
    781     HandleInvoke(invoke);
    782   }
    783 
    784   void VisitClinitCheck(HClinitCheck* clinit) override {
    785     HandleInvoke(clinit);
    786   }
    787 
    788   void VisitUnresolvedInstanceFieldGet(HUnresolvedInstanceFieldGet* instruction) override {
    789     // Conservatively treat it as an invocation.
    790     HandleInvoke(instruction);
    791   }
    792 
    793   void VisitUnresolvedInstanceFieldSet(HUnresolvedInstanceFieldSet* instruction) override {
    794     // Conservatively treat it as an invocation.
    795     HandleInvoke(instruction);
    796   }
    797 
    798   void VisitUnresolvedStaticFieldGet(HUnresolvedStaticFieldGet* instruction) override {
    799     // Conservatively treat it as an invocation.
    800     HandleInvoke(instruction);
    801   }
    802 
    803   void VisitUnresolvedStaticFieldSet(HUnresolvedStaticFieldSet* instruction) override {
    804     // Conservatively treat it as an invocation.
    805     HandleInvoke(instruction);
    806   }
    807 
    808   void VisitNewInstance(HNewInstance* new_instance) override {
    809     ReferenceInfo* ref_info = heap_location_collector_.FindReferenceInfoOf(new_instance);
    810     if (ref_info == nullptr) {
    811       // new_instance isn't used for field accesses. No need to process it.
    812       return;
    813     }
    814     if (ref_info->IsSingletonAndRemovable() && !new_instance->NeedsChecks()) {
    815       DCHECK(!new_instance->IsFinalizable());
    816       // new_instance can potentially be eliminated.
    817       singleton_new_instances_.push_back(new_instance);
    818     }
    819     ScopedArenaVector<HInstruction*>& heap_values =
    820         heap_values_for_[new_instance->GetBlock()->GetBlockId()];
    821     for (size_t i = 0; i < heap_values.size(); i++) {
    822       HInstruction* ref =
    823           heap_location_collector_.GetHeapLocation(i)->GetReferenceInfo()->GetReference();
    824       size_t offset = heap_location_collector_.GetHeapLocation(i)->GetOffset();
    825       if (ref == new_instance && offset >= mirror::kObjectHeaderSize) {
    826         // Instance fields except the header fields are set to default heap values.
    827         heap_values[i] = kDefaultHeapValue;
    828       }
    829     }
    830   }
    831 
    832   void VisitNewArray(HNewArray* new_array) override {
    833     ReferenceInfo* ref_info = heap_location_collector_.FindReferenceInfoOf(new_array);
    834     if (ref_info == nullptr) {
    835       // new_array isn't used for array accesses. No need to process it.
    836       return;
    837     }
    838     if (ref_info->IsSingletonAndRemovable()) {
    839       if (new_array->GetLength()->IsIntConstant() &&
    840           new_array->GetLength()->AsIntConstant()->GetValue() >= 0) {
    841         // new_array can potentially be eliminated.
    842         singleton_new_instances_.push_back(new_array);
    843       } else {
    844         // new_array may throw NegativeArraySizeException. Keep it.
    845       }
    846     }
    847     ScopedArenaVector<HInstruction*>& heap_values =
    848         heap_values_for_[new_array->GetBlock()->GetBlockId()];
    849     for (size_t i = 0; i < heap_values.size(); i++) {
    850       HeapLocation* location = heap_location_collector_.GetHeapLocation(i);
    851       HInstruction* ref = location->GetReferenceInfo()->GetReference();
    852       if (ref == new_array && location->GetIndex() != nullptr) {
    853         // Array elements are set to default heap values.
    854         heap_values[i] = kDefaultHeapValue;
    855       }
    856     }
    857   }
    858 
    859   const HeapLocationCollector& heap_location_collector_;
    860   const SideEffectsAnalysis& side_effects_;
    861 
    862   // Use local allocator for allocating memory.
    863   ScopedArenaAllocator allocator_;
    864 
    865   // One array of heap values for each block.
    866   ScopedArenaVector<ScopedArenaVector<HInstruction*>> heap_values_for_;
    867 
    868   // We record the instructions that should be eliminated but may be
    869   // used by heap locations. They'll be removed in the end.
    870   ScopedArenaVector<HInstruction*> removed_loads_;
    871   ScopedArenaVector<HInstruction*> substitute_instructions_for_loads_;
    872 
    873   // Stores in this list may be removed from the list later when it's
    874   // found that the store cannot be eliminated.
    875   ScopedArenaVector<HInstruction*> possibly_removed_stores_;
    876 
    877   ScopedArenaVector<HInstruction*> singleton_new_instances_;
    878 
    879   DISALLOW_COPY_AND_ASSIGN(LSEVisitor);
    880 };
    881 
    882 bool LoadStoreElimination::Run() {
    883   if (graph_->IsDebuggable() || graph_->HasTryCatch()) {
    884     // Debugger may set heap values or trigger deoptimization of callers.
    885     // Try/catch support not implemented yet.
    886     // Skip this optimization.
    887     return false;
    888   }
    889   const HeapLocationCollector& heap_location_collector = lsa_.GetHeapLocationCollector();
    890   if (heap_location_collector.GetNumberOfHeapLocations() == 0) {
    891     // No HeapLocation information from LSA, skip this optimization.
    892     return false;
    893   }
    894 
    895   // TODO: analyze VecLoad/VecStore better.
    896   if (graph_->HasSIMD()) {
    897     return false;
    898   }
    899 
    900   LSEVisitor lse_visitor(graph_, heap_location_collector, side_effects_, stats_);
    901   for (HBasicBlock* block : graph_->GetReversePostOrder()) {
    902     lse_visitor.VisitBasicBlock(block);
    903   }
    904   lse_visitor.RemoveInstructions();
    905 
    906   return true;
    907 }
    908 
    909 }  // namespace art
    910