xref: /aosp_15_r20/art/compiler/optimizing/load_store_elimination.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #include "load_store_elimination.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include <algorithm>
20*795d594fSAndroid Build Coastguard Worker #include <optional>
21*795d594fSAndroid Build Coastguard Worker #include <sstream>
22*795d594fSAndroid Build Coastguard Worker #include <variant>
23*795d594fSAndroid Build Coastguard Worker 
24*795d594fSAndroid Build Coastguard Worker #include "base/arena_allocator.h"
25*795d594fSAndroid Build Coastguard Worker #include "base/arena_bit_vector.h"
26*795d594fSAndroid Build Coastguard Worker #include "base/array_ref.h"
27*795d594fSAndroid Build Coastguard Worker #include "base/bit_vector-inl.h"
28*795d594fSAndroid Build Coastguard Worker #include "base/bit_vector.h"
29*795d594fSAndroid Build Coastguard Worker #include "base/globals.h"
30*795d594fSAndroid Build Coastguard Worker #include "base/indenter.h"
31*795d594fSAndroid Build Coastguard Worker #include "base/iteration_range.h"
32*795d594fSAndroid Build Coastguard Worker #include "base/scoped_arena_allocator.h"
33*795d594fSAndroid Build Coastguard Worker #include "base/scoped_arena_containers.h"
34*795d594fSAndroid Build Coastguard Worker #include "base/transform_iterator.h"
35*795d594fSAndroid Build Coastguard Worker #include "escape.h"
36*795d594fSAndroid Build Coastguard Worker #include "handle.h"
37*795d594fSAndroid Build Coastguard Worker #include "load_store_analysis.h"
38*795d594fSAndroid Build Coastguard Worker #include "mirror/class_loader.h"
39*795d594fSAndroid Build Coastguard Worker #include "mirror/dex_cache.h"
40*795d594fSAndroid Build Coastguard Worker #include "nodes.h"
41*795d594fSAndroid Build Coastguard Worker #include "oat/stack_map.h"
42*795d594fSAndroid Build Coastguard Worker #include "optimizing_compiler_stats.h"
43*795d594fSAndroid Build Coastguard Worker #include "reference_type_propagation.h"
44*795d594fSAndroid Build Coastguard Worker #include "side_effects_analysis.h"
45*795d594fSAndroid Build Coastguard Worker 
46*795d594fSAndroid Build Coastguard Worker /**
47*795d594fSAndroid Build Coastguard Worker  * The general algorithm of load-store elimination (LSE).
48*795d594fSAndroid Build Coastguard Worker  *
49*795d594fSAndroid Build Coastguard Worker  * We use load-store analysis to collect a list of heap locations and perform
50*795d594fSAndroid Build Coastguard Worker  * alias analysis of those heap locations. LSE then keeps track of a list of
51*795d594fSAndroid Build Coastguard Worker  * heap values corresponding to the heap locations and stores that put those
52*795d594fSAndroid Build Coastguard Worker  * values in these locations.
53*795d594fSAndroid Build Coastguard Worker  *  - In phase 1, we visit basic blocks in reverse post order and for each basic
54*795d594fSAndroid Build Coastguard Worker  *    block, visit instructions sequentially, recording heap values and looking
55*795d594fSAndroid Build Coastguard Worker  *    for loads and stores to eliminate without relying on loop Phis.
56*795d594fSAndroid Build Coastguard Worker  *  - In phase 2, we look for loads that can be replaced by creating loop Phis
57*795d594fSAndroid Build Coastguard Worker  *    or using a loop-invariant value.
58*795d594fSAndroid Build Coastguard Worker  *  - In phase 3, we determine which stores are dead and can be eliminated and
59*795d594fSAndroid Build Coastguard Worker  *    based on that information we re-evaluate whether some kept stores are
60*795d594fSAndroid Build Coastguard Worker  *    storing the same value as the value in the heap location; such stores are
61*795d594fSAndroid Build Coastguard Worker  *    also marked for elimination.
62*795d594fSAndroid Build Coastguard Worker  *  - In phase 4, we commit the changes, replacing loads marked for elimination
63*795d594fSAndroid Build Coastguard Worker  *    in previous processing and removing stores not marked for keeping. We also
64*795d594fSAndroid Build Coastguard Worker  *    remove allocations that are no longer needed.
65*795d594fSAndroid Build Coastguard Worker  *  - In phase 5, we move allocations which only escape along some executions
66*795d594fSAndroid Build Coastguard Worker  *    closer to their escape points and fixup non-escaping paths with their actual
67*795d594fSAndroid Build Coastguard Worker  *    values, creating PHIs when needed.
68*795d594fSAndroid Build Coastguard Worker  *
69*795d594fSAndroid Build Coastguard Worker  * 1. Walk over blocks and their instructions.
70*795d594fSAndroid Build Coastguard Worker  *
71*795d594fSAndroid Build Coastguard Worker  * The initial set of heap values for a basic block is
72*795d594fSAndroid Build Coastguard Worker  *  - For a loop header of an irreducible loop, all heap values are unknown.
73*795d594fSAndroid Build Coastguard Worker  *  - For a loop header of a normal loop, all values unknown at the end of the
74*795d594fSAndroid Build Coastguard Worker  *    preheader are initialized to unknown, other heap values are set to Phi
75*795d594fSAndroid Build Coastguard Worker  *    placeholders as we cannot determine yet whether these values are known on
76*795d594fSAndroid Build Coastguard Worker  *    all back-edges. We use Phi placeholders also for array heap locations with
77*795d594fSAndroid Build Coastguard Worker  *    index defined inside the loop but this helps only when the value remains
78*795d594fSAndroid Build Coastguard Worker  *    zero from the array allocation throughout the loop.
79*795d594fSAndroid Build Coastguard Worker  *  - For catch blocks, we clear all assumptions since we arrived due to an
80*795d594fSAndroid Build Coastguard Worker  *    instruction throwing.
81*795d594fSAndroid Build Coastguard Worker  *  - For other basic blocks, we merge incoming values from the end of all
82*795d594fSAndroid Build Coastguard Worker  *    predecessors. If any incoming value is unknown, the start value for this
83*795d594fSAndroid Build Coastguard Worker  *    block is also unknown. Otherwise, if all the incoming values are the same
84*795d594fSAndroid Build Coastguard Worker  *    (including the case of a single predecessor), the incoming value is used.
85*795d594fSAndroid Build Coastguard Worker  *    Otherwise, we use a Phi placeholder to indicate different incoming values.
86*795d594fSAndroid Build Coastguard Worker  *    We record whether such Phi placeholder depends on a loop Phi placeholder.
87*795d594fSAndroid Build Coastguard Worker  *
88*795d594fSAndroid Build Coastguard Worker  * For each instruction in the block
89*795d594fSAndroid Build Coastguard Worker  *  - If the instruction is a load from a heap location with a known value not
90*795d594fSAndroid Build Coastguard Worker  *    dependent on a loop Phi placeholder, the load can be eliminated, either by
91*795d594fSAndroid Build Coastguard Worker  *    using an existing instruction or by creating new Phi(s) instead. In order
92*795d594fSAndroid Build Coastguard Worker  *    to maintain the validity of all heap locations during the optimization
93*795d594fSAndroid Build Coastguard Worker  *    phase, we only record substitutes at this phase and the real elimination
94*795d594fSAndroid Build Coastguard Worker  *    is delayed till the end of LSE. Loads that require a loop Phi placeholder
95*795d594fSAndroid Build Coastguard Worker  *    replacement are recorded for processing later.
96*795d594fSAndroid Build Coastguard Worker  *  - If the instruction is a store, it updates the heap value for the heap
97*795d594fSAndroid Build Coastguard Worker  *    location with the stored value and records the store itself so that we can
98*795d594fSAndroid Build Coastguard Worker  *    mark it for keeping if the value becomes observable. Heap values are
99*795d594fSAndroid Build Coastguard Worker  *    invalidated for heap locations that may alias with the store instruction's
100*795d594fSAndroid Build Coastguard Worker  *    heap location and their recorded stores are marked for keeping as they are
101*795d594fSAndroid Build Coastguard Worker  *    now potentially observable. The store instruction can be eliminated unless
102*795d594fSAndroid Build Coastguard Worker  *    the value stored is later needed e.g. by a load from the same/aliased heap
103*795d594fSAndroid Build Coastguard Worker  *    location or the heap location persists at method return/deoptimization.
104*795d594fSAndroid Build Coastguard Worker  *  - A store that stores the same value as the heap value is eliminated.
105*795d594fSAndroid Build Coastguard Worker  *  - For newly instantiated instances, their heap values are initialized to
106*795d594fSAndroid Build Coastguard Worker  *    language defined default values.
107*795d594fSAndroid Build Coastguard Worker  *  - Finalizable objects are considered as persisting at method
108*795d594fSAndroid Build Coastguard Worker  *    return/deoptimization.
109*795d594fSAndroid Build Coastguard Worker  *  - Some instructions such as invokes are treated as loading and invalidating
110*795d594fSAndroid Build Coastguard Worker  *    all the heap values, depending on the instruction's side effects.
111*795d594fSAndroid Build Coastguard Worker  *  - SIMD graphs (with VecLoad and VecStore instructions) are also handled. Any
112*795d594fSAndroid Build Coastguard Worker  *    partial overlap access among ArrayGet/ArraySet/VecLoad/Store is seen as
113*795d594fSAndroid Build Coastguard Worker  *    alias and no load/store is eliminated in such case.
114*795d594fSAndroid Build Coastguard Worker  *
115*795d594fSAndroid Build Coastguard Worker  * The time complexity of the initial phase has several components. The total
116*795d594fSAndroid Build Coastguard Worker  * time for the initialization of heap values for all blocks is
117*795d594fSAndroid Build Coastguard Worker  *    O(heap_locations * edges)
118*795d594fSAndroid Build Coastguard Worker  * and the time complexity for simple instruction processing is
119*795d594fSAndroid Build Coastguard Worker  *    O(instructions).
120*795d594fSAndroid Build Coastguard Worker  * See the description of phase 3 for additional complexity due to matching of
121*795d594fSAndroid Build Coastguard Worker  * existing Phis for replacing loads.
122*795d594fSAndroid Build Coastguard Worker  *
123*795d594fSAndroid Build Coastguard Worker  * 2. Process loads that depend on loop Phi placeholders.
124*795d594fSAndroid Build Coastguard Worker  *
125*795d594fSAndroid Build Coastguard Worker  * We go over these loads to determine whether they can be eliminated. We look
126*795d594fSAndroid Build Coastguard Worker  * for the set of all Phi placeholders that feed the load and depend on a loop
127*795d594fSAndroid Build Coastguard Worker  * Phi placeholder and, if we find no unknown value, we construct the necessary
128*795d594fSAndroid Build Coastguard Worker  * Phi(s) or, if all other inputs are identical, i.e. the location does not
129*795d594fSAndroid Build Coastguard Worker  * change in the loop, just use that input. If we do find an unknown input, this
130*795d594fSAndroid Build Coastguard Worker  * must be from a loop back-edge and we replace the loop Phi placeholder with
131*795d594fSAndroid Build Coastguard Worker  * unknown value and re-process loads and stores that previously depended on
132*795d594fSAndroid Build Coastguard Worker  * loop Phi placeholders. This shall find at least one load of an unknown value
133*795d594fSAndroid Build Coastguard Worker  * which is now known to be unreplaceable or a new unknown value on a back-edge
134*795d594fSAndroid Build Coastguard Worker  * and we repeat this process until each load is either marked for replacement
135*795d594fSAndroid Build Coastguard Worker  * or found to be unreplaceable. As we mark at least one additional loop Phi
136*795d594fSAndroid Build Coastguard Worker  * placeholder as unreplacable in each iteration, this process shall terminate.
137*795d594fSAndroid Build Coastguard Worker  *
138*795d594fSAndroid Build Coastguard Worker  * The depth-first search for Phi placeholders in FindLoopPhisToMaterialize()
139*795d594fSAndroid Build Coastguard Worker  * is limited by the number of Phi placeholders and their dependencies we need
140*795d594fSAndroid Build Coastguard Worker  * to search with worst-case time complexity
141*795d594fSAndroid Build Coastguard Worker  *    O(phi_placeholder_dependencies) .
142*795d594fSAndroid Build Coastguard Worker  * The dependencies are usually just the Phi placeholders' potential inputs,
143*795d594fSAndroid Build Coastguard Worker  * but if we use TryReplacingLoopPhiPlaceholderWithDefault() for default value
144*795d594fSAndroid Build Coastguard Worker  * replacement search, there are additional dependencies to consider, see below.
145*795d594fSAndroid Build Coastguard Worker  *
146*795d594fSAndroid Build Coastguard Worker  * In the successful case (no unknown inputs found) we use the Floyd-Warshall
147*795d594fSAndroid Build Coastguard Worker  * algorithm to determine transitive closures for each found Phi placeholder,
148*795d594fSAndroid Build Coastguard Worker  * and then match or materialize Phis from the smallest transitive closure,
149*795d594fSAndroid Build Coastguard Worker  * so that we can determine if such subset has a single other input. This has
150*795d594fSAndroid Build Coastguard Worker  * time complexity
151*795d594fSAndroid Build Coastguard Worker  *    O(phi_placeholders_found^3) .
152*795d594fSAndroid Build Coastguard Worker  * Note that successful TryReplacingLoopPhiPlaceholderWithDefault() does not
153*795d594fSAndroid Build Coastguard Worker  * contribute to this as such Phi placeholders are replaced immediately.
154*795d594fSAndroid Build Coastguard Worker  * The total time of all such successful cases has time complexity
155*795d594fSAndroid Build Coastguard Worker  *    O(phi_placeholders^3)
156*795d594fSAndroid Build Coastguard Worker  * because the found sets are disjoint and `Sum(n_i^3) <= Sum(n_i)^3`. Similar
157*795d594fSAndroid Build Coastguard Worker  * argument applies to the searches used to find all successful cases, so their
158*795d594fSAndroid Build Coastguard Worker  * total contribution is also just an insignificant
159*795d594fSAndroid Build Coastguard Worker  *    O(phi_placeholder_dependencies) .
160*795d594fSAndroid Build Coastguard Worker  * The materialization of Phis has an insignificant total time complexity
161*795d594fSAndroid Build Coastguard Worker  *    O(phi_placeholders * edges) .
162*795d594fSAndroid Build Coastguard Worker  *
163*795d594fSAndroid Build Coastguard Worker  * If we find an unknown input, we re-process heap values and loads with a time
164*795d594fSAndroid Build Coastguard Worker  * complexity that's the same as the phase 1 in the worst case. Adding this to
165*795d594fSAndroid Build Coastguard Worker  * the depth-first search time complexity yields
166*795d594fSAndroid Build Coastguard Worker  *    O(phi_placeholder_dependencies + heap_locations * edges + instructions)
167*795d594fSAndroid Build Coastguard Worker  * for a single iteration. We can ignore the middle term as it's proprotional
168*795d594fSAndroid Build Coastguard Worker  * to the number of Phi placeholder inputs included in the first term. Using
169*795d594fSAndroid Build Coastguard Worker  * the upper limit of number of such iterations, the total time complexity is
170*795d594fSAndroid Build Coastguard Worker  *    O((phi_placeholder_dependencies + instructions) * phi_placeholders) .
171*795d594fSAndroid Build Coastguard Worker  *
172*795d594fSAndroid Build Coastguard Worker  * The upper bound of Phi placeholder inputs is
173*795d594fSAndroid Build Coastguard Worker  *    heap_locations * edges
174*795d594fSAndroid Build Coastguard Worker  * but if we use TryReplacingLoopPhiPlaceholderWithDefault(), the dependencies
175*795d594fSAndroid Build Coastguard Worker  * include other heap locations in predecessor blocks with the upper bound of
176*795d594fSAndroid Build Coastguard Worker  *    heap_locations^2 * edges .
177*795d594fSAndroid Build Coastguard Worker  * Using the estimate
178*795d594fSAndroid Build Coastguard Worker  *    edges <= blocks^2
179*795d594fSAndroid Build Coastguard Worker  * and
180*795d594fSAndroid Build Coastguard Worker  *    phi_placeholders <= heap_locations * blocks ,
181*795d594fSAndroid Build Coastguard Worker  * the worst-case time complexity of the
182*795d594fSAndroid Build Coastguard Worker  *    O(phi_placeholder_dependencies * phi_placeholders)
183*795d594fSAndroid Build Coastguard Worker  * term from unknown input cases is actually
184*795d594fSAndroid Build Coastguard Worker  *    O(heap_locations^3 * blocks^3) ,
185*795d594fSAndroid Build Coastguard Worker  * exactly as the estimate for the Floyd-Warshall parts of successful cases.
186*795d594fSAndroid Build Coastguard Worker  * Adding the other term from the unknown input cases (to account for the case
187*795d594fSAndroid Build Coastguard Worker  * with significantly more instructions than blocks and heap locations), the
188*795d594fSAndroid Build Coastguard Worker  * phase 2 time complexity is
189*795d594fSAndroid Build Coastguard Worker  *    O(heap_locations^3 * blocks^3 + heap_locations * blocks * instructions) .
190*795d594fSAndroid Build Coastguard Worker  *
191*795d594fSAndroid Build Coastguard Worker  * See the description of phase 3 for additional complexity due to matching of
192*795d594fSAndroid Build Coastguard Worker  * existing Phis for replacing loads.
193*795d594fSAndroid Build Coastguard Worker  *
194*795d594fSAndroid Build Coastguard Worker  * 3. Determine which stores to keep and which to eliminate.
195*795d594fSAndroid Build Coastguard Worker  *
196*795d594fSAndroid Build Coastguard Worker  * During instruction processing in phase 1 and re-processing in phase 2, we are
197*795d594fSAndroid Build Coastguard Worker  * keeping a record of the stores and Phi placeholders that become observable
198*795d594fSAndroid Build Coastguard Worker  * and now propagate the observable Phi placeholders to all actual stores that
199*795d594fSAndroid Build Coastguard Worker  * feed them. Having determined observable stores, we look for stores that just
200*795d594fSAndroid Build Coastguard Worker  * overwrite the old value with the same. Since ignoring non-observable stores
201*795d594fSAndroid Build Coastguard Worker  * actually changes the old values in heap locations, we need to recalculate
202*795d594fSAndroid Build Coastguard Worker  * Phi placeholder replacements but we proceed similarly to the previous phase.
203*795d594fSAndroid Build Coastguard Worker  * We look for the set of all Phis that feed the old value replaced by the store
204*795d594fSAndroid Build Coastguard Worker  * (but ignoring whether they depend on a loop Phi) and, if we find no unknown
205*795d594fSAndroid Build Coastguard Worker  * value, we try to match existing Phis (we do not create new Phis anymore) or,
206*795d594fSAndroid Build Coastguard Worker  * if all other inputs are identical, i.e. the location does not change in the
207*795d594fSAndroid Build Coastguard Worker  * loop, just use that input. If this succeeds and the old value is identical to
208*795d594fSAndroid Build Coastguard Worker  * the value we're storing, such store shall be eliminated.
209*795d594fSAndroid Build Coastguard Worker  *
210*795d594fSAndroid Build Coastguard Worker  * The work is similar to the phase 2, except that we're not re-processing loads
211*795d594fSAndroid Build Coastguard Worker  * and stores anymore, so the time complexity of phase 3 is
212*795d594fSAndroid Build Coastguard Worker  *    O(heap_locations^3 * blocks^3) .
213*795d594fSAndroid Build Coastguard Worker  *
214*795d594fSAndroid Build Coastguard Worker  * There is additional complexity in matching existing Phis shared between the
215*795d594fSAndroid Build Coastguard Worker  * phases 1, 2 and 3. We are never trying to match two or more Phis at the same
216*795d594fSAndroid Build Coastguard Worker  * time (this could be difficult and slow), so each matching attempt is just
217*795d594fSAndroid Build Coastguard Worker  * looking at Phis in the block (both old Phis and newly created Phis) and their
218*795d594fSAndroid Build Coastguard Worker  * inputs. As we create at most `heap_locations` Phis in each block, the upper
219*795d594fSAndroid Build Coastguard Worker  * bound on the number of Phis we look at is
220*795d594fSAndroid Build Coastguard Worker  *    heap_locations * (old_phis + heap_locations)
221*795d594fSAndroid Build Coastguard Worker  * and the worst-case time complexity is
222*795d594fSAndroid Build Coastguard Worker  *    O(heap_locations^2 * edges + heap_locations * old_phis * edges) .
223*795d594fSAndroid Build Coastguard Worker  * The first term is lower than one term in phase 2, so the relevant part is
224*795d594fSAndroid Build Coastguard Worker  *    O(heap_locations * old_phis * edges) .
225*795d594fSAndroid Build Coastguard Worker  *
226*795d594fSAndroid Build Coastguard Worker  * 4. Replace loads and remove unnecessary stores and singleton allocations.
227*795d594fSAndroid Build Coastguard Worker  *
228*795d594fSAndroid Build Coastguard Worker  * A special type of objects called singletons are instantiated in the method
229*795d594fSAndroid Build Coastguard Worker  * and have a single name, i.e. no aliases. Singletons have exclusive heap
230*795d594fSAndroid Build Coastguard Worker  * locations since they have no aliases. Singletons are helpful in narrowing
231*795d594fSAndroid Build Coastguard Worker  * down the life span of a heap location such that they do not always need to
232*795d594fSAndroid Build Coastguard Worker  * participate in merging heap values. Allocation of a singleton can be
233*795d594fSAndroid Build Coastguard Worker  * eliminated if that singleton is not used and does not persist at method
234*795d594fSAndroid Build Coastguard Worker  * return/deoptimization.
235*795d594fSAndroid Build Coastguard Worker  *
236*795d594fSAndroid Build Coastguard Worker  * The time complexity of this phase is
237*795d594fSAndroid Build Coastguard Worker  *    O(instructions + instruction_uses) .
238*795d594fSAndroid Build Coastguard Worker  *
239*795d594fSAndroid Build Coastguard Worker  * FIXME: The time complexities described above assumes that the
240*795d594fSAndroid Build Coastguard Worker  * HeapLocationCollector finds a heap location for an instruction in O(1)
241*795d594fSAndroid Build Coastguard Worker  * time but it is currently O(heap_locations); this can be fixed by adding
242*795d594fSAndroid Build Coastguard Worker  * a hash map to the HeapLocationCollector.
243*795d594fSAndroid Build Coastguard Worker  */
244*795d594fSAndroid Build Coastguard Worker 
245*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
246*795d594fSAndroid Build Coastguard Worker 
247*795d594fSAndroid Build Coastguard Worker #define LSE_VLOG \
248*795d594fSAndroid Build Coastguard Worker   if (::art::LoadStoreElimination::kVerboseLoggingMode && VLOG_IS_ON(compiler)) LOG(INFO)
249*795d594fSAndroid Build Coastguard Worker 
250*795d594fSAndroid Build Coastguard Worker class HeapRefHolder;
251*795d594fSAndroid Build Coastguard Worker 
252*795d594fSAndroid Build Coastguard Worker // Use HGraphDelegateVisitor for which all VisitInvokeXXX() delegate to VisitInvoke().
253*795d594fSAndroid Build Coastguard Worker class LSEVisitor final : private HGraphDelegateVisitor {
254*795d594fSAndroid Build Coastguard Worker  public:
255*795d594fSAndroid Build Coastguard Worker   LSEVisitor(HGraph* graph,
256*795d594fSAndroid Build Coastguard Worker              const HeapLocationCollector& heap_location_collector,
257*795d594fSAndroid Build Coastguard Worker              OptimizingCompilerStats* stats);
258*795d594fSAndroid Build Coastguard Worker 
259*795d594fSAndroid Build Coastguard Worker   void Run();
260*795d594fSAndroid Build Coastguard Worker 
261*795d594fSAndroid Build Coastguard Worker  private:
262*795d594fSAndroid Build Coastguard Worker   class PhiPlaceholder {
263*795d594fSAndroid Build Coastguard Worker    public:
PhiPlaceholder()264*795d594fSAndroid Build Coastguard Worker     constexpr PhiPlaceholder() : block_id_(-1), heap_location_(-1) {}
PhiPlaceholder(uint32_t block_id,size_t heap_location)265*795d594fSAndroid Build Coastguard Worker     constexpr PhiPlaceholder(uint32_t block_id, size_t heap_location)
266*795d594fSAndroid Build Coastguard Worker         : block_id_(block_id), heap_location_(dchecked_integral_cast<uint32_t>(heap_location)) {}
267*795d594fSAndroid Build Coastguard Worker 
268*795d594fSAndroid Build Coastguard Worker     constexpr PhiPlaceholder(const PhiPlaceholder& p) = default;
269*795d594fSAndroid Build Coastguard Worker     constexpr PhiPlaceholder(PhiPlaceholder&& p) = default;
270*795d594fSAndroid Build Coastguard Worker     constexpr PhiPlaceholder& operator=(const PhiPlaceholder& p) = default;
271*795d594fSAndroid Build Coastguard Worker     constexpr PhiPlaceholder& operator=(PhiPlaceholder&& p) = default;
272*795d594fSAndroid Build Coastguard Worker 
GetBlockId() const273*795d594fSAndroid Build Coastguard Worker     constexpr uint32_t GetBlockId() const {
274*795d594fSAndroid Build Coastguard Worker       return block_id_;
275*795d594fSAndroid Build Coastguard Worker     }
276*795d594fSAndroid Build Coastguard Worker 
GetHeapLocation() const277*795d594fSAndroid Build Coastguard Worker     constexpr size_t GetHeapLocation() const {
278*795d594fSAndroid Build Coastguard Worker       return heap_location_;
279*795d594fSAndroid Build Coastguard Worker     }
280*795d594fSAndroid Build Coastguard Worker 
Equals(const PhiPlaceholder & p2) const281*795d594fSAndroid Build Coastguard Worker     constexpr bool Equals(const PhiPlaceholder& p2) const {
282*795d594fSAndroid Build Coastguard Worker       return block_id_ == p2.block_id_ && heap_location_ == p2.heap_location_;
283*795d594fSAndroid Build Coastguard Worker     }
284*795d594fSAndroid Build Coastguard Worker 
Dump(std::ostream & oss) const285*795d594fSAndroid Build Coastguard Worker     void Dump(std::ostream& oss) const {
286*795d594fSAndroid Build Coastguard Worker       oss << "PhiPlaceholder[blk: " << block_id_ << ", heap_location_: " << heap_location_ << "]";
287*795d594fSAndroid Build Coastguard Worker     }
288*795d594fSAndroid Build Coastguard Worker 
289*795d594fSAndroid Build Coastguard Worker    private:
290*795d594fSAndroid Build Coastguard Worker     uint32_t block_id_;
291*795d594fSAndroid Build Coastguard Worker     uint32_t heap_location_;
292*795d594fSAndroid Build Coastguard Worker   };
293*795d594fSAndroid Build Coastguard Worker 
294*795d594fSAndroid Build Coastguard Worker   friend constexpr bool operator==(const PhiPlaceholder& p1, const PhiPlaceholder& p2);
295*795d594fSAndroid Build Coastguard Worker   friend std::ostream& operator<<(std::ostream& oss, const PhiPlaceholder& p2);
296*795d594fSAndroid Build Coastguard Worker 
297*795d594fSAndroid Build Coastguard Worker   class Value {
298*795d594fSAndroid Build Coastguard Worker    public:
299*795d594fSAndroid Build Coastguard Worker     enum class ValuelessType {
300*795d594fSAndroid Build Coastguard Worker       kInvalid,
301*795d594fSAndroid Build Coastguard Worker       kUnknown,
302*795d594fSAndroid Build Coastguard Worker       kDefault,
303*795d594fSAndroid Build Coastguard Worker     };
304*795d594fSAndroid Build Coastguard Worker     struct NeedsNonLoopPhiMarker {
305*795d594fSAndroid Build Coastguard Worker       PhiPlaceholder phi_;
306*795d594fSAndroid Build Coastguard Worker     };
307*795d594fSAndroid Build Coastguard Worker     struct NeedsLoopPhiMarker {
308*795d594fSAndroid Build Coastguard Worker       PhiPlaceholder phi_;
309*795d594fSAndroid Build Coastguard Worker     };
310*795d594fSAndroid Build Coastguard Worker 
Invalid()311*795d594fSAndroid Build Coastguard Worker     static constexpr Value Invalid() {
312*795d594fSAndroid Build Coastguard Worker       return Value(ValuelessType::kInvalid);
313*795d594fSAndroid Build Coastguard Worker     }
314*795d594fSAndroid Build Coastguard Worker 
315*795d594fSAndroid Build Coastguard Worker     // An unknown heap value. Loads with such a value in the heap location cannot be eliminated.
316*795d594fSAndroid Build Coastguard Worker     // A heap location can be set to an unknown heap value when:
317*795d594fSAndroid Build Coastguard Worker     // - it is coming from outside the method,
318*795d594fSAndroid Build Coastguard Worker     // - it is killed due to aliasing, or side effects, or merging with an unknown value.
Unknown()319*795d594fSAndroid Build Coastguard Worker     static constexpr Value Unknown() {
320*795d594fSAndroid Build Coastguard Worker       return Value(ValuelessType::kUnknown);
321*795d594fSAndroid Build Coastguard Worker     }
322*795d594fSAndroid Build Coastguard Worker 
323*795d594fSAndroid Build Coastguard Worker     // Default heap value after an allocation.
324*795d594fSAndroid Build Coastguard Worker     // A heap location can be set to that value right after an allocation.
Default()325*795d594fSAndroid Build Coastguard Worker     static constexpr Value Default() {
326*795d594fSAndroid Build Coastguard Worker       return Value(ValuelessType::kDefault);
327*795d594fSAndroid Build Coastguard Worker     }
328*795d594fSAndroid Build Coastguard Worker 
ForInstruction(HInstruction * instruction)329*795d594fSAndroid Build Coastguard Worker     static constexpr Value ForInstruction(HInstruction* instruction) {
330*795d594fSAndroid Build Coastguard Worker       return Value(instruction);
331*795d594fSAndroid Build Coastguard Worker     }
332*795d594fSAndroid Build Coastguard Worker 
ForNonLoopPhiPlaceholder(PhiPlaceholder phi_placeholder)333*795d594fSAndroid Build Coastguard Worker     static constexpr Value ForNonLoopPhiPlaceholder(PhiPlaceholder phi_placeholder) {
334*795d594fSAndroid Build Coastguard Worker       return Value(NeedsNonLoopPhiMarker{phi_placeholder});
335*795d594fSAndroid Build Coastguard Worker     }
336*795d594fSAndroid Build Coastguard Worker 
ForLoopPhiPlaceholder(PhiPlaceholder phi_placeholder)337*795d594fSAndroid Build Coastguard Worker     static constexpr Value ForLoopPhiPlaceholder(PhiPlaceholder phi_placeholder) {
338*795d594fSAndroid Build Coastguard Worker       return Value(NeedsLoopPhiMarker{phi_placeholder});
339*795d594fSAndroid Build Coastguard Worker     }
340*795d594fSAndroid Build Coastguard Worker 
ForPhiPlaceholder(PhiPlaceholder phi_placeholder,bool needs_loop_phi)341*795d594fSAndroid Build Coastguard Worker     static constexpr Value ForPhiPlaceholder(PhiPlaceholder phi_placeholder, bool needs_loop_phi) {
342*795d594fSAndroid Build Coastguard Worker       return needs_loop_phi ? ForLoopPhiPlaceholder(phi_placeholder)
343*795d594fSAndroid Build Coastguard Worker                             : ForNonLoopPhiPlaceholder(phi_placeholder);
344*795d594fSAndroid Build Coastguard Worker     }
345*795d594fSAndroid Build Coastguard Worker 
IsValid() const346*795d594fSAndroid Build Coastguard Worker     constexpr bool IsValid() const {
347*795d594fSAndroid Build Coastguard Worker       return !IsInvalid();
348*795d594fSAndroid Build Coastguard Worker     }
349*795d594fSAndroid Build Coastguard Worker 
IsInvalid() const350*795d594fSAndroid Build Coastguard Worker     constexpr bool IsInvalid() const {
351*795d594fSAndroid Build Coastguard Worker       return std::holds_alternative<ValuelessType>(value_) &&
352*795d594fSAndroid Build Coastguard Worker              GetValuelessType() == ValuelessType::kInvalid;
353*795d594fSAndroid Build Coastguard Worker     }
354*795d594fSAndroid Build Coastguard Worker 
IsUnknown() const355*795d594fSAndroid Build Coastguard Worker     bool IsUnknown() const {
356*795d594fSAndroid Build Coastguard Worker       return std::holds_alternative<ValuelessType>(value_) &&
357*795d594fSAndroid Build Coastguard Worker              GetValuelessType() == ValuelessType::kUnknown;
358*795d594fSAndroid Build Coastguard Worker     }
359*795d594fSAndroid Build Coastguard Worker 
IsDefault() const360*795d594fSAndroid Build Coastguard Worker     bool IsDefault() const {
361*795d594fSAndroid Build Coastguard Worker       return std::holds_alternative<ValuelessType>(value_) &&
362*795d594fSAndroid Build Coastguard Worker              GetValuelessType() == ValuelessType::kDefault;
363*795d594fSAndroid Build Coastguard Worker     }
364*795d594fSAndroid Build Coastguard Worker 
IsInstruction() const365*795d594fSAndroid Build Coastguard Worker     bool IsInstruction() const {
366*795d594fSAndroid Build Coastguard Worker       return std::holds_alternative<HInstruction*>(value_);
367*795d594fSAndroid Build Coastguard Worker     }
368*795d594fSAndroid Build Coastguard Worker 
NeedsNonLoopPhi() const369*795d594fSAndroid Build Coastguard Worker     bool NeedsNonLoopPhi() const {
370*795d594fSAndroid Build Coastguard Worker       return std::holds_alternative<NeedsNonLoopPhiMarker>(value_);
371*795d594fSAndroid Build Coastguard Worker     }
372*795d594fSAndroid Build Coastguard Worker 
NeedsLoopPhi() const373*795d594fSAndroid Build Coastguard Worker     bool NeedsLoopPhi() const {
374*795d594fSAndroid Build Coastguard Worker       return std::holds_alternative<NeedsLoopPhiMarker>(value_);
375*795d594fSAndroid Build Coastguard Worker     }
376*795d594fSAndroid Build Coastguard Worker 
NeedsPhi() const377*795d594fSAndroid Build Coastguard Worker     bool NeedsPhi() const {
378*795d594fSAndroid Build Coastguard Worker       return NeedsNonLoopPhi() || NeedsLoopPhi();
379*795d594fSAndroid Build Coastguard Worker     }
380*795d594fSAndroid Build Coastguard Worker 
GetInstruction() const381*795d594fSAndroid Build Coastguard Worker     HInstruction* GetInstruction() const {
382*795d594fSAndroid Build Coastguard Worker       DCHECK(IsInstruction()) << *this;
383*795d594fSAndroid Build Coastguard Worker       return std::get<HInstruction*>(value_);
384*795d594fSAndroid Build Coastguard Worker     }
385*795d594fSAndroid Build Coastguard Worker 
GetPhiPlaceholder() const386*795d594fSAndroid Build Coastguard Worker     PhiPlaceholder GetPhiPlaceholder() const {
387*795d594fSAndroid Build Coastguard Worker       DCHECK(NeedsPhi());
388*795d594fSAndroid Build Coastguard Worker       if (NeedsNonLoopPhi()) {
389*795d594fSAndroid Build Coastguard Worker         return std::get<NeedsNonLoopPhiMarker>(value_).phi_;
390*795d594fSAndroid Build Coastguard Worker       } else {
391*795d594fSAndroid Build Coastguard Worker         return std::get<NeedsLoopPhiMarker>(value_).phi_;
392*795d594fSAndroid Build Coastguard Worker       }
393*795d594fSAndroid Build Coastguard Worker     }
394*795d594fSAndroid Build Coastguard Worker 
GetHeapLocation() const395*795d594fSAndroid Build Coastguard Worker     size_t GetHeapLocation() const {
396*795d594fSAndroid Build Coastguard Worker       DCHECK(NeedsPhi()) << this;
397*795d594fSAndroid Build Coastguard Worker       return GetPhiPlaceholder().GetHeapLocation();
398*795d594fSAndroid Build Coastguard Worker     }
399*795d594fSAndroid Build Coastguard Worker 
400*795d594fSAndroid Build Coastguard Worker     constexpr bool ExactEquals(Value other) const;
401*795d594fSAndroid Build Coastguard Worker 
402*795d594fSAndroid Build Coastguard Worker     constexpr bool Equals(Value other) const;
403*795d594fSAndroid Build Coastguard Worker 
Equals(HInstruction * instruction) const404*795d594fSAndroid Build Coastguard Worker     constexpr bool Equals(HInstruction* instruction) const {
405*795d594fSAndroid Build Coastguard Worker       return Equals(ForInstruction(instruction));
406*795d594fSAndroid Build Coastguard Worker     }
407*795d594fSAndroid Build Coastguard Worker 
408*795d594fSAndroid Build Coastguard Worker     std::ostream& Dump(std::ostream& os) const;
409*795d594fSAndroid Build Coastguard Worker 
410*795d594fSAndroid Build Coastguard Worker     // Public for use with lists.
Value()411*795d594fSAndroid Build Coastguard Worker     constexpr Value() : value_(ValuelessType::kInvalid) {}
412*795d594fSAndroid Build Coastguard Worker 
413*795d594fSAndroid Build Coastguard Worker    private:
414*795d594fSAndroid Build Coastguard Worker     using ValueHolder = std::variant<ValuelessType,
415*795d594fSAndroid Build Coastguard Worker                                      HInstruction*,
416*795d594fSAndroid Build Coastguard Worker                                      NeedsNonLoopPhiMarker,
417*795d594fSAndroid Build Coastguard Worker                                      NeedsLoopPhiMarker>;
GetValuelessType() const418*795d594fSAndroid Build Coastguard Worker     constexpr ValuelessType GetValuelessType() const {
419*795d594fSAndroid Build Coastguard Worker       return std::get<ValuelessType>(value_);
420*795d594fSAndroid Build Coastguard Worker     }
421*795d594fSAndroid Build Coastguard Worker 
Value(ValueHolder v)422*795d594fSAndroid Build Coastguard Worker     constexpr explicit Value(ValueHolder v) : value_(v) {}
423*795d594fSAndroid Build Coastguard Worker 
424*795d594fSAndroid Build Coastguard Worker     friend std::ostream& operator<<(std::ostream& os, const Value& v);
425*795d594fSAndroid Build Coastguard Worker 
426*795d594fSAndroid Build Coastguard Worker     ValueHolder value_;
427*795d594fSAndroid Build Coastguard Worker 
428*795d594fSAndroid Build Coastguard Worker     static_assert(std::is_move_assignable<PhiPlaceholder>::value);
429*795d594fSAndroid Build Coastguard Worker   };
430*795d594fSAndroid Build Coastguard Worker 
431*795d594fSAndroid Build Coastguard Worker   friend constexpr bool operator==(const Value::NeedsLoopPhiMarker& p1,
432*795d594fSAndroid Build Coastguard Worker                                    const Value::NeedsLoopPhiMarker& p2);
433*795d594fSAndroid Build Coastguard Worker   friend constexpr bool operator==(const Value::NeedsNonLoopPhiMarker& p1,
434*795d594fSAndroid Build Coastguard Worker                                    const Value::NeedsNonLoopPhiMarker& p2);
435*795d594fSAndroid Build Coastguard Worker 
436*795d594fSAndroid Build Coastguard Worker   // Get Phi placeholder index for access to `phi_placeholder_replacements_`
437*795d594fSAndroid Build Coastguard Worker   // and "visited" bit vectors during depth-first searches.
PhiPlaceholderIndex(PhiPlaceholder phi_placeholder) const438*795d594fSAndroid Build Coastguard Worker   size_t PhiPlaceholderIndex(PhiPlaceholder phi_placeholder) const {
439*795d594fSAndroid Build Coastguard Worker     size_t res =
440*795d594fSAndroid Build Coastguard Worker         phi_placeholder.GetBlockId() * heap_location_collector_.GetNumberOfHeapLocations() +
441*795d594fSAndroid Build Coastguard Worker         phi_placeholder.GetHeapLocation();
442*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(phi_placeholder, GetPhiPlaceholderAt(res))
443*795d594fSAndroid Build Coastguard Worker         << res << "blks: " << GetGraph()->GetBlocks().size()
444*795d594fSAndroid Build Coastguard Worker         << " hls: " << heap_location_collector_.GetNumberOfHeapLocations();
445*795d594fSAndroid Build Coastguard Worker     return res;
446*795d594fSAndroid Build Coastguard Worker   }
447*795d594fSAndroid Build Coastguard Worker 
PhiPlaceholderIndex(Value phi_placeholder) const448*795d594fSAndroid Build Coastguard Worker   size_t PhiPlaceholderIndex(Value phi_placeholder) const {
449*795d594fSAndroid Build Coastguard Worker     return PhiPlaceholderIndex(phi_placeholder.GetPhiPlaceholder());
450*795d594fSAndroid Build Coastguard Worker   }
451*795d594fSAndroid Build Coastguard Worker 
IsEscapingObject(ReferenceInfo * info)452*795d594fSAndroid Build Coastguard Worker   bool IsEscapingObject(ReferenceInfo* info) { return !info->IsSingletonAndRemovable(); }
453*795d594fSAndroid Build Coastguard Worker 
GetPhiPlaceholderAt(size_t off) const454*795d594fSAndroid Build Coastguard Worker   PhiPlaceholder GetPhiPlaceholderAt(size_t off) const {
455*795d594fSAndroid Build Coastguard Worker     DCHECK_LT(off, num_phi_placeholders_);
456*795d594fSAndroid Build Coastguard Worker     size_t id = off % heap_location_collector_.GetNumberOfHeapLocations();
457*795d594fSAndroid Build Coastguard Worker     // Technically this should be (off - id) / NumberOfHeapLocations
458*795d594fSAndroid Build Coastguard Worker     // but due to truncation it's all the same.
459*795d594fSAndroid Build Coastguard Worker     size_t blk_id = off / heap_location_collector_.GetNumberOfHeapLocations();
460*795d594fSAndroid Build Coastguard Worker     return GetPhiPlaceholder(blk_id, id);
461*795d594fSAndroid Build Coastguard Worker   }
462*795d594fSAndroid Build Coastguard Worker 
GetPhiPlaceholder(uint32_t block_id,size_t idx) const463*795d594fSAndroid Build Coastguard Worker   PhiPlaceholder GetPhiPlaceholder(uint32_t block_id, size_t idx) const {
464*795d594fSAndroid Build Coastguard Worker     DCHECK(GetGraph()->GetBlocks()[block_id] != nullptr) << block_id;
465*795d594fSAndroid Build Coastguard Worker     return PhiPlaceholder(block_id, idx);
466*795d594fSAndroid Build Coastguard Worker   }
467*795d594fSAndroid Build Coastguard Worker 
Replacement(Value value) const468*795d594fSAndroid Build Coastguard Worker   Value Replacement(Value value) const {
469*795d594fSAndroid Build Coastguard Worker     DCHECK(value.NeedsPhi()) << value << " phase: " << current_phase_;
470*795d594fSAndroid Build Coastguard Worker     Value replacement = phi_placeholder_replacements_[PhiPlaceholderIndex(value)];
471*795d594fSAndroid Build Coastguard Worker     DCHECK(replacement.IsUnknown() || replacement.IsInstruction());
472*795d594fSAndroid Build Coastguard Worker     DCHECK(replacement.IsUnknown() ||
473*795d594fSAndroid Build Coastguard Worker            FindSubstitute(replacement.GetInstruction()) == replacement.GetInstruction());
474*795d594fSAndroid Build Coastguard Worker     return replacement;
475*795d594fSAndroid Build Coastguard Worker   }
476*795d594fSAndroid Build Coastguard Worker 
ReplacementOrValue(Value value) const477*795d594fSAndroid Build Coastguard Worker   Value ReplacementOrValue(Value value) const {
478*795d594fSAndroid Build Coastguard Worker     if (value.NeedsPhi() && phi_placeholder_replacements_[PhiPlaceholderIndex(value)].IsValid()) {
479*795d594fSAndroid Build Coastguard Worker       return Replacement(value);
480*795d594fSAndroid Build Coastguard Worker     } else {
481*795d594fSAndroid Build Coastguard Worker       DCHECK_IMPLIES(value.IsInstruction(),
482*795d594fSAndroid Build Coastguard Worker                      FindSubstitute(value.GetInstruction()) == value.GetInstruction());
483*795d594fSAndroid Build Coastguard Worker       return value;
484*795d594fSAndroid Build Coastguard Worker     }
485*795d594fSAndroid Build Coastguard Worker   }
486*795d594fSAndroid Build Coastguard Worker 
487*795d594fSAndroid Build Coastguard Worker   // The record of a heap value and instruction(s) that feed that value.
488*795d594fSAndroid Build Coastguard Worker   struct ValueRecord {
489*795d594fSAndroid Build Coastguard Worker     Value value;
490*795d594fSAndroid Build Coastguard Worker     Value stored_by;
491*795d594fSAndroid Build Coastguard Worker   };
492*795d594fSAndroid Build Coastguard Worker 
FindOrAddTypeConversionIfNecessary(HInstruction * instruction,HInstruction * value,DataType::Type expected_type)493*795d594fSAndroid Build Coastguard Worker   HTypeConversion* FindOrAddTypeConversionIfNecessary(HInstruction* instruction,
494*795d594fSAndroid Build Coastguard Worker                                                       HInstruction* value,
495*795d594fSAndroid Build Coastguard Worker                                                       DataType::Type expected_type) {
496*795d594fSAndroid Build Coastguard Worker     // Should never add type conversion into boolean value.
497*795d594fSAndroid Build Coastguard Worker     if (expected_type == DataType::Type::kBool ||
498*795d594fSAndroid Build Coastguard Worker         DataType::IsTypeConversionImplicit(value->GetType(), expected_type) ||
499*795d594fSAndroid Build Coastguard Worker         // TODO: This prevents type conversion of default values but we can still insert
500*795d594fSAndroid Build Coastguard Worker         // type conversion of other constants and there is no constant folding pass after LSE.
501*795d594fSAndroid Build Coastguard Worker         IsZeroBitPattern(value)) {
502*795d594fSAndroid Build Coastguard Worker       return nullptr;
503*795d594fSAndroid Build Coastguard Worker     }
504*795d594fSAndroid Build Coastguard Worker 
505*795d594fSAndroid Build Coastguard Worker     // Check if there is already a suitable TypeConversion we can reuse.
506*795d594fSAndroid Build Coastguard Worker     for (const HUseListNode<HInstruction*>& use : value->GetUses()) {
507*795d594fSAndroid Build Coastguard Worker       if (use.GetUser()->IsTypeConversion() &&
508*795d594fSAndroid Build Coastguard Worker           use.GetUser()->GetType() == expected_type &&
509*795d594fSAndroid Build Coastguard Worker           // TODO: We could move the TypeConversion to a common dominator
510*795d594fSAndroid Build Coastguard Worker           // if it does not cross irreducible loop header.
511*795d594fSAndroid Build Coastguard Worker           use.GetUser()->GetBlock()->Dominates(instruction->GetBlock()) &&
512*795d594fSAndroid Build Coastguard Worker           // Don't share across irreducible loop headers.
513*795d594fSAndroid Build Coastguard Worker           // TODO: can be more fine-grained than this by testing each dominator.
514*795d594fSAndroid Build Coastguard Worker           (use.GetUser()->GetBlock() == instruction->GetBlock() ||
515*795d594fSAndroid Build Coastguard Worker            !GetGraph()->HasIrreducibleLoops())) {
516*795d594fSAndroid Build Coastguard Worker         if (use.GetUser()->GetBlock() == instruction->GetBlock() &&
517*795d594fSAndroid Build Coastguard Worker             use.GetUser()->GetBlock()->GetInstructions().FoundBefore(instruction, use.GetUser())) {
518*795d594fSAndroid Build Coastguard Worker           // Move the TypeConversion before the instruction.
519*795d594fSAndroid Build Coastguard Worker           use.GetUser()->MoveBefore(instruction);
520*795d594fSAndroid Build Coastguard Worker         }
521*795d594fSAndroid Build Coastguard Worker         DCHECK(use.GetUser()->StrictlyDominates(instruction));
522*795d594fSAndroid Build Coastguard Worker         return use.GetUser()->AsTypeConversion();
523*795d594fSAndroid Build Coastguard Worker       }
524*795d594fSAndroid Build Coastguard Worker     }
525*795d594fSAndroid Build Coastguard Worker 
526*795d594fSAndroid Build Coastguard Worker     // We must create a new TypeConversion instruction.
527*795d594fSAndroid Build Coastguard Worker     HTypeConversion* type_conversion = new (GetGraph()->GetAllocator()) HTypeConversion(
528*795d594fSAndroid Build Coastguard Worker           expected_type, value, instruction->GetDexPc());
529*795d594fSAndroid Build Coastguard Worker     instruction->GetBlock()->InsertInstructionBefore(type_conversion, instruction);
530*795d594fSAndroid Build Coastguard Worker     return type_conversion;
531*795d594fSAndroid Build Coastguard Worker   }
532*795d594fSAndroid Build Coastguard Worker 
533*795d594fSAndroid Build Coastguard Worker   // Find an instruction's substitute if it's a removed load.
534*795d594fSAndroid Build Coastguard Worker   // Return the same instruction if it should not be removed.
FindSubstitute(HInstruction * instruction) const535*795d594fSAndroid Build Coastguard Worker   HInstruction* FindSubstitute(HInstruction* instruction) const {
536*795d594fSAndroid Build Coastguard Worker     size_t id = static_cast<size_t>(instruction->GetId());
537*795d594fSAndroid Build Coastguard Worker     if (id >= substitute_instructions_for_loads_.size()) {
538*795d594fSAndroid Build Coastguard Worker       // New Phi (may not be in the graph yet), or default value.
539*795d594fSAndroid Build Coastguard Worker       DCHECK(!IsLoad(instruction));
540*795d594fSAndroid Build Coastguard Worker       return instruction;
541*795d594fSAndroid Build Coastguard Worker     }
542*795d594fSAndroid Build Coastguard Worker     HInstruction* substitute = substitute_instructions_for_loads_[id];
543*795d594fSAndroid Build Coastguard Worker     DCHECK(substitute == nullptr || IsLoad(instruction));
544*795d594fSAndroid Build Coastguard Worker     return (substitute != nullptr) ? substitute : instruction;
545*795d594fSAndroid Build Coastguard Worker   }
546*795d594fSAndroid Build Coastguard Worker 
AddRemovedLoad(HInstruction * load,HInstruction * heap_value)547*795d594fSAndroid Build Coastguard Worker   void AddRemovedLoad(HInstruction* load, HInstruction* heap_value) {
548*795d594fSAndroid Build Coastguard Worker     DCHECK(IsLoad(load));
549*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(FindSubstitute(load), load);
550*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(FindSubstitute(heap_value), heap_value) <<
551*795d594fSAndroid Build Coastguard Worker         "Unexpected heap_value that has a substitute " << heap_value->DebugName();
552*795d594fSAndroid Build Coastguard Worker 
553*795d594fSAndroid Build Coastguard Worker     // The load expects to load the heap value as type load->GetType().
554*795d594fSAndroid Build Coastguard Worker     // However the tracked heap value may not be of that type. An explicit
555*795d594fSAndroid Build Coastguard Worker     // type conversion may be needed.
556*795d594fSAndroid Build Coastguard Worker     // There are actually three types involved here:
557*795d594fSAndroid Build Coastguard Worker     // (1) tracked heap value's type (type A)
558*795d594fSAndroid Build Coastguard Worker     // (2) heap location (field or element)'s type (type B)
559*795d594fSAndroid Build Coastguard Worker     // (3) load's type (type C)
560*795d594fSAndroid Build Coastguard Worker     // We guarantee that type A stored as type B and then fetched out as
561*795d594fSAndroid Build Coastguard Worker     // type C is the same as casting from type A to type C directly, since
562*795d594fSAndroid Build Coastguard Worker     // type B and type C will have the same size which is guaranteed in
563*795d594fSAndroid Build Coastguard Worker     // HInstanceFieldGet/HStaticFieldGet/HArrayGet/HVecLoad's SetType().
564*795d594fSAndroid Build Coastguard Worker     // So we only need one type conversion from type A to type C.
565*795d594fSAndroid Build Coastguard Worker     HTypeConversion* type_conversion = FindOrAddTypeConversionIfNecessary(
566*795d594fSAndroid Build Coastguard Worker         load, heap_value, load->GetType());
567*795d594fSAndroid Build Coastguard Worker 
568*795d594fSAndroid Build Coastguard Worker     substitute_instructions_for_loads_[load->GetId()] =
569*795d594fSAndroid Build Coastguard Worker         type_conversion != nullptr ? type_conversion : heap_value;
570*795d594fSAndroid Build Coastguard Worker   }
571*795d594fSAndroid Build Coastguard Worker 
IsLoad(HInstruction * instruction)572*795d594fSAndroid Build Coastguard Worker   static bool IsLoad(HInstruction* instruction) {
573*795d594fSAndroid Build Coastguard Worker     // Unresolved load is not treated as a load.
574*795d594fSAndroid Build Coastguard Worker     return instruction->IsInstanceFieldGet() ||
575*795d594fSAndroid Build Coastguard Worker            instruction->IsStaticFieldGet() ||
576*795d594fSAndroid Build Coastguard Worker            instruction->IsVecLoad() ||
577*795d594fSAndroid Build Coastguard Worker            instruction->IsArrayGet();
578*795d594fSAndroid Build Coastguard Worker   }
579*795d594fSAndroid Build Coastguard Worker 
IsStore(HInstruction * instruction)580*795d594fSAndroid Build Coastguard Worker   static bool IsStore(HInstruction* instruction) {
581*795d594fSAndroid Build Coastguard Worker     // Unresolved store is not treated as a store.
582*795d594fSAndroid Build Coastguard Worker     return instruction->IsInstanceFieldSet() ||
583*795d594fSAndroid Build Coastguard Worker            instruction->IsArraySet() ||
584*795d594fSAndroid Build Coastguard Worker            instruction->IsVecStore() ||
585*795d594fSAndroid Build Coastguard Worker            instruction->IsStaticFieldSet();
586*795d594fSAndroid Build Coastguard Worker   }
587*795d594fSAndroid Build Coastguard Worker 
588*795d594fSAndroid Build Coastguard Worker   // Check if it is allowed to use default values or Phis for the specified load.
IsDefaultOrPhiAllowedForLoad(HInstruction * instruction)589*795d594fSAndroid Build Coastguard Worker   static bool IsDefaultOrPhiAllowedForLoad(HInstruction* instruction) {
590*795d594fSAndroid Build Coastguard Worker     DCHECK(IsLoad(instruction));
591*795d594fSAndroid Build Coastguard Worker     // Using defaults for VecLoads requires to create additional vector operations.
592*795d594fSAndroid Build Coastguard Worker     // As there are some issues with scheduling vector operations it is better to avoid creating
593*795d594fSAndroid Build Coastguard Worker     // them.
594*795d594fSAndroid Build Coastguard Worker     return !instruction->IsVecOperation();
595*795d594fSAndroid Build Coastguard Worker   }
596*795d594fSAndroid Build Coastguard Worker 
597*795d594fSAndroid Build Coastguard Worker   // Keep the store referenced by the instruction, or all stores that feed a Phi placeholder.
598*795d594fSAndroid Build Coastguard Worker   // This is necessary if the stored heap value can be observed.
KeepStores(Value value)599*795d594fSAndroid Build Coastguard Worker   void KeepStores(Value value) {
600*795d594fSAndroid Build Coastguard Worker     if (value.IsUnknown()) {
601*795d594fSAndroid Build Coastguard Worker       return;
602*795d594fSAndroid Build Coastguard Worker     }
603*795d594fSAndroid Build Coastguard Worker     if (value.NeedsPhi()) {
604*795d594fSAndroid Build Coastguard Worker       phi_placeholders_to_search_for_kept_stores_.SetBit(PhiPlaceholderIndex(value));
605*795d594fSAndroid Build Coastguard Worker     } else {
606*795d594fSAndroid Build Coastguard Worker       HInstruction* instruction = value.GetInstruction();
607*795d594fSAndroid Build Coastguard Worker       DCHECK(IsStore(instruction));
608*795d594fSAndroid Build Coastguard Worker       kept_stores_.SetBit(instruction->GetId());
609*795d594fSAndroid Build Coastguard Worker     }
610*795d594fSAndroid Build Coastguard Worker   }
611*795d594fSAndroid Build Coastguard Worker 
612*795d594fSAndroid Build Coastguard Worker   // If a heap location X may alias with heap location at `loc_index`
613*795d594fSAndroid Build Coastguard Worker   // and heap_values of that heap location X holds a store, keep that store.
614*795d594fSAndroid Build Coastguard Worker   // It's needed for a dependent load that's not eliminated since any store
615*795d594fSAndroid Build Coastguard Worker   // that may put value into the load's heap location needs to be kept.
KeepStoresIfAliasedToLocation(ScopedArenaVector<ValueRecord> & heap_values,size_t loc_index)616*795d594fSAndroid Build Coastguard Worker   void KeepStoresIfAliasedToLocation(ScopedArenaVector<ValueRecord>& heap_values,
617*795d594fSAndroid Build Coastguard Worker                                      size_t loc_index) {
618*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0u, size = heap_values.size(); i != size; ++i) {
619*795d594fSAndroid Build Coastguard Worker       if (i == loc_index) {
620*795d594fSAndroid Build Coastguard Worker         // We use this function when reading a location with unknown value and
621*795d594fSAndroid Build Coastguard Worker         // therefore we cannot know what exact store wrote that unknown value.
622*795d594fSAndroid Build Coastguard Worker         // But we can have a phi placeholder here marking multiple stores to keep.
623*795d594fSAndroid Build Coastguard Worker         DCHECK(!heap_values[i].stored_by.IsInstruction());
624*795d594fSAndroid Build Coastguard Worker         KeepStores(heap_values[i].stored_by);
625*795d594fSAndroid Build Coastguard Worker         heap_values[i].stored_by = Value::Unknown();
626*795d594fSAndroid Build Coastguard Worker       } else if (heap_location_collector_.MayAlias(i, loc_index)) {
627*795d594fSAndroid Build Coastguard Worker         KeepStores(heap_values[i].stored_by);
628*795d594fSAndroid Build Coastguard Worker         heap_values[i].stored_by = Value::Unknown();
629*795d594fSAndroid Build Coastguard Worker       }
630*795d594fSAndroid Build Coastguard Worker     }
631*795d594fSAndroid Build Coastguard Worker   }
632*795d594fSAndroid Build Coastguard Worker 
GetDefaultValue(DataType::Type type)633*795d594fSAndroid Build Coastguard Worker   HInstruction* GetDefaultValue(DataType::Type type) {
634*795d594fSAndroid Build Coastguard Worker     switch (type) {
635*795d594fSAndroid Build Coastguard Worker       case DataType::Type::kReference:
636*795d594fSAndroid Build Coastguard Worker         return GetGraph()->GetNullConstant();
637*795d594fSAndroid Build Coastguard Worker       case DataType::Type::kBool:
638*795d594fSAndroid Build Coastguard Worker       case DataType::Type::kUint8:
639*795d594fSAndroid Build Coastguard Worker       case DataType::Type::kInt8:
640*795d594fSAndroid Build Coastguard Worker       case DataType::Type::kUint16:
641*795d594fSAndroid Build Coastguard Worker       case DataType::Type::kInt16:
642*795d594fSAndroid Build Coastguard Worker       case DataType::Type::kInt32:
643*795d594fSAndroid Build Coastguard Worker         return GetGraph()->GetIntConstant(0);
644*795d594fSAndroid Build Coastguard Worker       case DataType::Type::kInt64:
645*795d594fSAndroid Build Coastguard Worker         return GetGraph()->GetLongConstant(0);
646*795d594fSAndroid Build Coastguard Worker       case DataType::Type::kFloat32:
647*795d594fSAndroid Build Coastguard Worker         return GetGraph()->GetFloatConstant(0);
648*795d594fSAndroid Build Coastguard Worker       case DataType::Type::kFloat64:
649*795d594fSAndroid Build Coastguard Worker         return GetGraph()->GetDoubleConstant(0);
650*795d594fSAndroid Build Coastguard Worker       default:
651*795d594fSAndroid Build Coastguard Worker         UNREACHABLE();
652*795d594fSAndroid Build Coastguard Worker     }
653*795d594fSAndroid Build Coastguard Worker   }
654*795d594fSAndroid Build Coastguard Worker 
CanValueBeKeptIfSameAsNew(Value value,HInstruction * new_value,HInstruction * new_value_set_instr)655*795d594fSAndroid Build Coastguard Worker   bool CanValueBeKeptIfSameAsNew(Value value,
656*795d594fSAndroid Build Coastguard Worker                                  HInstruction* new_value,
657*795d594fSAndroid Build Coastguard Worker                                  HInstruction* new_value_set_instr) {
658*795d594fSAndroid Build Coastguard Worker     // For field/array set location operations, if the value is the same as the new_value
659*795d594fSAndroid Build Coastguard Worker     // it can be kept even if aliasing happens. All aliased operations will access the same memory
660*795d594fSAndroid Build Coastguard Worker     // range.
661*795d594fSAndroid Build Coastguard Worker     // For vector values, this is not true. For example:
662*795d594fSAndroid Build Coastguard Worker     //  packed_data = [0xA, 0xB, 0xC, 0xD];            <-- Different values in each lane.
663*795d594fSAndroid Build Coastguard Worker     //  VecStore array[i  ,i+1,i+2,i+3] = packed_data;
664*795d594fSAndroid Build Coastguard Worker     //  VecStore array[i+1,i+2,i+3,i+4] = packed_data; <-- We are here (partial overlap).
665*795d594fSAndroid Build Coastguard Worker     //  VecLoad  vx = array[i,i+1,i+2,i+3];            <-- Cannot be eliminated because the value
666*795d594fSAndroid Build Coastguard Worker     //                                                     here is not packed_data anymore.
667*795d594fSAndroid Build Coastguard Worker     //
668*795d594fSAndroid Build Coastguard Worker     // TODO: to allow such 'same value' optimization on vector data,
669*795d594fSAndroid Build Coastguard Worker     // LSA needs to report more fine-grain MAY alias information:
670*795d594fSAndroid Build Coastguard Worker     // (1) May alias due to two vector data partial overlap.
671*795d594fSAndroid Build Coastguard Worker     //     e.g. a[i..i+3] and a[i+1,..,i+4].
672*795d594fSAndroid Build Coastguard Worker     // (2) May alias due to two vector data may complete overlap each other.
673*795d594fSAndroid Build Coastguard Worker     //     e.g. a[i..i+3] and b[i..i+3].
674*795d594fSAndroid Build Coastguard Worker     // (3) May alias but the exact relationship between two locations is unknown.
675*795d594fSAndroid Build Coastguard Worker     //     e.g. a[i..i+3] and b[j..j+3], where values of a,b,i,j are all unknown.
676*795d594fSAndroid Build Coastguard Worker     // This 'same value' optimization can apply only on case (2).
677*795d594fSAndroid Build Coastguard Worker     if (new_value_set_instr->IsVecOperation()) {
678*795d594fSAndroid Build Coastguard Worker       return false;
679*795d594fSAndroid Build Coastguard Worker     }
680*795d594fSAndroid Build Coastguard Worker 
681*795d594fSAndroid Build Coastguard Worker     return value.Equals(new_value);
682*795d594fSAndroid Build Coastguard Worker   }
683*795d594fSAndroid Build Coastguard Worker 
684*795d594fSAndroid Build Coastguard Worker   Value PrepareLoopValue(HBasicBlock* block, size_t idx);
685*795d594fSAndroid Build Coastguard Worker   Value PrepareLoopStoredBy(HBasicBlock* block, size_t idx);
686*795d594fSAndroid Build Coastguard Worker   void PrepareLoopRecords(HBasicBlock* block);
687*795d594fSAndroid Build Coastguard Worker   Value MergePredecessorValues(HBasicBlock* block, size_t idx);
688*795d594fSAndroid Build Coastguard Worker   void MergePredecessorRecords(HBasicBlock* block);
689*795d594fSAndroid Build Coastguard Worker 
690*795d594fSAndroid Build Coastguard Worker   void MaterializeNonLoopPhis(PhiPlaceholder phi_placeholder, DataType::Type type);
691*795d594fSAndroid Build Coastguard Worker 
692*795d594fSAndroid Build Coastguard Worker   void VisitGetLocation(HInstruction* instruction, size_t idx);
693*795d594fSAndroid Build Coastguard Worker   void VisitSetLocation(HInstruction* instruction, size_t idx, HInstruction* value);
RecordFieldInfo(const FieldInfo * info,size_t heap_loc)694*795d594fSAndroid Build Coastguard Worker   void RecordFieldInfo(const FieldInfo* info, size_t heap_loc) {
695*795d594fSAndroid Build Coastguard Worker     field_infos_[heap_loc] = info;
696*795d594fSAndroid Build Coastguard Worker   }
697*795d594fSAndroid Build Coastguard Worker 
698*795d594fSAndroid Build Coastguard Worker   void VisitBasicBlock(HBasicBlock* block) override;
699*795d594fSAndroid Build Coastguard Worker 
700*795d594fSAndroid Build Coastguard Worker   enum class Phase {
701*795d594fSAndroid Build Coastguard Worker     kLoadElimination,
702*795d594fSAndroid Build Coastguard Worker     kStoreElimination,
703*795d594fSAndroid Build Coastguard Worker   };
704*795d594fSAndroid Build Coastguard Worker 
705*795d594fSAndroid Build Coastguard Worker   bool MayAliasOnBackEdge(HBasicBlock* loop_header, size_t idx1, size_t idx2) const;
706*795d594fSAndroid Build Coastguard Worker 
707*795d594fSAndroid Build Coastguard Worker   bool TryReplacingLoopPhiPlaceholderWithDefault(
708*795d594fSAndroid Build Coastguard Worker       PhiPlaceholder phi_placeholder,
709*795d594fSAndroid Build Coastguard Worker       DataType::Type type,
710*795d594fSAndroid Build Coastguard Worker       /*inout*/ ArenaBitVector* phi_placeholders_to_materialize);
711*795d594fSAndroid Build Coastguard Worker   bool TryReplacingLoopPhiPlaceholderWithSingleInput(
712*795d594fSAndroid Build Coastguard Worker       PhiPlaceholder phi_placeholder,
713*795d594fSAndroid Build Coastguard Worker       /*inout*/ ArenaBitVector* phi_placeholders_to_materialize);
714*795d594fSAndroid Build Coastguard Worker   std::optional<PhiPlaceholder> FindLoopPhisToMaterialize(
715*795d594fSAndroid Build Coastguard Worker       PhiPlaceholder phi_placeholder,
716*795d594fSAndroid Build Coastguard Worker       /*out*/ ArenaBitVector* phi_placeholders_to_materialize,
717*795d594fSAndroid Build Coastguard Worker       DataType::Type type,
718*795d594fSAndroid Build Coastguard Worker       bool can_use_default_or_phi);
719*795d594fSAndroid Build Coastguard Worker   bool MaterializeLoopPhis(const ScopedArenaVector<size_t>& phi_placeholder_indexes,
720*795d594fSAndroid Build Coastguard Worker                            DataType::Type type);
721*795d594fSAndroid Build Coastguard Worker   bool MaterializeLoopPhis(ArrayRef<const size_t> phi_placeholder_indexes, DataType::Type type);
722*795d594fSAndroid Build Coastguard Worker   bool MaterializeLoopPhis(const ArenaBitVector& phi_placeholders_to_materialize,
723*795d594fSAndroid Build Coastguard Worker                            DataType::Type type);
724*795d594fSAndroid Build Coastguard Worker   bool FullyMaterializePhi(PhiPlaceholder phi_placeholder, DataType::Type type);
725*795d594fSAndroid Build Coastguard Worker   std::optional<PhiPlaceholder> TryToMaterializeLoopPhis(PhiPlaceholder phi_placeholder,
726*795d594fSAndroid Build Coastguard Worker                                                          HInstruction* load);
727*795d594fSAndroid Build Coastguard Worker   void ProcessLoopPhiWithUnknownInput(PhiPlaceholder loop_phi_with_unknown_input);
728*795d594fSAndroid Build Coastguard Worker   void ProcessLoadsRequiringLoopPhis();
729*795d594fSAndroid Build Coastguard Worker 
730*795d594fSAndroid Build Coastguard Worker   void SearchPhiPlaceholdersForKeptStores();
731*795d594fSAndroid Build Coastguard Worker   void UpdateValueRecordForStoreElimination(/*inout*/ValueRecord* value_record);
732*795d594fSAndroid Build Coastguard Worker   void FindOldValueForPhiPlaceholder(PhiPlaceholder phi_placeholder, DataType::Type type);
733*795d594fSAndroid Build Coastguard Worker   void FindStoresWritingOldValues();
734*795d594fSAndroid Build Coastguard Worker   void FinishFullLSE();
735*795d594fSAndroid Build Coastguard Worker 
HandleAcquireLoad(HInstruction * instruction)736*795d594fSAndroid Build Coastguard Worker   void HandleAcquireLoad(HInstruction* instruction) {
737*795d594fSAndroid Build Coastguard Worker     DCHECK((instruction->IsInstanceFieldGet() && instruction->AsInstanceFieldGet()->IsVolatile()) ||
738*795d594fSAndroid Build Coastguard Worker            (instruction->IsStaticFieldGet() && instruction->AsStaticFieldGet()->IsVolatile()) ||
739*795d594fSAndroid Build Coastguard Worker            (instruction->IsMonitorOperation() && instruction->AsMonitorOperation()->IsEnter()))
740*795d594fSAndroid Build Coastguard Worker         << "Unexpected instruction " << instruction->GetId() << ": " << instruction->DebugName();
741*795d594fSAndroid Build Coastguard Worker 
742*795d594fSAndroid Build Coastguard Worker     // Acquire operations e.g. MONITOR_ENTER change the thread's view of the memory, so we must
743*795d594fSAndroid Build Coastguard Worker     // invalidate all current values.
744*795d594fSAndroid Build Coastguard Worker     ScopedArenaVector<ValueRecord>& heap_values =
745*795d594fSAndroid Build Coastguard Worker         heap_values_for_[instruction->GetBlock()->GetBlockId()];
746*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0u, size = heap_values.size(); i != size; ++i) {
747*795d594fSAndroid Build Coastguard Worker       KeepStores(heap_values[i].stored_by);
748*795d594fSAndroid Build Coastguard Worker       heap_values[i].stored_by = Value::Unknown();
749*795d594fSAndroid Build Coastguard Worker       heap_values[i].value = Value::Unknown();
750*795d594fSAndroid Build Coastguard Worker     }
751*795d594fSAndroid Build Coastguard Worker 
752*795d594fSAndroid Build Coastguard Worker     // Note that there's no need to record the load as subsequent acquire loads shouldn't be
753*795d594fSAndroid Build Coastguard Worker     // eliminated either.
754*795d594fSAndroid Build Coastguard Worker   }
755*795d594fSAndroid Build Coastguard Worker 
HandleReleaseStore(HInstruction * instruction)756*795d594fSAndroid Build Coastguard Worker   void HandleReleaseStore(HInstruction* instruction) {
757*795d594fSAndroid Build Coastguard Worker     DCHECK((instruction->IsInstanceFieldSet() && instruction->AsInstanceFieldSet()->IsVolatile()) ||
758*795d594fSAndroid Build Coastguard Worker            (instruction->IsStaticFieldSet() && instruction->AsStaticFieldSet()->IsVolatile()) ||
759*795d594fSAndroid Build Coastguard Worker            (instruction->IsMonitorOperation() && !instruction->AsMonitorOperation()->IsEnter()))
760*795d594fSAndroid Build Coastguard Worker         << "Unexpected instruction " << instruction->GetId() << ": " << instruction->DebugName();
761*795d594fSAndroid Build Coastguard Worker 
762*795d594fSAndroid Build Coastguard Worker     // Release operations e.g. MONITOR_EXIT do not affect this thread's view of the memory, but
763*795d594fSAndroid Build Coastguard Worker     // they will push the modifications for other threads to see. Therefore, we must keep the
764*795d594fSAndroid Build Coastguard Worker     // stores but there's no need to clobber the value.
765*795d594fSAndroid Build Coastguard Worker     ScopedArenaVector<ValueRecord>& heap_values =
766*795d594fSAndroid Build Coastguard Worker         heap_values_for_[instruction->GetBlock()->GetBlockId()];
767*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0u, size = heap_values.size(); i != size; ++i) {
768*795d594fSAndroid Build Coastguard Worker       KeepStores(heap_values[i].stored_by);
769*795d594fSAndroid Build Coastguard Worker       heap_values[i].stored_by = Value::Unknown();
770*795d594fSAndroid Build Coastguard Worker     }
771*795d594fSAndroid Build Coastguard Worker 
772*795d594fSAndroid Build Coastguard Worker     // Note that there's no need to record the store as subsequent release store shouldn't be
773*795d594fSAndroid Build Coastguard Worker     // eliminated either.
774*795d594fSAndroid Build Coastguard Worker   }
775*795d594fSAndroid Build Coastguard Worker 
VisitInstanceFieldGet(HInstanceFieldGet * instruction)776*795d594fSAndroid Build Coastguard Worker   void VisitInstanceFieldGet(HInstanceFieldGet* instruction) override {
777*795d594fSAndroid Build Coastguard Worker     HInstruction* object = instruction->InputAt(0);
778*795d594fSAndroid Build Coastguard Worker     if (instruction->IsVolatile()) {
779*795d594fSAndroid Build Coastguard Worker       ReferenceInfo* ref_info = heap_location_collector_.FindReferenceInfoOf(
780*795d594fSAndroid Build Coastguard Worker           heap_location_collector_.HuntForOriginalReference(object));
781*795d594fSAndroid Build Coastguard Worker       if (!ref_info->IsSingletonAndRemovable()) {
782*795d594fSAndroid Build Coastguard Worker         HandleAcquireLoad(instruction);
783*795d594fSAndroid Build Coastguard Worker         return;
784*795d594fSAndroid Build Coastguard Worker       }
785*795d594fSAndroid Build Coastguard Worker       // Treat it as a normal load if it is a removable singleton.
786*795d594fSAndroid Build Coastguard Worker     }
787*795d594fSAndroid Build Coastguard Worker 
788*795d594fSAndroid Build Coastguard Worker     const FieldInfo& field = instruction->GetFieldInfo();
789*795d594fSAndroid Build Coastguard Worker     VisitGetLocation(instruction, heap_location_collector_.GetFieldHeapLocation(object, &field));
790*795d594fSAndroid Build Coastguard Worker   }
791*795d594fSAndroid Build Coastguard Worker 
VisitInstanceFieldSet(HInstanceFieldSet * instruction)792*795d594fSAndroid Build Coastguard Worker   void VisitInstanceFieldSet(HInstanceFieldSet* instruction) override {
793*795d594fSAndroid Build Coastguard Worker     HInstruction* object = instruction->InputAt(0);
794*795d594fSAndroid Build Coastguard Worker     if (instruction->IsVolatile()) {
795*795d594fSAndroid Build Coastguard Worker       ReferenceInfo* ref_info = heap_location_collector_.FindReferenceInfoOf(
796*795d594fSAndroid Build Coastguard Worker           heap_location_collector_.HuntForOriginalReference(object));
797*795d594fSAndroid Build Coastguard Worker       if (!ref_info->IsSingletonAndRemovable()) {
798*795d594fSAndroid Build Coastguard Worker         HandleReleaseStore(instruction);
799*795d594fSAndroid Build Coastguard Worker         return;
800*795d594fSAndroid Build Coastguard Worker       }
801*795d594fSAndroid Build Coastguard Worker       // Treat it as a normal store if it is a removable singleton.
802*795d594fSAndroid Build Coastguard Worker     }
803*795d594fSAndroid Build Coastguard Worker 
804*795d594fSAndroid Build Coastguard Worker     const FieldInfo& field = instruction->GetFieldInfo();
805*795d594fSAndroid Build Coastguard Worker     HInstruction* value = instruction->InputAt(1);
806*795d594fSAndroid Build Coastguard Worker     size_t idx = heap_location_collector_.GetFieldHeapLocation(object, &field);
807*795d594fSAndroid Build Coastguard Worker     VisitSetLocation(instruction, idx, value);
808*795d594fSAndroid Build Coastguard Worker   }
809*795d594fSAndroid Build Coastguard Worker 
VisitStaticFieldGet(HStaticFieldGet * instruction)810*795d594fSAndroid Build Coastguard Worker   void VisitStaticFieldGet(HStaticFieldGet* instruction) override {
811*795d594fSAndroid Build Coastguard Worker     if (instruction->IsVolatile()) {
812*795d594fSAndroid Build Coastguard Worker       HandleAcquireLoad(instruction);
813*795d594fSAndroid Build Coastguard Worker       return;
814*795d594fSAndroid Build Coastguard Worker     }
815*795d594fSAndroid Build Coastguard Worker 
816*795d594fSAndroid Build Coastguard Worker     const FieldInfo& field = instruction->GetFieldInfo();
817*795d594fSAndroid Build Coastguard Worker     HInstruction* cls = instruction->InputAt(0);
818*795d594fSAndroid Build Coastguard Worker     VisitGetLocation(instruction, heap_location_collector_.GetFieldHeapLocation(cls, &field));
819*795d594fSAndroid Build Coastguard Worker   }
820*795d594fSAndroid Build Coastguard Worker 
VisitStaticFieldSet(HStaticFieldSet * instruction)821*795d594fSAndroid Build Coastguard Worker   void VisitStaticFieldSet(HStaticFieldSet* instruction) override {
822*795d594fSAndroid Build Coastguard Worker     if (instruction->IsVolatile()) {
823*795d594fSAndroid Build Coastguard Worker       HandleReleaseStore(instruction);
824*795d594fSAndroid Build Coastguard Worker       return;
825*795d594fSAndroid Build Coastguard Worker     }
826*795d594fSAndroid Build Coastguard Worker 
827*795d594fSAndroid Build Coastguard Worker     const FieldInfo& field = instruction->GetFieldInfo();
828*795d594fSAndroid Build Coastguard Worker     HInstruction* cls = instruction->InputAt(0);
829*795d594fSAndroid Build Coastguard Worker     HInstruction* value = instruction->InputAt(1);
830*795d594fSAndroid Build Coastguard Worker     size_t idx = heap_location_collector_.GetFieldHeapLocation(cls, &field);
831*795d594fSAndroid Build Coastguard Worker     VisitSetLocation(instruction, idx, value);
832*795d594fSAndroid Build Coastguard Worker   }
833*795d594fSAndroid Build Coastguard Worker 
VisitMonitorOperation(HMonitorOperation * monitor_op)834*795d594fSAndroid Build Coastguard Worker   void VisitMonitorOperation(HMonitorOperation* monitor_op) override {
835*795d594fSAndroid Build Coastguard Worker     HInstruction* object = monitor_op->InputAt(0);
836*795d594fSAndroid Build Coastguard Worker     ReferenceInfo* ref_info = heap_location_collector_.FindReferenceInfoOf(
837*795d594fSAndroid Build Coastguard Worker         heap_location_collector_.HuntForOriginalReference(object));
838*795d594fSAndroid Build Coastguard Worker     if (ref_info->IsSingletonAndRemovable()) {
839*795d594fSAndroid Build Coastguard Worker       // If the object is a removable singleton, we know that no other threads will have
840*795d594fSAndroid Build Coastguard Worker       // access to it, and we can remove the MonitorOperation instruction.
841*795d594fSAndroid Build Coastguard Worker       // MONITOR_ENTER throws when encountering a null object. If `object` is a removable
842*795d594fSAndroid Build Coastguard Worker       // singleton, it is guaranteed to be non-null so we don't have to worry about the NullCheck.
843*795d594fSAndroid Build Coastguard Worker       DCHECK(!object->CanBeNull());
844*795d594fSAndroid Build Coastguard Worker       monitor_op->GetBlock()->RemoveInstruction(monitor_op);
845*795d594fSAndroid Build Coastguard Worker       MaybeRecordStat(stats_, MethodCompilationStat::kRemovedMonitorOp);
846*795d594fSAndroid Build Coastguard Worker       return;
847*795d594fSAndroid Build Coastguard Worker     }
848*795d594fSAndroid Build Coastguard Worker 
849*795d594fSAndroid Build Coastguard Worker     // We detected a monitor operation that we couldn't remove. See also LSEVisitor::Run().
850*795d594fSAndroid Build Coastguard Worker     monitor_op->GetBlock()->GetGraph()->SetHasMonitorOperations(true);
851*795d594fSAndroid Build Coastguard Worker     if (monitor_op->IsEnter()) {
852*795d594fSAndroid Build Coastguard Worker       HandleAcquireLoad(monitor_op);
853*795d594fSAndroid Build Coastguard Worker     } else {
854*795d594fSAndroid Build Coastguard Worker       HandleReleaseStore(monitor_op);
855*795d594fSAndroid Build Coastguard Worker     }
856*795d594fSAndroid Build Coastguard Worker   }
857*795d594fSAndroid Build Coastguard Worker 
VisitArrayGet(HArrayGet * instruction)858*795d594fSAndroid Build Coastguard Worker   void VisitArrayGet(HArrayGet* instruction) override {
859*795d594fSAndroid Build Coastguard Worker     VisitGetLocation(instruction, heap_location_collector_.GetArrayHeapLocation(instruction));
860*795d594fSAndroid Build Coastguard Worker   }
861*795d594fSAndroid Build Coastguard Worker 
VisitArraySet(HArraySet * instruction)862*795d594fSAndroid Build Coastguard Worker   void VisitArraySet(HArraySet* instruction) override {
863*795d594fSAndroid Build Coastguard Worker     size_t idx = heap_location_collector_.GetArrayHeapLocation(instruction);
864*795d594fSAndroid Build Coastguard Worker     VisitSetLocation(instruction, idx, instruction->GetValue());
865*795d594fSAndroid Build Coastguard Worker   }
866*795d594fSAndroid Build Coastguard Worker 
VisitVecLoad(HVecLoad * instruction)867*795d594fSAndroid Build Coastguard Worker   void VisitVecLoad(HVecLoad* instruction) override {
868*795d594fSAndroid Build Coastguard Worker     DCHECK(!instruction->IsPredicated());
869*795d594fSAndroid Build Coastguard Worker     VisitGetLocation(instruction, heap_location_collector_.GetArrayHeapLocation(instruction));
870*795d594fSAndroid Build Coastguard Worker   }
871*795d594fSAndroid Build Coastguard Worker 
VisitVecStore(HVecStore * instruction)872*795d594fSAndroid Build Coastguard Worker   void VisitVecStore(HVecStore* instruction) override {
873*795d594fSAndroid Build Coastguard Worker     DCHECK(!instruction->IsPredicated());
874*795d594fSAndroid Build Coastguard Worker     size_t idx = heap_location_collector_.GetArrayHeapLocation(instruction);
875*795d594fSAndroid Build Coastguard Worker     VisitSetLocation(instruction, idx, instruction->GetValue());
876*795d594fSAndroid Build Coastguard Worker   }
877*795d594fSAndroid Build Coastguard Worker 
VisitDeoptimize(HDeoptimize * instruction)878*795d594fSAndroid Build Coastguard Worker   void VisitDeoptimize(HDeoptimize* instruction) override {
879*795d594fSAndroid Build Coastguard Worker     // If we are in a try, even singletons are observable.
880*795d594fSAndroid Build Coastguard Worker     const bool inside_a_try = instruction->GetBlock()->IsTryBlock();
881*795d594fSAndroid Build Coastguard Worker     HBasicBlock* block = instruction->GetBlock();
882*795d594fSAndroid Build Coastguard Worker     ScopedArenaVector<ValueRecord>& heap_values = heap_values_for_[block->GetBlockId()];
883*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0u, size = heap_values.size(); i != size; ++i) {
884*795d594fSAndroid Build Coastguard Worker       Value* stored_by = &heap_values[i].stored_by;
885*795d594fSAndroid Build Coastguard Worker       if (stored_by->IsUnknown()) {
886*795d594fSAndroid Build Coastguard Worker         continue;
887*795d594fSAndroid Build Coastguard Worker       }
888*795d594fSAndroid Build Coastguard Worker       // Stores are generally observeable after deoptimization, except
889*795d594fSAndroid Build Coastguard Worker       // for singletons that don't escape in the deoptimization environment.
890*795d594fSAndroid Build Coastguard Worker       bool observable = true;
891*795d594fSAndroid Build Coastguard Worker       ReferenceInfo* info = heap_location_collector_.GetHeapLocation(i)->GetReferenceInfo();
892*795d594fSAndroid Build Coastguard Worker       if (!inside_a_try && info->IsSingleton()) {
893*795d594fSAndroid Build Coastguard Worker         HInstruction* reference = info->GetReference();
894*795d594fSAndroid Build Coastguard Worker         // Finalizable objects always escape.
895*795d594fSAndroid Build Coastguard Worker         const bool finalizable_object =
896*795d594fSAndroid Build Coastguard Worker             reference->IsNewInstance() && reference->AsNewInstance()->IsFinalizable();
897*795d594fSAndroid Build Coastguard Worker         if (!finalizable_object && !IsEscapingObject(info)) {
898*795d594fSAndroid Build Coastguard Worker           // Check whether the reference for a store is used by an environment local of
899*795d594fSAndroid Build Coastguard Worker           // the HDeoptimize. If not, the singleton is not observed after deoptimization.
900*795d594fSAndroid Build Coastguard Worker           const HUseList<HEnvironment*>& env_uses = reference->GetEnvUses();
901*795d594fSAndroid Build Coastguard Worker           observable = std::any_of(
902*795d594fSAndroid Build Coastguard Worker               env_uses.begin(),
903*795d594fSAndroid Build Coastguard Worker               env_uses.end(),
904*795d594fSAndroid Build Coastguard Worker               [instruction](const HUseListNode<HEnvironment*>& use) {
905*795d594fSAndroid Build Coastguard Worker                 return use.GetUser()->GetHolder() == instruction;
906*795d594fSAndroid Build Coastguard Worker               });
907*795d594fSAndroid Build Coastguard Worker         }
908*795d594fSAndroid Build Coastguard Worker       }
909*795d594fSAndroid Build Coastguard Worker       if (observable) {
910*795d594fSAndroid Build Coastguard Worker         KeepStores(*stored_by);
911*795d594fSAndroid Build Coastguard Worker         *stored_by = Value::Unknown();
912*795d594fSAndroid Build Coastguard Worker       }
913*795d594fSAndroid Build Coastguard Worker     }
914*795d594fSAndroid Build Coastguard Worker   }
915*795d594fSAndroid Build Coastguard Worker 
916*795d594fSAndroid Build Coastguard Worker   // Keep necessary stores before exiting a method via return/throw.
HandleExit(HBasicBlock * block,bool must_keep_stores=false)917*795d594fSAndroid Build Coastguard Worker   void HandleExit(HBasicBlock* block, bool must_keep_stores = false) {
918*795d594fSAndroid Build Coastguard Worker     ScopedArenaVector<ValueRecord>& heap_values = heap_values_for_[block->GetBlockId()];
919*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0u, size = heap_values.size(); i != size; ++i) {
920*795d594fSAndroid Build Coastguard Worker       ReferenceInfo* ref_info = heap_location_collector_.GetHeapLocation(i)->GetReferenceInfo();
921*795d594fSAndroid Build Coastguard Worker       if (must_keep_stores || IsEscapingObject(ref_info)) {
922*795d594fSAndroid Build Coastguard Worker         KeepStores(heap_values[i].stored_by);
923*795d594fSAndroid Build Coastguard Worker         heap_values[i].stored_by = Value::Unknown();
924*795d594fSAndroid Build Coastguard Worker       }
925*795d594fSAndroid Build Coastguard Worker     }
926*795d594fSAndroid Build Coastguard Worker   }
927*795d594fSAndroid Build Coastguard Worker 
VisitReturn(HReturn * instruction)928*795d594fSAndroid Build Coastguard Worker   void VisitReturn(HReturn* instruction) override {
929*795d594fSAndroid Build Coastguard Worker     HandleExit(instruction->GetBlock());
930*795d594fSAndroid Build Coastguard Worker   }
931*795d594fSAndroid Build Coastguard Worker 
VisitReturnVoid(HReturnVoid * return_void)932*795d594fSAndroid Build Coastguard Worker   void VisitReturnVoid(HReturnVoid* return_void) override {
933*795d594fSAndroid Build Coastguard Worker     HandleExit(return_void->GetBlock());
934*795d594fSAndroid Build Coastguard Worker   }
935*795d594fSAndroid Build Coastguard Worker 
HandleThrowingInstruction(HInstruction * instruction)936*795d594fSAndroid Build Coastguard Worker   void HandleThrowingInstruction(HInstruction* instruction) {
937*795d594fSAndroid Build Coastguard Worker     DCHECK(instruction->CanThrow());
938*795d594fSAndroid Build Coastguard Worker     // If we are inside of a try, singletons can become visible since we may not exit the method.
939*795d594fSAndroid Build Coastguard Worker     HandleExit(instruction->GetBlock(), instruction->GetBlock()->IsTryBlock());
940*795d594fSAndroid Build Coastguard Worker   }
941*795d594fSAndroid Build Coastguard Worker 
VisitMethodEntryHook(HMethodEntryHook * method_entry)942*795d594fSAndroid Build Coastguard Worker   void VisitMethodEntryHook(HMethodEntryHook* method_entry) override {
943*795d594fSAndroid Build Coastguard Worker     HandleThrowingInstruction(method_entry);
944*795d594fSAndroid Build Coastguard Worker   }
945*795d594fSAndroid Build Coastguard Worker 
VisitMethodExitHook(HMethodExitHook * method_exit)946*795d594fSAndroid Build Coastguard Worker   void VisitMethodExitHook(HMethodExitHook* method_exit) override {
947*795d594fSAndroid Build Coastguard Worker     HandleThrowingInstruction(method_exit);
948*795d594fSAndroid Build Coastguard Worker   }
949*795d594fSAndroid Build Coastguard Worker 
VisitDivZeroCheck(HDivZeroCheck * div_zero_check)950*795d594fSAndroid Build Coastguard Worker   void VisitDivZeroCheck(HDivZeroCheck* div_zero_check) override {
951*795d594fSAndroid Build Coastguard Worker     HandleThrowingInstruction(div_zero_check);
952*795d594fSAndroid Build Coastguard Worker   }
953*795d594fSAndroid Build Coastguard Worker 
VisitNullCheck(HNullCheck * null_check)954*795d594fSAndroid Build Coastguard Worker   void VisitNullCheck(HNullCheck* null_check) override {
955*795d594fSAndroid Build Coastguard Worker     HandleThrowingInstruction(null_check);
956*795d594fSAndroid Build Coastguard Worker   }
957*795d594fSAndroid Build Coastguard Worker 
VisitBoundsCheck(HBoundsCheck * bounds_check)958*795d594fSAndroid Build Coastguard Worker   void VisitBoundsCheck(HBoundsCheck* bounds_check) override {
959*795d594fSAndroid Build Coastguard Worker     HandleThrowingInstruction(bounds_check);
960*795d594fSAndroid Build Coastguard Worker   }
961*795d594fSAndroid Build Coastguard Worker 
VisitLoadClass(HLoadClass * load_class)962*795d594fSAndroid Build Coastguard Worker   void VisitLoadClass(HLoadClass* load_class) override {
963*795d594fSAndroid Build Coastguard Worker     if (load_class->CanThrow()) {
964*795d594fSAndroid Build Coastguard Worker       HandleThrowingInstruction(load_class);
965*795d594fSAndroid Build Coastguard Worker     }
966*795d594fSAndroid Build Coastguard Worker   }
967*795d594fSAndroid Build Coastguard Worker 
VisitLoadString(HLoadString * load_string)968*795d594fSAndroid Build Coastguard Worker   void VisitLoadString(HLoadString* load_string) override {
969*795d594fSAndroid Build Coastguard Worker     if (load_string->CanThrow()) {
970*795d594fSAndroid Build Coastguard Worker       HandleThrowingInstruction(load_string);
971*795d594fSAndroid Build Coastguard Worker     }
972*795d594fSAndroid Build Coastguard Worker   }
973*795d594fSAndroid Build Coastguard Worker 
VisitLoadMethodHandle(HLoadMethodHandle * load_method_handle)974*795d594fSAndroid Build Coastguard Worker   void VisitLoadMethodHandle(HLoadMethodHandle* load_method_handle) override {
975*795d594fSAndroid Build Coastguard Worker     HandleThrowingInstruction(load_method_handle);
976*795d594fSAndroid Build Coastguard Worker   }
977*795d594fSAndroid Build Coastguard Worker 
VisitLoadMethodType(HLoadMethodType * load_method_type)978*795d594fSAndroid Build Coastguard Worker   void VisitLoadMethodType(HLoadMethodType* load_method_type) override {
979*795d594fSAndroid Build Coastguard Worker     HandleThrowingInstruction(load_method_type);
980*795d594fSAndroid Build Coastguard Worker   }
981*795d594fSAndroid Build Coastguard Worker 
VisitStringBuilderAppend(HStringBuilderAppend * sb_append)982*795d594fSAndroid Build Coastguard Worker   void VisitStringBuilderAppend(HStringBuilderAppend* sb_append) override {
983*795d594fSAndroid Build Coastguard Worker     HandleThrowingInstruction(sb_append);
984*795d594fSAndroid Build Coastguard Worker   }
985*795d594fSAndroid Build Coastguard Worker 
VisitThrow(HThrow * throw_instruction)986*795d594fSAndroid Build Coastguard Worker   void VisitThrow(HThrow* throw_instruction) override {
987*795d594fSAndroid Build Coastguard Worker     HandleThrowingInstruction(throw_instruction);
988*795d594fSAndroid Build Coastguard Worker   }
989*795d594fSAndroid Build Coastguard Worker 
VisitCheckCast(HCheckCast * check_cast)990*795d594fSAndroid Build Coastguard Worker   void VisitCheckCast(HCheckCast* check_cast) override {
991*795d594fSAndroid Build Coastguard Worker     HandleThrowingInstruction(check_cast);
992*795d594fSAndroid Build Coastguard Worker   }
993*795d594fSAndroid Build Coastguard Worker 
HandleInvoke(HInstruction * instruction)994*795d594fSAndroid Build Coastguard Worker   void HandleInvoke(HInstruction* instruction) {
995*795d594fSAndroid Build Coastguard Worker     // If `instruction` can throw we have to presume all stores are visible.
996*795d594fSAndroid Build Coastguard Worker     const bool can_throw = instruction->CanThrow();
997*795d594fSAndroid Build Coastguard Worker     // If we are in a try, even singletons are observable.
998*795d594fSAndroid Build Coastguard Worker     const bool can_throw_inside_a_try = can_throw && instruction->GetBlock()->IsTryBlock();
999*795d594fSAndroid Build Coastguard Worker     SideEffects side_effects = instruction->GetSideEffects();
1000*795d594fSAndroid Build Coastguard Worker     ScopedArenaVector<ValueRecord>& heap_values =
1001*795d594fSAndroid Build Coastguard Worker         heap_values_for_[instruction->GetBlock()->GetBlockId()];
1002*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0u, size = heap_values.size(); i != size; ++i) {
1003*795d594fSAndroid Build Coastguard Worker       ReferenceInfo* ref_info = heap_location_collector_.GetHeapLocation(i)->GetReferenceInfo();
1004*795d594fSAndroid Build Coastguard Worker       // We don't need to do anything if the reference has not escaped at this point.
1005*795d594fSAndroid Build Coastguard Worker       // This is true if we never escape.
1006*795d594fSAndroid Build Coastguard Worker       if (!can_throw_inside_a_try && ref_info->IsSingleton()) {
1007*795d594fSAndroid Build Coastguard Worker         // Singleton references cannot be seen by the callee.
1008*795d594fSAndroid Build Coastguard Worker       } else {
1009*795d594fSAndroid Build Coastguard Worker         if (can_throw || side_effects.DoesAnyRead() || side_effects.DoesAnyWrite()) {
1010*795d594fSAndroid Build Coastguard Worker           // Previous stores may become visible (read) and/or impossible for LSE to track (write).
1011*795d594fSAndroid Build Coastguard Worker           KeepStores(heap_values[i].stored_by);
1012*795d594fSAndroid Build Coastguard Worker           heap_values[i].stored_by = Value::Unknown();
1013*795d594fSAndroid Build Coastguard Worker         }
1014*795d594fSAndroid Build Coastguard Worker         if (side_effects.DoesAnyWrite()) {
1015*795d594fSAndroid Build Coastguard Worker           // The value may be clobbered.
1016*795d594fSAndroid Build Coastguard Worker           heap_values[i].value = Value::Unknown();
1017*795d594fSAndroid Build Coastguard Worker         }
1018*795d594fSAndroid Build Coastguard Worker       }
1019*795d594fSAndroid Build Coastguard Worker     }
1020*795d594fSAndroid Build Coastguard Worker   }
1021*795d594fSAndroid Build Coastguard Worker 
VisitInvoke(HInvoke * invoke)1022*795d594fSAndroid Build Coastguard Worker   void VisitInvoke(HInvoke* invoke) override {
1023*795d594fSAndroid Build Coastguard Worker     HandleInvoke(invoke);
1024*795d594fSAndroid Build Coastguard Worker   }
1025*795d594fSAndroid Build Coastguard Worker 
VisitClinitCheck(HClinitCheck * clinit)1026*795d594fSAndroid Build Coastguard Worker   void VisitClinitCheck(HClinitCheck* clinit) override {
1027*795d594fSAndroid Build Coastguard Worker     // Class initialization check can result in class initializer calling arbitrary methods.
1028*795d594fSAndroid Build Coastguard Worker     HandleInvoke(clinit);
1029*795d594fSAndroid Build Coastguard Worker   }
1030*795d594fSAndroid Build Coastguard Worker 
VisitUnresolvedInstanceFieldGet(HUnresolvedInstanceFieldGet * instruction)1031*795d594fSAndroid Build Coastguard Worker   void VisitUnresolvedInstanceFieldGet(HUnresolvedInstanceFieldGet* instruction) override {
1032*795d594fSAndroid Build Coastguard Worker     // Conservatively treat it as an invocation.
1033*795d594fSAndroid Build Coastguard Worker     HandleInvoke(instruction);
1034*795d594fSAndroid Build Coastguard Worker   }
1035*795d594fSAndroid Build Coastguard Worker 
VisitUnresolvedInstanceFieldSet(HUnresolvedInstanceFieldSet * instruction)1036*795d594fSAndroid Build Coastguard Worker   void VisitUnresolvedInstanceFieldSet(HUnresolvedInstanceFieldSet* instruction) override {
1037*795d594fSAndroid Build Coastguard Worker     // Conservatively treat it as an invocation.
1038*795d594fSAndroid Build Coastguard Worker     HandleInvoke(instruction);
1039*795d594fSAndroid Build Coastguard Worker   }
1040*795d594fSAndroid Build Coastguard Worker 
VisitUnresolvedStaticFieldGet(HUnresolvedStaticFieldGet * instruction)1041*795d594fSAndroid Build Coastguard Worker   void VisitUnresolvedStaticFieldGet(HUnresolvedStaticFieldGet* instruction) override {
1042*795d594fSAndroid Build Coastguard Worker     // Conservatively treat it as an invocation.
1043*795d594fSAndroid Build Coastguard Worker     HandleInvoke(instruction);
1044*795d594fSAndroid Build Coastguard Worker   }
1045*795d594fSAndroid Build Coastguard Worker 
VisitUnresolvedStaticFieldSet(HUnresolvedStaticFieldSet * instruction)1046*795d594fSAndroid Build Coastguard Worker   void VisitUnresolvedStaticFieldSet(HUnresolvedStaticFieldSet* instruction) override {
1047*795d594fSAndroid Build Coastguard Worker     // Conservatively treat it as an invocation.
1048*795d594fSAndroid Build Coastguard Worker     HandleInvoke(instruction);
1049*795d594fSAndroid Build Coastguard Worker   }
1050*795d594fSAndroid Build Coastguard Worker 
VisitNewInstance(HNewInstance * new_instance)1051*795d594fSAndroid Build Coastguard Worker   void VisitNewInstance(HNewInstance* new_instance) override {
1052*795d594fSAndroid Build Coastguard Worker     // If we are in a try, even singletons are observable.
1053*795d594fSAndroid Build Coastguard Worker     const bool inside_a_try = new_instance->GetBlock()->IsTryBlock();
1054*795d594fSAndroid Build Coastguard Worker     ReferenceInfo* ref_info = heap_location_collector_.FindReferenceInfoOf(new_instance);
1055*795d594fSAndroid Build Coastguard Worker     if (ref_info == nullptr) {
1056*795d594fSAndroid Build Coastguard Worker       // new_instance isn't used for field accesses. No need to process it.
1057*795d594fSAndroid Build Coastguard Worker       return;
1058*795d594fSAndroid Build Coastguard Worker     }
1059*795d594fSAndroid Build Coastguard Worker     if (ref_info->IsSingletonAndRemovable() && !new_instance->NeedsChecks()) {
1060*795d594fSAndroid Build Coastguard Worker       DCHECK(!new_instance->IsFinalizable());
1061*795d594fSAndroid Build Coastguard Worker       // new_instance can potentially be eliminated.
1062*795d594fSAndroid Build Coastguard Worker       singleton_new_instances_.push_back(new_instance);
1063*795d594fSAndroid Build Coastguard Worker     }
1064*795d594fSAndroid Build Coastguard Worker     HBasicBlock* block = new_instance->GetBlock();
1065*795d594fSAndroid Build Coastguard Worker     ScopedArenaVector<ValueRecord>& heap_values = heap_values_for_[block->GetBlockId()];
1066*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0u, size = heap_values.size(); i != size; ++i) {
1067*795d594fSAndroid Build Coastguard Worker       ReferenceInfo* info = heap_location_collector_.GetHeapLocation(i)->GetReferenceInfo();
1068*795d594fSAndroid Build Coastguard Worker       HInstruction* ref = info->GetReference();
1069*795d594fSAndroid Build Coastguard Worker       size_t offset = heap_location_collector_.GetHeapLocation(i)->GetOffset();
1070*795d594fSAndroid Build Coastguard Worker       if (ref == new_instance) {
1071*795d594fSAndroid Build Coastguard Worker         if (offset >= mirror::kObjectHeaderSize ||
1072*795d594fSAndroid Build Coastguard Worker             MemberOffset(offset) == mirror::Object::MonitorOffset()) {
1073*795d594fSAndroid Build Coastguard Worker           // Instance fields except the header fields are set to default heap values.
1074*795d594fSAndroid Build Coastguard Worker           // The shadow$_monitor_ field is set to the default value however.
1075*795d594fSAndroid Build Coastguard Worker           heap_values[i].value = Value::Default();
1076*795d594fSAndroid Build Coastguard Worker           heap_values[i].stored_by = Value::Unknown();
1077*795d594fSAndroid Build Coastguard Worker         } else if (MemberOffset(offset) == mirror::Object::ClassOffset()) {
1078*795d594fSAndroid Build Coastguard Worker           // The shadow$_klass_ field is special and has an actual value however.
1079*795d594fSAndroid Build Coastguard Worker           heap_values[i].value = Value::ForInstruction(new_instance->GetLoadClass());
1080*795d594fSAndroid Build Coastguard Worker           heap_values[i].stored_by = Value::Unknown();
1081*795d594fSAndroid Build Coastguard Worker         }
1082*795d594fSAndroid Build Coastguard Worker       } else if (inside_a_try || IsEscapingObject(info)) {
1083*795d594fSAndroid Build Coastguard Worker         // Since NewInstance can throw, we presume all previous stores could be visible.
1084*795d594fSAndroid Build Coastguard Worker         KeepStores(heap_values[i].stored_by);
1085*795d594fSAndroid Build Coastguard Worker         heap_values[i].stored_by = Value::Unknown();
1086*795d594fSAndroid Build Coastguard Worker       }
1087*795d594fSAndroid Build Coastguard Worker     }
1088*795d594fSAndroid Build Coastguard Worker   }
1089*795d594fSAndroid Build Coastguard Worker 
VisitNewArray(HNewArray * new_array)1090*795d594fSAndroid Build Coastguard Worker   void VisitNewArray(HNewArray* new_array) override {
1091*795d594fSAndroid Build Coastguard Worker     // If we are in a try, even singletons are observable.
1092*795d594fSAndroid Build Coastguard Worker     const bool inside_a_try = new_array->GetBlock()->IsTryBlock();
1093*795d594fSAndroid Build Coastguard Worker     ReferenceInfo* ref_info = heap_location_collector_.FindReferenceInfoOf(new_array);
1094*795d594fSAndroid Build Coastguard Worker     if (ref_info == nullptr) {
1095*795d594fSAndroid Build Coastguard Worker       // new_array isn't used for array accesses. No need to process it.
1096*795d594fSAndroid Build Coastguard Worker       return;
1097*795d594fSAndroid Build Coastguard Worker     }
1098*795d594fSAndroid Build Coastguard Worker     if (ref_info->IsSingletonAndRemovable()) {
1099*795d594fSAndroid Build Coastguard Worker       if (new_array->GetLength()->IsIntConstant() &&
1100*795d594fSAndroid Build Coastguard Worker           new_array->GetLength()->AsIntConstant()->GetValue() >= 0) {
1101*795d594fSAndroid Build Coastguard Worker         // new_array can potentially be eliminated.
1102*795d594fSAndroid Build Coastguard Worker         singleton_new_instances_.push_back(new_array);
1103*795d594fSAndroid Build Coastguard Worker       } else {
1104*795d594fSAndroid Build Coastguard Worker         // new_array may throw NegativeArraySizeException. Keep it.
1105*795d594fSAndroid Build Coastguard Worker       }
1106*795d594fSAndroid Build Coastguard Worker     }
1107*795d594fSAndroid Build Coastguard Worker     HBasicBlock* block = new_array->GetBlock();
1108*795d594fSAndroid Build Coastguard Worker     ScopedArenaVector<ValueRecord>& heap_values = heap_values_for_[block->GetBlockId()];
1109*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0u, size = heap_values.size(); i != size; ++i) {
1110*795d594fSAndroid Build Coastguard Worker       HeapLocation* location = heap_location_collector_.GetHeapLocation(i);
1111*795d594fSAndroid Build Coastguard Worker       ReferenceInfo* info = location->GetReferenceInfo();
1112*795d594fSAndroid Build Coastguard Worker       HInstruction* ref = info->GetReference();
1113*795d594fSAndroid Build Coastguard Worker       if (ref == new_array && location->GetIndex() != nullptr) {
1114*795d594fSAndroid Build Coastguard Worker         // Array elements are set to default heap values.
1115*795d594fSAndroid Build Coastguard Worker         heap_values[i].value = Value::Default();
1116*795d594fSAndroid Build Coastguard Worker         heap_values[i].stored_by = Value::Unknown();
1117*795d594fSAndroid Build Coastguard Worker       } else if (inside_a_try || IsEscapingObject(info)) {
1118*795d594fSAndroid Build Coastguard Worker         // Since NewArray can throw, we presume all previous stores could be visible.
1119*795d594fSAndroid Build Coastguard Worker         KeepStores(heap_values[i].stored_by);
1120*795d594fSAndroid Build Coastguard Worker         heap_values[i].stored_by = Value::Unknown();
1121*795d594fSAndroid Build Coastguard Worker       }
1122*795d594fSAndroid Build Coastguard Worker     }
1123*795d594fSAndroid Build Coastguard Worker   }
1124*795d594fSAndroid Build Coastguard Worker 
VisitInstruction(HInstruction * instruction)1125*795d594fSAndroid Build Coastguard Worker   void VisitInstruction(HInstruction* instruction) override {
1126*795d594fSAndroid Build Coastguard Worker     // Throwing instructions must be handled specially.
1127*795d594fSAndroid Build Coastguard Worker     DCHECK(!instruction->CanThrow());
1128*795d594fSAndroid Build Coastguard Worker   }
1129*795d594fSAndroid Build Coastguard Worker 
1130*795d594fSAndroid Build Coastguard Worker   const HeapLocationCollector& heap_location_collector_;
1131*795d594fSAndroid Build Coastguard Worker 
1132*795d594fSAndroid Build Coastguard Worker   // Use local allocator for allocating memory.
1133*795d594fSAndroid Build Coastguard Worker   ScopedArenaAllocator allocator_;
1134*795d594fSAndroid Build Coastguard Worker 
1135*795d594fSAndroid Build Coastguard Worker   // The number of unique phi_placeholders there possibly are
1136*795d594fSAndroid Build Coastguard Worker   size_t num_phi_placeholders_;
1137*795d594fSAndroid Build Coastguard Worker 
1138*795d594fSAndroid Build Coastguard Worker   // One array of heap value records for each block.
1139*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<ScopedArenaVector<ValueRecord>> heap_values_for_;
1140*795d594fSAndroid Build Coastguard Worker 
1141*795d594fSAndroid Build Coastguard Worker   // We record loads and stores for re-processing when we find a loop Phi placeholder
1142*795d594fSAndroid Build Coastguard Worker   // with unknown value from a predecessor, and also for removing stores that are
1143*795d594fSAndroid Build Coastguard Worker   // found to be dead, i.e. not marked in `kept_stores_` at the end.
1144*795d594fSAndroid Build Coastguard Worker   struct LoadStoreRecord {
1145*795d594fSAndroid Build Coastguard Worker     HInstruction* load_or_store;
1146*795d594fSAndroid Build Coastguard Worker     size_t heap_location_index;
1147*795d594fSAndroid Build Coastguard Worker   };
1148*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<LoadStoreRecord> loads_and_stores_;
1149*795d594fSAndroid Build Coastguard Worker 
1150*795d594fSAndroid Build Coastguard Worker   // We record the substitute instructions for loads that should be
1151*795d594fSAndroid Build Coastguard Worker   // eliminated but may be used by heap locations. They'll be removed
1152*795d594fSAndroid Build Coastguard Worker   // in the end. These are indexed by the load's id.
1153*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<HInstruction*> substitute_instructions_for_loads_;
1154*795d594fSAndroid Build Coastguard Worker 
1155*795d594fSAndroid Build Coastguard Worker   // Record stores to keep in a bit vector indexed by instruction ID.
1156*795d594fSAndroid Build Coastguard Worker   ArenaBitVector kept_stores_;
1157*795d594fSAndroid Build Coastguard Worker   // When we need to keep all stores that feed a Phi placeholder, we just record the
1158*795d594fSAndroid Build Coastguard Worker   // index of that placeholder for processing after graph traversal.
1159*795d594fSAndroid Build Coastguard Worker   ArenaBitVector phi_placeholders_to_search_for_kept_stores_;
1160*795d594fSAndroid Build Coastguard Worker 
1161*795d594fSAndroid Build Coastguard Worker   // Loads that would require a loop Phi to replace are recorded for processing
1162*795d594fSAndroid Build Coastguard Worker   // later as we do not have enough information from back-edges to determine if
1163*795d594fSAndroid Build Coastguard Worker   // a suitable Phi can be found or created when we visit these loads.
1164*795d594fSAndroid Build Coastguard Worker   // This is a flat "map" indexed by the load instruction id.
1165*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<ValueRecord*> loads_requiring_loop_phi_;
1166*795d594fSAndroid Build Coastguard Worker 
1167*795d594fSAndroid Build Coastguard Worker   // For stores, record the old value records that were replaced and the stored values.
1168*795d594fSAndroid Build Coastguard Worker   struct StoreRecord {
StoreRecordart::LSEVisitor::StoreRecord1169*795d594fSAndroid Build Coastguard Worker     StoreRecord(ValueRecord old_value_record_in, HInstruction* stored_value_in)
1170*795d594fSAndroid Build Coastguard Worker         : old_value_record(old_value_record_in), stored_value(stored_value_in) {}
1171*795d594fSAndroid Build Coastguard Worker     ValueRecord old_value_record;
1172*795d594fSAndroid Build Coastguard Worker     HInstruction* stored_value;
1173*795d594fSAndroid Build Coastguard Worker   };
1174*795d594fSAndroid Build Coastguard Worker   // This is a flat "map" indexed by the store instruction id.
1175*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<StoreRecord*> store_records_;
1176*795d594fSAndroid Build Coastguard Worker 
1177*795d594fSAndroid Build Coastguard Worker   // Replacements for Phi placeholders.
1178*795d594fSAndroid Build Coastguard Worker   // The invalid heap value is used to mark Phi placeholders that cannot be replaced.
1179*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<Value> phi_placeholder_replacements_;
1180*795d594fSAndroid Build Coastguard Worker 
1181*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<HInstruction*> singleton_new_instances_;
1182*795d594fSAndroid Build Coastguard Worker 
1183*795d594fSAndroid Build Coastguard Worker   // The field infos for each heap location (if relevant).
1184*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<const FieldInfo*> field_infos_;
1185*795d594fSAndroid Build Coastguard Worker 
1186*795d594fSAndroid Build Coastguard Worker   Phase current_phase_;
1187*795d594fSAndroid Build Coastguard Worker 
1188*795d594fSAndroid Build Coastguard Worker   friend std::ostream& operator<<(std::ostream& os, const Value& v);
1189*795d594fSAndroid Build Coastguard Worker   friend std::ostream& operator<<(std::ostream& oss, const LSEVisitor::Phase& phase);
1190*795d594fSAndroid Build Coastguard Worker 
1191*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(LSEVisitor);
1192*795d594fSAndroid Build Coastguard Worker };
1193*795d594fSAndroid Build Coastguard Worker 
operator <<(std::ostream & oss,const LSEVisitor::Phase & phase)1194*795d594fSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& oss, const LSEVisitor::Phase& phase) {
1195*795d594fSAndroid Build Coastguard Worker   switch (phase) {
1196*795d594fSAndroid Build Coastguard Worker     case LSEVisitor::Phase::kLoadElimination:
1197*795d594fSAndroid Build Coastguard Worker       return oss << "kLoadElimination";
1198*795d594fSAndroid Build Coastguard Worker     case LSEVisitor::Phase::kStoreElimination:
1199*795d594fSAndroid Build Coastguard Worker       return oss << "kStoreElimination";
1200*795d594fSAndroid Build Coastguard Worker   }
1201*795d594fSAndroid Build Coastguard Worker }
1202*795d594fSAndroid Build Coastguard Worker 
operator ==(const LSEVisitor::PhiPlaceholder & p1,const LSEVisitor::PhiPlaceholder & p2)1203*795d594fSAndroid Build Coastguard Worker constexpr bool operator==(const LSEVisitor::PhiPlaceholder& p1,
1204*795d594fSAndroid Build Coastguard Worker                           const LSEVisitor::PhiPlaceholder& p2) {
1205*795d594fSAndroid Build Coastguard Worker   return p1.Equals(p2);
1206*795d594fSAndroid Build Coastguard Worker }
1207*795d594fSAndroid Build Coastguard Worker 
operator ==(const LSEVisitor::Value::NeedsLoopPhiMarker & p1,const LSEVisitor::Value::NeedsLoopPhiMarker & p2)1208*795d594fSAndroid Build Coastguard Worker constexpr bool operator==(const LSEVisitor::Value::NeedsLoopPhiMarker& p1,
1209*795d594fSAndroid Build Coastguard Worker                           const LSEVisitor::Value::NeedsLoopPhiMarker& p2) {
1210*795d594fSAndroid Build Coastguard Worker   return p1.phi_ == p2.phi_;
1211*795d594fSAndroid Build Coastguard Worker }
1212*795d594fSAndroid Build Coastguard Worker 
operator ==(const LSEVisitor::Value::NeedsNonLoopPhiMarker & p1,const LSEVisitor::Value::NeedsNonLoopPhiMarker & p2)1213*795d594fSAndroid Build Coastguard Worker constexpr bool operator==(const LSEVisitor::Value::NeedsNonLoopPhiMarker& p1,
1214*795d594fSAndroid Build Coastguard Worker                           const LSEVisitor::Value::NeedsNonLoopPhiMarker& p2) {
1215*795d594fSAndroid Build Coastguard Worker   return p1.phi_ == p2.phi_;
1216*795d594fSAndroid Build Coastguard Worker }
1217*795d594fSAndroid Build Coastguard Worker 
operator <<(std::ostream & oss,const LSEVisitor::PhiPlaceholder & p)1218*795d594fSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& oss, const LSEVisitor::PhiPlaceholder& p) {
1219*795d594fSAndroid Build Coastguard Worker   p.Dump(oss);
1220*795d594fSAndroid Build Coastguard Worker   return oss;
1221*795d594fSAndroid Build Coastguard Worker }
1222*795d594fSAndroid Build Coastguard Worker 
ExactEquals(LSEVisitor::Value other) const1223*795d594fSAndroid Build Coastguard Worker constexpr bool LSEVisitor::Value::ExactEquals(LSEVisitor::Value other) const {
1224*795d594fSAndroid Build Coastguard Worker   return value_ == other.value_;
1225*795d594fSAndroid Build Coastguard Worker }
1226*795d594fSAndroid Build Coastguard Worker 
Equals(LSEVisitor::Value other) const1227*795d594fSAndroid Build Coastguard Worker constexpr bool LSEVisitor::Value::Equals(LSEVisitor::Value other) const {
1228*795d594fSAndroid Build Coastguard Worker   // Only valid values can be compared.
1229*795d594fSAndroid Build Coastguard Worker   DCHECK(IsValid());
1230*795d594fSAndroid Build Coastguard Worker   DCHECK(other.IsValid());
1231*795d594fSAndroid Build Coastguard Worker   if (value_ == other.value_) {
1232*795d594fSAndroid Build Coastguard Worker     // Note: Two unknown values are considered different.
1233*795d594fSAndroid Build Coastguard Worker     return !IsUnknown();
1234*795d594fSAndroid Build Coastguard Worker   } else {
1235*795d594fSAndroid Build Coastguard Worker     // Default is considered equal to zero-bit-pattern instructions.
1236*795d594fSAndroid Build Coastguard Worker     return (IsDefault() && other.IsInstruction() && IsZeroBitPattern(other.GetInstruction())) ||
1237*795d594fSAndroid Build Coastguard Worker             (other.IsDefault() && IsInstruction() && IsZeroBitPattern(GetInstruction()));
1238*795d594fSAndroid Build Coastguard Worker   }
1239*795d594fSAndroid Build Coastguard Worker }
1240*795d594fSAndroid Build Coastguard Worker 
Dump(std::ostream & os) const1241*795d594fSAndroid Build Coastguard Worker std::ostream& LSEVisitor::Value::Dump(std::ostream& os) const {
1242*795d594fSAndroid Build Coastguard Worker   if (std::holds_alternative<LSEVisitor::Value::ValuelessType>(value_)) {
1243*795d594fSAndroid Build Coastguard Worker     switch (GetValuelessType()) {
1244*795d594fSAndroid Build Coastguard Worker       case ValuelessType::kDefault:
1245*795d594fSAndroid Build Coastguard Worker         return os << "Default";
1246*795d594fSAndroid Build Coastguard Worker       case ValuelessType::kUnknown:
1247*795d594fSAndroid Build Coastguard Worker         return os << "Unknown";
1248*795d594fSAndroid Build Coastguard Worker       case ValuelessType::kInvalid:
1249*795d594fSAndroid Build Coastguard Worker         return os << "Invalid";
1250*795d594fSAndroid Build Coastguard Worker     }
1251*795d594fSAndroid Build Coastguard Worker   } else if (IsInstruction()) {
1252*795d594fSAndroid Build Coastguard Worker     return os << "Instruction[id: " << GetInstruction()->GetId()
1253*795d594fSAndroid Build Coastguard Worker               << ", block: " << GetInstruction()->GetBlock()->GetBlockId() << "]";
1254*795d594fSAndroid Build Coastguard Worker   } else if (NeedsLoopPhi()) {
1255*795d594fSAndroid Build Coastguard Worker     return os << "NeedsLoopPhi[block: " << GetPhiPlaceholder().GetBlockId()
1256*795d594fSAndroid Build Coastguard Worker               << ", heap_loc: " << GetPhiPlaceholder().GetHeapLocation() << "]";
1257*795d594fSAndroid Build Coastguard Worker   } else {
1258*795d594fSAndroid Build Coastguard Worker     return os << "NeedsNonLoopPhi[block: " << GetPhiPlaceholder().GetBlockId()
1259*795d594fSAndroid Build Coastguard Worker               << ", heap_loc: " << GetPhiPlaceholder().GetHeapLocation() << "]";
1260*795d594fSAndroid Build Coastguard Worker   }
1261*795d594fSAndroid Build Coastguard Worker }
1262*795d594fSAndroid Build Coastguard Worker 
operator <<(std::ostream & os,const LSEVisitor::Value & v)1263*795d594fSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, const LSEVisitor::Value& v) {
1264*795d594fSAndroid Build Coastguard Worker   return v.Dump(os);
1265*795d594fSAndroid Build Coastguard Worker }
1266*795d594fSAndroid Build Coastguard Worker 
LSEVisitor(HGraph * graph,const HeapLocationCollector & heap_location_collector,OptimizingCompilerStats * stats)1267*795d594fSAndroid Build Coastguard Worker LSEVisitor::LSEVisitor(HGraph* graph,
1268*795d594fSAndroid Build Coastguard Worker                        const HeapLocationCollector& heap_location_collector,
1269*795d594fSAndroid Build Coastguard Worker                        OptimizingCompilerStats* stats)
1270*795d594fSAndroid Build Coastguard Worker     : HGraphDelegateVisitor(graph, stats),
1271*795d594fSAndroid Build Coastguard Worker       heap_location_collector_(heap_location_collector),
1272*795d594fSAndroid Build Coastguard Worker       allocator_(graph->GetArenaStack()),
1273*795d594fSAndroid Build Coastguard Worker       num_phi_placeholders_(GetGraph()->GetBlocks().size() *
1274*795d594fSAndroid Build Coastguard Worker                             heap_location_collector_.GetNumberOfHeapLocations()),
1275*795d594fSAndroid Build Coastguard Worker       heap_values_for_(graph->GetBlocks().size(),
1276*795d594fSAndroid Build Coastguard Worker                        ScopedArenaVector<ValueRecord>(allocator_.Adapter(kArenaAllocLSE)),
1277*795d594fSAndroid Build Coastguard Worker                        allocator_.Adapter(kArenaAllocLSE)),
1278*795d594fSAndroid Build Coastguard Worker       loads_and_stores_(allocator_.Adapter(kArenaAllocLSE)),
1279*795d594fSAndroid Build Coastguard Worker       // We may add new instructions (default values, Phis) but we're not adding loads
1280*795d594fSAndroid Build Coastguard Worker       // or stores, so we shall not need to resize following vector and BitVector.
1281*795d594fSAndroid Build Coastguard Worker       substitute_instructions_for_loads_(
1282*795d594fSAndroid Build Coastguard Worker           graph->GetCurrentInstructionId(), nullptr, allocator_.Adapter(kArenaAllocLSE)),
1283*795d594fSAndroid Build Coastguard Worker       kept_stores_(&allocator_,
1284*795d594fSAndroid Build Coastguard Worker                    /*start_bits=*/graph->GetCurrentInstructionId(),
1285*795d594fSAndroid Build Coastguard Worker                    /*expandable=*/false,
1286*795d594fSAndroid Build Coastguard Worker                    kArenaAllocLSE),
1287*795d594fSAndroid Build Coastguard Worker       phi_placeholders_to_search_for_kept_stores_(&allocator_,
1288*795d594fSAndroid Build Coastguard Worker                                                   num_phi_placeholders_,
1289*795d594fSAndroid Build Coastguard Worker                                                   /*expandable=*/false,
1290*795d594fSAndroid Build Coastguard Worker                                                   kArenaAllocLSE),
1291*795d594fSAndroid Build Coastguard Worker       loads_requiring_loop_phi_(allocator_.Adapter(kArenaAllocLSE)),
1292*795d594fSAndroid Build Coastguard Worker       store_records_(allocator_.Adapter(kArenaAllocLSE)),
1293*795d594fSAndroid Build Coastguard Worker       phi_placeholder_replacements_(
1294*795d594fSAndroid Build Coastguard Worker           num_phi_placeholders_, Value::Invalid(), allocator_.Adapter(kArenaAllocLSE)),
1295*795d594fSAndroid Build Coastguard Worker       singleton_new_instances_(allocator_.Adapter(kArenaAllocLSE)),
1296*795d594fSAndroid Build Coastguard Worker       field_infos_(heap_location_collector_.GetNumberOfHeapLocations(),
1297*795d594fSAndroid Build Coastguard Worker                    allocator_.Adapter(kArenaAllocLSE)),
1298*795d594fSAndroid Build Coastguard Worker       current_phase_(Phase::kLoadElimination) {}
1299*795d594fSAndroid Build Coastguard Worker 
PrepareLoopValue(HBasicBlock * block,size_t idx)1300*795d594fSAndroid Build Coastguard Worker LSEVisitor::Value LSEVisitor::PrepareLoopValue(HBasicBlock* block, size_t idx) {
1301*795d594fSAndroid Build Coastguard Worker   // If the pre-header value is known (which implies that the reference dominates this
1302*795d594fSAndroid Build Coastguard Worker   // block), use a Phi placeholder for the value in the loop header. If all predecessors
1303*795d594fSAndroid Build Coastguard Worker   // are later found to have a known value, we can replace loads from this location,
1304*795d594fSAndroid Build Coastguard Worker   // either with the pre-header value or with a new Phi. For array locations, the index
1305*795d594fSAndroid Build Coastguard Worker   // may be defined inside the loop but the only known value in that case should be the
1306*795d594fSAndroid Build Coastguard Worker   // default value or a Phi placeholder that can be replaced only with the default value.
1307*795d594fSAndroid Build Coastguard Worker   HLoopInformation* loop_info = block->GetLoopInformation();
1308*795d594fSAndroid Build Coastguard Worker   uint32_t pre_header_block_id = loop_info->GetPreHeader()->GetBlockId();
1309*795d594fSAndroid Build Coastguard Worker   Value pre_header_value = ReplacementOrValue(heap_values_for_[pre_header_block_id][idx].value);
1310*795d594fSAndroid Build Coastguard Worker   if (pre_header_value.IsUnknown()) {
1311*795d594fSAndroid Build Coastguard Worker     return pre_header_value;
1312*795d594fSAndroid Build Coastguard Worker   }
1313*795d594fSAndroid Build Coastguard Worker   if (kIsDebugBuild) {
1314*795d594fSAndroid Build Coastguard Worker     // Check that the reference indeed dominates this loop.
1315*795d594fSAndroid Build Coastguard Worker     HeapLocation* location = heap_location_collector_.GetHeapLocation(idx);
1316*795d594fSAndroid Build Coastguard Worker     HInstruction* ref = location->GetReferenceInfo()->GetReference();
1317*795d594fSAndroid Build Coastguard Worker     CHECK(ref->GetBlock() != block && ref->GetBlock()->Dominates(block))
1318*795d594fSAndroid Build Coastguard Worker         << GetGraph()->PrettyMethod();
1319*795d594fSAndroid Build Coastguard Worker     // Check that the index, if defined inside the loop, tracks a default value
1320*795d594fSAndroid Build Coastguard Worker     // or a Phi placeholder requiring a loop Phi.
1321*795d594fSAndroid Build Coastguard Worker     HInstruction* index = location->GetIndex();
1322*795d594fSAndroid Build Coastguard Worker     if (index != nullptr && loop_info->Contains(*index->GetBlock())) {
1323*795d594fSAndroid Build Coastguard Worker       CHECK(pre_header_value.NeedsLoopPhi() || pre_header_value.Equals(Value::Default()))
1324*795d594fSAndroid Build Coastguard Worker           << GetGraph()->PrettyMethod() << " blk: " << block->GetBlockId() << " "
1325*795d594fSAndroid Build Coastguard Worker           << pre_header_value;
1326*795d594fSAndroid Build Coastguard Worker     }
1327*795d594fSAndroid Build Coastguard Worker   }
1328*795d594fSAndroid Build Coastguard Worker   PhiPlaceholder phi_placeholder = GetPhiPlaceholder(block->GetBlockId(), idx);
1329*795d594fSAndroid Build Coastguard Worker   return ReplacementOrValue(Value::ForLoopPhiPlaceholder(phi_placeholder));
1330*795d594fSAndroid Build Coastguard Worker }
1331*795d594fSAndroid Build Coastguard Worker 
PrepareLoopStoredBy(HBasicBlock * block,size_t idx)1332*795d594fSAndroid Build Coastguard Worker LSEVisitor::Value LSEVisitor::PrepareLoopStoredBy(HBasicBlock* block, size_t idx) {
1333*795d594fSAndroid Build Coastguard Worker   // Use the Phi placeholder for `stored_by` to make sure all incoming stores are kept
1334*795d594fSAndroid Build Coastguard Worker   // if the value in the location escapes. This is not applicable to singletons that are
1335*795d594fSAndroid Build Coastguard Worker   // defined inside the loop as they shall be dead in the loop header.
1336*795d594fSAndroid Build Coastguard Worker   const ReferenceInfo* ref_info = heap_location_collector_.GetHeapLocation(idx)->GetReferenceInfo();
1337*795d594fSAndroid Build Coastguard Worker   const HInstruction* reference = ref_info->GetReference();
1338*795d594fSAndroid Build Coastguard Worker   // Finalizable objects always escape.
1339*795d594fSAndroid Build Coastguard Worker   const bool is_finalizable =
1340*795d594fSAndroid Build Coastguard Worker       reference->IsNewInstance() && reference->AsNewInstance()->IsFinalizable();
1341*795d594fSAndroid Build Coastguard Worker   if (ref_info->IsSingleton() &&
1342*795d594fSAndroid Build Coastguard Worker       block->GetLoopInformation()->Contains(*reference->GetBlock()) &&
1343*795d594fSAndroid Build Coastguard Worker       !is_finalizable) {
1344*795d594fSAndroid Build Coastguard Worker     return Value::Unknown();
1345*795d594fSAndroid Build Coastguard Worker   }
1346*795d594fSAndroid Build Coastguard Worker   PhiPlaceholder phi_placeholder = GetPhiPlaceholder(block->GetBlockId(), idx);
1347*795d594fSAndroid Build Coastguard Worker   return Value::ForLoopPhiPlaceholder(phi_placeholder);
1348*795d594fSAndroid Build Coastguard Worker }
1349*795d594fSAndroid Build Coastguard Worker 
PrepareLoopRecords(HBasicBlock * block)1350*795d594fSAndroid Build Coastguard Worker void LSEVisitor::PrepareLoopRecords(HBasicBlock* block) {
1351*795d594fSAndroid Build Coastguard Worker   DCHECK(block->IsLoopHeader());
1352*795d594fSAndroid Build Coastguard Worker   int block_id = block->GetBlockId();
1353*795d594fSAndroid Build Coastguard Worker   HBasicBlock* pre_header = block->GetLoopInformation()->GetPreHeader();
1354*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<ValueRecord>& pre_header_heap_values =
1355*795d594fSAndroid Build Coastguard Worker       heap_values_for_[pre_header->GetBlockId()];
1356*795d594fSAndroid Build Coastguard Worker   size_t num_heap_locations = heap_location_collector_.GetNumberOfHeapLocations();
1357*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(num_heap_locations, pre_header_heap_values.size());
1358*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<ValueRecord>& heap_values = heap_values_for_[block_id];
1359*795d594fSAndroid Build Coastguard Worker   DCHECK(heap_values.empty());
1360*795d594fSAndroid Build Coastguard Worker 
1361*795d594fSAndroid Build Coastguard Worker   // Don't eliminate loads in irreducible loops.
1362*795d594fSAndroid Build Coastguard Worker   if (block->GetLoopInformation()->IsIrreducible()) {
1363*795d594fSAndroid Build Coastguard Worker     heap_values.resize(num_heap_locations,
1364*795d594fSAndroid Build Coastguard Worker                        {/*value=*/Value::Unknown(), /*stored_by=*/Value::Unknown()});
1365*795d594fSAndroid Build Coastguard Worker     // Also keep the stores before the loop header, including in blocks that were not visited yet.
1366*795d594fSAndroid Build Coastguard Worker     for (size_t idx = 0u; idx != num_heap_locations; ++idx) {
1367*795d594fSAndroid Build Coastguard Worker       KeepStores(Value::ForLoopPhiPlaceholder(GetPhiPlaceholder(block->GetBlockId(), idx)));
1368*795d594fSAndroid Build Coastguard Worker     }
1369*795d594fSAndroid Build Coastguard Worker     return;
1370*795d594fSAndroid Build Coastguard Worker   }
1371*795d594fSAndroid Build Coastguard Worker 
1372*795d594fSAndroid Build Coastguard Worker   // Fill `heap_values` based on values from pre-header.
1373*795d594fSAndroid Build Coastguard Worker   heap_values.reserve(num_heap_locations);
1374*795d594fSAndroid Build Coastguard Worker   for (size_t idx = 0u; idx != num_heap_locations; ++idx) {
1375*795d594fSAndroid Build Coastguard Worker     heap_values.push_back({ PrepareLoopValue(block, idx), PrepareLoopStoredBy(block, idx) });
1376*795d594fSAndroid Build Coastguard Worker   }
1377*795d594fSAndroid Build Coastguard Worker }
1378*795d594fSAndroid Build Coastguard Worker 
MergePredecessorValues(HBasicBlock * block,size_t idx)1379*795d594fSAndroid Build Coastguard Worker LSEVisitor::Value LSEVisitor::MergePredecessorValues(HBasicBlock* block, size_t idx) {
1380*795d594fSAndroid Build Coastguard Worker   ArrayRef<HBasicBlock* const> predecessors(block->GetPredecessors());
1381*795d594fSAndroid Build Coastguard Worker   DCHECK(!predecessors.empty());
1382*795d594fSAndroid Build Coastguard Worker   Value merged_value =
1383*795d594fSAndroid Build Coastguard Worker       ReplacementOrValue(heap_values_for_[predecessors[0]->GetBlockId()][idx].value);
1384*795d594fSAndroid Build Coastguard Worker   for (size_t i = 1u, size = predecessors.size(); i != size; ++i) {
1385*795d594fSAndroid Build Coastguard Worker     Value pred_value =
1386*795d594fSAndroid Build Coastguard Worker         ReplacementOrValue(heap_values_for_[predecessors[i]->GetBlockId()][idx].value);
1387*795d594fSAndroid Build Coastguard Worker     if (pred_value.Equals(merged_value)) {
1388*795d594fSAndroid Build Coastguard Worker       // Value is the same. No need to update our merged value.
1389*795d594fSAndroid Build Coastguard Worker       continue;
1390*795d594fSAndroid Build Coastguard Worker     } else if (pred_value.IsUnknown() || merged_value.IsUnknown()) {
1391*795d594fSAndroid Build Coastguard Worker       // If one is unknown and the other is not, the merged value is unknown.
1392*795d594fSAndroid Build Coastguard Worker       merged_value = Value::Unknown();
1393*795d594fSAndroid Build Coastguard Worker       break;
1394*795d594fSAndroid Build Coastguard Worker     } else {
1395*795d594fSAndroid Build Coastguard Worker       // There are conflicting known values. We may still be able to replace loads with a Phi.
1396*795d594fSAndroid Build Coastguard Worker       PhiPlaceholder phi_placeholder = GetPhiPlaceholder(block->GetBlockId(), idx);
1397*795d594fSAndroid Build Coastguard Worker       // Propagate the need for a new loop Phi from all predecessors.
1398*795d594fSAndroid Build Coastguard Worker       bool needs_loop_phi = merged_value.NeedsLoopPhi() || pred_value.NeedsLoopPhi();
1399*795d594fSAndroid Build Coastguard Worker       merged_value = ReplacementOrValue(Value::ForPhiPlaceholder(phi_placeholder, needs_loop_phi));
1400*795d594fSAndroid Build Coastguard Worker     }
1401*795d594fSAndroid Build Coastguard Worker   }
1402*795d594fSAndroid Build Coastguard Worker   return merged_value;
1403*795d594fSAndroid Build Coastguard Worker }
1404*795d594fSAndroid Build Coastguard Worker 
MergePredecessorRecords(HBasicBlock * block)1405*795d594fSAndroid Build Coastguard Worker void LSEVisitor::MergePredecessorRecords(HBasicBlock* block) {
1406*795d594fSAndroid Build Coastguard Worker   if (block->IsExitBlock()) {
1407*795d594fSAndroid Build Coastguard Worker     // Exit block doesn't really merge values since the control flow ends in
1408*795d594fSAndroid Build Coastguard Worker     // its predecessors. Each predecessor needs to make sure stores are kept
1409*795d594fSAndroid Build Coastguard Worker     // if necessary.
1410*795d594fSAndroid Build Coastguard Worker     return;
1411*795d594fSAndroid Build Coastguard Worker   }
1412*795d594fSAndroid Build Coastguard Worker 
1413*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<ValueRecord>& heap_values = heap_values_for_[block->GetBlockId()];
1414*795d594fSAndroid Build Coastguard Worker   DCHECK(heap_values.empty());
1415*795d594fSAndroid Build Coastguard Worker   size_t num_heap_locations = heap_location_collector_.GetNumberOfHeapLocations();
1416*795d594fSAndroid Build Coastguard Worker   if (block->GetPredecessors().empty() || block->IsCatchBlock()) {
1417*795d594fSAndroid Build Coastguard Worker     DCHECK_IMPLIES(block->GetPredecessors().empty(), block->IsEntryBlock());
1418*795d594fSAndroid Build Coastguard Worker     heap_values.resize(num_heap_locations,
1419*795d594fSAndroid Build Coastguard Worker                        {/*value=*/Value::Unknown(), /*stored_by=*/Value::Unknown()});
1420*795d594fSAndroid Build Coastguard Worker     return;
1421*795d594fSAndroid Build Coastguard Worker   }
1422*795d594fSAndroid Build Coastguard Worker 
1423*795d594fSAndroid Build Coastguard Worker   heap_values.reserve(num_heap_locations);
1424*795d594fSAndroid Build Coastguard Worker   for (size_t idx = 0u; idx != num_heap_locations; ++idx) {
1425*795d594fSAndroid Build Coastguard Worker     Value merged_value = MergePredecessorValues(block, idx);
1426*795d594fSAndroid Build Coastguard Worker     if (kIsDebugBuild) {
1427*795d594fSAndroid Build Coastguard Worker       if (merged_value.NeedsPhi()) {
1428*795d594fSAndroid Build Coastguard Worker         uint32_t block_id = merged_value.GetPhiPlaceholder().GetBlockId();
1429*795d594fSAndroid Build Coastguard Worker         CHECK(GetGraph()->GetBlocks()[block_id]->Dominates(block));
1430*795d594fSAndroid Build Coastguard Worker       } else if (merged_value.IsInstruction()) {
1431*795d594fSAndroid Build Coastguard Worker         CHECK(merged_value.GetInstruction()->GetBlock()->Dominates(block));
1432*795d594fSAndroid Build Coastguard Worker       }
1433*795d594fSAndroid Build Coastguard Worker     }
1434*795d594fSAndroid Build Coastguard Worker     ArrayRef<HBasicBlock* const> predecessors(block->GetPredecessors());
1435*795d594fSAndroid Build Coastguard Worker     Value merged_stored_by = heap_values_for_[predecessors[0]->GetBlockId()][idx].stored_by;
1436*795d594fSAndroid Build Coastguard Worker     for (size_t predecessor_idx = 1u; predecessor_idx != predecessors.size(); ++predecessor_idx) {
1437*795d594fSAndroid Build Coastguard Worker       uint32_t predecessor_block_id = predecessors[predecessor_idx]->GetBlockId();
1438*795d594fSAndroid Build Coastguard Worker       Value stored_by = heap_values_for_[predecessor_block_id][idx].stored_by;
1439*795d594fSAndroid Build Coastguard Worker       if ((!stored_by.IsUnknown() || !merged_stored_by.IsUnknown()) &&
1440*795d594fSAndroid Build Coastguard Worker           !merged_stored_by.Equals(stored_by)) {
1441*795d594fSAndroid Build Coastguard Worker         // Use the Phi placeholder to track that we need to keep stores from all predecessors.
1442*795d594fSAndroid Build Coastguard Worker         PhiPlaceholder phi_placeholder = GetPhiPlaceholder(block->GetBlockId(), idx);
1443*795d594fSAndroid Build Coastguard Worker         merged_stored_by = Value::ForNonLoopPhiPlaceholder(phi_placeholder);
1444*795d594fSAndroid Build Coastguard Worker         break;
1445*795d594fSAndroid Build Coastguard Worker       }
1446*795d594fSAndroid Build Coastguard Worker     }
1447*795d594fSAndroid Build Coastguard Worker     heap_values.push_back({ merged_value, merged_stored_by });
1448*795d594fSAndroid Build Coastguard Worker   }
1449*795d594fSAndroid Build Coastguard Worker }
1450*795d594fSAndroid Build Coastguard Worker 
FindOrConstructNonLoopPhi(HBasicBlock * block,const ScopedArenaVector<HInstruction * > & phi_inputs,DataType::Type type)1451*795d594fSAndroid Build Coastguard Worker static HInstruction* FindOrConstructNonLoopPhi(
1452*795d594fSAndroid Build Coastguard Worker     HBasicBlock* block,
1453*795d594fSAndroid Build Coastguard Worker     const ScopedArenaVector<HInstruction*>& phi_inputs,
1454*795d594fSAndroid Build Coastguard Worker     DataType::Type type) {
1455*795d594fSAndroid Build Coastguard Worker   for (HInstructionIterator phi_it(block->GetPhis()); !phi_it.Done(); phi_it.Advance()) {
1456*795d594fSAndroid Build Coastguard Worker     HInstruction* phi = phi_it.Current();
1457*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(phi->InputCount(), phi_inputs.size());
1458*795d594fSAndroid Build Coastguard Worker     auto cmp = [](HInstruction* lhs, const HUserRecord<HInstruction*>& rhs) {
1459*795d594fSAndroid Build Coastguard Worker       return lhs == rhs.GetInstruction();
1460*795d594fSAndroid Build Coastguard Worker     };
1461*795d594fSAndroid Build Coastguard Worker     if (std::equal(phi_inputs.begin(), phi_inputs.end(), phi->GetInputRecords().begin(), cmp)) {
1462*795d594fSAndroid Build Coastguard Worker       return phi;
1463*795d594fSAndroid Build Coastguard Worker     }
1464*795d594fSAndroid Build Coastguard Worker   }
1465*795d594fSAndroid Build Coastguard Worker   ArenaAllocator* allocator = block->GetGraph()->GetAllocator();
1466*795d594fSAndroid Build Coastguard Worker   HPhi* phi = new (allocator) HPhi(allocator, kNoRegNumber, phi_inputs.size(), type);
1467*795d594fSAndroid Build Coastguard Worker   for (size_t i = 0, size = phi_inputs.size(); i != size; ++i) {
1468*795d594fSAndroid Build Coastguard Worker     DCHECK_NE(phi_inputs[i]->GetType(), DataType::Type::kVoid) << phi_inputs[i]->DebugName();
1469*795d594fSAndroid Build Coastguard Worker     phi->SetRawInputAt(i, phi_inputs[i]);
1470*795d594fSAndroid Build Coastguard Worker   }
1471*795d594fSAndroid Build Coastguard Worker   block->AddPhi(phi);
1472*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kReference) {
1473*795d594fSAndroid Build Coastguard Worker     // Update reference type information. Pass invalid handles, these are not used for Phis.
1474*795d594fSAndroid Build Coastguard Worker     ReferenceTypePropagation rtp_fixup(block->GetGraph(),
1475*795d594fSAndroid Build Coastguard Worker                                        Handle<mirror::DexCache>(),
1476*795d594fSAndroid Build Coastguard Worker                                        /* is_first_run= */ false);
1477*795d594fSAndroid Build Coastguard Worker     rtp_fixup.Visit(phi);
1478*795d594fSAndroid Build Coastguard Worker   }
1479*795d594fSAndroid Build Coastguard Worker   return phi;
1480*795d594fSAndroid Build Coastguard Worker }
1481*795d594fSAndroid Build Coastguard Worker 
MaterializeNonLoopPhis(PhiPlaceholder phi_placeholder,DataType::Type type)1482*795d594fSAndroid Build Coastguard Worker void LSEVisitor::MaterializeNonLoopPhis(PhiPlaceholder phi_placeholder, DataType::Type type) {
1483*795d594fSAndroid Build Coastguard Worker   DCHECK(phi_placeholder_replacements_[PhiPlaceholderIndex(phi_placeholder)].IsInvalid());
1484*795d594fSAndroid Build Coastguard Worker   const ArenaVector<HBasicBlock*>& blocks = GetGraph()->GetBlocks();
1485*795d594fSAndroid Build Coastguard Worker   size_t idx = phi_placeholder.GetHeapLocation();
1486*795d594fSAndroid Build Coastguard Worker 
1487*795d594fSAndroid Build Coastguard Worker   // Use local allocator to reduce peak memory usage.
1488*795d594fSAndroid Build Coastguard Worker   ScopedArenaAllocator allocator(allocator_.GetArenaStack());
1489*795d594fSAndroid Build Coastguard Worker   // Reuse the same vector for collecting phi inputs.
1490*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<HInstruction*> phi_inputs(allocator.Adapter(kArenaAllocLSE));
1491*795d594fSAndroid Build Coastguard Worker 
1492*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<PhiPlaceholder> work_queue(allocator.Adapter(kArenaAllocLSE));
1493*795d594fSAndroid Build Coastguard Worker   work_queue.push_back(phi_placeholder);
1494*795d594fSAndroid Build Coastguard Worker   while (!work_queue.empty()) {
1495*795d594fSAndroid Build Coastguard Worker     PhiPlaceholder current_phi_placeholder = work_queue.back();
1496*795d594fSAndroid Build Coastguard Worker     if (phi_placeholder_replacements_[PhiPlaceholderIndex(current_phi_placeholder)].IsValid()) {
1497*795d594fSAndroid Build Coastguard Worker       // This Phi placeholder was pushed to the `work_queue` followed by another Phi placeholder
1498*795d594fSAndroid Build Coastguard Worker       // that directly or indirectly depends on it, so it was already processed as part of the
1499*795d594fSAndroid Build Coastguard Worker       // other Phi placeholder's dependencies before this one got back to the top of the stack.
1500*795d594fSAndroid Build Coastguard Worker       work_queue.pop_back();
1501*795d594fSAndroid Build Coastguard Worker       continue;
1502*795d594fSAndroid Build Coastguard Worker     }
1503*795d594fSAndroid Build Coastguard Worker     uint32_t current_block_id = current_phi_placeholder.GetBlockId();
1504*795d594fSAndroid Build Coastguard Worker     HBasicBlock* current_block = blocks[current_block_id];
1505*795d594fSAndroid Build Coastguard Worker     DCHECK_GE(current_block->GetPredecessors().size(), 2u);
1506*795d594fSAndroid Build Coastguard Worker 
1507*795d594fSAndroid Build Coastguard Worker     // Non-loop Phis cannot depend on a loop Phi, so we should not see any loop header here.
1508*795d594fSAndroid Build Coastguard Worker     // And the only way for such merged value to reach a different heap location is through
1509*795d594fSAndroid Build Coastguard Worker     // a load at which point we materialize the Phi. Therefore all non-loop Phi placeholders
1510*795d594fSAndroid Build Coastguard Worker     // seen here are tied to one heap location.
1511*795d594fSAndroid Build Coastguard Worker     DCHECK(!current_block->IsLoopHeader())
1512*795d594fSAndroid Build Coastguard Worker         << current_phi_placeholder << " phase: " << current_phase_;
1513*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(current_phi_placeholder.GetHeapLocation(), idx);
1514*795d594fSAndroid Build Coastguard Worker 
1515*795d594fSAndroid Build Coastguard Worker     phi_inputs.clear();
1516*795d594fSAndroid Build Coastguard Worker     for (HBasicBlock* predecessor : current_block->GetPredecessors()) {
1517*795d594fSAndroid Build Coastguard Worker       Value pred_value = ReplacementOrValue(heap_values_for_[predecessor->GetBlockId()][idx].value);
1518*795d594fSAndroid Build Coastguard Worker       DCHECK(!pred_value.IsUnknown()) << pred_value << " block " << current_block->GetBlockId()
1519*795d594fSAndroid Build Coastguard Worker                                       << " pred: " << predecessor->GetBlockId();
1520*795d594fSAndroid Build Coastguard Worker       if (pred_value.NeedsNonLoopPhi()) {
1521*795d594fSAndroid Build Coastguard Worker         // We need to process the Phi placeholder first.
1522*795d594fSAndroid Build Coastguard Worker         work_queue.push_back(pred_value.GetPhiPlaceholder());
1523*795d594fSAndroid Build Coastguard Worker       } else if (pred_value.IsDefault()) {
1524*795d594fSAndroid Build Coastguard Worker         phi_inputs.push_back(GetDefaultValue(type));
1525*795d594fSAndroid Build Coastguard Worker       } else {
1526*795d594fSAndroid Build Coastguard Worker         DCHECK(pred_value.IsInstruction()) << pred_value << " block " << current_block->GetBlockId()
1527*795d594fSAndroid Build Coastguard Worker                                            << " pred: " << predecessor->GetBlockId();
1528*795d594fSAndroid Build Coastguard Worker         phi_inputs.push_back(pred_value.GetInstruction());
1529*795d594fSAndroid Build Coastguard Worker       }
1530*795d594fSAndroid Build Coastguard Worker     }
1531*795d594fSAndroid Build Coastguard Worker     if (phi_inputs.size() == current_block->GetPredecessors().size()) {
1532*795d594fSAndroid Build Coastguard Worker       // All inputs are available. Find or construct the Phi replacement.
1533*795d594fSAndroid Build Coastguard Worker       phi_placeholder_replacements_[PhiPlaceholderIndex(current_phi_placeholder)] =
1534*795d594fSAndroid Build Coastguard Worker           Value::ForInstruction(FindOrConstructNonLoopPhi(current_block, phi_inputs, type));
1535*795d594fSAndroid Build Coastguard Worker       // Remove the block from the queue.
1536*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(current_phi_placeholder, work_queue.back());
1537*795d594fSAndroid Build Coastguard Worker       work_queue.pop_back();
1538*795d594fSAndroid Build Coastguard Worker     }
1539*795d594fSAndroid Build Coastguard Worker   }
1540*795d594fSAndroid Build Coastguard Worker }
1541*795d594fSAndroid Build Coastguard Worker 
VisitGetLocation(HInstruction * instruction,size_t idx)1542*795d594fSAndroid Build Coastguard Worker void LSEVisitor::VisitGetLocation(HInstruction* instruction, size_t idx) {
1543*795d594fSAndroid Build Coastguard Worker   DCHECK_NE(idx, HeapLocationCollector::kHeapLocationNotFound);
1544*795d594fSAndroid Build Coastguard Worker   uint32_t block_id = instruction->GetBlock()->GetBlockId();
1545*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<ValueRecord>& heap_values = heap_values_for_[block_id];
1546*795d594fSAndroid Build Coastguard Worker   ValueRecord& record = heap_values[idx];
1547*795d594fSAndroid Build Coastguard Worker   if (instruction->IsFieldAccess()) {
1548*795d594fSAndroid Build Coastguard Worker     RecordFieldInfo(&instruction->GetFieldInfo(), idx);
1549*795d594fSAndroid Build Coastguard Worker   }
1550*795d594fSAndroid Build Coastguard Worker   DCHECK(record.value.IsUnknown() || record.value.Equals(ReplacementOrValue(record.value)));
1551*795d594fSAndroid Build Coastguard Worker   loads_and_stores_.push_back({ instruction, idx });
1552*795d594fSAndroid Build Coastguard Worker   if ((record.value.IsDefault() || record.value.NeedsNonLoopPhi()) &&
1553*795d594fSAndroid Build Coastguard Worker       !IsDefaultOrPhiAllowedForLoad(instruction)) {
1554*795d594fSAndroid Build Coastguard Worker     record.value = Value::Unknown();
1555*795d594fSAndroid Build Coastguard Worker   }
1556*795d594fSAndroid Build Coastguard Worker   if (record.value.IsDefault()) {
1557*795d594fSAndroid Build Coastguard Worker     KeepStores(record.stored_by);
1558*795d594fSAndroid Build Coastguard Worker     HInstruction* constant = GetDefaultValue(instruction->GetType());
1559*795d594fSAndroid Build Coastguard Worker     AddRemovedLoad(instruction, constant);
1560*795d594fSAndroid Build Coastguard Worker     record.value = Value::ForInstruction(constant);
1561*795d594fSAndroid Build Coastguard Worker   } else if (record.value.IsUnknown()) {
1562*795d594fSAndroid Build Coastguard Worker     // Load isn't eliminated. Put the load as the value into the HeapLocation.
1563*795d594fSAndroid Build Coastguard Worker     // This acts like GVN but with better aliasing analysis.
1564*795d594fSAndroid Build Coastguard Worker     Value old_value = record.value;
1565*795d594fSAndroid Build Coastguard Worker     record.value = Value::ForInstruction(instruction);
1566*795d594fSAndroid Build Coastguard Worker     KeepStoresIfAliasedToLocation(heap_values, idx);
1567*795d594fSAndroid Build Coastguard Worker     KeepStores(old_value);
1568*795d594fSAndroid Build Coastguard Worker   } else if (record.value.NeedsLoopPhi()) {
1569*795d594fSAndroid Build Coastguard Worker     // We do not know yet if the value is known for all back edges. Record for future processing.
1570*795d594fSAndroid Build Coastguard Worker     if (loads_requiring_loop_phi_.empty()) {
1571*795d594fSAndroid Build Coastguard Worker       loads_requiring_loop_phi_.resize(GetGraph()->GetCurrentInstructionId(), nullptr);
1572*795d594fSAndroid Build Coastguard Worker     }
1573*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(loads_requiring_loop_phi_[instruction->GetId()], nullptr);
1574*795d594fSAndroid Build Coastguard Worker     loads_requiring_loop_phi_[instruction->GetId()] =
1575*795d594fSAndroid Build Coastguard Worker         new (allocator_.Alloc<ValueRecord>(kArenaAllocLSE)) ValueRecord(record);
1576*795d594fSAndroid Build Coastguard Worker   } else {
1577*795d594fSAndroid Build Coastguard Worker     // This load can be eliminated but we may need to construct non-loop Phis.
1578*795d594fSAndroid Build Coastguard Worker     if (record.value.NeedsNonLoopPhi()) {
1579*795d594fSAndroid Build Coastguard Worker       MaterializeNonLoopPhis(record.value.GetPhiPlaceholder(), instruction->GetType());
1580*795d594fSAndroid Build Coastguard Worker       record.value = Replacement(record.value);
1581*795d594fSAndroid Build Coastguard Worker     }
1582*795d594fSAndroid Build Coastguard Worker     HInstruction* heap_value = FindSubstitute(record.value.GetInstruction());
1583*795d594fSAndroid Build Coastguard Worker     AddRemovedLoad(instruction, heap_value);
1584*795d594fSAndroid Build Coastguard Worker   }
1585*795d594fSAndroid Build Coastguard Worker }
1586*795d594fSAndroid Build Coastguard Worker 
VisitSetLocation(HInstruction * instruction,size_t idx,HInstruction * value)1587*795d594fSAndroid Build Coastguard Worker void LSEVisitor::VisitSetLocation(HInstruction* instruction, size_t idx, HInstruction* value) {
1588*795d594fSAndroid Build Coastguard Worker   DCHECK_NE(idx, HeapLocationCollector::kHeapLocationNotFound);
1589*795d594fSAndroid Build Coastguard Worker   DCHECK(!IsStore(value)) << value->DebugName();
1590*795d594fSAndroid Build Coastguard Worker   if (instruction->IsFieldAccess()) {
1591*795d594fSAndroid Build Coastguard Worker     RecordFieldInfo(&instruction->GetFieldInfo(), idx);
1592*795d594fSAndroid Build Coastguard Worker   }
1593*795d594fSAndroid Build Coastguard Worker   // value may already have a substitute.
1594*795d594fSAndroid Build Coastguard Worker   value = FindSubstitute(value);
1595*795d594fSAndroid Build Coastguard Worker   HBasicBlock* block = instruction->GetBlock();
1596*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<ValueRecord>& heap_values = heap_values_for_[block->GetBlockId()];
1597*795d594fSAndroid Build Coastguard Worker   ValueRecord& record = heap_values[idx];
1598*795d594fSAndroid Build Coastguard Worker   DCHECK_IMPLIES(record.value.IsInstruction(),
1599*795d594fSAndroid Build Coastguard Worker                  FindSubstitute(record.value.GetInstruction()) == record.value.GetInstruction());
1600*795d594fSAndroid Build Coastguard Worker 
1601*795d594fSAndroid Build Coastguard Worker   if (record.value.Equals(value)) {
1602*795d594fSAndroid Build Coastguard Worker     // Store into the heap location with the same value.
1603*795d594fSAndroid Build Coastguard Worker     // This store can be eliminated right away.
1604*795d594fSAndroid Build Coastguard Worker     block->RemoveInstruction(instruction);
1605*795d594fSAndroid Build Coastguard Worker     return;
1606*795d594fSAndroid Build Coastguard Worker   }
1607*795d594fSAndroid Build Coastguard Worker 
1608*795d594fSAndroid Build Coastguard Worker   if (store_records_.empty()) {
1609*795d594fSAndroid Build Coastguard Worker     store_records_.resize(GetGraph()->GetCurrentInstructionId(), nullptr);
1610*795d594fSAndroid Build Coastguard Worker   }
1611*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(store_records_[instruction->GetId()], nullptr);
1612*795d594fSAndroid Build Coastguard Worker   store_records_[instruction->GetId()] =
1613*795d594fSAndroid Build Coastguard Worker       new (allocator_.Alloc<StoreRecord>(kArenaAllocLSE)) StoreRecord(record, value);
1614*795d594fSAndroid Build Coastguard Worker   loads_and_stores_.push_back({ instruction, idx });
1615*795d594fSAndroid Build Coastguard Worker 
1616*795d594fSAndroid Build Coastguard Worker   // If the `record.stored_by` specified a store from this block, it shall be removed
1617*795d594fSAndroid Build Coastguard Worker   // at the end, except for throwing ArraySet; it cannot be marked for keeping in
1618*795d594fSAndroid Build Coastguard Worker   // `kept_stores_` anymore after we update the `record.stored_by` below.
1619*795d594fSAndroid Build Coastguard Worker   DCHECK(!record.stored_by.IsInstruction() ||
1620*795d594fSAndroid Build Coastguard Worker          record.stored_by.GetInstruction()->GetBlock() != block ||
1621*795d594fSAndroid Build Coastguard Worker          record.stored_by.GetInstruction()->CanThrow() ||
1622*795d594fSAndroid Build Coastguard Worker          !kept_stores_.IsBitSet(record.stored_by.GetInstruction()->GetId()));
1623*795d594fSAndroid Build Coastguard Worker 
1624*795d594fSAndroid Build Coastguard Worker   if (instruction->CanThrow()) {
1625*795d594fSAndroid Build Coastguard Worker     // Previous stores can become visible.
1626*795d594fSAndroid Build Coastguard Worker     HandleThrowingInstruction(instruction);
1627*795d594fSAndroid Build Coastguard Worker     // We cannot remove a possibly throwing store.
1628*795d594fSAndroid Build Coastguard Worker     // After marking it as kept, it does not matter if we track it in `stored_by` or not.
1629*795d594fSAndroid Build Coastguard Worker     kept_stores_.SetBit(instruction->GetId());
1630*795d594fSAndroid Build Coastguard Worker   }
1631*795d594fSAndroid Build Coastguard Worker 
1632*795d594fSAndroid Build Coastguard Worker   // Update the record.
1633*795d594fSAndroid Build Coastguard Worker   // Note that the `value` can be a newly created `Phi` with an id that falls outside
1634*795d594fSAndroid Build Coastguard Worker   // the allocated `loads_requiring_loop_phi_` range.
1635*795d594fSAndroid Build Coastguard Worker   DCHECK_IMPLIES(IsLoad(value) && !loads_requiring_loop_phi_.empty(),
1636*795d594fSAndroid Build Coastguard Worker                  static_cast<size_t>(value->GetId()) < loads_requiring_loop_phi_.size());
1637*795d594fSAndroid Build Coastguard Worker   if (static_cast<size_t>(value->GetId()) < loads_requiring_loop_phi_.size() &&
1638*795d594fSAndroid Build Coastguard Worker       loads_requiring_loop_phi_[value->GetId()] != nullptr) {
1639*795d594fSAndroid Build Coastguard Worker     // Propapate the Phi placeholder to the record.
1640*795d594fSAndroid Build Coastguard Worker     record.value = loads_requiring_loop_phi_[value->GetId()]->value;
1641*795d594fSAndroid Build Coastguard Worker     DCHECK(record.value.NeedsLoopPhi());
1642*795d594fSAndroid Build Coastguard Worker   } else {
1643*795d594fSAndroid Build Coastguard Worker     record.value = Value::ForInstruction(value);
1644*795d594fSAndroid Build Coastguard Worker   }
1645*795d594fSAndroid Build Coastguard Worker   // Track the store in the value record. If the value is loaded or needed after
1646*795d594fSAndroid Build Coastguard Worker   // return/deoptimization later, this store isn't really redundant.
1647*795d594fSAndroid Build Coastguard Worker   record.stored_by = Value::ForInstruction(instruction);
1648*795d594fSAndroid Build Coastguard Worker 
1649*795d594fSAndroid Build Coastguard Worker   // This store may kill values in other heap locations due to aliasing.
1650*795d594fSAndroid Build Coastguard Worker   for (size_t i = 0u, size = heap_values.size(); i != size; ++i) {
1651*795d594fSAndroid Build Coastguard Worker     if (i == idx ||
1652*795d594fSAndroid Build Coastguard Worker         heap_values[i].value.IsUnknown() ||
1653*795d594fSAndroid Build Coastguard Worker         CanValueBeKeptIfSameAsNew(heap_values[i].value, value, instruction) ||
1654*795d594fSAndroid Build Coastguard Worker         !heap_location_collector_.MayAlias(i, idx)) {
1655*795d594fSAndroid Build Coastguard Worker       continue;
1656*795d594fSAndroid Build Coastguard Worker     }
1657*795d594fSAndroid Build Coastguard Worker     // Kill heap locations that may alias and keep previous stores to these locations.
1658*795d594fSAndroid Build Coastguard Worker     KeepStores(heap_values[i].stored_by);
1659*795d594fSAndroid Build Coastguard Worker     heap_values[i].stored_by = Value::Unknown();
1660*795d594fSAndroid Build Coastguard Worker     heap_values[i].value = Value::Unknown();
1661*795d594fSAndroid Build Coastguard Worker   }
1662*795d594fSAndroid Build Coastguard Worker }
1663*795d594fSAndroid Build Coastguard Worker 
VisitBasicBlock(HBasicBlock * block)1664*795d594fSAndroid Build Coastguard Worker void LSEVisitor::VisitBasicBlock(HBasicBlock* block) {
1665*795d594fSAndroid Build Coastguard Worker   // Populate the heap_values array for this block.
1666*795d594fSAndroid Build Coastguard Worker   // TODO: try to reuse the heap_values array from one predecessor if possible.
1667*795d594fSAndroid Build Coastguard Worker   if (block->IsLoopHeader()) {
1668*795d594fSAndroid Build Coastguard Worker     PrepareLoopRecords(block);
1669*795d594fSAndroid Build Coastguard Worker   } else {
1670*795d594fSAndroid Build Coastguard Worker     MergePredecessorRecords(block);
1671*795d594fSAndroid Build Coastguard Worker   }
1672*795d594fSAndroid Build Coastguard Worker   // Visit non-Phi instructions.
1673*795d594fSAndroid Build Coastguard Worker   VisitNonPhiInstructions(block);
1674*795d594fSAndroid Build Coastguard Worker }
1675*795d594fSAndroid Build Coastguard Worker 
MayAliasOnBackEdge(HBasicBlock * loop_header,size_t idx1,size_t idx2) const1676*795d594fSAndroid Build Coastguard Worker bool LSEVisitor::MayAliasOnBackEdge(HBasicBlock* loop_header, size_t idx1, size_t idx2) const {
1677*795d594fSAndroid Build Coastguard Worker   DCHECK_NE(idx1, idx2);
1678*795d594fSAndroid Build Coastguard Worker   DCHECK(loop_header->IsLoopHeader());
1679*795d594fSAndroid Build Coastguard Worker   if (heap_location_collector_.MayAlias(idx1, idx2)) {
1680*795d594fSAndroid Build Coastguard Worker     return true;
1681*795d594fSAndroid Build Coastguard Worker   }
1682*795d594fSAndroid Build Coastguard Worker   // For array locations with index defined inside the loop, include
1683*795d594fSAndroid Build Coastguard Worker   // all other locations in the array, even those that LSA declares
1684*795d594fSAndroid Build Coastguard Worker   // non-aliasing, such as `a[i]` and `a[i + 1]`, as they may actually
1685*795d594fSAndroid Build Coastguard Worker   // refer to the same locations for different iterations. (LSA's
1686*795d594fSAndroid Build Coastguard Worker   // `ComputeMayAlias()` does not consider different loop iterations.)
1687*795d594fSAndroid Build Coastguard Worker   HeapLocation* loc1 = heap_location_collector_.GetHeapLocation(idx1);
1688*795d594fSAndroid Build Coastguard Worker   HeapLocation* loc2 = heap_location_collector_.GetHeapLocation(idx2);
1689*795d594fSAndroid Build Coastguard Worker   if (loc1->IsArray() &&
1690*795d594fSAndroid Build Coastguard Worker       loc2->IsArray() &&
1691*795d594fSAndroid Build Coastguard Worker       HeapLocationCollector::CanReferencesAlias(loc1->GetReferenceInfo(),
1692*795d594fSAndroid Build Coastguard Worker                                                 loc2->GetReferenceInfo())) {
1693*795d594fSAndroid Build Coastguard Worker     HLoopInformation* loop_info = loop_header->GetLoopInformation();
1694*795d594fSAndroid Build Coastguard Worker     if (loop_info->Contains(*loc1->GetIndex()->GetBlock()) ||
1695*795d594fSAndroid Build Coastguard Worker         loop_info->Contains(*loc2->GetIndex()->GetBlock())) {
1696*795d594fSAndroid Build Coastguard Worker       // Consider the locations aliasing. Do not optimize the case where both indexes
1697*795d594fSAndroid Build Coastguard Worker       // are loop invariants defined inside the loop, rely on LICM to pull them out.
1698*795d594fSAndroid Build Coastguard Worker       return true;
1699*795d594fSAndroid Build Coastguard Worker     }
1700*795d594fSAndroid Build Coastguard Worker   }
1701*795d594fSAndroid Build Coastguard Worker   return false;
1702*795d594fSAndroid Build Coastguard Worker }
1703*795d594fSAndroid Build Coastguard Worker 
TryReplacingLoopPhiPlaceholderWithDefault(PhiPlaceholder phi_placeholder,DataType::Type type,ArenaBitVector * phi_placeholders_to_materialize)1704*795d594fSAndroid Build Coastguard Worker bool LSEVisitor::TryReplacingLoopPhiPlaceholderWithDefault(
1705*795d594fSAndroid Build Coastguard Worker     PhiPlaceholder phi_placeholder,
1706*795d594fSAndroid Build Coastguard Worker     DataType::Type type,
1707*795d594fSAndroid Build Coastguard Worker     /*inout*/ ArenaBitVector* phi_placeholders_to_materialize) {
1708*795d594fSAndroid Build Coastguard Worker   // Use local allocator to reduce peak memory usage.
1709*795d594fSAndroid Build Coastguard Worker   ScopedArenaAllocator allocator(allocator_.GetArenaStack());
1710*795d594fSAndroid Build Coastguard Worker   ArenaBitVector visited(&allocator,
1711*795d594fSAndroid Build Coastguard Worker                          /*start_bits=*/ num_phi_placeholders_,
1712*795d594fSAndroid Build Coastguard Worker                          /*expandable=*/ false,
1713*795d594fSAndroid Build Coastguard Worker                          kArenaAllocLSE);
1714*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<PhiPlaceholder> work_queue(allocator.Adapter(kArenaAllocLSE));
1715*795d594fSAndroid Build Coastguard Worker 
1716*795d594fSAndroid Build Coastguard Worker   // Use depth first search to check if any non-Phi input is unknown.
1717*795d594fSAndroid Build Coastguard Worker   const ArenaVector<HBasicBlock*>& blocks = GetGraph()->GetBlocks();
1718*795d594fSAndroid Build Coastguard Worker   size_t num_heap_locations = heap_location_collector_.GetNumberOfHeapLocations();
1719*795d594fSAndroid Build Coastguard Worker   visited.SetBit(PhiPlaceholderIndex(phi_placeholder));
1720*795d594fSAndroid Build Coastguard Worker   work_queue.push_back(phi_placeholder);
1721*795d594fSAndroid Build Coastguard Worker   while (!work_queue.empty()) {
1722*795d594fSAndroid Build Coastguard Worker     PhiPlaceholder current_phi_placeholder = work_queue.back();
1723*795d594fSAndroid Build Coastguard Worker     work_queue.pop_back();
1724*795d594fSAndroid Build Coastguard Worker     HBasicBlock* block = blocks[current_phi_placeholder.GetBlockId()];
1725*795d594fSAndroid Build Coastguard Worker     DCHECK_GE(block->GetPredecessors().size(), 2u);
1726*795d594fSAndroid Build Coastguard Worker     size_t idx = current_phi_placeholder.GetHeapLocation();
1727*795d594fSAndroid Build Coastguard Worker     for (HBasicBlock* predecessor : block->GetPredecessors()) {
1728*795d594fSAndroid Build Coastguard Worker       Value value = ReplacementOrValue(heap_values_for_[predecessor->GetBlockId()][idx].value);
1729*795d594fSAndroid Build Coastguard Worker       if (value.NeedsPhi()) {
1730*795d594fSAndroid Build Coastguard Worker         // Visit the predecessor Phi placeholder if it's not visited yet.
1731*795d594fSAndroid Build Coastguard Worker         if (!visited.IsBitSet(PhiPlaceholderIndex(value))) {
1732*795d594fSAndroid Build Coastguard Worker           visited.SetBit(PhiPlaceholderIndex(value));
1733*795d594fSAndroid Build Coastguard Worker           work_queue.push_back(value.GetPhiPlaceholder());
1734*795d594fSAndroid Build Coastguard Worker         }
1735*795d594fSAndroid Build Coastguard Worker       } else if (!value.Equals(Value::Default())) {
1736*795d594fSAndroid Build Coastguard Worker         return false;  // Report failure.
1737*795d594fSAndroid Build Coastguard Worker       }
1738*795d594fSAndroid Build Coastguard Worker     }
1739*795d594fSAndroid Build Coastguard Worker     if (block->IsLoopHeader()) {
1740*795d594fSAndroid Build Coastguard Worker       // For back-edges we need to check all locations that write to the same array,
1741*795d594fSAndroid Build Coastguard Worker       // even those that LSA declares non-aliasing, such as `a[i]` and `a[i + 1]`
1742*795d594fSAndroid Build Coastguard Worker       // as they may actually refer to the same locations for different iterations.
1743*795d594fSAndroid Build Coastguard Worker       for (size_t i = 0; i != num_heap_locations; ++i) {
1744*795d594fSAndroid Build Coastguard Worker         if (i == idx ||
1745*795d594fSAndroid Build Coastguard Worker             heap_location_collector_.GetHeapLocation(i)->GetReferenceInfo() !=
1746*795d594fSAndroid Build Coastguard Worker                 heap_location_collector_.GetHeapLocation(idx)->GetReferenceInfo()) {
1747*795d594fSAndroid Build Coastguard Worker           continue;
1748*795d594fSAndroid Build Coastguard Worker         }
1749*795d594fSAndroid Build Coastguard Worker         for (HBasicBlock* predecessor : block->GetPredecessors()) {
1750*795d594fSAndroid Build Coastguard Worker           // Check if there were any writes to this location.
1751*795d594fSAndroid Build Coastguard Worker           // Note: We could simply process the values but due to the vector operation
1752*795d594fSAndroid Build Coastguard Worker           // carve-out (see `IsDefaultOrPhiAllowedForLoad()`), a vector load can cause
1753*795d594fSAndroid Build Coastguard Worker           // the value to change and not be equal to default. To work around this and
1754*795d594fSAndroid Build Coastguard Worker           // allow replacing the non-vector load of loop-invariant default values
1755*795d594fSAndroid Build Coastguard Worker           // anyway, skip over paths that do not have any writes.
1756*795d594fSAndroid Build Coastguard Worker           ValueRecord record = heap_values_for_[predecessor->GetBlockId()][i];
1757*795d594fSAndroid Build Coastguard Worker           while (record.stored_by.NeedsLoopPhi() &&
1758*795d594fSAndroid Build Coastguard Worker                  blocks[record.stored_by.GetPhiPlaceholder().GetBlockId()]->IsLoopHeader()) {
1759*795d594fSAndroid Build Coastguard Worker             HLoopInformation* loop_info =
1760*795d594fSAndroid Build Coastguard Worker                 blocks[record.stored_by.GetPhiPlaceholder().GetBlockId()]->GetLoopInformation();
1761*795d594fSAndroid Build Coastguard Worker             record = heap_values_for_[loop_info->GetPreHeader()->GetBlockId()][i];
1762*795d594fSAndroid Build Coastguard Worker           }
1763*795d594fSAndroid Build Coastguard Worker           Value value = ReplacementOrValue(record.value);
1764*795d594fSAndroid Build Coastguard Worker           if (value.NeedsPhi()) {
1765*795d594fSAndroid Build Coastguard Worker             // Visit the predecessor Phi placeholder if it's not visited yet.
1766*795d594fSAndroid Build Coastguard Worker             if (!visited.IsBitSet(PhiPlaceholderIndex(value))) {
1767*795d594fSAndroid Build Coastguard Worker               visited.SetBit(PhiPlaceholderIndex(value));
1768*795d594fSAndroid Build Coastguard Worker               work_queue.push_back(value.GetPhiPlaceholder());
1769*795d594fSAndroid Build Coastguard Worker             }
1770*795d594fSAndroid Build Coastguard Worker           } else if (!value.Equals(Value::Default())) {
1771*795d594fSAndroid Build Coastguard Worker             return false;  // Report failure.
1772*795d594fSAndroid Build Coastguard Worker           }
1773*795d594fSAndroid Build Coastguard Worker         }
1774*795d594fSAndroid Build Coastguard Worker       }
1775*795d594fSAndroid Build Coastguard Worker     }
1776*795d594fSAndroid Build Coastguard Worker   }
1777*795d594fSAndroid Build Coastguard Worker 
1778*795d594fSAndroid Build Coastguard Worker   // Record replacement and report success.
1779*795d594fSAndroid Build Coastguard Worker   HInstruction* replacement = GetDefaultValue(type);
1780*795d594fSAndroid Build Coastguard Worker   for (uint32_t phi_placeholder_index : visited.Indexes()) {
1781*795d594fSAndroid Build Coastguard Worker     DCHECK(phi_placeholder_replacements_[phi_placeholder_index].IsInvalid());
1782*795d594fSAndroid Build Coastguard Worker     PhiPlaceholder curr = GetPhiPlaceholderAt(phi_placeholder_index);
1783*795d594fSAndroid Build Coastguard Worker     HeapLocation* hl = heap_location_collector_.GetHeapLocation(curr.GetHeapLocation());
1784*795d594fSAndroid Build Coastguard Worker     // We use both vector and non vector operations to analyze the information. However, we replace
1785*795d594fSAndroid Build Coastguard Worker     // only non vector operations in this code path.
1786*795d594fSAndroid Build Coastguard Worker     if (!hl->IsVecOp()) {
1787*795d594fSAndroid Build Coastguard Worker       phi_placeholder_replacements_[phi_placeholder_index] = Value::ForInstruction(replacement);
1788*795d594fSAndroid Build Coastguard Worker       phi_placeholders_to_materialize->ClearBit(phi_placeholder_index);
1789*795d594fSAndroid Build Coastguard Worker     }
1790*795d594fSAndroid Build Coastguard Worker   }
1791*795d594fSAndroid Build Coastguard Worker   return true;
1792*795d594fSAndroid Build Coastguard Worker }
1793*795d594fSAndroid Build Coastguard Worker 
TryReplacingLoopPhiPlaceholderWithSingleInput(PhiPlaceholder phi_placeholder,ArenaBitVector * phi_placeholders_to_materialize)1794*795d594fSAndroid Build Coastguard Worker bool LSEVisitor::TryReplacingLoopPhiPlaceholderWithSingleInput(
1795*795d594fSAndroid Build Coastguard Worker     PhiPlaceholder phi_placeholder,
1796*795d594fSAndroid Build Coastguard Worker     /*inout*/ ArenaBitVector* phi_placeholders_to_materialize) {
1797*795d594fSAndroid Build Coastguard Worker   // Use local allocator to reduce peak memory usage.
1798*795d594fSAndroid Build Coastguard Worker   ScopedArenaAllocator allocator(allocator_.GetArenaStack());
1799*795d594fSAndroid Build Coastguard Worker   ArenaBitVector visited(&allocator,
1800*795d594fSAndroid Build Coastguard Worker                          /*start_bits=*/ num_phi_placeholders_,
1801*795d594fSAndroid Build Coastguard Worker                          /*expandable=*/ false,
1802*795d594fSAndroid Build Coastguard Worker                          kArenaAllocLSE);
1803*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<PhiPlaceholder> work_queue(allocator.Adapter(kArenaAllocLSE));
1804*795d594fSAndroid Build Coastguard Worker 
1805*795d594fSAndroid Build Coastguard Worker   // Use depth first search to check if any non-Phi input is unknown.
1806*795d594fSAndroid Build Coastguard Worker   HInstruction* replacement = nullptr;
1807*795d594fSAndroid Build Coastguard Worker   const ArenaVector<HBasicBlock*>& blocks = GetGraph()->GetBlocks();
1808*795d594fSAndroid Build Coastguard Worker   visited.SetBit(PhiPlaceholderIndex(phi_placeholder));
1809*795d594fSAndroid Build Coastguard Worker   work_queue.push_back(phi_placeholder);
1810*795d594fSAndroid Build Coastguard Worker   while (!work_queue.empty()) {
1811*795d594fSAndroid Build Coastguard Worker     PhiPlaceholder current_phi_placeholder = work_queue.back();
1812*795d594fSAndroid Build Coastguard Worker     work_queue.pop_back();
1813*795d594fSAndroid Build Coastguard Worker     HBasicBlock* current_block = blocks[current_phi_placeholder.GetBlockId()];
1814*795d594fSAndroid Build Coastguard Worker     DCHECK_GE(current_block->GetPredecessors().size(), 2u);
1815*795d594fSAndroid Build Coastguard Worker     size_t idx = current_phi_placeholder.GetHeapLocation();
1816*795d594fSAndroid Build Coastguard Worker     for (HBasicBlock* predecessor : current_block->GetPredecessors()) {
1817*795d594fSAndroid Build Coastguard Worker       Value value = ReplacementOrValue(heap_values_for_[predecessor->GetBlockId()][idx].value);
1818*795d594fSAndroid Build Coastguard Worker       if (value.NeedsPhi()) {
1819*795d594fSAndroid Build Coastguard Worker         // Visit the predecessor Phi placeholder if it's not visited yet.
1820*795d594fSAndroid Build Coastguard Worker         if (!visited.IsBitSet(PhiPlaceholderIndex(value))) {
1821*795d594fSAndroid Build Coastguard Worker           visited.SetBit(PhiPlaceholderIndex(value));
1822*795d594fSAndroid Build Coastguard Worker           work_queue.push_back(value.GetPhiPlaceholder());
1823*795d594fSAndroid Build Coastguard Worker         }
1824*795d594fSAndroid Build Coastguard Worker       } else {
1825*795d594fSAndroid Build Coastguard Worker         if (!value.IsInstruction() ||
1826*795d594fSAndroid Build Coastguard Worker             (replacement != nullptr && replacement != value.GetInstruction())) {
1827*795d594fSAndroid Build Coastguard Worker           return false;  // Report failure.
1828*795d594fSAndroid Build Coastguard Worker         }
1829*795d594fSAndroid Build Coastguard Worker         replacement = value.GetInstruction();
1830*795d594fSAndroid Build Coastguard Worker       }
1831*795d594fSAndroid Build Coastguard Worker     }
1832*795d594fSAndroid Build Coastguard Worker     // While `TryReplacingLoopPhiPlaceholderWithDefault()` has special treatment
1833*795d594fSAndroid Build Coastguard Worker     // for back-edges, it is not needed here. When looking for a single input
1834*795d594fSAndroid Build Coastguard Worker     // instruction coming from before the loop, the array index must also be
1835*795d594fSAndroid Build Coastguard Worker     // defined before the loop and the aliasing analysis done by LSA is sufficient.
1836*795d594fSAndroid Build Coastguard Worker     // Any writes of a different value with an index that is not loop invariant
1837*795d594fSAndroid Build Coastguard Worker     // would invalidate the heap location in `VisitSetLocation()`.
1838*795d594fSAndroid Build Coastguard Worker   }
1839*795d594fSAndroid Build Coastguard Worker 
1840*795d594fSAndroid Build Coastguard Worker   // Record replacement and report success.
1841*795d594fSAndroid Build Coastguard Worker   DCHECK(replacement != nullptr);
1842*795d594fSAndroid Build Coastguard Worker   for (uint32_t phi_placeholder_index : visited.Indexes()) {
1843*795d594fSAndroid Build Coastguard Worker     DCHECK(phi_placeholder_replacements_[phi_placeholder_index].IsInvalid());
1844*795d594fSAndroid Build Coastguard Worker     PhiPlaceholder curr = GetPhiPlaceholderAt(phi_placeholder_index);
1845*795d594fSAndroid Build Coastguard Worker     HeapLocation* hl = heap_location_collector_.GetHeapLocation(curr.GetHeapLocation());
1846*795d594fSAndroid Build Coastguard Worker     // We use both vector and non vector operations to analyze the information. However, we replace
1847*795d594fSAndroid Build Coastguard Worker     // only vector operations in this code path.
1848*795d594fSAndroid Build Coastguard Worker     if (hl->IsVecOp()) {
1849*795d594fSAndroid Build Coastguard Worker       phi_placeholder_replacements_[phi_placeholder_index] = Value::ForInstruction(replacement);
1850*795d594fSAndroid Build Coastguard Worker       phi_placeholders_to_materialize->ClearBit(phi_placeholder_index);
1851*795d594fSAndroid Build Coastguard Worker     }
1852*795d594fSAndroid Build Coastguard Worker   }
1853*795d594fSAndroid Build Coastguard Worker   return true;
1854*795d594fSAndroid Build Coastguard Worker }
1855*795d594fSAndroid Build Coastguard Worker 
FindLoopPhisToMaterialize(PhiPlaceholder phi_placeholder,ArenaBitVector * phi_placeholders_to_materialize,DataType::Type type,bool can_use_default_or_phi)1856*795d594fSAndroid Build Coastguard Worker std::optional<LSEVisitor::PhiPlaceholder> LSEVisitor::FindLoopPhisToMaterialize(
1857*795d594fSAndroid Build Coastguard Worker     PhiPlaceholder phi_placeholder,
1858*795d594fSAndroid Build Coastguard Worker     /*inout*/ ArenaBitVector* phi_placeholders_to_materialize,
1859*795d594fSAndroid Build Coastguard Worker     DataType::Type type,
1860*795d594fSAndroid Build Coastguard Worker     bool can_use_default_or_phi) {
1861*795d594fSAndroid Build Coastguard Worker   DCHECK(phi_placeholder_replacements_[PhiPlaceholderIndex(phi_placeholder)].IsInvalid());
1862*795d594fSAndroid Build Coastguard Worker 
1863*795d594fSAndroid Build Coastguard Worker   // Use local allocator to reduce peak memory usage.
1864*795d594fSAndroid Build Coastguard Worker   ScopedArenaAllocator allocator(allocator_.GetArenaStack());
1865*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<PhiPlaceholder> work_queue(allocator.Adapter(kArenaAllocLSE));
1866*795d594fSAndroid Build Coastguard Worker 
1867*795d594fSAndroid Build Coastguard Worker   // Use depth first search to check if any non-Phi input is unknown.
1868*795d594fSAndroid Build Coastguard Worker   const ArenaVector<HBasicBlock*>& blocks = GetGraph()->GetBlocks();
1869*795d594fSAndroid Build Coastguard Worker   phi_placeholders_to_materialize->ClearAllBits();
1870*795d594fSAndroid Build Coastguard Worker   phi_placeholders_to_materialize->SetBit(PhiPlaceholderIndex(phi_placeholder));
1871*795d594fSAndroid Build Coastguard Worker   work_queue.push_back(phi_placeholder);
1872*795d594fSAndroid Build Coastguard Worker   while (!work_queue.empty()) {
1873*795d594fSAndroid Build Coastguard Worker     PhiPlaceholder current_phi_placeholder = work_queue.back();
1874*795d594fSAndroid Build Coastguard Worker     work_queue.pop_back();
1875*795d594fSAndroid Build Coastguard Worker     if (!phi_placeholders_to_materialize->IsBitSet(PhiPlaceholderIndex(current_phi_placeholder))) {
1876*795d594fSAndroid Build Coastguard Worker       // Replaced by `TryReplacingLoopPhiPlaceholderWith{Default,SingleInput}()`.
1877*795d594fSAndroid Build Coastguard Worker       DCHECK(phi_placeholder_replacements_[PhiPlaceholderIndex(current_phi_placeholder)].Equals(
1878*795d594fSAndroid Build Coastguard Worker                  Value::Default()));
1879*795d594fSAndroid Build Coastguard Worker       continue;
1880*795d594fSAndroid Build Coastguard Worker     }
1881*795d594fSAndroid Build Coastguard Worker     HBasicBlock* current_block = blocks[current_phi_placeholder.GetBlockId()];
1882*795d594fSAndroid Build Coastguard Worker     DCHECK_GE(current_block->GetPredecessors().size(), 2u);
1883*795d594fSAndroid Build Coastguard Worker     size_t idx = current_phi_placeholder.GetHeapLocation();
1884*795d594fSAndroid Build Coastguard Worker     if (current_block->IsLoopHeader()) {
1885*795d594fSAndroid Build Coastguard Worker       // If the index is defined inside the loop, it may reference different elements of the
1886*795d594fSAndroid Build Coastguard Worker       // array on each iteration. Since we do not track if all elements of an array are set
1887*795d594fSAndroid Build Coastguard Worker       // to the same value explicitly, the only known value in pre-header can be the default
1888*795d594fSAndroid Build Coastguard Worker       // value from NewArray or a Phi placeholder depending on a default value from some outer
1889*795d594fSAndroid Build Coastguard Worker       // loop pre-header. This Phi placeholder can be replaced only by the default value.
1890*795d594fSAndroid Build Coastguard Worker       HInstruction* index = heap_location_collector_.GetHeapLocation(idx)->GetIndex();
1891*795d594fSAndroid Build Coastguard Worker       if (index != nullptr && current_block->GetLoopInformation()->Contains(*index->GetBlock())) {
1892*795d594fSAndroid Build Coastguard Worker         if (can_use_default_or_phi &&
1893*795d594fSAndroid Build Coastguard Worker             TryReplacingLoopPhiPlaceholderWithDefault(current_phi_placeholder,
1894*795d594fSAndroid Build Coastguard Worker                                                       type,
1895*795d594fSAndroid Build Coastguard Worker                                                       phi_placeholders_to_materialize)) {
1896*795d594fSAndroid Build Coastguard Worker           continue;
1897*795d594fSAndroid Build Coastguard Worker         } else {
1898*795d594fSAndroid Build Coastguard Worker           return current_phi_placeholder;  // Report the loop Phi placeholder.
1899*795d594fSAndroid Build Coastguard Worker         }
1900*795d594fSAndroid Build Coastguard Worker       }
1901*795d594fSAndroid Build Coastguard Worker       // A similar situation arises with the index defined outside the loop if we cannot use
1902*795d594fSAndroid Build Coastguard Worker       // default values or Phis, i.e. for vector loads, as we can only replace the Phi
1903*795d594fSAndroid Build Coastguard Worker       // placeholder with a single instruction defined before the loop.
1904*795d594fSAndroid Build Coastguard Worker       if (!can_use_default_or_phi) {
1905*795d594fSAndroid Build Coastguard Worker         DCHECK(index != nullptr);  // Vector operations are array operations.
1906*795d594fSAndroid Build Coastguard Worker         if (TryReplacingLoopPhiPlaceholderWithSingleInput(current_phi_placeholder,
1907*795d594fSAndroid Build Coastguard Worker                                                           phi_placeholders_to_materialize)) {
1908*795d594fSAndroid Build Coastguard Worker           continue;
1909*795d594fSAndroid Build Coastguard Worker         } else {
1910*795d594fSAndroid Build Coastguard Worker           return current_phi_placeholder;  // Report the loop Phi placeholder.
1911*795d594fSAndroid Build Coastguard Worker         }
1912*795d594fSAndroid Build Coastguard Worker       }
1913*795d594fSAndroid Build Coastguard Worker     }
1914*795d594fSAndroid Build Coastguard Worker     for (HBasicBlock* predecessor : current_block->GetPredecessors()) {
1915*795d594fSAndroid Build Coastguard Worker       ScopedArenaVector<ValueRecord>& heap_values = heap_values_for_[predecessor->GetBlockId()];
1916*795d594fSAndroid Build Coastguard Worker       Value value = ReplacementOrValue(heap_values[idx].value);
1917*795d594fSAndroid Build Coastguard Worker       if (value.IsUnknown()) {
1918*795d594fSAndroid Build Coastguard Worker         // We cannot create a Phi for this loop Phi placeholder.
1919*795d594fSAndroid Build Coastguard Worker         return current_phi_placeholder;  // Report the loop Phi placeholder.
1920*795d594fSAndroid Build Coastguard Worker       }
1921*795d594fSAndroid Build Coastguard Worker       // For arrays, the location may have been clobbered by writes to other locations
1922*795d594fSAndroid Build Coastguard Worker       // in a loop that LSA does not consider aliasing, such as `a[i]` and `a[i + 1]`.
1923*795d594fSAndroid Build Coastguard Worker       if (current_block->IsLoopHeader() &&
1924*795d594fSAndroid Build Coastguard Worker           predecessor != current_block->GetLoopInformation()->GetPreHeader() &&
1925*795d594fSAndroid Build Coastguard Worker           heap_location_collector_.GetHeapLocation(idx)->GetIndex() != nullptr) {
1926*795d594fSAndroid Build Coastguard Worker         for (size_t i = 0, size = heap_values.size(); i != size; ++i) {
1927*795d594fSAndroid Build Coastguard Worker           if (i != idx &&
1928*795d594fSAndroid Build Coastguard Worker               !heap_values[i].stored_by.IsUnknown() &&
1929*795d594fSAndroid Build Coastguard Worker               MayAliasOnBackEdge(current_block, idx, i)) {
1930*795d594fSAndroid Build Coastguard Worker             // We cannot create a Phi for this loop Phi placeholder.
1931*795d594fSAndroid Build Coastguard Worker             return current_phi_placeholder;
1932*795d594fSAndroid Build Coastguard Worker           }
1933*795d594fSAndroid Build Coastguard Worker         }
1934*795d594fSAndroid Build Coastguard Worker       }
1935*795d594fSAndroid Build Coastguard Worker       if (value.NeedsLoopPhi()) {
1936*795d594fSAndroid Build Coastguard Worker         // Visit the predecessor Phi placeholder if it's not visited yet.
1937*795d594fSAndroid Build Coastguard Worker         if (!phi_placeholders_to_materialize->IsBitSet(PhiPlaceholderIndex(value))) {
1938*795d594fSAndroid Build Coastguard Worker           phi_placeholders_to_materialize->SetBit(PhiPlaceholderIndex(value));
1939*795d594fSAndroid Build Coastguard Worker           work_queue.push_back(value.GetPhiPlaceholder());
1940*795d594fSAndroid Build Coastguard Worker           LSE_VLOG << "For materialization of " << phi_placeholder
1941*795d594fSAndroid Build Coastguard Worker                    << " we need to materialize " << value;
1942*795d594fSAndroid Build Coastguard Worker         }
1943*795d594fSAndroid Build Coastguard Worker       }
1944*795d594fSAndroid Build Coastguard Worker     }
1945*795d594fSAndroid Build Coastguard Worker   }
1946*795d594fSAndroid Build Coastguard Worker 
1947*795d594fSAndroid Build Coastguard Worker   // There are no unknown values feeding this Phi, so we can construct the Phis if needed.
1948*795d594fSAndroid Build Coastguard Worker   return std::nullopt;
1949*795d594fSAndroid Build Coastguard Worker }
1950*795d594fSAndroid Build Coastguard Worker 
MaterializeLoopPhis(const ScopedArenaVector<size_t> & phi_placeholder_indexes,DataType::Type type)1951*795d594fSAndroid Build Coastguard Worker bool LSEVisitor::MaterializeLoopPhis(const ScopedArenaVector<size_t>& phi_placeholder_indexes,
1952*795d594fSAndroid Build Coastguard Worker                                      DataType::Type type) {
1953*795d594fSAndroid Build Coastguard Worker   return MaterializeLoopPhis(ArrayRef<const size_t>(phi_placeholder_indexes), type);
1954*795d594fSAndroid Build Coastguard Worker }
1955*795d594fSAndroid Build Coastguard Worker 
MaterializeLoopPhis(ArrayRef<const size_t> phi_placeholder_indexes,DataType::Type type)1956*795d594fSAndroid Build Coastguard Worker bool LSEVisitor::MaterializeLoopPhis(ArrayRef<const size_t> phi_placeholder_indexes,
1957*795d594fSAndroid Build Coastguard Worker                                      DataType::Type type) {
1958*795d594fSAndroid Build Coastguard Worker   // Materialize all predecessors that do not need a loop Phi and determine if all inputs
1959*795d594fSAndroid Build Coastguard Worker   // other than loop Phis are the same.
1960*795d594fSAndroid Build Coastguard Worker   const ArenaVector<HBasicBlock*>& blocks = GetGraph()->GetBlocks();
1961*795d594fSAndroid Build Coastguard Worker   std::optional<Value> other_value = std::nullopt;
1962*795d594fSAndroid Build Coastguard Worker   for (size_t phi_placeholder_index : phi_placeholder_indexes) {
1963*795d594fSAndroid Build Coastguard Worker     PhiPlaceholder phi_placeholder = GetPhiPlaceholderAt(phi_placeholder_index);
1964*795d594fSAndroid Build Coastguard Worker     HBasicBlock* block = blocks[phi_placeholder.GetBlockId()];
1965*795d594fSAndroid Build Coastguard Worker     DCHECK_GE(block->GetPredecessors().size(), 2u);
1966*795d594fSAndroid Build Coastguard Worker     size_t idx = phi_placeholder.GetHeapLocation();
1967*795d594fSAndroid Build Coastguard Worker     for (HBasicBlock* predecessor : block->GetPredecessors()) {
1968*795d594fSAndroid Build Coastguard Worker       Value value = ReplacementOrValue(heap_values_for_[predecessor->GetBlockId()][idx].value);
1969*795d594fSAndroid Build Coastguard Worker       if (value.NeedsNonLoopPhi()) {
1970*795d594fSAndroid Build Coastguard Worker         DCHECK(current_phase_ == Phase::kLoadElimination) << current_phase_;
1971*795d594fSAndroid Build Coastguard Worker         MaterializeNonLoopPhis(value.GetPhiPlaceholder(), type);
1972*795d594fSAndroid Build Coastguard Worker         value = Replacement(value);
1973*795d594fSAndroid Build Coastguard Worker       }
1974*795d594fSAndroid Build Coastguard Worker       if (!value.NeedsLoopPhi()) {
1975*795d594fSAndroid Build Coastguard Worker         if (!other_value) {
1976*795d594fSAndroid Build Coastguard Worker           // The first other value we found.
1977*795d594fSAndroid Build Coastguard Worker           other_value = value;
1978*795d594fSAndroid Build Coastguard Worker         } else if (!other_value->IsInvalid()) {
1979*795d594fSAndroid Build Coastguard Worker           // Check if the current `value` differs from the previous `other_value`.
1980*795d594fSAndroid Build Coastguard Worker           if (!value.Equals(*other_value)) {
1981*795d594fSAndroid Build Coastguard Worker             other_value = Value::Invalid();
1982*795d594fSAndroid Build Coastguard Worker           }
1983*795d594fSAndroid Build Coastguard Worker         }
1984*795d594fSAndroid Build Coastguard Worker       }
1985*795d594fSAndroid Build Coastguard Worker     }
1986*795d594fSAndroid Build Coastguard Worker   }
1987*795d594fSAndroid Build Coastguard Worker 
1988*795d594fSAndroid Build Coastguard Worker   DCHECK(other_value.has_value());
1989*795d594fSAndroid Build Coastguard Worker   if (!other_value->IsInvalid()) {
1990*795d594fSAndroid Build Coastguard Worker     HInstruction* replacement =
1991*795d594fSAndroid Build Coastguard Worker         (other_value->IsDefault()) ? GetDefaultValue(type) : other_value->GetInstruction();
1992*795d594fSAndroid Build Coastguard Worker     for (size_t phi_placeholder_index : phi_placeholder_indexes) {
1993*795d594fSAndroid Build Coastguard Worker       phi_placeholder_replacements_[phi_placeholder_index] = Value::ForInstruction(replacement);
1994*795d594fSAndroid Build Coastguard Worker     }
1995*795d594fSAndroid Build Coastguard Worker     return true;
1996*795d594fSAndroid Build Coastguard Worker   }
1997*795d594fSAndroid Build Coastguard Worker 
1998*795d594fSAndroid Build Coastguard Worker   // If we're materializing only a single Phi, try to match it with an existing Phi.
1999*795d594fSAndroid Build Coastguard Worker   // (Matching multiple Phis would need investigation. It may be prohibitively slow.)
2000*795d594fSAndroid Build Coastguard Worker   // This also covers the case when after replacing a previous set of Phi placeholders,
2001*795d594fSAndroid Build Coastguard Worker   // we continue with a Phi placeholder that does not really need a loop Phi anymore.
2002*795d594fSAndroid Build Coastguard Worker   if (phi_placeholder_indexes.size() == 1u) {
2003*795d594fSAndroid Build Coastguard Worker     PhiPlaceholder phi_placeholder = GetPhiPlaceholderAt(phi_placeholder_indexes[0]);
2004*795d594fSAndroid Build Coastguard Worker     size_t idx = phi_placeholder.GetHeapLocation();
2005*795d594fSAndroid Build Coastguard Worker     HBasicBlock* block = GetGraph()->GetBlocks()[phi_placeholder.GetBlockId()];
2006*795d594fSAndroid Build Coastguard Worker     ArrayRef<HBasicBlock* const> predecessors(block->GetPredecessors());
2007*795d594fSAndroid Build Coastguard Worker     for (HInstructionIterator phi_it(block->GetPhis()); !phi_it.Done(); phi_it.Advance()) {
2008*795d594fSAndroid Build Coastguard Worker       HInstruction* phi = phi_it.Current();
2009*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(phi->InputCount(), predecessors.size());
2010*795d594fSAndroid Build Coastguard Worker       ArrayRef<HUserRecord<HInstruction*>> phi_inputs = phi->GetInputRecords();
2011*795d594fSAndroid Build Coastguard Worker       auto cmp = [=, this](const HUserRecord<HInstruction*>& lhs, HBasicBlock* rhs) {
2012*795d594fSAndroid Build Coastguard Worker         Value value = ReplacementOrValue(heap_values_for_[rhs->GetBlockId()][idx].value);
2013*795d594fSAndroid Build Coastguard Worker         if (value.NeedsPhi()) {
2014*795d594fSAndroid Build Coastguard Worker           DCHECK(value.GetPhiPlaceholder() == phi_placeholder);
2015*795d594fSAndroid Build Coastguard Worker           return lhs.GetInstruction() == phi;
2016*795d594fSAndroid Build Coastguard Worker         } else {
2017*795d594fSAndroid Build Coastguard Worker           DCHECK(value.IsDefault() || value.IsInstruction());
2018*795d594fSAndroid Build Coastguard Worker           return value.Equals(lhs.GetInstruction());
2019*795d594fSAndroid Build Coastguard Worker         }
2020*795d594fSAndroid Build Coastguard Worker       };
2021*795d594fSAndroid Build Coastguard Worker       if (std::equal(phi_inputs.begin(), phi_inputs.end(), predecessors.begin(), cmp)) {
2022*795d594fSAndroid Build Coastguard Worker         phi_placeholder_replacements_[phi_placeholder_indexes[0]] = Value::ForInstruction(phi);
2023*795d594fSAndroid Build Coastguard Worker         return true;
2024*795d594fSAndroid Build Coastguard Worker       }
2025*795d594fSAndroid Build Coastguard Worker     }
2026*795d594fSAndroid Build Coastguard Worker   }
2027*795d594fSAndroid Build Coastguard Worker 
2028*795d594fSAndroid Build Coastguard Worker   if (current_phase_ == Phase::kStoreElimination) {
2029*795d594fSAndroid Build Coastguard Worker     // We're not creating Phis during the final store elimination phase.
2030*795d594fSAndroid Build Coastguard Worker     return false;
2031*795d594fSAndroid Build Coastguard Worker   }
2032*795d594fSAndroid Build Coastguard Worker 
2033*795d594fSAndroid Build Coastguard Worker   // There are different inputs to the Phi chain. Create the Phis.
2034*795d594fSAndroid Build Coastguard Worker   ArenaAllocator* allocator = GetGraph()->GetAllocator();
2035*795d594fSAndroid Build Coastguard Worker   for (size_t phi_placeholder_index : phi_placeholder_indexes) {
2036*795d594fSAndroid Build Coastguard Worker     PhiPlaceholder phi_placeholder = GetPhiPlaceholderAt(phi_placeholder_index);
2037*795d594fSAndroid Build Coastguard Worker     HBasicBlock* block = blocks[phi_placeholder.GetBlockId()];
2038*795d594fSAndroid Build Coastguard Worker     CHECK_GE(block->GetPredecessors().size(), 2u);
2039*795d594fSAndroid Build Coastguard Worker     phi_placeholder_replacements_[phi_placeholder_index] = Value::ForInstruction(
2040*795d594fSAndroid Build Coastguard Worker         new (allocator) HPhi(allocator, kNoRegNumber, block->GetPredecessors().size(), type));
2041*795d594fSAndroid Build Coastguard Worker   }
2042*795d594fSAndroid Build Coastguard Worker   // Fill the Phi inputs.
2043*795d594fSAndroid Build Coastguard Worker   for (size_t phi_placeholder_index : phi_placeholder_indexes) {
2044*795d594fSAndroid Build Coastguard Worker     PhiPlaceholder phi_placeholder = GetPhiPlaceholderAt(phi_placeholder_index);
2045*795d594fSAndroid Build Coastguard Worker     HBasicBlock* block = blocks[phi_placeholder.GetBlockId()];
2046*795d594fSAndroid Build Coastguard Worker     size_t idx = phi_placeholder.GetHeapLocation();
2047*795d594fSAndroid Build Coastguard Worker     HInstruction* phi = phi_placeholder_replacements_[phi_placeholder_index].GetInstruction();
2048*795d594fSAndroid Build Coastguard Worker     DCHECK(DataType::IsTypeConversionImplicit(type, phi->GetType()))
2049*795d594fSAndroid Build Coastguard Worker         << "type=" << type << " vs phi-type=" << phi->GetType();
2050*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0, size = block->GetPredecessors().size(); i != size; ++i) {
2051*795d594fSAndroid Build Coastguard Worker       HBasicBlock* predecessor = block->GetPredecessors()[i];
2052*795d594fSAndroid Build Coastguard Worker       Value value = ReplacementOrValue(heap_values_for_[predecessor->GetBlockId()][idx].value);
2053*795d594fSAndroid Build Coastguard Worker       HInstruction* input = value.IsDefault() ? GetDefaultValue(type) : value.GetInstruction();
2054*795d594fSAndroid Build Coastguard Worker       DCHECK_NE(input->GetType(), DataType::Type::kVoid);
2055*795d594fSAndroid Build Coastguard Worker       phi->SetRawInputAt(i, input);
2056*795d594fSAndroid Build Coastguard Worker       DCHECK(DataType::IsTypeConversionImplicit(input->GetType(), phi->GetType()))
2057*795d594fSAndroid Build Coastguard Worker           << " input: " << input->GetType() << value << " phi: " << phi->GetType()
2058*795d594fSAndroid Build Coastguard Worker           << " request: " << type;
2059*795d594fSAndroid Build Coastguard Worker     }
2060*795d594fSAndroid Build Coastguard Worker   }
2061*795d594fSAndroid Build Coastguard Worker   // Add the Phis to their blocks.
2062*795d594fSAndroid Build Coastguard Worker   for (size_t phi_placeholder_index : phi_placeholder_indexes) {
2063*795d594fSAndroid Build Coastguard Worker     PhiPlaceholder phi_placeholder = GetPhiPlaceholderAt(phi_placeholder_index);
2064*795d594fSAndroid Build Coastguard Worker     HBasicBlock* block = blocks[phi_placeholder.GetBlockId()];
2065*795d594fSAndroid Build Coastguard Worker     block->AddPhi(phi_placeholder_replacements_[phi_placeholder_index].GetInstruction()->AsPhi());
2066*795d594fSAndroid Build Coastguard Worker   }
2067*795d594fSAndroid Build Coastguard Worker   if (type == DataType::Type::kReference) {
2068*795d594fSAndroid Build Coastguard Worker     ScopedArenaAllocator local_allocator(allocator_.GetArenaStack());
2069*795d594fSAndroid Build Coastguard Worker     ScopedArenaVector<HInstruction*> phis(local_allocator.Adapter(kArenaAllocLSE));
2070*795d594fSAndroid Build Coastguard Worker     for (size_t phi_placeholder_index : phi_placeholder_indexes) {
2071*795d594fSAndroid Build Coastguard Worker       phis.push_back(phi_placeholder_replacements_[phi_placeholder_index].GetInstruction());
2072*795d594fSAndroid Build Coastguard Worker     }
2073*795d594fSAndroid Build Coastguard Worker     // Update reference type information. Pass invalid handles, these are not used for Phis.
2074*795d594fSAndroid Build Coastguard Worker     ReferenceTypePropagation rtp_fixup(GetGraph(),
2075*795d594fSAndroid Build Coastguard Worker                                        Handle<mirror::DexCache>(),
2076*795d594fSAndroid Build Coastguard Worker                                        /* is_first_run= */ false);
2077*795d594fSAndroid Build Coastguard Worker     rtp_fixup.Visit(ArrayRef<HInstruction* const>(phis));
2078*795d594fSAndroid Build Coastguard Worker   }
2079*795d594fSAndroid Build Coastguard Worker 
2080*795d594fSAndroid Build Coastguard Worker   return true;
2081*795d594fSAndroid Build Coastguard Worker }
2082*795d594fSAndroid Build Coastguard Worker 
MaterializeLoopPhis(const ArenaBitVector & phi_placeholders_to_materialize,DataType::Type type)2083*795d594fSAndroid Build Coastguard Worker bool LSEVisitor::MaterializeLoopPhis(const ArenaBitVector& phi_placeholders_to_materialize,
2084*795d594fSAndroid Build Coastguard Worker                                      DataType::Type type) {
2085*795d594fSAndroid Build Coastguard Worker   // Use local allocator to reduce peak memory usage.
2086*795d594fSAndroid Build Coastguard Worker   ScopedArenaAllocator allocator(allocator_.GetArenaStack());
2087*795d594fSAndroid Build Coastguard Worker 
2088*795d594fSAndroid Build Coastguard Worker   // We want to recognize when a subset of these loop Phis that do not need other
2089*795d594fSAndroid Build Coastguard Worker   // loop Phis, i.e. a transitive closure, has only one other instruction as an input,
2090*795d594fSAndroid Build Coastguard Worker   // i.e. that instruction can be used instead of each Phi in the set. See for example
2091*795d594fSAndroid Build Coastguard Worker   // Main.testLoop{5,6,7,8}() in the test 530-checker-lse. To do that, we shall
2092*795d594fSAndroid Build Coastguard Worker   // materialize these loop Phis from the smallest transitive closure.
2093*795d594fSAndroid Build Coastguard Worker 
2094*795d594fSAndroid Build Coastguard Worker   // Construct a matrix of loop phi placeholder dependencies. To reduce the memory usage,
2095*795d594fSAndroid Build Coastguard Worker   // assign new indexes to the Phi placeholders, making the matrix dense.
2096*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<size_t> matrix_indexes(num_phi_placeholders_,
2097*795d594fSAndroid Build Coastguard Worker                                            static_cast<size_t>(-1),  // Invalid.
2098*795d594fSAndroid Build Coastguard Worker                                            allocator.Adapter(kArenaAllocLSE));
2099*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<size_t> phi_placeholder_indexes(allocator.Adapter(kArenaAllocLSE));
2100*795d594fSAndroid Build Coastguard Worker   size_t num_phi_placeholders = phi_placeholders_to_materialize.NumSetBits();
2101*795d594fSAndroid Build Coastguard Worker   phi_placeholder_indexes.reserve(num_phi_placeholders);
2102*795d594fSAndroid Build Coastguard Worker   for (uint32_t marker_index : phi_placeholders_to_materialize.Indexes()) {
2103*795d594fSAndroid Build Coastguard Worker     matrix_indexes[marker_index] = phi_placeholder_indexes.size();
2104*795d594fSAndroid Build Coastguard Worker     phi_placeholder_indexes.push_back(marker_index);
2105*795d594fSAndroid Build Coastguard Worker   }
2106*795d594fSAndroid Build Coastguard Worker   const ArenaVector<HBasicBlock*>& blocks = GetGraph()->GetBlocks();
2107*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<ArenaBitVector*> dependencies(allocator.Adapter(kArenaAllocLSE));
2108*795d594fSAndroid Build Coastguard Worker   dependencies.reserve(num_phi_placeholders);
2109*795d594fSAndroid Build Coastguard Worker   for (size_t matrix_index = 0; matrix_index != num_phi_placeholders; ++matrix_index) {
2110*795d594fSAndroid Build Coastguard Worker     static constexpr bool kExpandable = false;
2111*795d594fSAndroid Build Coastguard Worker     dependencies.push_back(
2112*795d594fSAndroid Build Coastguard Worker         ArenaBitVector::Create(&allocator, num_phi_placeholders, kExpandable, kArenaAllocLSE));
2113*795d594fSAndroid Build Coastguard Worker     ArenaBitVector* current_dependencies = dependencies.back();
2114*795d594fSAndroid Build Coastguard Worker     current_dependencies->SetBit(matrix_index);  // Count the Phi placeholder as its own dependency.
2115*795d594fSAndroid Build Coastguard Worker     PhiPlaceholder current_phi_placeholder =
2116*795d594fSAndroid Build Coastguard Worker         GetPhiPlaceholderAt(phi_placeholder_indexes[matrix_index]);
2117*795d594fSAndroid Build Coastguard Worker     HBasicBlock* current_block = blocks[current_phi_placeholder.GetBlockId()];
2118*795d594fSAndroid Build Coastguard Worker     DCHECK_GE(current_block->GetPredecessors().size(), 2u);
2119*795d594fSAndroid Build Coastguard Worker     size_t idx = current_phi_placeholder.GetHeapLocation();
2120*795d594fSAndroid Build Coastguard Worker     for (HBasicBlock* predecessor : current_block->GetPredecessors()) {
2121*795d594fSAndroid Build Coastguard Worker       Value pred_value = ReplacementOrValue(heap_values_for_[predecessor->GetBlockId()][idx].value);
2122*795d594fSAndroid Build Coastguard Worker       if (pred_value.NeedsLoopPhi()) {
2123*795d594fSAndroid Build Coastguard Worker         size_t pred_value_index = PhiPlaceholderIndex(pred_value);
2124*795d594fSAndroid Build Coastguard Worker         DCHECK(phi_placeholder_replacements_[pred_value_index].IsInvalid());
2125*795d594fSAndroid Build Coastguard Worker         DCHECK_NE(matrix_indexes[pred_value_index], static_cast<size_t>(-1));
2126*795d594fSAndroid Build Coastguard Worker         current_dependencies->SetBit(matrix_indexes[PhiPlaceholderIndex(pred_value)]);
2127*795d594fSAndroid Build Coastguard Worker       }
2128*795d594fSAndroid Build Coastguard Worker     }
2129*795d594fSAndroid Build Coastguard Worker   }
2130*795d594fSAndroid Build Coastguard Worker 
2131*795d594fSAndroid Build Coastguard Worker   // Use the Floyd-Warshall algorithm to determine all transitive dependencies.
2132*795d594fSAndroid Build Coastguard Worker   for (size_t k = 0; k != num_phi_placeholders; ++k) {
2133*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0; i != num_phi_placeholders; ++i) {
2134*795d594fSAndroid Build Coastguard Worker       for (size_t j = 0; j != num_phi_placeholders; ++j) {
2135*795d594fSAndroid Build Coastguard Worker         if (dependencies[i]->IsBitSet(k) && dependencies[k]->IsBitSet(j)) {
2136*795d594fSAndroid Build Coastguard Worker           dependencies[i]->SetBit(j);
2137*795d594fSAndroid Build Coastguard Worker         }
2138*795d594fSAndroid Build Coastguard Worker       }
2139*795d594fSAndroid Build Coastguard Worker     }
2140*795d594fSAndroid Build Coastguard Worker   }
2141*795d594fSAndroid Build Coastguard Worker 
2142*795d594fSAndroid Build Coastguard Worker   // Count the number of transitive dependencies for each replaceable Phi placeholder.
2143*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<size_t> num_dependencies(allocator.Adapter(kArenaAllocLSE));
2144*795d594fSAndroid Build Coastguard Worker   num_dependencies.reserve(num_phi_placeholders);
2145*795d594fSAndroid Build Coastguard Worker   for (size_t matrix_index = 0; matrix_index != num_phi_placeholders; ++matrix_index) {
2146*795d594fSAndroid Build Coastguard Worker     num_dependencies.push_back(dependencies[matrix_index]->NumSetBits());
2147*795d594fSAndroid Build Coastguard Worker   }
2148*795d594fSAndroid Build Coastguard Worker 
2149*795d594fSAndroid Build Coastguard Worker   // Pick a Phi placeholder with the smallest number of transitive dependencies and
2150*795d594fSAndroid Build Coastguard Worker   // materialize it and its dependencies. Repeat until we have materialized all.
2151*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<size_t> current_subset(allocator.Adapter(kArenaAllocLSE));
2152*795d594fSAndroid Build Coastguard Worker   current_subset.reserve(num_phi_placeholders);
2153*795d594fSAndroid Build Coastguard Worker   size_t remaining_phi_placeholders = num_phi_placeholders;
2154*795d594fSAndroid Build Coastguard Worker   while (remaining_phi_placeholders != 0u) {
2155*795d594fSAndroid Build Coastguard Worker     auto it = std::min_element(num_dependencies.begin(), num_dependencies.end());
2156*795d594fSAndroid Build Coastguard Worker     DCHECK_LE(*it, remaining_phi_placeholders);
2157*795d594fSAndroid Build Coastguard Worker     size_t current_matrix_index = std::distance(num_dependencies.begin(), it);
2158*795d594fSAndroid Build Coastguard Worker     ArenaBitVector* current_dependencies = dependencies[current_matrix_index];
2159*795d594fSAndroid Build Coastguard Worker     size_t current_num_dependencies = num_dependencies[current_matrix_index];
2160*795d594fSAndroid Build Coastguard Worker     current_subset.clear();
2161*795d594fSAndroid Build Coastguard Worker     for (uint32_t matrix_index : current_dependencies->Indexes()) {
2162*795d594fSAndroid Build Coastguard Worker       current_subset.push_back(phi_placeholder_indexes[matrix_index]);
2163*795d594fSAndroid Build Coastguard Worker     }
2164*795d594fSAndroid Build Coastguard Worker     if (!MaterializeLoopPhis(current_subset, type)) {
2165*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(current_phase_, Phase::kStoreElimination);
2166*795d594fSAndroid Build Coastguard Worker       // This is the final store elimination phase and we shall not be able to eliminate any
2167*795d594fSAndroid Build Coastguard Worker       // stores that depend on the current subset, so mark these Phi placeholders unreplaceable.
2168*795d594fSAndroid Build Coastguard Worker       for (uint32_t matrix_index = 0; matrix_index != num_phi_placeholders; ++matrix_index) {
2169*795d594fSAndroid Build Coastguard Worker         if (dependencies[matrix_index]->IsBitSet(current_matrix_index)) {
2170*795d594fSAndroid Build Coastguard Worker           DCHECK(phi_placeholder_replacements_[phi_placeholder_indexes[matrix_index]].IsInvalid());
2171*795d594fSAndroid Build Coastguard Worker           phi_placeholder_replacements_[phi_placeholder_indexes[matrix_index]] = Value::Unknown();
2172*795d594fSAndroid Build Coastguard Worker         }
2173*795d594fSAndroid Build Coastguard Worker       }
2174*795d594fSAndroid Build Coastguard Worker       return false;
2175*795d594fSAndroid Build Coastguard Worker     }
2176*795d594fSAndroid Build Coastguard Worker     for (uint32_t matrix_index = 0; matrix_index != num_phi_placeholders; ++matrix_index) {
2177*795d594fSAndroid Build Coastguard Worker       if (current_dependencies->IsBitSet(matrix_index)) {
2178*795d594fSAndroid Build Coastguard Worker         // Mark all dependencies as done by incrementing their `num_dependencies[.]`,
2179*795d594fSAndroid Build Coastguard Worker         // so that they shall never be the minimum again.
2180*795d594fSAndroid Build Coastguard Worker         num_dependencies[matrix_index] = num_phi_placeholders;
2181*795d594fSAndroid Build Coastguard Worker       } else if (dependencies[matrix_index]->IsBitSet(current_matrix_index)) {
2182*795d594fSAndroid Build Coastguard Worker         // Remove dependencies from other Phi placeholders.
2183*795d594fSAndroid Build Coastguard Worker         dependencies[matrix_index]->Subtract(current_dependencies);
2184*795d594fSAndroid Build Coastguard Worker         num_dependencies[matrix_index] -= current_num_dependencies;
2185*795d594fSAndroid Build Coastguard Worker       }
2186*795d594fSAndroid Build Coastguard Worker     }
2187*795d594fSAndroid Build Coastguard Worker     remaining_phi_placeholders -= current_num_dependencies;
2188*795d594fSAndroid Build Coastguard Worker   }
2189*795d594fSAndroid Build Coastguard Worker   return true;
2190*795d594fSAndroid Build Coastguard Worker }
2191*795d594fSAndroid Build Coastguard Worker 
FullyMaterializePhi(PhiPlaceholder phi_placeholder,DataType::Type type)2192*795d594fSAndroid Build Coastguard Worker bool LSEVisitor::FullyMaterializePhi(PhiPlaceholder phi_placeholder, DataType::Type type) {
2193*795d594fSAndroid Build Coastguard Worker   ScopedArenaAllocator saa(GetGraph()->GetArenaStack());
2194*795d594fSAndroid Build Coastguard Worker   ArenaBitVector abv(&saa, num_phi_placeholders_, false, ArenaAllocKind::kArenaAllocLSE);
2195*795d594fSAndroid Build Coastguard Worker   auto res =
2196*795d594fSAndroid Build Coastguard Worker       FindLoopPhisToMaterialize(phi_placeholder, &abv, type, /* can_use_default_or_phi=*/true);
2197*795d594fSAndroid Build Coastguard Worker   CHECK(!res.has_value()) << *res;
2198*795d594fSAndroid Build Coastguard Worker   return MaterializeLoopPhis(abv, type);
2199*795d594fSAndroid Build Coastguard Worker }
2200*795d594fSAndroid Build Coastguard Worker 
TryToMaterializeLoopPhis(PhiPlaceholder phi_placeholder,HInstruction * load)2201*795d594fSAndroid Build Coastguard Worker std::optional<LSEVisitor::PhiPlaceholder> LSEVisitor::TryToMaterializeLoopPhis(
2202*795d594fSAndroid Build Coastguard Worker     PhiPlaceholder phi_placeholder, HInstruction* load) {
2203*795d594fSAndroid Build Coastguard Worker   DCHECK(phi_placeholder_replacements_[PhiPlaceholderIndex(phi_placeholder)].IsInvalid());
2204*795d594fSAndroid Build Coastguard Worker 
2205*795d594fSAndroid Build Coastguard Worker   // Use local allocator to reduce peak memory usage.
2206*795d594fSAndroid Build Coastguard Worker   ScopedArenaAllocator allocator(allocator_.GetArenaStack());
2207*795d594fSAndroid Build Coastguard Worker 
2208*795d594fSAndroid Build Coastguard Worker   // Find Phi placeholders to materialize.
2209*795d594fSAndroid Build Coastguard Worker   ArenaBitVector phi_placeholders_to_materialize(
2210*795d594fSAndroid Build Coastguard Worker       &allocator, num_phi_placeholders_, /*expandable=*/ false, kArenaAllocLSE);
2211*795d594fSAndroid Build Coastguard Worker   DataType::Type type = load->GetType();
2212*795d594fSAndroid Build Coastguard Worker   bool can_use_default_or_phi = IsDefaultOrPhiAllowedForLoad(load);
2213*795d594fSAndroid Build Coastguard Worker   std::optional<PhiPlaceholder> loop_phi_with_unknown_input = FindLoopPhisToMaterialize(
2214*795d594fSAndroid Build Coastguard Worker       phi_placeholder, &phi_placeholders_to_materialize, type, can_use_default_or_phi);
2215*795d594fSAndroid Build Coastguard Worker   if (loop_phi_with_unknown_input) {
2216*795d594fSAndroid Build Coastguard Worker     DCHECK_GE(GetGraph()
2217*795d594fSAndroid Build Coastguard Worker                   ->GetBlocks()[loop_phi_with_unknown_input->GetBlockId()]
2218*795d594fSAndroid Build Coastguard Worker                   ->GetPredecessors()
2219*795d594fSAndroid Build Coastguard Worker                   .size(),
2220*795d594fSAndroid Build Coastguard Worker               2u);
2221*795d594fSAndroid Build Coastguard Worker     return loop_phi_with_unknown_input;  // Return failure.
2222*795d594fSAndroid Build Coastguard Worker   }
2223*795d594fSAndroid Build Coastguard Worker 
2224*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(current_phase_, Phase::kLoadElimination);
2225*795d594fSAndroid Build Coastguard Worker   bool success = MaterializeLoopPhis(phi_placeholders_to_materialize, type);
2226*795d594fSAndroid Build Coastguard Worker   DCHECK(success);
2227*795d594fSAndroid Build Coastguard Worker 
2228*795d594fSAndroid Build Coastguard Worker   // Report success.
2229*795d594fSAndroid Build Coastguard Worker   return std::nullopt;
2230*795d594fSAndroid Build Coastguard Worker }
2231*795d594fSAndroid Build Coastguard Worker 
2232*795d594fSAndroid Build Coastguard Worker // Re-process loads and stores in successors from the `loop_phi_with_unknown_input`. This may
2233*795d594fSAndroid Build Coastguard Worker // find one or more loads from `loads_requiring_loop_phi_` which cannot be replaced by Phis and
2234*795d594fSAndroid Build Coastguard Worker // propagate the load(s) as the new value(s) to successors; this may uncover new elimination
2235*795d594fSAndroid Build Coastguard Worker // opportunities. If we find no such load, we shall at least propagate an unknown value to some
2236*795d594fSAndroid Build Coastguard Worker // heap location that is needed by another loop Phi placeholder.
ProcessLoopPhiWithUnknownInput(PhiPlaceholder loop_phi_with_unknown_input)2237*795d594fSAndroid Build Coastguard Worker void LSEVisitor::ProcessLoopPhiWithUnknownInput(PhiPlaceholder loop_phi_with_unknown_input) {
2238*795d594fSAndroid Build Coastguard Worker   DCHECK(!loads_requiring_loop_phi_.empty());
2239*795d594fSAndroid Build Coastguard Worker   size_t loop_phi_with_unknown_input_index = PhiPlaceholderIndex(loop_phi_with_unknown_input);
2240*795d594fSAndroid Build Coastguard Worker   DCHECK(phi_placeholder_replacements_[loop_phi_with_unknown_input_index].IsInvalid());
2241*795d594fSAndroid Build Coastguard Worker   phi_placeholder_replacements_[loop_phi_with_unknown_input_index] = Value::Unknown();
2242*795d594fSAndroid Build Coastguard Worker 
2243*795d594fSAndroid Build Coastguard Worker   uint32_t block_id = loop_phi_with_unknown_input.GetBlockId();
2244*795d594fSAndroid Build Coastguard Worker   const ArenaVector<HBasicBlock*> reverse_post_order = GetGraph()->GetReversePostOrder();
2245*795d594fSAndroid Build Coastguard Worker   size_t reverse_post_order_index = 0;
2246*795d594fSAndroid Build Coastguard Worker   size_t reverse_post_order_size = reverse_post_order.size();
2247*795d594fSAndroid Build Coastguard Worker   size_t loads_and_stores_index = 0u;
2248*795d594fSAndroid Build Coastguard Worker   size_t loads_and_stores_size = loads_and_stores_.size();
2249*795d594fSAndroid Build Coastguard Worker 
2250*795d594fSAndroid Build Coastguard Worker   // Skip blocks and instructions before the block containing the loop phi with unknown input.
2251*795d594fSAndroid Build Coastguard Worker   DCHECK_NE(reverse_post_order_index, reverse_post_order_size);
2252*795d594fSAndroid Build Coastguard Worker   while (reverse_post_order[reverse_post_order_index]->GetBlockId() != block_id) {
2253*795d594fSAndroid Build Coastguard Worker     HBasicBlock* block = reverse_post_order[reverse_post_order_index];
2254*795d594fSAndroid Build Coastguard Worker     while (loads_and_stores_index != loads_and_stores_size &&
2255*795d594fSAndroid Build Coastguard Worker            loads_and_stores_[loads_and_stores_index].load_or_store->GetBlock() == block) {
2256*795d594fSAndroid Build Coastguard Worker       ++loads_and_stores_index;
2257*795d594fSAndroid Build Coastguard Worker     }
2258*795d594fSAndroid Build Coastguard Worker     ++reverse_post_order_index;
2259*795d594fSAndroid Build Coastguard Worker     DCHECK_NE(reverse_post_order_index, reverse_post_order_size);
2260*795d594fSAndroid Build Coastguard Worker   }
2261*795d594fSAndroid Build Coastguard Worker 
2262*795d594fSAndroid Build Coastguard Worker   // Use local allocator to reduce peak memory usage.
2263*795d594fSAndroid Build Coastguard Worker   ScopedArenaAllocator allocator(allocator_.GetArenaStack());
2264*795d594fSAndroid Build Coastguard Worker   // Reuse one temporary vector for all remaining blocks.
2265*795d594fSAndroid Build Coastguard Worker   size_t num_heap_locations = heap_location_collector_.GetNumberOfHeapLocations();
2266*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<Value> local_heap_values(allocator.Adapter(kArenaAllocLSE));
2267*795d594fSAndroid Build Coastguard Worker 
2268*795d594fSAndroid Build Coastguard Worker   auto get_initial_value = [this](HBasicBlock* block, size_t idx) {
2269*795d594fSAndroid Build Coastguard Worker     Value value;
2270*795d594fSAndroid Build Coastguard Worker     if (block->IsLoopHeader()) {
2271*795d594fSAndroid Build Coastguard Worker       if (block->GetLoopInformation()->IsIrreducible()) {
2272*795d594fSAndroid Build Coastguard Worker         value = Value::Unknown();
2273*795d594fSAndroid Build Coastguard Worker       } else {
2274*795d594fSAndroid Build Coastguard Worker         value = PrepareLoopValue(block, idx);
2275*795d594fSAndroid Build Coastguard Worker       }
2276*795d594fSAndroid Build Coastguard Worker     } else {
2277*795d594fSAndroid Build Coastguard Worker       value = MergePredecessorValues(block, idx);
2278*795d594fSAndroid Build Coastguard Worker     }
2279*795d594fSAndroid Build Coastguard Worker     DCHECK(value.IsUnknown() || ReplacementOrValue(value).Equals(value));
2280*795d594fSAndroid Build Coastguard Worker     return value;
2281*795d594fSAndroid Build Coastguard Worker   };
2282*795d594fSAndroid Build Coastguard Worker 
2283*795d594fSAndroid Build Coastguard Worker   // Process remaining blocks and instructions.
2284*795d594fSAndroid Build Coastguard Worker   bool found_unreplaceable_load = false;
2285*795d594fSAndroid Build Coastguard Worker   bool replaced_heap_value_with_unknown = false;
2286*795d594fSAndroid Build Coastguard Worker   for (; reverse_post_order_index != reverse_post_order_size; ++reverse_post_order_index) {
2287*795d594fSAndroid Build Coastguard Worker     HBasicBlock* block = reverse_post_order[reverse_post_order_index];
2288*795d594fSAndroid Build Coastguard Worker     if (block->IsExitBlock()) {
2289*795d594fSAndroid Build Coastguard Worker       continue;
2290*795d594fSAndroid Build Coastguard Worker     }
2291*795d594fSAndroid Build Coastguard Worker 
2292*795d594fSAndroid Build Coastguard Worker     // We shall reconstruct only the heap values that we need for processing loads and stores.
2293*795d594fSAndroid Build Coastguard Worker     local_heap_values.clear();
2294*795d594fSAndroid Build Coastguard Worker     local_heap_values.resize(num_heap_locations, Value::Invalid());
2295*795d594fSAndroid Build Coastguard Worker 
2296*795d594fSAndroid Build Coastguard Worker     for (; loads_and_stores_index != loads_and_stores_size; ++loads_and_stores_index) {
2297*795d594fSAndroid Build Coastguard Worker       HInstruction* load_or_store = loads_and_stores_[loads_and_stores_index].load_or_store;
2298*795d594fSAndroid Build Coastguard Worker       size_t idx = loads_and_stores_[loads_and_stores_index].heap_location_index;
2299*795d594fSAndroid Build Coastguard Worker       if (load_or_store->GetBlock() != block) {
2300*795d594fSAndroid Build Coastguard Worker         break;  // End of instructions from the current block.
2301*795d594fSAndroid Build Coastguard Worker       }
2302*795d594fSAndroid Build Coastguard Worker       if (IsStore(load_or_store)) {
2303*795d594fSAndroid Build Coastguard Worker         StoreRecord* store_record = store_records_[load_or_store->GetId()];
2304*795d594fSAndroid Build Coastguard Worker         DCHECK(store_record != nullptr);
2305*795d594fSAndroid Build Coastguard Worker         HInstruction* stored_value = store_record->stored_value;
2306*795d594fSAndroid Build Coastguard Worker         DCHECK(stored_value != nullptr);
2307*795d594fSAndroid Build Coastguard Worker         // Note that the `stored_value` can be a newly created `Phi` with an id that falls
2308*795d594fSAndroid Build Coastguard Worker         // outside the allocated `loads_requiring_loop_phi_` range.
2309*795d594fSAndroid Build Coastguard Worker         DCHECK_IMPLIES(
2310*795d594fSAndroid Build Coastguard Worker             IsLoad(stored_value),
2311*795d594fSAndroid Build Coastguard Worker             static_cast<size_t>(stored_value->GetId()) < loads_requiring_loop_phi_.size());
2312*795d594fSAndroid Build Coastguard Worker         if (static_cast<size_t>(stored_value->GetId()) >= loads_requiring_loop_phi_.size() ||
2313*795d594fSAndroid Build Coastguard Worker             loads_requiring_loop_phi_[stored_value->GetId()] == nullptr) {
2314*795d594fSAndroid Build Coastguard Worker           continue;  // This store never needed a loop Phi.
2315*795d594fSAndroid Build Coastguard Worker         }
2316*795d594fSAndroid Build Coastguard Worker         ValueRecord* record = loads_requiring_loop_phi_[stored_value->GetId()];
2317*795d594fSAndroid Build Coastguard Worker         // Process the store by updating `local_heap_values[idx]`. The last update shall
2318*795d594fSAndroid Build Coastguard Worker         // be propagated to the `heap_values[idx].value` if it previously needed a loop Phi
2319*795d594fSAndroid Build Coastguard Worker         // at the end of the block.
2320*795d594fSAndroid Build Coastguard Worker         Value replacement = ReplacementOrValue(record->value);
2321*795d594fSAndroid Build Coastguard Worker         if (replacement.NeedsLoopPhi()) {
2322*795d594fSAndroid Build Coastguard Worker           // No replacement yet, use the Phi placeholder from the load.
2323*795d594fSAndroid Build Coastguard Worker           DCHECK(record->value.NeedsLoopPhi());
2324*795d594fSAndroid Build Coastguard Worker           local_heap_values[idx] = record->value;
2325*795d594fSAndroid Build Coastguard Worker         } else {
2326*795d594fSAndroid Build Coastguard Worker           // If the load fetched a known value, use it, otherwise use the load.
2327*795d594fSAndroid Build Coastguard Worker           local_heap_values[idx] = Value::ForInstruction(
2328*795d594fSAndroid Build Coastguard Worker               replacement.IsUnknown() ? stored_value : replacement.GetInstruction());
2329*795d594fSAndroid Build Coastguard Worker         }
2330*795d594fSAndroid Build Coastguard Worker       } else {
2331*795d594fSAndroid Build Coastguard Worker         // Process the load unless it has previously been marked unreplaceable.
2332*795d594fSAndroid Build Coastguard Worker         DCHECK(IsLoad(load_or_store));
2333*795d594fSAndroid Build Coastguard Worker         ValueRecord* record = loads_requiring_loop_phi_[load_or_store->GetId()];
2334*795d594fSAndroid Build Coastguard Worker         if (record == nullptr) {
2335*795d594fSAndroid Build Coastguard Worker           continue;  // This load never needed a loop Phi.
2336*795d594fSAndroid Build Coastguard Worker         }
2337*795d594fSAndroid Build Coastguard Worker         if (record->value.NeedsLoopPhi()) {
2338*795d594fSAndroid Build Coastguard Worker           if (local_heap_values[idx].IsInvalid()) {
2339*795d594fSAndroid Build Coastguard Worker             local_heap_values[idx] = get_initial_value(block, idx);
2340*795d594fSAndroid Build Coastguard Worker           }
2341*795d594fSAndroid Build Coastguard Worker           if (local_heap_values[idx].IsUnknown()) {
2342*795d594fSAndroid Build Coastguard Worker             // This load cannot be replaced. Keep stores that feed the Phi placeholder
2343*795d594fSAndroid Build Coastguard Worker             // (no aliasing since then, otherwise the Phi placeholder would not have been
2344*795d594fSAndroid Build Coastguard Worker             // propagated as a value to this load) and store the load as the new heap value.
2345*795d594fSAndroid Build Coastguard Worker             found_unreplaceable_load = true;
2346*795d594fSAndroid Build Coastguard Worker             KeepStores(record->value);
2347*795d594fSAndroid Build Coastguard Worker             record->value = Value::Unknown();
2348*795d594fSAndroid Build Coastguard Worker             local_heap_values[idx] = Value::ForInstruction(load_or_store);
2349*795d594fSAndroid Build Coastguard Worker           } else if (local_heap_values[idx].NeedsLoopPhi()) {
2350*795d594fSAndroid Build Coastguard Worker             // The load may still be replaced with a Phi later.
2351*795d594fSAndroid Build Coastguard Worker             DCHECK(local_heap_values[idx].Equals(record->value));
2352*795d594fSAndroid Build Coastguard Worker           } else {
2353*795d594fSAndroid Build Coastguard Worker             // This load can be eliminated but we may need to construct non-loop Phis.
2354*795d594fSAndroid Build Coastguard Worker             if (local_heap_values[idx].NeedsNonLoopPhi()) {
2355*795d594fSAndroid Build Coastguard Worker               MaterializeNonLoopPhis(local_heap_values[idx].GetPhiPlaceholder(),
2356*795d594fSAndroid Build Coastguard Worker                                      load_or_store->GetType());
2357*795d594fSAndroid Build Coastguard Worker               local_heap_values[idx] = Replacement(local_heap_values[idx]);
2358*795d594fSAndroid Build Coastguard Worker             }
2359*795d594fSAndroid Build Coastguard Worker             record->value = local_heap_values[idx];
2360*795d594fSAndroid Build Coastguard Worker             DCHECK(local_heap_values[idx].IsDefault() || local_heap_values[idx].IsInstruction())
2361*795d594fSAndroid Build Coastguard Worker                 << "The replacement heap value can be an HIR instruction or the default value.";
2362*795d594fSAndroid Build Coastguard Worker             HInstruction* heap_value = local_heap_values[idx].IsDefault() ?
2363*795d594fSAndroid Build Coastguard Worker                                            GetDefaultValue(load_or_store->GetType()) :
2364*795d594fSAndroid Build Coastguard Worker                                            local_heap_values[idx].GetInstruction();
2365*795d594fSAndroid Build Coastguard Worker             AddRemovedLoad(load_or_store, heap_value);
2366*795d594fSAndroid Build Coastguard Worker           }
2367*795d594fSAndroid Build Coastguard Worker         }
2368*795d594fSAndroid Build Coastguard Worker       }
2369*795d594fSAndroid Build Coastguard Worker     }
2370*795d594fSAndroid Build Coastguard Worker 
2371*795d594fSAndroid Build Coastguard Worker     // All heap values that previously needed a loop Phi at the end of the block
2372*795d594fSAndroid Build Coastguard Worker     // need to be updated for processing successors.
2373*795d594fSAndroid Build Coastguard Worker     ScopedArenaVector<ValueRecord>& heap_values = heap_values_for_[block->GetBlockId()];
2374*795d594fSAndroid Build Coastguard Worker     for (size_t idx = 0; idx != num_heap_locations; ++idx) {
2375*795d594fSAndroid Build Coastguard Worker       if (heap_values[idx].value.NeedsLoopPhi()) {
2376*795d594fSAndroid Build Coastguard Worker         if (local_heap_values[idx].IsValid()) {
2377*795d594fSAndroid Build Coastguard Worker           heap_values[idx].value = local_heap_values[idx];
2378*795d594fSAndroid Build Coastguard Worker         } else {
2379*795d594fSAndroid Build Coastguard Worker           heap_values[idx].value = get_initial_value(block, idx);
2380*795d594fSAndroid Build Coastguard Worker         }
2381*795d594fSAndroid Build Coastguard Worker         if (heap_values[idx].value.IsUnknown()) {
2382*795d594fSAndroid Build Coastguard Worker           replaced_heap_value_with_unknown = true;
2383*795d594fSAndroid Build Coastguard Worker         }
2384*795d594fSAndroid Build Coastguard Worker       }
2385*795d594fSAndroid Build Coastguard Worker     }
2386*795d594fSAndroid Build Coastguard Worker   }
2387*795d594fSAndroid Build Coastguard Worker   DCHECK(found_unreplaceable_load || replaced_heap_value_with_unknown);
2388*795d594fSAndroid Build Coastguard Worker }
2389*795d594fSAndroid Build Coastguard Worker 
ProcessLoadsRequiringLoopPhis()2390*795d594fSAndroid Build Coastguard Worker void LSEVisitor::ProcessLoadsRequiringLoopPhis() {
2391*795d594fSAndroid Build Coastguard Worker   // Note: The vector operations carve-out (see `IsDefaultOrPhiAllowedForLoad()`) can possibly
2392*795d594fSAndroid Build Coastguard Worker   // make the result of the processing depend on the order in which we process these loads.
2393*795d594fSAndroid Build Coastguard Worker   // To make sure the result is deterministic, iterate over `loads_and_stores_` instead of the
2394*795d594fSAndroid Build Coastguard Worker   // `loads_requiring_loop_phi_` indexed by non-deterministic pointers.
2395*795d594fSAndroid Build Coastguard Worker   if (loads_requiring_loop_phi_.empty()) {
2396*795d594fSAndroid Build Coastguard Worker     return;  // No loads to process.
2397*795d594fSAndroid Build Coastguard Worker   }
2398*795d594fSAndroid Build Coastguard Worker   for (const LoadStoreRecord& load_store_record : loads_and_stores_) {
2399*795d594fSAndroid Build Coastguard Worker     ValueRecord* record = loads_requiring_loop_phi_[load_store_record.load_or_store->GetId()];
2400*795d594fSAndroid Build Coastguard Worker     if (record == nullptr) {
2401*795d594fSAndroid Build Coastguard Worker       continue;
2402*795d594fSAndroid Build Coastguard Worker     }
2403*795d594fSAndroid Build Coastguard Worker     HInstruction* load = load_store_record.load_or_store;
2404*795d594fSAndroid Build Coastguard Worker     while (record->value.NeedsLoopPhi() &&
2405*795d594fSAndroid Build Coastguard Worker            phi_placeholder_replacements_[PhiPlaceholderIndex(record->value)].IsInvalid()) {
2406*795d594fSAndroid Build Coastguard Worker       std::optional<PhiPlaceholder> loop_phi_with_unknown_input =
2407*795d594fSAndroid Build Coastguard Worker           TryToMaterializeLoopPhis(record->value.GetPhiPlaceholder(), load);
2408*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(loop_phi_with_unknown_input.has_value(),
2409*795d594fSAndroid Build Coastguard Worker                 phi_placeholder_replacements_[PhiPlaceholderIndex(record->value)].IsInvalid());
2410*795d594fSAndroid Build Coastguard Worker       if (loop_phi_with_unknown_input) {
2411*795d594fSAndroid Build Coastguard Worker         DCHECK_GE(GetGraph()
2412*795d594fSAndroid Build Coastguard Worker                       ->GetBlocks()[loop_phi_with_unknown_input->GetBlockId()]
2413*795d594fSAndroid Build Coastguard Worker                       ->GetPredecessors()
2414*795d594fSAndroid Build Coastguard Worker                       .size(),
2415*795d594fSAndroid Build Coastguard Worker                   2u);
2416*795d594fSAndroid Build Coastguard Worker         ProcessLoopPhiWithUnknownInput(*loop_phi_with_unknown_input);
2417*795d594fSAndroid Build Coastguard Worker       }
2418*795d594fSAndroid Build Coastguard Worker     }
2419*795d594fSAndroid Build Coastguard Worker     // The load could have been marked as unreplaceable (and stores marked for keeping)
2420*795d594fSAndroid Build Coastguard Worker     // or marked for replacement with an instruction in ProcessLoopPhiWithUnknownInput().
2421*795d594fSAndroid Build Coastguard Worker     DCHECK(record->value.IsUnknown() ||
2422*795d594fSAndroid Build Coastguard Worker            record->value.IsInstruction() ||
2423*795d594fSAndroid Build Coastguard Worker            record->value.NeedsLoopPhi());
2424*795d594fSAndroid Build Coastguard Worker     if (record->value.NeedsLoopPhi()) {
2425*795d594fSAndroid Build Coastguard Worker       record->value = Replacement(record->value);
2426*795d594fSAndroid Build Coastguard Worker       HInstruction* heap_value = record->value.GetInstruction();
2427*795d594fSAndroid Build Coastguard Worker       AddRemovedLoad(load, heap_value);
2428*795d594fSAndroid Build Coastguard Worker     }
2429*795d594fSAndroid Build Coastguard Worker   }
2430*795d594fSAndroid Build Coastguard Worker }
2431*795d594fSAndroid Build Coastguard Worker 
SearchPhiPlaceholdersForKeptStores()2432*795d594fSAndroid Build Coastguard Worker void LSEVisitor::SearchPhiPlaceholdersForKeptStores() {
2433*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<uint32_t> work_queue(allocator_.Adapter(kArenaAllocLSE));
2434*795d594fSAndroid Build Coastguard Worker   size_t start_size = phi_placeholders_to_search_for_kept_stores_.NumSetBits();
2435*795d594fSAndroid Build Coastguard Worker   work_queue.reserve(((start_size * 3u) + 1u) / 2u);  // Reserve 1.5x start size, rounded up.
2436*795d594fSAndroid Build Coastguard Worker   for (uint32_t index : phi_placeholders_to_search_for_kept_stores_.Indexes()) {
2437*795d594fSAndroid Build Coastguard Worker     work_queue.push_back(index);
2438*795d594fSAndroid Build Coastguard Worker   }
2439*795d594fSAndroid Build Coastguard Worker   const ArenaVector<HBasicBlock*>& blocks = GetGraph()->GetBlocks();
2440*795d594fSAndroid Build Coastguard Worker   while (!work_queue.empty()) {
2441*795d594fSAndroid Build Coastguard Worker     uint32_t cur_phi_idx = work_queue.back();
2442*795d594fSAndroid Build Coastguard Worker     PhiPlaceholder phi_placeholder = GetPhiPlaceholderAt(cur_phi_idx);
2443*795d594fSAndroid Build Coastguard Worker     work_queue.pop_back();
2444*795d594fSAndroid Build Coastguard Worker     size_t idx = phi_placeholder.GetHeapLocation();
2445*795d594fSAndroid Build Coastguard Worker     HBasicBlock* block = blocks[phi_placeholder.GetBlockId()];
2446*795d594fSAndroid Build Coastguard Worker     DCHECK(block != nullptr) << cur_phi_idx << " phi: " << phi_placeholder
2447*795d594fSAndroid Build Coastguard Worker                              << " (blocks: " << blocks.size() << ")";
2448*795d594fSAndroid Build Coastguard Worker     for (HBasicBlock* predecessor : block->GetPredecessors()) {
2449*795d594fSAndroid Build Coastguard Worker       ScopedArenaVector<ValueRecord>& heap_values = heap_values_for_[predecessor->GetBlockId()];
2450*795d594fSAndroid Build Coastguard Worker       // For loop back-edges we must also preserve all stores to locations that
2451*795d594fSAndroid Build Coastguard Worker       // may alias with the location `idx`.
2452*795d594fSAndroid Build Coastguard Worker       // TODO: Add tests cases around this.
2453*795d594fSAndroid Build Coastguard Worker       bool is_back_edge =
2454*795d594fSAndroid Build Coastguard Worker           block->IsLoopHeader() && predecessor != block->GetLoopInformation()->GetPreHeader();
2455*795d594fSAndroid Build Coastguard Worker       size_t start = is_back_edge ? 0u : idx;
2456*795d594fSAndroid Build Coastguard Worker       size_t end = is_back_edge ? heap_values.size() : idx + 1u;
2457*795d594fSAndroid Build Coastguard Worker       for (size_t i = start; i != end; ++i) {
2458*795d594fSAndroid Build Coastguard Worker         Value stored_by = heap_values[i].stored_by;
2459*795d594fSAndroid Build Coastguard Worker         if (!stored_by.IsUnknown() && (i == idx || MayAliasOnBackEdge(block, idx, i))) {
2460*795d594fSAndroid Build Coastguard Worker           if (stored_by.NeedsPhi()) {
2461*795d594fSAndroid Build Coastguard Worker             size_t phi_placeholder_index = PhiPlaceholderIndex(stored_by);
2462*795d594fSAndroid Build Coastguard Worker             if (!phi_placeholders_to_search_for_kept_stores_.IsBitSet(phi_placeholder_index)) {
2463*795d594fSAndroid Build Coastguard Worker               phi_placeholders_to_search_for_kept_stores_.SetBit(phi_placeholder_index);
2464*795d594fSAndroid Build Coastguard Worker               work_queue.push_back(phi_placeholder_index);
2465*795d594fSAndroid Build Coastguard Worker             }
2466*795d594fSAndroid Build Coastguard Worker           } else {
2467*795d594fSAndroid Build Coastguard Worker             DCHECK(IsStore(stored_by.GetInstruction()));
2468*795d594fSAndroid Build Coastguard Worker             ReferenceInfo* ri = heap_location_collector_.GetHeapLocation(i)->GetReferenceInfo();
2469*795d594fSAndroid Build Coastguard Worker             DCHECK(ri != nullptr) << "No heap value for " << stored_by.GetInstruction()->DebugName()
2470*795d594fSAndroid Build Coastguard Worker                                   << " id: " << stored_by.GetInstruction()->GetId() << " block: "
2471*795d594fSAndroid Build Coastguard Worker                                   << stored_by.GetInstruction()->GetBlock()->GetBlockId();
2472*795d594fSAndroid Build Coastguard Worker             kept_stores_.SetBit(stored_by.GetInstruction()->GetId());
2473*795d594fSAndroid Build Coastguard Worker           }
2474*795d594fSAndroid Build Coastguard Worker         }
2475*795d594fSAndroid Build Coastguard Worker       }
2476*795d594fSAndroid Build Coastguard Worker     }
2477*795d594fSAndroid Build Coastguard Worker   }
2478*795d594fSAndroid Build Coastguard Worker }
2479*795d594fSAndroid Build Coastguard Worker 
UpdateValueRecordForStoreElimination(ValueRecord * value_record)2480*795d594fSAndroid Build Coastguard Worker void LSEVisitor::UpdateValueRecordForStoreElimination(/*inout*/ValueRecord* value_record) {
2481*795d594fSAndroid Build Coastguard Worker   while (value_record->stored_by.IsInstruction() &&
2482*795d594fSAndroid Build Coastguard Worker          !kept_stores_.IsBitSet(value_record->stored_by.GetInstruction()->GetId())) {
2483*795d594fSAndroid Build Coastguard Worker     StoreRecord* store_record = store_records_[value_record->stored_by.GetInstruction()->GetId()];
2484*795d594fSAndroid Build Coastguard Worker     DCHECK(store_record != nullptr);
2485*795d594fSAndroid Build Coastguard Worker     *value_record = store_record->old_value_record;
2486*795d594fSAndroid Build Coastguard Worker   }
2487*795d594fSAndroid Build Coastguard Worker   if (value_record->stored_by.NeedsPhi() &&
2488*795d594fSAndroid Build Coastguard Worker       !phi_placeholders_to_search_for_kept_stores_.IsBitSet(
2489*795d594fSAndroid Build Coastguard Worker            PhiPlaceholderIndex(value_record->stored_by))) {
2490*795d594fSAndroid Build Coastguard Worker     // Some stores feeding this heap location may have been eliminated. Use the `stored_by`
2491*795d594fSAndroid Build Coastguard Worker     // Phi placeholder to recalculate the actual value.
2492*795d594fSAndroid Build Coastguard Worker     value_record->value = value_record->stored_by;
2493*795d594fSAndroid Build Coastguard Worker   }
2494*795d594fSAndroid Build Coastguard Worker   value_record->value = ReplacementOrValue(value_record->value);
2495*795d594fSAndroid Build Coastguard Worker   if (value_record->value.NeedsNonLoopPhi()) {
2496*795d594fSAndroid Build Coastguard Worker     // Treat all Phi placeholders as requiring loop Phis at this point.
2497*795d594fSAndroid Build Coastguard Worker     // We do not want MaterializeLoopPhis() to call MaterializeNonLoopPhis().
2498*795d594fSAndroid Build Coastguard Worker     value_record->value = Value::ForLoopPhiPlaceholder(value_record->value.GetPhiPlaceholder());
2499*795d594fSAndroid Build Coastguard Worker   }
2500*795d594fSAndroid Build Coastguard Worker }
2501*795d594fSAndroid Build Coastguard Worker 
FindOldValueForPhiPlaceholder(PhiPlaceholder phi_placeholder,DataType::Type type)2502*795d594fSAndroid Build Coastguard Worker void LSEVisitor::FindOldValueForPhiPlaceholder(PhiPlaceholder phi_placeholder,
2503*795d594fSAndroid Build Coastguard Worker                                                DataType::Type type) {
2504*795d594fSAndroid Build Coastguard Worker   DCHECK(phi_placeholder_replacements_[PhiPlaceholderIndex(phi_placeholder)].IsInvalid());
2505*795d594fSAndroid Build Coastguard Worker 
2506*795d594fSAndroid Build Coastguard Worker   // Use local allocator to reduce peak memory usage.
2507*795d594fSAndroid Build Coastguard Worker   ScopedArenaAllocator allocator(allocator_.GetArenaStack());
2508*795d594fSAndroid Build Coastguard Worker   ArenaBitVector visited(&allocator,
2509*795d594fSAndroid Build Coastguard Worker                          /*start_bits=*/ num_phi_placeholders_,
2510*795d594fSAndroid Build Coastguard Worker                          /*expandable=*/ false,
2511*795d594fSAndroid Build Coastguard Worker                          kArenaAllocLSE);
2512*795d594fSAndroid Build Coastguard Worker 
2513*795d594fSAndroid Build Coastguard Worker   // Find Phi placeholders to try and match against existing Phis or other replacement values.
2514*795d594fSAndroid Build Coastguard Worker   ArenaBitVector phi_placeholders_to_materialize(
2515*795d594fSAndroid Build Coastguard Worker       &allocator, num_phi_placeholders_, /*expandable=*/ false, kArenaAllocLSE);
2516*795d594fSAndroid Build Coastguard Worker   std::optional<PhiPlaceholder> loop_phi_with_unknown_input = FindLoopPhisToMaterialize(
2517*795d594fSAndroid Build Coastguard Worker       phi_placeholder, &phi_placeholders_to_materialize, type, /*can_use_default_or_phi=*/true);
2518*795d594fSAndroid Build Coastguard Worker   if (loop_phi_with_unknown_input) {
2519*795d594fSAndroid Build Coastguard Worker     DCHECK_GE(GetGraph()
2520*795d594fSAndroid Build Coastguard Worker                   ->GetBlocks()[loop_phi_with_unknown_input->GetBlockId()]
2521*795d594fSAndroid Build Coastguard Worker                   ->GetPredecessors()
2522*795d594fSAndroid Build Coastguard Worker                   .size(),
2523*795d594fSAndroid Build Coastguard Worker               2u);
2524*795d594fSAndroid Build Coastguard Worker     // Mark the unreplacable placeholder as well as the input Phi placeholder as unreplaceable.
2525*795d594fSAndroid Build Coastguard Worker     phi_placeholder_replacements_[PhiPlaceholderIndex(phi_placeholder)] = Value::Unknown();
2526*795d594fSAndroid Build Coastguard Worker     phi_placeholder_replacements_[PhiPlaceholderIndex(*loop_phi_with_unknown_input)] =
2527*795d594fSAndroid Build Coastguard Worker         Value::Unknown();
2528*795d594fSAndroid Build Coastguard Worker     return;
2529*795d594fSAndroid Build Coastguard Worker   }
2530*795d594fSAndroid Build Coastguard Worker 
2531*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(current_phase_, Phase::kStoreElimination);
2532*795d594fSAndroid Build Coastguard Worker   bool success = MaterializeLoopPhis(phi_placeholders_to_materialize, type);
2533*795d594fSAndroid Build Coastguard Worker   DCHECK(phi_placeholder_replacements_[PhiPlaceholderIndex(phi_placeholder)].IsValid());
2534*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(phi_placeholder_replacements_[PhiPlaceholderIndex(phi_placeholder)].IsUnknown(),
2535*795d594fSAndroid Build Coastguard Worker             !success);
2536*795d594fSAndroid Build Coastguard Worker }
2537*795d594fSAndroid Build Coastguard Worker 
FindStoresWritingOldValues()2538*795d594fSAndroid Build Coastguard Worker void LSEVisitor::FindStoresWritingOldValues() {
2539*795d594fSAndroid Build Coastguard Worker   // The Phi placeholder replacements have so far been used for eliminating loads,
2540*795d594fSAndroid Build Coastguard Worker   // tracking values that would be stored if all stores were kept. As we want to
2541*795d594fSAndroid Build Coastguard Worker   // compare actual old values after removing unmarked stores, prune the Phi
2542*795d594fSAndroid Build Coastguard Worker   // placeholder replacements that can be fed by values we may not actually store.
2543*795d594fSAndroid Build Coastguard Worker   // Replacements marked as unknown can be kept as they are fed by some unknown
2544*795d594fSAndroid Build Coastguard Worker   // value and would end up as unknown again if we recalculated them.
2545*795d594fSAndroid Build Coastguard Worker   for (size_t i = 0, size = phi_placeholder_replacements_.size(); i != size; ++i) {
2546*795d594fSAndroid Build Coastguard Worker     if (!phi_placeholder_replacements_[i].IsUnknown() &&
2547*795d594fSAndroid Build Coastguard Worker         !phi_placeholders_to_search_for_kept_stores_.IsBitSet(i)) {
2548*795d594fSAndroid Build Coastguard Worker       phi_placeholder_replacements_[i] = Value::Invalid();
2549*795d594fSAndroid Build Coastguard Worker     }
2550*795d594fSAndroid Build Coastguard Worker   }
2551*795d594fSAndroid Build Coastguard Worker 
2552*795d594fSAndroid Build Coastguard Worker   // Update heap values at end of blocks.
2553*795d594fSAndroid Build Coastguard Worker   for (HBasicBlock* block : GetGraph()->GetReversePostOrder()) {
2554*795d594fSAndroid Build Coastguard Worker     for (ValueRecord& value_record : heap_values_for_[block->GetBlockId()]) {
2555*795d594fSAndroid Build Coastguard Worker       UpdateValueRecordForStoreElimination(&value_record);
2556*795d594fSAndroid Build Coastguard Worker     }
2557*795d594fSAndroid Build Coastguard Worker   }
2558*795d594fSAndroid Build Coastguard Worker 
2559*795d594fSAndroid Build Coastguard Worker   // Use local allocator to reduce peak memory usage.
2560*795d594fSAndroid Build Coastguard Worker   ScopedArenaAllocator allocator(allocator_.GetArenaStack());
2561*795d594fSAndroid Build Coastguard Worker   // Mark the stores we want to eliminate in a separate bit vector.
2562*795d594fSAndroid Build Coastguard Worker   ArenaBitVector eliminated_stores(&allocator,
2563*795d594fSAndroid Build Coastguard Worker                                    /*start_bits=*/ GetGraph()->GetCurrentInstructionId(),
2564*795d594fSAndroid Build Coastguard Worker                                    /*expandable=*/ false,
2565*795d594fSAndroid Build Coastguard Worker                                    kArenaAllocLSE);
2566*795d594fSAndroid Build Coastguard Worker 
2567*795d594fSAndroid Build Coastguard Worker   for (uint32_t store_id : kept_stores_.Indexes()) {
2568*795d594fSAndroid Build Coastguard Worker     DCHECK(kept_stores_.IsBitSet(store_id));
2569*795d594fSAndroid Build Coastguard Worker     StoreRecord* store_record = store_records_[store_id];
2570*795d594fSAndroid Build Coastguard Worker     DCHECK(store_record != nullptr);
2571*795d594fSAndroid Build Coastguard Worker     UpdateValueRecordForStoreElimination(&store_record->old_value_record);
2572*795d594fSAndroid Build Coastguard Worker     if (store_record->old_value_record.value.NeedsPhi()) {
2573*795d594fSAndroid Build Coastguard Worker       DataType::Type type = store_record->stored_value->GetType();
2574*795d594fSAndroid Build Coastguard Worker       FindOldValueForPhiPlaceholder(store_record->old_value_record.value.GetPhiPlaceholder(), type);
2575*795d594fSAndroid Build Coastguard Worker       store_record->old_value_record.value =
2576*795d594fSAndroid Build Coastguard Worker           ReplacementOrValue(store_record->old_value_record.value);
2577*795d594fSAndroid Build Coastguard Worker     }
2578*795d594fSAndroid Build Coastguard Worker     DCHECK(!store_record->old_value_record.value.NeedsPhi());
2579*795d594fSAndroid Build Coastguard Worker     HInstruction* stored_value = FindSubstitute(store_record->stored_value);
2580*795d594fSAndroid Build Coastguard Worker     if (store_record->old_value_record.value.Equals(stored_value)) {
2581*795d594fSAndroid Build Coastguard Worker       eliminated_stores.SetBit(store_id);
2582*795d594fSAndroid Build Coastguard Worker     }
2583*795d594fSAndroid Build Coastguard Worker   }
2584*795d594fSAndroid Build Coastguard Worker 
2585*795d594fSAndroid Build Coastguard Worker   // Commit the stores to eliminate by removing them from `kept_stores_`.
2586*795d594fSAndroid Build Coastguard Worker   kept_stores_.Subtract(&eliminated_stores);
2587*795d594fSAndroid Build Coastguard Worker }
2588*795d594fSAndroid Build Coastguard Worker 
Run()2589*795d594fSAndroid Build Coastguard Worker void LSEVisitor::Run() {
2590*795d594fSAndroid Build Coastguard Worker   // 0. Set HasMonitorOperations to false. If we encounter some MonitorOperations that we can't
2591*795d594fSAndroid Build Coastguard Worker   // remove, we will set it to true in VisitMonitorOperation.
2592*795d594fSAndroid Build Coastguard Worker   GetGraph()->SetHasMonitorOperations(false);
2593*795d594fSAndroid Build Coastguard Worker 
2594*795d594fSAndroid Build Coastguard Worker   // 1. Process blocks and instructions in reverse post order.
2595*795d594fSAndroid Build Coastguard Worker   for (HBasicBlock* block : GetGraph()->GetReversePostOrder()) {
2596*795d594fSAndroid Build Coastguard Worker     VisitBasicBlock(block);
2597*795d594fSAndroid Build Coastguard Worker   }
2598*795d594fSAndroid Build Coastguard Worker 
2599*795d594fSAndroid Build Coastguard Worker   // 2. Process loads that require loop Phis, trying to find/create replacements.
2600*795d594fSAndroid Build Coastguard Worker   current_phase_ = Phase::kLoadElimination;
2601*795d594fSAndroid Build Coastguard Worker   ProcessLoadsRequiringLoopPhis();
2602*795d594fSAndroid Build Coastguard Worker 
2603*795d594fSAndroid Build Coastguard Worker   // 3. Determine which stores to keep and which to eliminate.
2604*795d594fSAndroid Build Coastguard Worker   current_phase_ = Phase::kStoreElimination;
2605*795d594fSAndroid Build Coastguard Worker   // Finish marking stores for keeping.
2606*795d594fSAndroid Build Coastguard Worker   SearchPhiPlaceholdersForKeptStores();
2607*795d594fSAndroid Build Coastguard Worker 
2608*795d594fSAndroid Build Coastguard Worker   // Find stores that write the same value as is already present in the location.
2609*795d594fSAndroid Build Coastguard Worker   FindStoresWritingOldValues();
2610*795d594fSAndroid Build Coastguard Worker 
2611*795d594fSAndroid Build Coastguard Worker   // 4. Replace loads and remove unnecessary stores and singleton allocations.
2612*795d594fSAndroid Build Coastguard Worker   FinishFullLSE();
2613*795d594fSAndroid Build Coastguard Worker }
2614*795d594fSAndroid Build Coastguard Worker 
2615*795d594fSAndroid Build Coastguard Worker 
FinishFullLSE()2616*795d594fSAndroid Build Coastguard Worker void LSEVisitor::FinishFullLSE() {
2617*795d594fSAndroid Build Coastguard Worker   // Remove recorded load instructions that should be eliminated.
2618*795d594fSAndroid Build Coastguard Worker   for (const LoadStoreRecord& record : loads_and_stores_) {
2619*795d594fSAndroid Build Coastguard Worker     size_t id = dchecked_integral_cast<size_t>(record.load_or_store->GetId());
2620*795d594fSAndroid Build Coastguard Worker     HInstruction* substitute = substitute_instructions_for_loads_[id];
2621*795d594fSAndroid Build Coastguard Worker     if (substitute == nullptr) {
2622*795d594fSAndroid Build Coastguard Worker       continue;
2623*795d594fSAndroid Build Coastguard Worker     }
2624*795d594fSAndroid Build Coastguard Worker     HInstruction* load = record.load_or_store;
2625*795d594fSAndroid Build Coastguard Worker     DCHECK(load != nullptr);
2626*795d594fSAndroid Build Coastguard Worker     DCHECK(IsLoad(load));
2627*795d594fSAndroid Build Coastguard Worker     DCHECK(load->GetBlock() != nullptr) << load->DebugName() << "@" << load->GetDexPc();
2628*795d594fSAndroid Build Coastguard Worker     // We proactively retrieve the substitute for a removed load, so
2629*795d594fSAndroid Build Coastguard Worker     // a load that has a substitute should not be observed as a heap
2630*795d594fSAndroid Build Coastguard Worker     // location value.
2631*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(FindSubstitute(substitute), substitute);
2632*795d594fSAndroid Build Coastguard Worker 
2633*795d594fSAndroid Build Coastguard Worker     load->ReplaceWith(substitute);
2634*795d594fSAndroid Build Coastguard Worker     load->GetBlock()->RemoveInstruction(load);
2635*795d594fSAndroid Build Coastguard Worker     if ((load->IsInstanceFieldGet() && load->AsInstanceFieldGet()->IsVolatile()) ||
2636*795d594fSAndroid Build Coastguard Worker         (load->IsStaticFieldGet() && load->AsStaticFieldGet()->IsVolatile())) {
2637*795d594fSAndroid Build Coastguard Worker       MaybeRecordStat(stats_, MethodCompilationStat::kRemovedVolatileLoad);
2638*795d594fSAndroid Build Coastguard Worker     }
2639*795d594fSAndroid Build Coastguard Worker   }
2640*795d594fSAndroid Build Coastguard Worker 
2641*795d594fSAndroid Build Coastguard Worker   // Remove all the stores we can.
2642*795d594fSAndroid Build Coastguard Worker   for (const LoadStoreRecord& record : loads_and_stores_) {
2643*795d594fSAndroid Build Coastguard Worker     if (IsStore(record.load_or_store) && !kept_stores_.IsBitSet(record.load_or_store->GetId())) {
2644*795d594fSAndroid Build Coastguard Worker       record.load_or_store->GetBlock()->RemoveInstruction(record.load_or_store);
2645*795d594fSAndroid Build Coastguard Worker       if ((record.load_or_store->IsInstanceFieldSet() &&
2646*795d594fSAndroid Build Coastguard Worker            record.load_or_store->AsInstanceFieldSet()->IsVolatile()) ||
2647*795d594fSAndroid Build Coastguard Worker           (record.load_or_store->IsStaticFieldSet() &&
2648*795d594fSAndroid Build Coastguard Worker            record.load_or_store->AsStaticFieldSet()->IsVolatile())) {
2649*795d594fSAndroid Build Coastguard Worker         MaybeRecordStat(stats_, MethodCompilationStat::kRemovedVolatileStore);
2650*795d594fSAndroid Build Coastguard Worker       }
2651*795d594fSAndroid Build Coastguard Worker     }
2652*795d594fSAndroid Build Coastguard Worker   }
2653*795d594fSAndroid Build Coastguard Worker 
2654*795d594fSAndroid Build Coastguard Worker   // Eliminate singleton-classified instructions:
2655*795d594fSAndroid Build Coastguard Worker   //   * - Constructor fences (they never escape this thread).
2656*795d594fSAndroid Build Coastguard Worker   //   * - Allocations (if they are unused).
2657*795d594fSAndroid Build Coastguard Worker   for (HInstruction* new_instance : singleton_new_instances_) {
2658*795d594fSAndroid Build Coastguard Worker     size_t removed = HConstructorFence::RemoveConstructorFences(new_instance);
2659*795d594fSAndroid Build Coastguard Worker     MaybeRecordStat(stats_,
2660*795d594fSAndroid Build Coastguard Worker                     MethodCompilationStat::kConstructorFenceRemovedLSE,
2661*795d594fSAndroid Build Coastguard Worker                     removed);
2662*795d594fSAndroid Build Coastguard Worker 
2663*795d594fSAndroid Build Coastguard Worker     if (!new_instance->HasNonEnvironmentUses()) {
2664*795d594fSAndroid Build Coastguard Worker       new_instance->RemoveEnvironmentUsers();
2665*795d594fSAndroid Build Coastguard Worker       new_instance->GetBlock()->RemoveInstruction(new_instance);
2666*795d594fSAndroid Build Coastguard Worker       MaybeRecordStat(stats_, MethodCompilationStat::kFullLSEAllocationRemoved);
2667*795d594fSAndroid Build Coastguard Worker     }
2668*795d594fSAndroid Build Coastguard Worker   }
2669*795d594fSAndroid Build Coastguard Worker }
2670*795d594fSAndroid Build Coastguard Worker 
2671*795d594fSAndroid Build Coastguard Worker // The LSEVisitor is a ValueObject (indirectly through base classes) and therefore
2672*795d594fSAndroid Build Coastguard Worker // cannot be directly allocated with an arena allocator, so we need to wrap it.
2673*795d594fSAndroid Build Coastguard Worker class LSEVisitorWrapper : public DeletableArenaObject<kArenaAllocLSE> {
2674*795d594fSAndroid Build Coastguard Worker  public:
LSEVisitorWrapper(HGraph * graph,const HeapLocationCollector & heap_location_collector,OptimizingCompilerStats * stats)2675*795d594fSAndroid Build Coastguard Worker   LSEVisitorWrapper(HGraph* graph,
2676*795d594fSAndroid Build Coastguard Worker                     const HeapLocationCollector& heap_location_collector,
2677*795d594fSAndroid Build Coastguard Worker                     OptimizingCompilerStats* stats)
2678*795d594fSAndroid Build Coastguard Worker       : lse_visitor_(graph, heap_location_collector, stats) {}
2679*795d594fSAndroid Build Coastguard Worker 
Run()2680*795d594fSAndroid Build Coastguard Worker   void Run() {
2681*795d594fSAndroid Build Coastguard Worker     lse_visitor_.Run();
2682*795d594fSAndroid Build Coastguard Worker   }
2683*795d594fSAndroid Build Coastguard Worker 
2684*795d594fSAndroid Build Coastguard Worker  private:
2685*795d594fSAndroid Build Coastguard Worker   LSEVisitor lse_visitor_;
2686*795d594fSAndroid Build Coastguard Worker };
2687*795d594fSAndroid Build Coastguard Worker 
Run()2688*795d594fSAndroid Build Coastguard Worker bool LoadStoreElimination::Run() {
2689*795d594fSAndroid Build Coastguard Worker   if (graph_->IsDebuggable()) {
2690*795d594fSAndroid Build Coastguard Worker     // Debugger may set heap values or trigger deoptimization of callers.
2691*795d594fSAndroid Build Coastguard Worker     // Skip this optimization.
2692*795d594fSAndroid Build Coastguard Worker     return false;
2693*795d594fSAndroid Build Coastguard Worker   }
2694*795d594fSAndroid Build Coastguard Worker   ScopedArenaAllocator allocator(graph_->GetArenaStack());
2695*795d594fSAndroid Build Coastguard Worker   LoadStoreAnalysis lsa(graph_, stats_, &allocator);
2696*795d594fSAndroid Build Coastguard Worker   lsa.Run();
2697*795d594fSAndroid Build Coastguard Worker   const HeapLocationCollector& heap_location_collector = lsa.GetHeapLocationCollector();
2698*795d594fSAndroid Build Coastguard Worker   if (heap_location_collector.GetNumberOfHeapLocations() == 0) {
2699*795d594fSAndroid Build Coastguard Worker     // No HeapLocation information from LSA, skip this optimization.
2700*795d594fSAndroid Build Coastguard Worker     return false;
2701*795d594fSAndroid Build Coastguard Worker   }
2702*795d594fSAndroid Build Coastguard Worker 
2703*795d594fSAndroid Build Coastguard Worker   // Currently load_store analysis can't handle predicated load/stores; specifically pairs of
2704*795d594fSAndroid Build Coastguard Worker   // memory operations with different predicates.
2705*795d594fSAndroid Build Coastguard Worker   // TODO: support predicated SIMD.
2706*795d594fSAndroid Build Coastguard Worker   if (graph_->HasPredicatedSIMD()) {
2707*795d594fSAndroid Build Coastguard Worker     return false;
2708*795d594fSAndroid Build Coastguard Worker   }
2709*795d594fSAndroid Build Coastguard Worker 
2710*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<LSEVisitorWrapper> lse_visitor(
2711*795d594fSAndroid Build Coastguard Worker       new (&allocator) LSEVisitorWrapper(graph_, heap_location_collector, stats_));
2712*795d594fSAndroid Build Coastguard Worker   lse_visitor->Run();
2713*795d594fSAndroid Build Coastguard Worker   return true;
2714*795d594fSAndroid Build Coastguard Worker }
2715*795d594fSAndroid Build Coastguard Worker 
2716*795d594fSAndroid Build Coastguard Worker #undef LSE_VLOG
2717*795d594fSAndroid Build Coastguard Worker 
2718*795d594fSAndroid Build Coastguard Worker }  // namespace art
2719