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