xref: /aosp_15_r20/art/compiler/optimizing/gvn.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2014 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 "gvn.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include "base/arena_bit_vector.h"
20*795d594fSAndroid Build Coastguard Worker #include "base/bit_vector-inl.h"
21*795d594fSAndroid Build Coastguard Worker #include "base/scoped_arena_allocator.h"
22*795d594fSAndroid Build Coastguard Worker #include "base/scoped_arena_containers.h"
23*795d594fSAndroid Build Coastguard Worker #include "base/utils.h"
24*795d594fSAndroid Build Coastguard Worker #include "side_effects_analysis.h"
25*795d594fSAndroid Build Coastguard Worker 
26*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
27*795d594fSAndroid Build Coastguard Worker 
28*795d594fSAndroid Build Coastguard Worker /**
29*795d594fSAndroid Build Coastguard Worker  * A ValueSet holds instructions that can replace other instructions. It is updated
30*795d594fSAndroid Build Coastguard Worker  * through the `Add` method, and the `Kill` method. The `Kill` method removes
31*795d594fSAndroid Build Coastguard Worker  * instructions that are affected by the given side effect.
32*795d594fSAndroid Build Coastguard Worker  *
33*795d594fSAndroid Build Coastguard Worker  * The `Lookup` method returns an equivalent instruction to the given instruction
34*795d594fSAndroid Build Coastguard Worker  * if there is one in the set. In GVN, we would say those instructions have the
35*795d594fSAndroid Build Coastguard Worker  * same "number".
36*795d594fSAndroid Build Coastguard Worker  */
37*795d594fSAndroid Build Coastguard Worker class ValueSet : public ArenaObject<kArenaAllocGvn> {
38*795d594fSAndroid Build Coastguard Worker  public:
39*795d594fSAndroid Build Coastguard Worker   // Constructs an empty ValueSet which owns all its buckets.
ValueSet(ScopedArenaAllocator * allocator)40*795d594fSAndroid Build Coastguard Worker   explicit ValueSet(ScopedArenaAllocator* allocator)
41*795d594fSAndroid Build Coastguard Worker       : allocator_(allocator),
42*795d594fSAndroid Build Coastguard Worker         num_buckets_(kMinimumNumberOfBuckets),
43*795d594fSAndroid Build Coastguard Worker         buckets_(allocator->AllocArray<Node*>(num_buckets_, kArenaAllocGvn)),
44*795d594fSAndroid Build Coastguard Worker         buckets_owned_(allocator, num_buckets_, false, kArenaAllocGvn),
45*795d594fSAndroid Build Coastguard Worker         num_entries_(0u) {
46*795d594fSAndroid Build Coastguard Worker     DCHECK(IsPowerOfTwo(num_buckets_));
47*795d594fSAndroid Build Coastguard Worker     std::fill_n(buckets_, num_buckets_, nullptr);
48*795d594fSAndroid Build Coastguard Worker     buckets_owned_.SetInitialBits(num_buckets_);
49*795d594fSAndroid Build Coastguard Worker   }
50*795d594fSAndroid Build Coastguard Worker 
51*795d594fSAndroid Build Coastguard Worker   // Copy constructor. Depending on the load factor, it will either make a deep
52*795d594fSAndroid Build Coastguard Worker   // copy (all buckets owned) or a shallow one (buckets pointing to the parent).
ValueSet(ScopedArenaAllocator * allocator,const ValueSet & other)53*795d594fSAndroid Build Coastguard Worker   ValueSet(ScopedArenaAllocator* allocator, const ValueSet& other)
54*795d594fSAndroid Build Coastguard Worker       : allocator_(allocator),
55*795d594fSAndroid Build Coastguard Worker         num_buckets_(other.IdealBucketCount()),
56*795d594fSAndroid Build Coastguard Worker         buckets_(allocator->AllocArray<Node*>(num_buckets_, kArenaAllocGvn)),
57*795d594fSAndroid Build Coastguard Worker         buckets_owned_(allocator, num_buckets_, false, kArenaAllocGvn),
58*795d594fSAndroid Build Coastguard Worker         num_entries_(0u) {
59*795d594fSAndroid Build Coastguard Worker     DCHECK(IsPowerOfTwo(num_buckets_));
60*795d594fSAndroid Build Coastguard Worker     PopulateFromInternal(other);
61*795d594fSAndroid Build Coastguard Worker   }
62*795d594fSAndroid Build Coastguard Worker 
63*795d594fSAndroid Build Coastguard Worker   // Erases all values in this set and populates it with values from `other`.
PopulateFrom(const ValueSet & other)64*795d594fSAndroid Build Coastguard Worker   void PopulateFrom(const ValueSet& other) {
65*795d594fSAndroid Build Coastguard Worker     if (this == &other) {
66*795d594fSAndroid Build Coastguard Worker       return;
67*795d594fSAndroid Build Coastguard Worker     }
68*795d594fSAndroid Build Coastguard Worker     PopulateFromInternal(other);
69*795d594fSAndroid Build Coastguard Worker   }
70*795d594fSAndroid Build Coastguard Worker 
71*795d594fSAndroid Build Coastguard Worker   // Returns true if `this` has enough buckets so that if `other` is copied into
72*795d594fSAndroid Build Coastguard Worker   // it, the load factor will not cross the upper threshold.
73*795d594fSAndroid Build Coastguard Worker   // If `exact_match` is set, true is returned only if `this` has the ideal
74*795d594fSAndroid Build Coastguard Worker   // number of buckets. Larger number of buckets is allowed otherwise.
CanHoldCopyOf(const ValueSet & other,bool exact_match)75*795d594fSAndroid Build Coastguard Worker   bool CanHoldCopyOf(const ValueSet& other, bool exact_match) {
76*795d594fSAndroid Build Coastguard Worker     if (exact_match) {
77*795d594fSAndroid Build Coastguard Worker       return other.IdealBucketCount() == num_buckets_;
78*795d594fSAndroid Build Coastguard Worker     } else {
79*795d594fSAndroid Build Coastguard Worker       return other.IdealBucketCount() <= num_buckets_;
80*795d594fSAndroid Build Coastguard Worker     }
81*795d594fSAndroid Build Coastguard Worker   }
82*795d594fSAndroid Build Coastguard Worker 
83*795d594fSAndroid Build Coastguard Worker   // Adds an instruction in the set.
Add(HInstruction * instruction)84*795d594fSAndroid Build Coastguard Worker   void Add(HInstruction* instruction) {
85*795d594fSAndroid Build Coastguard Worker     DCHECK(Lookup(instruction) == nullptr);
86*795d594fSAndroid Build Coastguard Worker     size_t hash_code = HashCode(instruction);
87*795d594fSAndroid Build Coastguard Worker     size_t index = BucketIndex(hash_code);
88*795d594fSAndroid Build Coastguard Worker 
89*795d594fSAndroid Build Coastguard Worker     if (!buckets_owned_.IsBitSet(index)) {
90*795d594fSAndroid Build Coastguard Worker       CloneBucket(index);
91*795d594fSAndroid Build Coastguard Worker     }
92*795d594fSAndroid Build Coastguard Worker     buckets_[index] = new (allocator_) Node(instruction, hash_code, buckets_[index]);
93*795d594fSAndroid Build Coastguard Worker     ++num_entries_;
94*795d594fSAndroid Build Coastguard Worker   }
95*795d594fSAndroid Build Coastguard Worker 
96*795d594fSAndroid Build Coastguard Worker   // If in the set, returns an equivalent instruction to the given instruction.
97*795d594fSAndroid Build Coastguard Worker   // Returns null otherwise.
Lookup(HInstruction * instruction) const98*795d594fSAndroid Build Coastguard Worker   HInstruction* Lookup(HInstruction* instruction) const {
99*795d594fSAndroid Build Coastguard Worker     size_t hash_code = HashCode(instruction);
100*795d594fSAndroid Build Coastguard Worker     size_t index = BucketIndex(hash_code);
101*795d594fSAndroid Build Coastguard Worker 
102*795d594fSAndroid Build Coastguard Worker     for (Node* node = buckets_[index]; node != nullptr; node = node->GetNext()) {
103*795d594fSAndroid Build Coastguard Worker       if (node->GetHashCode() == hash_code) {
104*795d594fSAndroid Build Coastguard Worker         HInstruction* existing = node->GetInstruction();
105*795d594fSAndroid Build Coastguard Worker         if (existing->Equals(instruction)) {
106*795d594fSAndroid Build Coastguard Worker           return existing;
107*795d594fSAndroid Build Coastguard Worker         }
108*795d594fSAndroid Build Coastguard Worker       }
109*795d594fSAndroid Build Coastguard Worker     }
110*795d594fSAndroid Build Coastguard Worker     return nullptr;
111*795d594fSAndroid Build Coastguard Worker   }
112*795d594fSAndroid Build Coastguard Worker 
113*795d594fSAndroid Build Coastguard Worker   // Returns whether instruction is in the set.
Contains(HInstruction * instruction) const114*795d594fSAndroid Build Coastguard Worker   bool Contains(HInstruction* instruction) const {
115*795d594fSAndroid Build Coastguard Worker     size_t hash_code = HashCode(instruction);
116*795d594fSAndroid Build Coastguard Worker     size_t index = BucketIndex(hash_code);
117*795d594fSAndroid Build Coastguard Worker 
118*795d594fSAndroid Build Coastguard Worker     for (Node* node = buckets_[index]; node != nullptr; node = node->GetNext()) {
119*795d594fSAndroid Build Coastguard Worker       if (node->GetInstruction() == instruction) {
120*795d594fSAndroid Build Coastguard Worker         return true;
121*795d594fSAndroid Build Coastguard Worker       }
122*795d594fSAndroid Build Coastguard Worker     }
123*795d594fSAndroid Build Coastguard Worker     return false;
124*795d594fSAndroid Build Coastguard Worker   }
125*795d594fSAndroid Build Coastguard Worker 
126*795d594fSAndroid Build Coastguard Worker   // Removes all instructions in the set affected by the given side effects.
Kill(SideEffects side_effects)127*795d594fSAndroid Build Coastguard Worker   void Kill(SideEffects side_effects) {
128*795d594fSAndroid Build Coastguard Worker     DeleteAllImpureWhich([side_effects](Node* node) {
129*795d594fSAndroid Build Coastguard Worker       return node->GetSideEffects().MayDependOn(side_effects);
130*795d594fSAndroid Build Coastguard Worker     });
131*795d594fSAndroid Build Coastguard Worker   }
132*795d594fSAndroid Build Coastguard Worker 
Clear()133*795d594fSAndroid Build Coastguard Worker   void Clear() {
134*795d594fSAndroid Build Coastguard Worker     num_entries_ = 0;
135*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0; i < num_buckets_; ++i) {
136*795d594fSAndroid Build Coastguard Worker       buckets_[i] = nullptr;
137*795d594fSAndroid Build Coastguard Worker     }
138*795d594fSAndroid Build Coastguard Worker     buckets_owned_.SetInitialBits(num_buckets_);
139*795d594fSAndroid Build Coastguard Worker   }
140*795d594fSAndroid Build Coastguard Worker 
141*795d594fSAndroid Build Coastguard Worker   // Updates this set by intersecting with instructions in a predecessor's set.
IntersectWith(ValueSet * predecessor)142*795d594fSAndroid Build Coastguard Worker   void IntersectWith(ValueSet* predecessor) {
143*795d594fSAndroid Build Coastguard Worker     if (IsEmpty()) {
144*795d594fSAndroid Build Coastguard Worker       return;
145*795d594fSAndroid Build Coastguard Worker     } else if (predecessor->IsEmpty()) {
146*795d594fSAndroid Build Coastguard Worker       Clear();
147*795d594fSAndroid Build Coastguard Worker     } else {
148*795d594fSAndroid Build Coastguard Worker       // Pure instructions do not need to be tested because only impure
149*795d594fSAndroid Build Coastguard Worker       // instructions can be killed.
150*795d594fSAndroid Build Coastguard Worker       DeleteAllImpureWhich([predecessor](Node* node) {
151*795d594fSAndroid Build Coastguard Worker         return !predecessor->Contains(node->GetInstruction());
152*795d594fSAndroid Build Coastguard Worker       });
153*795d594fSAndroid Build Coastguard Worker     }
154*795d594fSAndroid Build Coastguard Worker   }
155*795d594fSAndroid Build Coastguard Worker 
IsEmpty() const156*795d594fSAndroid Build Coastguard Worker   bool IsEmpty() const { return num_entries_ == 0; }
GetNumberOfEntries() const157*795d594fSAndroid Build Coastguard Worker   size_t GetNumberOfEntries() const { return num_entries_; }
158*795d594fSAndroid Build Coastguard Worker 
159*795d594fSAndroid Build Coastguard Worker  private:
160*795d594fSAndroid Build Coastguard Worker   // Copies all entries from `other` to `this`.
PopulateFromInternal(const ValueSet & other)161*795d594fSAndroid Build Coastguard Worker   void PopulateFromInternal(const ValueSet& other) {
162*795d594fSAndroid Build Coastguard Worker     DCHECK_NE(this, &other);
163*795d594fSAndroid Build Coastguard Worker     DCHECK_GE(num_buckets_, other.IdealBucketCount());
164*795d594fSAndroid Build Coastguard Worker 
165*795d594fSAndroid Build Coastguard Worker     if (num_buckets_ == other.num_buckets_) {
166*795d594fSAndroid Build Coastguard Worker       // Hash table remains the same size. We copy the bucket pointers and leave
167*795d594fSAndroid Build Coastguard Worker       // all buckets_owned_ bits false.
168*795d594fSAndroid Build Coastguard Worker       buckets_owned_.ClearAllBits();
169*795d594fSAndroid Build Coastguard Worker       memcpy(buckets_, other.buckets_, num_buckets_ * sizeof(Node*));
170*795d594fSAndroid Build Coastguard Worker     } else {
171*795d594fSAndroid Build Coastguard Worker       // Hash table size changes. We copy and rehash all entries, and set all
172*795d594fSAndroid Build Coastguard Worker       // buckets_owned_ bits to true.
173*795d594fSAndroid Build Coastguard Worker       std::fill_n(buckets_, num_buckets_, nullptr);
174*795d594fSAndroid Build Coastguard Worker       for (size_t i = 0; i < other.num_buckets_; ++i) {
175*795d594fSAndroid Build Coastguard Worker         for (Node* node = other.buckets_[i]; node != nullptr; node = node->GetNext()) {
176*795d594fSAndroid Build Coastguard Worker           size_t new_index = BucketIndex(node->GetHashCode());
177*795d594fSAndroid Build Coastguard Worker           buckets_[new_index] = node->Dup(allocator_, buckets_[new_index]);
178*795d594fSAndroid Build Coastguard Worker         }
179*795d594fSAndroid Build Coastguard Worker       }
180*795d594fSAndroid Build Coastguard Worker       buckets_owned_.SetInitialBits(num_buckets_);
181*795d594fSAndroid Build Coastguard Worker     }
182*795d594fSAndroid Build Coastguard Worker 
183*795d594fSAndroid Build Coastguard Worker     num_entries_ = other.num_entries_;
184*795d594fSAndroid Build Coastguard Worker   }
185*795d594fSAndroid Build Coastguard Worker 
186*795d594fSAndroid Build Coastguard Worker   class Node : public ArenaObject<kArenaAllocGvn> {
187*795d594fSAndroid Build Coastguard Worker    public:
Node(HInstruction * instruction,size_t hash_code,Node * next)188*795d594fSAndroid Build Coastguard Worker     Node(HInstruction* instruction, size_t hash_code, Node* next)
189*795d594fSAndroid Build Coastguard Worker         : instruction_(instruction), hash_code_(hash_code), next_(next) {}
190*795d594fSAndroid Build Coastguard Worker 
GetHashCode() const191*795d594fSAndroid Build Coastguard Worker     size_t GetHashCode() const { return hash_code_; }
GetInstruction() const192*795d594fSAndroid Build Coastguard Worker     HInstruction* GetInstruction() const { return instruction_; }
GetNext() const193*795d594fSAndroid Build Coastguard Worker     Node* GetNext() const { return next_; }
SetNext(Node * node)194*795d594fSAndroid Build Coastguard Worker     void SetNext(Node* node) { next_ = node; }
195*795d594fSAndroid Build Coastguard Worker 
Dup(ScopedArenaAllocator * allocator,Node * new_next=nullptr)196*795d594fSAndroid Build Coastguard Worker     Node* Dup(ScopedArenaAllocator* allocator, Node* new_next = nullptr) {
197*795d594fSAndroid Build Coastguard Worker       return new (allocator) Node(instruction_, hash_code_, new_next);
198*795d594fSAndroid Build Coastguard Worker     }
199*795d594fSAndroid Build Coastguard Worker 
GetSideEffects() const200*795d594fSAndroid Build Coastguard Worker     SideEffects GetSideEffects() const {
201*795d594fSAndroid Build Coastguard Worker       // Deoptimize is a weird instruction since it's predicated and
202*795d594fSAndroid Build Coastguard Worker       // never-return. Its side-effects are to prevent the splitting of dex
203*795d594fSAndroid Build Coastguard Worker       // instructions across it (which could cause inconsistencies once we begin
204*795d594fSAndroid Build Coastguard Worker       // interpreting again). In the context of GVN the 'perform-deopt' branch is not
205*795d594fSAndroid Build Coastguard Worker       // relevant and we only need to care about the no-op case, in which case there are
206*795d594fSAndroid Build Coastguard Worker       // no side-effects. By doing this we are able to eliminate redundant (i.e.
207*795d594fSAndroid Build Coastguard Worker       // dominated deopts with GVNd conditions) deoptimizations.
208*795d594fSAndroid Build Coastguard Worker       if (instruction_->IsDeoptimize()) {
209*795d594fSAndroid Build Coastguard Worker         return SideEffects::None();
210*795d594fSAndroid Build Coastguard Worker       } else {
211*795d594fSAndroid Build Coastguard Worker         return instruction_->GetSideEffects();
212*795d594fSAndroid Build Coastguard Worker       }
213*795d594fSAndroid Build Coastguard Worker     }
214*795d594fSAndroid Build Coastguard Worker 
215*795d594fSAndroid Build Coastguard Worker    private:
216*795d594fSAndroid Build Coastguard Worker     HInstruction* const instruction_;
217*795d594fSAndroid Build Coastguard Worker     const size_t hash_code_;
218*795d594fSAndroid Build Coastguard Worker     Node* next_;
219*795d594fSAndroid Build Coastguard Worker 
220*795d594fSAndroid Build Coastguard Worker     DISALLOW_COPY_AND_ASSIGN(Node);
221*795d594fSAndroid Build Coastguard Worker   };
222*795d594fSAndroid Build Coastguard Worker 
223*795d594fSAndroid Build Coastguard Worker   // Creates our own copy of a bucket that is currently pointing to a parent.
224*795d594fSAndroid Build Coastguard Worker   // This algorithm can be called while iterating over the bucket because it
225*795d594fSAndroid Build Coastguard Worker   // preserves the order of entries in the bucket and will return the clone of
226*795d594fSAndroid Build Coastguard Worker   // the given 'iterator'.
CloneBucket(size_t index,Node * iterator=nullptr)227*795d594fSAndroid Build Coastguard Worker   Node* CloneBucket(size_t index, Node* iterator = nullptr) {
228*795d594fSAndroid Build Coastguard Worker     DCHECK(!buckets_owned_.IsBitSet(index));
229*795d594fSAndroid Build Coastguard Worker     Node* clone_current = nullptr;
230*795d594fSAndroid Build Coastguard Worker     Node* clone_previous = nullptr;
231*795d594fSAndroid Build Coastguard Worker     Node* clone_iterator = nullptr;
232*795d594fSAndroid Build Coastguard Worker     for (Node* node = buckets_[index]; node != nullptr; node = node->GetNext()) {
233*795d594fSAndroid Build Coastguard Worker       clone_current = node->Dup(allocator_, nullptr);
234*795d594fSAndroid Build Coastguard Worker       if (node == iterator) {
235*795d594fSAndroid Build Coastguard Worker         clone_iterator = clone_current;
236*795d594fSAndroid Build Coastguard Worker       }
237*795d594fSAndroid Build Coastguard Worker       if (clone_previous == nullptr) {
238*795d594fSAndroid Build Coastguard Worker         buckets_[index] = clone_current;
239*795d594fSAndroid Build Coastguard Worker       } else {
240*795d594fSAndroid Build Coastguard Worker         clone_previous->SetNext(clone_current);
241*795d594fSAndroid Build Coastguard Worker       }
242*795d594fSAndroid Build Coastguard Worker       clone_previous = clone_current;
243*795d594fSAndroid Build Coastguard Worker     }
244*795d594fSAndroid Build Coastguard Worker     buckets_owned_.SetBit(index);
245*795d594fSAndroid Build Coastguard Worker     return clone_iterator;
246*795d594fSAndroid Build Coastguard Worker   }
247*795d594fSAndroid Build Coastguard Worker 
248*795d594fSAndroid Build Coastguard Worker   // Iterates over buckets with impure instructions (even indices) and deletes
249*795d594fSAndroid Build Coastguard Worker   // the ones on which 'cond' returns true.
250*795d594fSAndroid Build Coastguard Worker   template<typename Functor>
DeleteAllImpureWhich(Functor && cond)251*795d594fSAndroid Build Coastguard Worker   void DeleteAllImpureWhich(Functor&& cond) {
252*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0; i < num_buckets_; i += 2) {
253*795d594fSAndroid Build Coastguard Worker       Node* node = buckets_[i];
254*795d594fSAndroid Build Coastguard Worker       Node* previous = nullptr;
255*795d594fSAndroid Build Coastguard Worker 
256*795d594fSAndroid Build Coastguard Worker       if (node == nullptr) {
257*795d594fSAndroid Build Coastguard Worker         continue;
258*795d594fSAndroid Build Coastguard Worker       }
259*795d594fSAndroid Build Coastguard Worker 
260*795d594fSAndroid Build Coastguard Worker       if (!buckets_owned_.IsBitSet(i)) {
261*795d594fSAndroid Build Coastguard Worker         // Bucket is not owned but maybe we won't need to change it at all.
262*795d594fSAndroid Build Coastguard Worker         // Iterate as long as the entries don't satisfy 'cond'.
263*795d594fSAndroid Build Coastguard Worker         while (node != nullptr) {
264*795d594fSAndroid Build Coastguard Worker           if (cond(node)) {
265*795d594fSAndroid Build Coastguard Worker             // We do need to delete an entry but we do not own the bucket.
266*795d594fSAndroid Build Coastguard Worker             // Clone the bucket, make sure 'previous' and 'node' point to
267*795d594fSAndroid Build Coastguard Worker             // the cloned entries and break.
268*795d594fSAndroid Build Coastguard Worker             previous = CloneBucket(i, previous);
269*795d594fSAndroid Build Coastguard Worker             node = (previous == nullptr) ? buckets_[i] : previous->GetNext();
270*795d594fSAndroid Build Coastguard Worker             break;
271*795d594fSAndroid Build Coastguard Worker           }
272*795d594fSAndroid Build Coastguard Worker           previous = node;
273*795d594fSAndroid Build Coastguard Worker           node = node->GetNext();
274*795d594fSAndroid Build Coastguard Worker         }
275*795d594fSAndroid Build Coastguard Worker       }
276*795d594fSAndroid Build Coastguard Worker 
277*795d594fSAndroid Build Coastguard Worker       // By this point we either own the bucket and can start deleting entries,
278*795d594fSAndroid Build Coastguard Worker       // or we do not own it but no entries matched 'cond'.
279*795d594fSAndroid Build Coastguard Worker       DCHECK(buckets_owned_.IsBitSet(i) || node == nullptr);
280*795d594fSAndroid Build Coastguard Worker 
281*795d594fSAndroid Build Coastguard Worker       // We iterate over the remainder of entries and delete those that match
282*795d594fSAndroid Build Coastguard Worker       // the given condition.
283*795d594fSAndroid Build Coastguard Worker       while (node != nullptr) {
284*795d594fSAndroid Build Coastguard Worker         Node* next = node->GetNext();
285*795d594fSAndroid Build Coastguard Worker         if (cond(node)) {
286*795d594fSAndroid Build Coastguard Worker           if (previous == nullptr) {
287*795d594fSAndroid Build Coastguard Worker             buckets_[i] = next;
288*795d594fSAndroid Build Coastguard Worker           } else {
289*795d594fSAndroid Build Coastguard Worker             previous->SetNext(next);
290*795d594fSAndroid Build Coastguard Worker           }
291*795d594fSAndroid Build Coastguard Worker         } else {
292*795d594fSAndroid Build Coastguard Worker           previous = node;
293*795d594fSAndroid Build Coastguard Worker         }
294*795d594fSAndroid Build Coastguard Worker         node = next;
295*795d594fSAndroid Build Coastguard Worker       }
296*795d594fSAndroid Build Coastguard Worker     }
297*795d594fSAndroid Build Coastguard Worker   }
298*795d594fSAndroid Build Coastguard Worker 
299*795d594fSAndroid Build Coastguard Worker   // Computes a bucket count such that the load factor is reasonable.
300*795d594fSAndroid Build Coastguard Worker   // This is estimated as (num_entries_ * 1.5) and rounded up to nearest pow2.
IdealBucketCount() const301*795d594fSAndroid Build Coastguard Worker   size_t IdealBucketCount() const {
302*795d594fSAndroid Build Coastguard Worker     size_t bucket_count = RoundUpToPowerOfTwo(num_entries_ + (num_entries_ >> 1));
303*795d594fSAndroid Build Coastguard Worker     if (bucket_count > kMinimumNumberOfBuckets) {
304*795d594fSAndroid Build Coastguard Worker       return bucket_count;
305*795d594fSAndroid Build Coastguard Worker     } else {
306*795d594fSAndroid Build Coastguard Worker       return kMinimumNumberOfBuckets;
307*795d594fSAndroid Build Coastguard Worker     }
308*795d594fSAndroid Build Coastguard Worker   }
309*795d594fSAndroid Build Coastguard Worker 
310*795d594fSAndroid Build Coastguard Worker   // Generates a hash code for an instruction.
HashCode(HInstruction * instruction) const311*795d594fSAndroid Build Coastguard Worker   size_t HashCode(HInstruction* instruction) const {
312*795d594fSAndroid Build Coastguard Worker     size_t hash_code = instruction->ComputeHashCode();
313*795d594fSAndroid Build Coastguard Worker     // Pure instructions are put into odd buckets to speed up deletion. Note that in the
314*795d594fSAndroid Build Coastguard Worker     // case of irreducible loops, we don't put pure instructions in odd buckets, as we
315*795d594fSAndroid Build Coastguard Worker     // need to delete them when entering the loop.
316*795d594fSAndroid Build Coastguard Worker     // ClinitCheck is treated as a pure instruction since it's only executed
317*795d594fSAndroid Build Coastguard Worker     // once.
318*795d594fSAndroid Build Coastguard Worker     bool pure = !instruction->GetSideEffects().HasDependencies() ||
319*795d594fSAndroid Build Coastguard Worker                 instruction->IsClinitCheck();
320*795d594fSAndroid Build Coastguard Worker     if (!pure || instruction->GetBlock()->GetGraph()->HasIrreducibleLoops()) {
321*795d594fSAndroid Build Coastguard Worker       return (hash_code << 1) | 0;
322*795d594fSAndroid Build Coastguard Worker     } else {
323*795d594fSAndroid Build Coastguard Worker       return (hash_code << 1) | 1;
324*795d594fSAndroid Build Coastguard Worker     }
325*795d594fSAndroid Build Coastguard Worker   }
326*795d594fSAndroid Build Coastguard Worker 
327*795d594fSAndroid Build Coastguard Worker   // Converts a hash code to a bucket index.
BucketIndex(size_t hash_code) const328*795d594fSAndroid Build Coastguard Worker   size_t BucketIndex(size_t hash_code) const {
329*795d594fSAndroid Build Coastguard Worker     return hash_code & (num_buckets_ - 1);
330*795d594fSAndroid Build Coastguard Worker   }
331*795d594fSAndroid Build Coastguard Worker 
332*795d594fSAndroid Build Coastguard Worker   ScopedArenaAllocator* const allocator_;
333*795d594fSAndroid Build Coastguard Worker 
334*795d594fSAndroid Build Coastguard Worker   // The internal bucket implementation of the set.
335*795d594fSAndroid Build Coastguard Worker   size_t const num_buckets_;
336*795d594fSAndroid Build Coastguard Worker   Node** const buckets_;
337*795d594fSAndroid Build Coastguard Worker 
338*795d594fSAndroid Build Coastguard Worker   // Flags specifying which buckets were copied into the set from its parent.
339*795d594fSAndroid Build Coastguard Worker   // If a flag is not set, the corresponding bucket points to entries in the
340*795d594fSAndroid Build Coastguard Worker   // parent and must be cloned prior to making changes.
341*795d594fSAndroid Build Coastguard Worker   ArenaBitVector buckets_owned_;
342*795d594fSAndroid Build Coastguard Worker 
343*795d594fSAndroid Build Coastguard Worker   // The number of entries in the set.
344*795d594fSAndroid Build Coastguard Worker   size_t num_entries_;
345*795d594fSAndroid Build Coastguard Worker 
346*795d594fSAndroid Build Coastguard Worker   static constexpr size_t kMinimumNumberOfBuckets = 8;
347*795d594fSAndroid Build Coastguard Worker 
348*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(ValueSet);
349*795d594fSAndroid Build Coastguard Worker };
350*795d594fSAndroid Build Coastguard Worker 
351*795d594fSAndroid Build Coastguard Worker /**
352*795d594fSAndroid Build Coastguard Worker  * Optimization phase that removes redundant instruction.
353*795d594fSAndroid Build Coastguard Worker  */
354*795d594fSAndroid Build Coastguard Worker class GlobalValueNumberer : public ValueObject {
355*795d594fSAndroid Build Coastguard Worker  public:
GlobalValueNumberer(HGraph * graph,const SideEffectsAnalysis & side_effects)356*795d594fSAndroid Build Coastguard Worker   GlobalValueNumberer(HGraph* graph, const SideEffectsAnalysis& side_effects)
357*795d594fSAndroid Build Coastguard Worker       : graph_(graph),
358*795d594fSAndroid Build Coastguard Worker         allocator_(graph->GetArenaStack()),
359*795d594fSAndroid Build Coastguard Worker         side_effects_(side_effects),
360*795d594fSAndroid Build Coastguard Worker         sets_(graph->GetBlocks().size(), nullptr, allocator_.Adapter(kArenaAllocGvn)),
361*795d594fSAndroid Build Coastguard Worker         visited_blocks_(
362*795d594fSAndroid Build Coastguard Worker             &allocator_, graph->GetBlocks().size(), /* expandable= */ false, kArenaAllocGvn),
363*795d594fSAndroid Build Coastguard Worker         did_optimization_(false) {}
364*795d594fSAndroid Build Coastguard Worker 
365*795d594fSAndroid Build Coastguard Worker   bool Run();
366*795d594fSAndroid Build Coastguard Worker 
367*795d594fSAndroid Build Coastguard Worker  private:
368*795d594fSAndroid Build Coastguard Worker   // Per-block GVN. Will also update the ValueSet of the dominated and
369*795d594fSAndroid Build Coastguard Worker   // successor blocks.
370*795d594fSAndroid Build Coastguard Worker   void VisitBasicBlock(HBasicBlock* block);
371*795d594fSAndroid Build Coastguard Worker 
372*795d594fSAndroid Build Coastguard Worker   HGraph* graph_;
373*795d594fSAndroid Build Coastguard Worker   ScopedArenaAllocator allocator_;
374*795d594fSAndroid Build Coastguard Worker   const SideEffectsAnalysis& side_effects_;
375*795d594fSAndroid Build Coastguard Worker 
FindSetFor(HBasicBlock * block) const376*795d594fSAndroid Build Coastguard Worker   ValueSet* FindSetFor(HBasicBlock* block) const {
377*795d594fSAndroid Build Coastguard Worker     ValueSet* result = sets_[block->GetBlockId()];
378*795d594fSAndroid Build Coastguard Worker     DCHECK(result != nullptr) << "Could not find set for block B" << block->GetBlockId();
379*795d594fSAndroid Build Coastguard Worker     return result;
380*795d594fSAndroid Build Coastguard Worker   }
381*795d594fSAndroid Build Coastguard Worker 
AbandonSetFor(HBasicBlock * block)382*795d594fSAndroid Build Coastguard Worker   void AbandonSetFor(HBasicBlock* block) {
383*795d594fSAndroid Build Coastguard Worker     DCHECK(sets_[block->GetBlockId()] != nullptr)
384*795d594fSAndroid Build Coastguard Worker         << "Block B" << block->GetBlockId() << " expected to have a set";
385*795d594fSAndroid Build Coastguard Worker     sets_[block->GetBlockId()] = nullptr;
386*795d594fSAndroid Build Coastguard Worker   }
387*795d594fSAndroid Build Coastguard Worker 
388*795d594fSAndroid Build Coastguard Worker   // Returns false if the GlobalValueNumberer has already visited all blocks
389*795d594fSAndroid Build Coastguard Worker   // which may reference `block`.
390*795d594fSAndroid Build Coastguard Worker   bool WillBeReferencedAgain(HBasicBlock* block) const;
391*795d594fSAndroid Build Coastguard Worker 
392*795d594fSAndroid Build Coastguard Worker   // Iterates over visited blocks and finds one which has a ValueSet such that:
393*795d594fSAndroid Build Coastguard Worker   // (a) it will not be referenced in the future, and
394*795d594fSAndroid Build Coastguard Worker   // (b) it can hold a copy of `reference_set` with a reasonable load factor.
395*795d594fSAndroid Build Coastguard Worker   HBasicBlock* FindVisitedBlockWithRecyclableSet(HBasicBlock* block,
396*795d594fSAndroid Build Coastguard Worker                                                  const ValueSet& reference_set) const;
397*795d594fSAndroid Build Coastguard Worker 
398*795d594fSAndroid Build Coastguard Worker   // ValueSet for blocks. Initially null, but for an individual block they
399*795d594fSAndroid Build Coastguard Worker   // are allocated and populated by the dominator, and updated by all blocks
400*795d594fSAndroid Build Coastguard Worker   // in the path from the dominator to the block.
401*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<ValueSet*> sets_;
402*795d594fSAndroid Build Coastguard Worker 
403*795d594fSAndroid Build Coastguard Worker   // BitVector which serves as a fast-access map from block id to
404*795d594fSAndroid Build Coastguard Worker   // visited/unvisited Boolean.
405*795d594fSAndroid Build Coastguard Worker   ArenaBitVector visited_blocks_;
406*795d594fSAndroid Build Coastguard Worker 
407*795d594fSAndroid Build Coastguard Worker   // True if GVN did at least one removal.
408*795d594fSAndroid Build Coastguard Worker   bool did_optimization_;
409*795d594fSAndroid Build Coastguard Worker 
410*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(GlobalValueNumberer);
411*795d594fSAndroid Build Coastguard Worker };
412*795d594fSAndroid Build Coastguard Worker 
Run()413*795d594fSAndroid Build Coastguard Worker bool GlobalValueNumberer::Run() {
414*795d594fSAndroid Build Coastguard Worker   DCHECK(side_effects_.HasRun());
415*795d594fSAndroid Build Coastguard Worker   sets_[graph_->GetEntryBlock()->GetBlockId()] = new (&allocator_) ValueSet(&allocator_);
416*795d594fSAndroid Build Coastguard Worker 
417*795d594fSAndroid Build Coastguard Worker   // Use the reverse post order to ensure the non back-edge predecessors of a block are
418*795d594fSAndroid Build Coastguard Worker   // visited before the block itself.
419*795d594fSAndroid Build Coastguard Worker   for (HBasicBlock* block : graph_->GetReversePostOrder()) {
420*795d594fSAndroid Build Coastguard Worker     VisitBasicBlock(block);
421*795d594fSAndroid Build Coastguard Worker   }
422*795d594fSAndroid Build Coastguard Worker   return did_optimization_;
423*795d594fSAndroid Build Coastguard Worker }
424*795d594fSAndroid Build Coastguard Worker 
VisitBasicBlock(HBasicBlock * block)425*795d594fSAndroid Build Coastguard Worker void GlobalValueNumberer::VisitBasicBlock(HBasicBlock* block) {
426*795d594fSAndroid Build Coastguard Worker   ValueSet* set = nullptr;
427*795d594fSAndroid Build Coastguard Worker 
428*795d594fSAndroid Build Coastguard Worker   const ArenaVector<HBasicBlock*>& predecessors = block->GetPredecessors();
429*795d594fSAndroid Build Coastguard Worker   if (predecessors.size() == 0 || predecessors[0]->IsEntryBlock()) {
430*795d594fSAndroid Build Coastguard Worker     // The entry block should only accumulate constant instructions, and
431*795d594fSAndroid Build Coastguard Worker     // the builder puts constants only in the entry block.
432*795d594fSAndroid Build Coastguard Worker     // Therefore, there is no need to propagate the value set to the next block.
433*795d594fSAndroid Build Coastguard Worker     set = new (&allocator_) ValueSet(&allocator_);
434*795d594fSAndroid Build Coastguard Worker   } else {
435*795d594fSAndroid Build Coastguard Worker     HBasicBlock* dominator = block->GetDominator();
436*795d594fSAndroid Build Coastguard Worker     ValueSet* dominator_set = FindSetFor(dominator);
437*795d594fSAndroid Build Coastguard Worker 
438*795d594fSAndroid Build Coastguard Worker     if (dominator->GetSuccessors().size() == 1) {
439*795d594fSAndroid Build Coastguard Worker       // `block` is a direct successor of its dominator. No need to clone the
440*795d594fSAndroid Build Coastguard Worker       // dominator's set, `block` can take over its ownership including its buckets.
441*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(dominator->GetSingleSuccessor(), block);
442*795d594fSAndroid Build Coastguard Worker       AbandonSetFor(dominator);
443*795d594fSAndroid Build Coastguard Worker       set = dominator_set;
444*795d594fSAndroid Build Coastguard Worker     } else {
445*795d594fSAndroid Build Coastguard Worker       // Try to find a basic block which will never be referenced again and whose
446*795d594fSAndroid Build Coastguard Worker       // ValueSet can therefore be recycled. We will need to copy `dominator_set`
447*795d594fSAndroid Build Coastguard Worker       // into the recycled set, so we pass `dominator_set` as a reference for size.
448*795d594fSAndroid Build Coastguard Worker       HBasicBlock* recyclable = FindVisitedBlockWithRecyclableSet(block, *dominator_set);
449*795d594fSAndroid Build Coastguard Worker       if (recyclable == nullptr) {
450*795d594fSAndroid Build Coastguard Worker         // No block with a suitable ValueSet found. Allocate a new one and
451*795d594fSAndroid Build Coastguard Worker         // copy `dominator_set` into it.
452*795d594fSAndroid Build Coastguard Worker         set = new (&allocator_) ValueSet(&allocator_, *dominator_set);
453*795d594fSAndroid Build Coastguard Worker       } else {
454*795d594fSAndroid Build Coastguard Worker         // Block with a recyclable ValueSet found. Clone `dominator_set` into it.
455*795d594fSAndroid Build Coastguard Worker         set = FindSetFor(recyclable);
456*795d594fSAndroid Build Coastguard Worker         AbandonSetFor(recyclable);
457*795d594fSAndroid Build Coastguard Worker         set->PopulateFrom(*dominator_set);
458*795d594fSAndroid Build Coastguard Worker       }
459*795d594fSAndroid Build Coastguard Worker     }
460*795d594fSAndroid Build Coastguard Worker 
461*795d594fSAndroid Build Coastguard Worker     if (!set->IsEmpty()) {
462*795d594fSAndroid Build Coastguard Worker       if (block->IsLoopHeader()) {
463*795d594fSAndroid Build Coastguard Worker         if (block->GetLoopInformation()->ContainsIrreducibleLoop()) {
464*795d594fSAndroid Build Coastguard Worker           // To satisfy our linear scan algorithm, no instruction should flow in an irreducible
465*795d594fSAndroid Build Coastguard Worker           // loop header. We clear the set at entry of irreducible loops and any loop containing
466*795d594fSAndroid Build Coastguard Worker           // an irreducible loop, as in both cases, GVN can extend the liveness of an instruction
467*795d594fSAndroid Build Coastguard Worker           // across the irreducible loop.
468*795d594fSAndroid Build Coastguard Worker           // Note that, if we're not compiling OSR, we could still do GVN and introduce
469*795d594fSAndroid Build Coastguard Worker           // phis at irreducible loop headers. We decided it was not worth the complexity.
470*795d594fSAndroid Build Coastguard Worker           set->Clear();
471*795d594fSAndroid Build Coastguard Worker         } else {
472*795d594fSAndroid Build Coastguard Worker           DCHECK(!block->GetLoopInformation()->IsIrreducible());
473*795d594fSAndroid Build Coastguard Worker           DCHECK_EQ(block->GetDominator(), block->GetLoopInformation()->GetPreHeader());
474*795d594fSAndroid Build Coastguard Worker           set->Kill(side_effects_.GetLoopEffects(block));
475*795d594fSAndroid Build Coastguard Worker         }
476*795d594fSAndroid Build Coastguard Worker       } else if (predecessors.size() > 1) {
477*795d594fSAndroid Build Coastguard Worker         for (HBasicBlock* predecessor : predecessors) {
478*795d594fSAndroid Build Coastguard Worker           set->IntersectWith(FindSetFor(predecessor));
479*795d594fSAndroid Build Coastguard Worker           if (set->IsEmpty()) {
480*795d594fSAndroid Build Coastguard Worker             break;
481*795d594fSAndroid Build Coastguard Worker           }
482*795d594fSAndroid Build Coastguard Worker         }
483*795d594fSAndroid Build Coastguard Worker       }
484*795d594fSAndroid Build Coastguard Worker     }
485*795d594fSAndroid Build Coastguard Worker   }
486*795d594fSAndroid Build Coastguard Worker 
487*795d594fSAndroid Build Coastguard Worker   sets_[block->GetBlockId()] = set;
488*795d594fSAndroid Build Coastguard Worker 
489*795d594fSAndroid Build Coastguard Worker   HInstruction* current = block->GetFirstInstruction();
490*795d594fSAndroid Build Coastguard Worker   while (current != nullptr) {
491*795d594fSAndroid Build Coastguard Worker     // Save the next instruction in case `current` is removed from the graph.
492*795d594fSAndroid Build Coastguard Worker     HInstruction* next = current->GetNext();
493*795d594fSAndroid Build Coastguard Worker     // Do not kill the set with the side effects of the instruction just now: if
494*795d594fSAndroid Build Coastguard Worker     // the instruction is GVN'ed, we don't need to kill.
495*795d594fSAndroid Build Coastguard Worker     //
496*795d594fSAndroid Build Coastguard Worker     // BoundType is a special case example of an instruction which shouldn't be moved but can be
497*795d594fSAndroid Build Coastguard Worker     // GVN'ed.
498*795d594fSAndroid Build Coastguard Worker     //
499*795d594fSAndroid Build Coastguard Worker     // Deoptimize is a special case since even though we don't want to move it we can still remove
500*795d594fSAndroid Build Coastguard Worker     // it for GVN.
501*795d594fSAndroid Build Coastguard Worker     if (current->CanBeMoved() || current->IsBoundType() || current->IsDeoptimize()) {
502*795d594fSAndroid Build Coastguard Worker       if (current->IsBinaryOperation() && current->AsBinaryOperation()->IsCommutative()) {
503*795d594fSAndroid Build Coastguard Worker         // For commutative ops, (x op y) will be treated the same as (y op x)
504*795d594fSAndroid Build Coastguard Worker         // after fixed ordering.
505*795d594fSAndroid Build Coastguard Worker         current->AsBinaryOperation()->OrderInputs();
506*795d594fSAndroid Build Coastguard Worker       }
507*795d594fSAndroid Build Coastguard Worker       HInstruction* existing = set->Lookup(current);
508*795d594fSAndroid Build Coastguard Worker       if (existing != nullptr) {
509*795d594fSAndroid Build Coastguard Worker         // This replacement doesn't make more OrderInputs() necessary since
510*795d594fSAndroid Build Coastguard Worker         // current is either used by an instruction that it dominates,
511*795d594fSAndroid Build Coastguard Worker         // which hasn't been visited yet due to the order we visit instructions.
512*795d594fSAndroid Build Coastguard Worker         // Or current is used by a phi, and we don't do OrderInputs() on a phi anyway.
513*795d594fSAndroid Build Coastguard Worker         current->ReplaceWith(existing);
514*795d594fSAndroid Build Coastguard Worker         current->GetBlock()->RemoveInstruction(current);
515*795d594fSAndroid Build Coastguard Worker         did_optimization_ = true;
516*795d594fSAndroid Build Coastguard Worker       } else {
517*795d594fSAndroid Build Coastguard Worker         set->Kill(current->GetSideEffects());
518*795d594fSAndroid Build Coastguard Worker         set->Add(current);
519*795d594fSAndroid Build Coastguard Worker       }
520*795d594fSAndroid Build Coastguard Worker     } else {
521*795d594fSAndroid Build Coastguard Worker       set->Kill(current->GetSideEffects());
522*795d594fSAndroid Build Coastguard Worker     }
523*795d594fSAndroid Build Coastguard Worker     current = next;
524*795d594fSAndroid Build Coastguard Worker   }
525*795d594fSAndroid Build Coastguard Worker 
526*795d594fSAndroid Build Coastguard Worker   visited_blocks_.SetBit(block->GetBlockId());
527*795d594fSAndroid Build Coastguard Worker }
528*795d594fSAndroid Build Coastguard Worker 
WillBeReferencedAgain(HBasicBlock * block) const529*795d594fSAndroid Build Coastguard Worker bool GlobalValueNumberer::WillBeReferencedAgain(HBasicBlock* block) const {
530*795d594fSAndroid Build Coastguard Worker   DCHECK(visited_blocks_.IsBitSet(block->GetBlockId()));
531*795d594fSAndroid Build Coastguard Worker 
532*795d594fSAndroid Build Coastguard Worker   for (const HBasicBlock* dominated_block : block->GetDominatedBlocks()) {
533*795d594fSAndroid Build Coastguard Worker     if (!visited_blocks_.IsBitSet(dominated_block->GetBlockId())) {
534*795d594fSAndroid Build Coastguard Worker       return true;
535*795d594fSAndroid Build Coastguard Worker     }
536*795d594fSAndroid Build Coastguard Worker   }
537*795d594fSAndroid Build Coastguard Worker 
538*795d594fSAndroid Build Coastguard Worker   for (const HBasicBlock* successor : block->GetSuccessors()) {
539*795d594fSAndroid Build Coastguard Worker     if (!visited_blocks_.IsBitSet(successor->GetBlockId())) {
540*795d594fSAndroid Build Coastguard Worker       return true;
541*795d594fSAndroid Build Coastguard Worker     }
542*795d594fSAndroid Build Coastguard Worker   }
543*795d594fSAndroid Build Coastguard Worker 
544*795d594fSAndroid Build Coastguard Worker   return false;
545*795d594fSAndroid Build Coastguard Worker }
546*795d594fSAndroid Build Coastguard Worker 
FindVisitedBlockWithRecyclableSet(HBasicBlock * block,const ValueSet & reference_set) const547*795d594fSAndroid Build Coastguard Worker HBasicBlock* GlobalValueNumberer::FindVisitedBlockWithRecyclableSet(
548*795d594fSAndroid Build Coastguard Worker     HBasicBlock* block, const ValueSet& reference_set) const {
549*795d594fSAndroid Build Coastguard Worker   HBasicBlock* secondary_match = nullptr;
550*795d594fSAndroid Build Coastguard Worker 
551*795d594fSAndroid Build Coastguard Worker   for (size_t block_id : visited_blocks_.Indexes()) {
552*795d594fSAndroid Build Coastguard Worker     ValueSet* current_set = sets_[block_id];
553*795d594fSAndroid Build Coastguard Worker     if (current_set == nullptr) {
554*795d594fSAndroid Build Coastguard Worker       // Set was already recycled.
555*795d594fSAndroid Build Coastguard Worker       continue;
556*795d594fSAndroid Build Coastguard Worker     }
557*795d594fSAndroid Build Coastguard Worker 
558*795d594fSAndroid Build Coastguard Worker     HBasicBlock* current_block = block->GetGraph()->GetBlocks()[block_id];
559*795d594fSAndroid Build Coastguard Worker 
560*795d594fSAndroid Build Coastguard Worker     // We test if `current_set` has enough buckets to store a copy of
561*795d594fSAndroid Build Coastguard Worker     // `reference_set` with a reasonable load factor. If we find a set whose
562*795d594fSAndroid Build Coastguard Worker     // number of buckets matches perfectly, we return right away. If we find one
563*795d594fSAndroid Build Coastguard Worker     // that is larger, we return it if no perfectly-matching set is found.
564*795d594fSAndroid Build Coastguard Worker     // Note that we defer testing WillBeReferencedAgain until all other criteria
565*795d594fSAndroid Build Coastguard Worker     // have been satisfied because it might be expensive.
566*795d594fSAndroid Build Coastguard Worker     if (current_set->CanHoldCopyOf(reference_set, /* exact_match= */ true)) {
567*795d594fSAndroid Build Coastguard Worker       if (!WillBeReferencedAgain(current_block)) {
568*795d594fSAndroid Build Coastguard Worker         return current_block;
569*795d594fSAndroid Build Coastguard Worker       }
570*795d594fSAndroid Build Coastguard Worker     } else if (secondary_match == nullptr &&
571*795d594fSAndroid Build Coastguard Worker                current_set->CanHoldCopyOf(reference_set, /* exact_match= */ false)) {
572*795d594fSAndroid Build Coastguard Worker       if (!WillBeReferencedAgain(current_block)) {
573*795d594fSAndroid Build Coastguard Worker         secondary_match = current_block;
574*795d594fSAndroid Build Coastguard Worker       }
575*795d594fSAndroid Build Coastguard Worker     }
576*795d594fSAndroid Build Coastguard Worker   }
577*795d594fSAndroid Build Coastguard Worker 
578*795d594fSAndroid Build Coastguard Worker   return secondary_match;
579*795d594fSAndroid Build Coastguard Worker }
580*795d594fSAndroid Build Coastguard Worker 
Run()581*795d594fSAndroid Build Coastguard Worker bool GVNOptimization::Run() {
582*795d594fSAndroid Build Coastguard Worker   GlobalValueNumberer gvn(graph_, side_effects_);
583*795d594fSAndroid Build Coastguard Worker   return gvn.Run();
584*795d594fSAndroid Build Coastguard Worker }
585*795d594fSAndroid Build Coastguard Worker 
586*795d594fSAndroid Build Coastguard Worker }  // namespace art
587