Reduce memory usage of SSA Phi elimination and make it faster.

Use an ArenaBitVector instead of an ArenaSet<> that leaks
its allocated memory on clear(). We were also erroneously
using the O(n) helper ContainsElement() for the ArenaSet<>
instead of the O(log n) ArenaSet<>::find() which made the
methods with large number of processed Phis also very slow
to compile in addition to the enormous memory usage.

Bug: 28684584
Change-Id: Idc7604e51cfae643debd0378baf828a1430ec14c
diff --git a/compiler/optimizing/ssa_phi_elimination.cc b/compiler/optimizing/ssa_phi_elimination.cc
index 44bcadf..c67612e 100644
--- a/compiler/optimizing/ssa_phi_elimination.cc
+++ b/compiler/optimizing/ssa_phi_elimination.cc
@@ -17,6 +17,7 @@
 #include "ssa_phi_elimination.h"
 
 #include "base/arena_containers.h"
+#include "base/arena_bit_vector.h"
 #include "base/bit_vector-inl.h"
 
 namespace art {
@@ -127,8 +128,10 @@
     }
   }
 
-  ArenaSet<uint32_t> visited_phis_in_cycle(
-      graph_->GetArena()->Adapter(kArenaAllocSsaPhiElimination));
+  ArenaBitVector visited_phis_in_cycle(graph_->GetArena(),
+                                       graph_->GetCurrentInstructionId(),
+                                       /* expandable */ false,
+                                       kArenaAllocSsaPhiElimination);
   ArenaVector<HPhi*> cycle_worklist(graph_->GetArena()->Adapter(kArenaAllocSsaPhiElimination));
 
   while (!worklist_.empty()) {
@@ -147,11 +150,11 @@
     }
 
     HInstruction* candidate = nullptr;
-    visited_phis_in_cycle.clear();
+    visited_phis_in_cycle.ClearAllBits();
     cycle_worklist.clear();
 
     cycle_worklist.push_back(phi);
-    visited_phis_in_cycle.insert(phi->GetId());
+    visited_phis_in_cycle.SetBit(phi->GetId());
     bool catch_phi_in_cycle = phi->IsCatchPhi();
     bool irreducible_loop_phi_in_cycle = phi->IsIrreducibleLoopHeaderPhi();
 
@@ -183,9 +186,9 @@
           if (input == current) {
             continue;
           } else if (input->IsPhi()) {
-            if (!ContainsElement(visited_phis_in_cycle, input->GetId())) {
+            if (!visited_phis_in_cycle.IsBitSet(input->GetId())) {
               cycle_worklist.push_back(input->AsPhi());
-              visited_phis_in_cycle.insert(input->GetId());
+              visited_phis_in_cycle.SetBit(input->GetId());
               catch_phi_in_cycle |= input->AsPhi()->IsCatchPhi();
               irreducible_loop_phi_in_cycle |= input->IsIrreducibleLoopHeaderPhi();
             } else {
@@ -234,7 +237,7 @@
       // for elimination. Add phis that use this phi to the worklist.
       for (const HUseListNode<HInstruction*>& use : current->GetUses()) {
         HInstruction* user = use.GetUser();
-        if (user->IsPhi() && !ContainsElement(visited_phis_in_cycle, user->GetId())) {
+        if (user->IsPhi() && !visited_phis_in_cycle.IsBitSet(user->GetId())) {
           worklist_.push_back(user->AsPhi());
         }
       }