Home | History | Annotate | Download | only in optimizing
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "ssa_builder.h"
     18 
     19 #include "nodes.h"
     20 #include "primitive_type_propagation.h"
     21 #include "ssa_phi_elimination.h"
     22 
     23 namespace art {
     24 
     25 /**
     26  * A debuggable application may require to reviving phis, to ensure their
     27  * associated DEX register is available to a debugger. This class implements
     28  * the logic for statement (c) of the SsaBuilder (see ssa_builder.h). It
     29  * also makes sure that phis with incompatible input types are not revived
     30  * (statement (b) of the SsaBuilder).
     31  *
     32  * This phase must be run after detecting dead phis through the
     33  * DeadPhiElimination phase, and before deleting the dead phis.
     34  */
     35 class DeadPhiHandling : public ValueObject {
     36  public:
     37   explicit DeadPhiHandling(HGraph* graph)
     38       : graph_(graph), worklist_(graph->GetArena(), kDefaultWorklistSize) {}
     39 
     40   void Run();
     41 
     42  private:
     43   void VisitBasicBlock(HBasicBlock* block);
     44   void ProcessWorklist();
     45   void AddToWorklist(HPhi* phi);
     46   void AddDependentInstructionsToWorklist(HPhi* phi);
     47   bool UpdateType(HPhi* phi);
     48 
     49   HGraph* const graph_;
     50   GrowableArray<HPhi*> worklist_;
     51 
     52   static constexpr size_t kDefaultWorklistSize = 8;
     53 
     54   DISALLOW_COPY_AND_ASSIGN(DeadPhiHandling);
     55 };
     56 
     57 bool DeadPhiHandling::UpdateType(HPhi* phi) {
     58   Primitive::Type existing = phi->GetType();
     59   DCHECK(phi->IsLive());
     60 
     61   bool conflict = false;
     62   Primitive::Type new_type = existing;
     63   for (size_t i = 0, e = phi->InputCount(); i < e; ++i) {
     64     HInstruction* input = phi->InputAt(i);
     65     if (input->IsPhi() && input->AsPhi()->IsDead()) {
     66       // We are doing a reverse post order visit of the graph, reviving
     67       // phis that have environment uses and updating their types. If an
     68       // input is a phi, and it is dead (because its input types are
     69       // conflicting), this phi must be marked dead as well.
     70       conflict = true;
     71       break;
     72     }
     73     Primitive::Type input_type = HPhi::ToPhiType(input->GetType());
     74 
     75     // The only acceptable transitions are:
     76     // - From void to typed: first time we update the type of this phi.
     77     // - From int to reference (or reference to int): the phi has to change
     78     //   to reference type. If the integer input cannot be converted to a
     79     //   reference input, the phi will remain dead.
     80     if (new_type == Primitive::kPrimVoid) {
     81       new_type = input_type;
     82     } else if (new_type == Primitive::kPrimNot && input_type == Primitive::kPrimInt) {
     83       HInstruction* equivalent = SsaBuilder::GetReferenceTypeEquivalent(input);
     84       if (equivalent == nullptr) {
     85         conflict = true;
     86         break;
     87       } else {
     88         phi->ReplaceInput(equivalent, i);
     89         if (equivalent->IsPhi()) {
     90           DCHECK_EQ(equivalent->GetType(), Primitive::kPrimNot);
     91           // We created a new phi, but that phi has the same inputs as the old phi. We
     92           // add it to the worklist to ensure its inputs can also be converted to reference.
     93           // If not, it will remain dead, and the algorithm will make the current phi dead
     94           // as well.
     95           equivalent->AsPhi()->SetLive();
     96           AddToWorklist(equivalent->AsPhi());
     97         }
     98       }
     99     } else if (new_type == Primitive::kPrimInt && input_type == Primitive::kPrimNot) {
    100       new_type = Primitive::kPrimNot;
    101       // Start over, we may request reference equivalents for the inputs of the phi.
    102       i = -1;
    103     } else if (new_type != input_type) {
    104       conflict = true;
    105       break;
    106     }
    107   }
    108 
    109   if (conflict) {
    110     phi->SetType(Primitive::kPrimVoid);
    111     phi->SetDead();
    112     return true;
    113   } else {
    114     DCHECK(phi->IsLive());
    115     phi->SetType(new_type);
    116     return existing != new_type;
    117   }
    118 }
    119 
    120 void DeadPhiHandling::VisitBasicBlock(HBasicBlock* block) {
    121   for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
    122     HPhi* phi = it.Current()->AsPhi();
    123     if (phi->IsDead() && phi->HasEnvironmentUses()) {
    124       phi->SetLive();
    125       if (block->IsLoopHeader()) {
    126         // Give a type to the loop phi, to guarantee convergence of the algorithm.
    127         phi->SetType(phi->InputAt(0)->GetType());
    128         AddToWorklist(phi);
    129       } else {
    130         // Because we are doing a reverse post order visit, all inputs of
    131         // this phi have been visited and therefore had their (initial) type set.
    132         UpdateType(phi);
    133       }
    134     }
    135   }
    136 }
    137 
    138 void DeadPhiHandling::ProcessWorklist() {
    139   while (!worklist_.IsEmpty()) {
    140     HPhi* instruction = worklist_.Pop();
    141     // Note that the same equivalent phi can be added multiple times in the work list, if
    142     // used by multiple phis. The first call to `UpdateType` will know whether the phi is
    143     // dead or live.
    144     if (instruction->IsLive() && UpdateType(instruction)) {
    145       AddDependentInstructionsToWorklist(instruction);
    146     }
    147   }
    148 }
    149 
    150 void DeadPhiHandling::AddToWorklist(HPhi* instruction) {
    151   DCHECK(instruction->IsLive());
    152   worklist_.Add(instruction);
    153 }
    154 
    155 void DeadPhiHandling::AddDependentInstructionsToWorklist(HPhi* instruction) {
    156   for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) {
    157     HPhi* phi = it.Current()->GetUser()->AsPhi();
    158     if (phi != nullptr && !phi->IsDead()) {
    159       AddToWorklist(phi);
    160     }
    161   }
    162 }
    163 
    164 void DeadPhiHandling::Run() {
    165   for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
    166     VisitBasicBlock(it.Current());
    167   }
    168   ProcessWorklist();
    169 }
    170 
    171 static bool IsPhiEquivalentOf(HInstruction* instruction, HPhi* phi) {
    172   return instruction != nullptr
    173       && instruction->IsPhi()
    174       && instruction->AsPhi()->GetRegNumber() == phi->GetRegNumber();
    175 }
    176 
    177 void SsaBuilder::FixNullConstantType() {
    178   // The order doesn't matter here.
    179   for (HReversePostOrderIterator itb(*GetGraph()); !itb.Done(); itb.Advance()) {
    180     for (HInstructionIterator it(itb.Current()->GetInstructions()); !it.Done(); it.Advance()) {
    181       HInstruction* equality_instr = it.Current();
    182       if (!equality_instr->IsEqual() && !equality_instr->IsNotEqual()) {
    183         continue;
    184       }
    185       HInstruction* left = equality_instr->InputAt(0);
    186       HInstruction* right = equality_instr->InputAt(1);
    187       HInstruction* int_operand = nullptr;
    188 
    189       if ((left->GetType() == Primitive::kPrimNot) && (right->GetType() == Primitive::kPrimInt)) {
    190         int_operand = right;
    191       } else if ((right->GetType() == Primitive::kPrimNot)
    192                  && (left->GetType() == Primitive::kPrimInt)) {
    193         int_operand = left;
    194       } else {
    195         continue;
    196       }
    197 
    198       // If we got here, we are comparing against a reference and the int constant
    199       // should be replaced with a null constant.
    200       // Both type propagation and redundant phi elimination ensure `int_operand`
    201       // can only be the 0 constant.
    202       DCHECK(int_operand->IsIntConstant());
    203       DCHECK_EQ(0, int_operand->AsIntConstant()->GetValue());
    204       equality_instr->ReplaceInput(GetGraph()->GetNullConstant(), int_operand == right ? 1 : 0);
    205     }
    206   }
    207 }
    208 
    209 void SsaBuilder::EquivalentPhisCleanup() {
    210   // The order doesn't matter here.
    211   for (HReversePostOrderIterator itb(*GetGraph()); !itb.Done(); itb.Advance()) {
    212     for (HInstructionIterator it(itb.Current()->GetPhis()); !it.Done(); it.Advance()) {
    213       HPhi* phi = it.Current()->AsPhi();
    214       HPhi* next = phi->GetNextEquivalentPhiWithSameType();
    215       if (next != nullptr) {
    216         // Make sure we do not replace a live phi with a dead phi. A live phi has been
    217         // handled by the type propagation phase, unlike a dead phi.
    218         if (next->IsLive()) {
    219           phi->ReplaceWith(next);
    220         } else {
    221           next->ReplaceWith(phi);
    222         }
    223         DCHECK(next->GetNextEquivalentPhiWithSameType() == nullptr)
    224             << "More then one phi equivalent with type " << phi->GetType()
    225             << " found for phi" << phi->GetId();
    226       }
    227     }
    228   }
    229 }
    230 
    231 void SsaBuilder::BuildSsa() {
    232   // 1) Visit in reverse post order. We need to have all predecessors of a block visited
    233   // (with the exception of loops) in order to create the right environment for that
    234   // block. For loops, we create phis whose inputs will be set in 2).
    235   for (HReversePostOrderIterator it(*GetGraph()); !it.Done(); it.Advance()) {
    236     VisitBasicBlock(it.Current());
    237   }
    238 
    239   // 2) Set inputs of loop phis.
    240   for (size_t i = 0; i < loop_headers_.Size(); i++) {
    241     HBasicBlock* block = loop_headers_.Get(i);
    242     for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
    243       HPhi* phi = it.Current()->AsPhi();
    244       for (size_t pred = 0; pred < block->GetPredecessors().Size(); pred++) {
    245         HInstruction* input = ValueOfLocal(block->GetPredecessors().Get(pred), phi->GetRegNumber());
    246         phi->AddInput(input);
    247       }
    248     }
    249   }
    250 
    251   // 3) Mark dead phis. This will mark phis that are only used by environments:
    252   // at the DEX level, the type of these phis does not need to be consistent, but
    253   // our code generator will complain if the inputs of a phi do not have the same
    254   // type. The marking allows the type propagation to know which phis it needs
    255   // to handle. We mark but do not eliminate: the elimination will be done in
    256   // step 9).
    257   SsaDeadPhiElimination dead_phis_for_type_propagation(GetGraph());
    258   dead_phis_for_type_propagation.MarkDeadPhis();
    259 
    260   // 4) Propagate types of phis. At this point, phis are typed void in the general
    261   // case, or float/double/reference when we created an equivalent phi. So we
    262   // need to propagate the types across phis to give them a correct type.
    263   PrimitiveTypePropagation type_propagation(GetGraph());
    264   type_propagation.Run();
    265 
    266   // 5) When creating equivalent phis we copy the inputs of the original phi which
    267   // may be improperly typed. This was fixed during the type propagation in 4) but
    268   // as a result we may end up with two equivalent phis with the same type for
    269   // the same dex register. This pass cleans them up.
    270   EquivalentPhisCleanup();
    271 
    272   // 6) Mark dead phis again. Step 4) may have introduced new phis.
    273   // Step 5) might enable the death of new phis.
    274   SsaDeadPhiElimination dead_phis(GetGraph());
    275   dead_phis.MarkDeadPhis();
    276 
    277   // 7) Now that the graph is correctly typed, we can get rid of redundant phis.
    278   // Note that we cannot do this phase before type propagation, otherwise
    279   // we could get rid of phi equivalents, whose presence is a requirement for the
    280   // type propagation phase. Note that this is to satisfy statement (a) of the
    281   // SsaBuilder (see ssa_builder.h).
    282   SsaRedundantPhiElimination redundant_phi(GetGraph());
    283   redundant_phi.Run();
    284 
    285   // 8) Fix the type for null constants which are part of an equality comparison.
    286   // We need to do this after redundant phi elimination, to ensure the only cases
    287   // that we can see are reference comparison against 0. The redundant phi
    288   // elimination ensures we do not see a phi taking two 0 constants in a HEqual
    289   // or HNotEqual.
    290   FixNullConstantType();
    291 
    292   // 9) Make sure environments use the right phi "equivalent": a phi marked dead
    293   // can have a phi equivalent that is not dead. We must therefore update
    294   // all environment uses of the dead phi to use its equivalent. Note that there
    295   // can be multiple phis for the same Dex register that are live (for example
    296   // when merging constants), in which case it is OK for the environments
    297   // to just reference one.
    298   for (HReversePostOrderIterator it(*GetGraph()); !it.Done(); it.Advance()) {
    299     HBasicBlock* block = it.Current();
    300     for (HInstructionIterator it_phis(block->GetPhis()); !it_phis.Done(); it_phis.Advance()) {
    301       HPhi* phi = it_phis.Current()->AsPhi();
    302       // If the phi is not dead, or has no environment uses, there is nothing to do.
    303       if (!phi->IsDead() || !phi->HasEnvironmentUses()) continue;
    304       HInstruction* next = phi->GetNext();
    305       if (!IsPhiEquivalentOf(next, phi)) continue;
    306       if (next->AsPhi()->IsDead()) {
    307         // If the phi equivalent is dead, check if there is another one.
    308         next = next->GetNext();
    309         if (!IsPhiEquivalentOf(next, phi)) continue;
    310         // There can be at most two phi equivalents.
    311         DCHECK(!IsPhiEquivalentOf(next->GetNext(), phi));
    312         if (next->AsPhi()->IsDead()) continue;
    313       }
    314       // We found a live phi equivalent. Update the environment uses of `phi` with it.
    315       phi->ReplaceWith(next);
    316     }
    317   }
    318 
    319   // 10) Deal with phis to guarantee liveness of phis in case of a debuggable
    320   // application. This is for satisfying statement (c) of the SsaBuilder
    321   // (see ssa_builder.h).
    322   if (GetGraph()->IsDebuggable()) {
    323     DeadPhiHandling dead_phi_handler(GetGraph());
    324     dead_phi_handler.Run();
    325   }
    326 
    327   // 11) Now that the right phis are used for the environments, and we
    328   // have potentially revive dead phis in case of a debuggable application,
    329   // we can eliminate phis we do not need. Regardless of the debuggable status,
    330   // this phase is necessary for statement (b) of the SsaBuilder (see ssa_builder.h),
    331   // as well as for the code generation, which does not deal with phis of conflicting
    332   // input types.
    333   dead_phis.EliminateDeadPhis();
    334 
    335   // 12) Clear locals.
    336   for (HInstructionIterator it(GetGraph()->GetEntryBlock()->GetInstructions());
    337        !it.Done();
    338        it.Advance()) {
    339     HInstruction* current = it.Current();
    340     if (current->IsLocal()) {
    341       current->GetBlock()->RemoveInstruction(current);
    342     }
    343   }
    344 }
    345 
    346 HInstruction* SsaBuilder::ValueOfLocal(HBasicBlock* block, size_t local) {
    347   return GetLocalsFor(block)->Get(local);
    348 }
    349 
    350 void SsaBuilder::VisitBasicBlock(HBasicBlock* block) {
    351   current_locals_ = GetLocalsFor(block);
    352 
    353   if (block->IsLoopHeader()) {
    354     // If the block is a loop header, we know we only have visited the pre header
    355     // because we are visiting in reverse post order. We create phis for all initialized
    356     // locals from the pre header. Their inputs will be populated at the end of
    357     // the analysis.
    358     for (size_t local = 0; local < current_locals_->Size(); local++) {
    359       HInstruction* incoming = ValueOfLocal(block->GetLoopInformation()->GetPreHeader(), local);
    360       if (incoming != nullptr) {
    361         HPhi* phi = new (GetGraph()->GetArena()) HPhi(
    362             GetGraph()->GetArena(), local, 0, Primitive::kPrimVoid);
    363         block->AddPhi(phi);
    364         current_locals_->Put(local, phi);
    365       }
    366     }
    367     // Save the loop header so that the last phase of the analysis knows which
    368     // blocks need to be updated.
    369     loop_headers_.Add(block);
    370   } else if (block->GetPredecessors().Size() > 0) {
    371     // All predecessors have already been visited because we are visiting in reverse post order.
    372     // We merge the values of all locals, creating phis if those values differ.
    373     for (size_t local = 0; local < current_locals_->Size(); local++) {
    374       bool one_predecessor_has_no_value = false;
    375       bool is_different = false;
    376       HInstruction* value = ValueOfLocal(block->GetPredecessors().Get(0), local);
    377 
    378       for (size_t i = 0, e = block->GetPredecessors().Size(); i < e; ++i) {
    379         HInstruction* current = ValueOfLocal(block->GetPredecessors().Get(i), local);
    380         if (current == nullptr) {
    381           one_predecessor_has_no_value = true;
    382           break;
    383         } else if (current != value) {
    384           is_different = true;
    385         }
    386       }
    387 
    388       if (one_predecessor_has_no_value) {
    389         // If one predecessor has no value for this local, we trust the verifier has
    390         // successfully checked that there is a store dominating any read after this block.
    391         continue;
    392       }
    393 
    394       if (is_different) {
    395         HPhi* phi = new (GetGraph()->GetArena()) HPhi(
    396             GetGraph()->GetArena(), local, block->GetPredecessors().Size(), Primitive::kPrimVoid);
    397         for (size_t i = 0; i < block->GetPredecessors().Size(); i++) {
    398           HInstruction* pred_value = ValueOfLocal(block->GetPredecessors().Get(i), local);
    399           phi->SetRawInputAt(i, pred_value);
    400         }
    401         block->AddPhi(phi);
    402         value = phi;
    403       }
    404       current_locals_->Put(local, value);
    405     }
    406   }
    407 
    408   // Visit all instructions. The instructions of interest are:
    409   // - HLoadLocal: replace them with the current value of the local.
    410   // - HStoreLocal: update current value of the local and remove the instruction.
    411   // - Instructions that require an environment: populate their environment
    412   //   with the current values of the locals.
    413   for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
    414     it.Current()->Accept(this);
    415   }
    416 }
    417 
    418 /**
    419  * Constants in the Dex format are not typed. So the builder types them as
    420  * integers, but when doing the SSA form, we might realize the constant
    421  * is used for floating point operations. We create a floating-point equivalent
    422  * constant to make the operations correctly typed.
    423  */
    424 HFloatConstant* SsaBuilder::GetFloatEquivalent(HIntConstant* constant) {
    425   // We place the floating point constant next to this constant.
    426   HFloatConstant* result = constant->GetNext()->AsFloatConstant();
    427   if (result == nullptr) {
    428     HGraph* graph = constant->GetBlock()->GetGraph();
    429     ArenaAllocator* allocator = graph->GetArena();
    430     result = new (allocator) HFloatConstant(bit_cast<float, int32_t>(constant->GetValue()));
    431     constant->GetBlock()->InsertInstructionBefore(result, constant->GetNext());
    432     graph->CacheFloatConstant(result);
    433   } else {
    434     // If there is already a constant with the expected type, we know it is
    435     // the floating point equivalent of this constant.
    436     DCHECK_EQ((bit_cast<int32_t, float>(result->GetValue())), constant->GetValue());
    437   }
    438   return result;
    439 }
    440 
    441 /**
    442  * Wide constants in the Dex format are not typed. So the builder types them as
    443  * longs, but when doing the SSA form, we might realize the constant
    444  * is used for floating point operations. We create a floating-point equivalent
    445  * constant to make the operations correctly typed.
    446  */
    447 HDoubleConstant* SsaBuilder::GetDoubleEquivalent(HLongConstant* constant) {
    448   // We place the floating point constant next to this constant.
    449   HDoubleConstant* result = constant->GetNext()->AsDoubleConstant();
    450   if (result == nullptr) {
    451     HGraph* graph = constant->GetBlock()->GetGraph();
    452     ArenaAllocator* allocator = graph->GetArena();
    453     result = new (allocator) HDoubleConstant(bit_cast<double, int64_t>(constant->GetValue()));
    454     constant->GetBlock()->InsertInstructionBefore(result, constant->GetNext());
    455     graph->CacheDoubleConstant(result);
    456   } else {
    457     // If there is already a constant with the expected type, we know it is
    458     // the floating point equivalent of this constant.
    459     DCHECK_EQ((bit_cast<int64_t, double>(result->GetValue())), constant->GetValue());
    460   }
    461   return result;
    462 }
    463 
    464 /**
    465  * Because of Dex format, we might end up having the same phi being
    466  * used for non floating point operations and floating point / reference operations.
    467  * Because we want the graph to be correctly typed (and thereafter avoid moves between
    468  * floating point registers and core registers), we need to create a copy of the
    469  * phi with a floating point / reference type.
    470  */
    471 HPhi* SsaBuilder::GetFloatDoubleOrReferenceEquivalentOfPhi(HPhi* phi, Primitive::Type type) {
    472   // We place the floating point /reference phi next to this phi.
    473   HInstruction* next = phi->GetNext();
    474   if (next != nullptr
    475       && next->AsPhi()->GetRegNumber() == phi->GetRegNumber()
    476       && next->GetType() != type) {
    477     // Move to the next phi to see if it is the one we are looking for.
    478     next = next->GetNext();
    479   }
    480 
    481   if (next == nullptr
    482       || (next->AsPhi()->GetRegNumber() != phi->GetRegNumber())
    483       || (next->GetType() != type)) {
    484     ArenaAllocator* allocator = phi->GetBlock()->GetGraph()->GetArena();
    485     HPhi* new_phi = new (allocator) HPhi(allocator, phi->GetRegNumber(), phi->InputCount(), type);
    486     for (size_t i = 0, e = phi->InputCount(); i < e; ++i) {
    487       // Copy the inputs. Note that the graph may not be correctly typed by doing this copy,
    488       // but the type propagation phase will fix it.
    489       new_phi->SetRawInputAt(i, phi->InputAt(i));
    490     }
    491     phi->GetBlock()->InsertPhiAfter(new_phi, phi);
    492     return new_phi;
    493   } else {
    494     DCHECK_EQ(next->GetType(), type);
    495     return next->AsPhi();
    496   }
    497 }
    498 
    499 HInstruction* SsaBuilder::GetFloatOrDoubleEquivalent(HInstruction* user,
    500                                                      HInstruction* value,
    501                                                      Primitive::Type type) {
    502   if (value->IsArrayGet()) {
    503     // The verifier has checked that values in arrays cannot be used for both
    504     // floating point and non-floating point operations. It is therefore safe to just
    505     // change the type of the operation.
    506     value->AsArrayGet()->SetType(type);
    507     return value;
    508   } else if (value->IsLongConstant()) {
    509     return GetDoubleEquivalent(value->AsLongConstant());
    510   } else if (value->IsIntConstant()) {
    511     return GetFloatEquivalent(value->AsIntConstant());
    512   } else if (value->IsPhi()) {
    513     return GetFloatDoubleOrReferenceEquivalentOfPhi(value->AsPhi(), type);
    514   } else {
    515     // For other instructions, we assume the verifier has checked that the dex format is correctly
    516     // typed and the value in a dex register will not be used for both floating point and
    517     // non-floating point operations. So the only reason an instruction would want a floating
    518     // point equivalent is for an unused phi that will be removed by the dead phi elimination phase.
    519     DCHECK(user->IsPhi());
    520     return value;
    521   }
    522 }
    523 
    524 HInstruction* SsaBuilder::GetReferenceTypeEquivalent(HInstruction* value) {
    525   if (value->IsIntConstant() && value->AsIntConstant()->GetValue() == 0) {
    526     return value->GetBlock()->GetGraph()->GetNullConstant();
    527   } else if (value->IsPhi()) {
    528     return GetFloatDoubleOrReferenceEquivalentOfPhi(value->AsPhi(), Primitive::kPrimNot);
    529   } else {
    530     return nullptr;
    531   }
    532 }
    533 
    534 void SsaBuilder::VisitLoadLocal(HLoadLocal* load) {
    535   HInstruction* value = current_locals_->Get(load->GetLocal()->GetRegNumber());
    536   // If the operation requests a specific type, we make sure its input is of that type.
    537   if (load->GetType() != value->GetType()) {
    538     if (load->GetType() == Primitive::kPrimFloat || load->GetType() == Primitive::kPrimDouble) {
    539       value = GetFloatOrDoubleEquivalent(load, value, load->GetType());
    540     } else if (load->GetType() == Primitive::kPrimNot) {
    541       value = GetReferenceTypeEquivalent(value);
    542     }
    543   }
    544   load->ReplaceWith(value);
    545   load->GetBlock()->RemoveInstruction(load);
    546 }
    547 
    548 void SsaBuilder::VisitStoreLocal(HStoreLocal* store) {
    549   current_locals_->Put(store->GetLocal()->GetRegNumber(), store->InputAt(1));
    550   store->GetBlock()->RemoveInstruction(store);
    551 }
    552 
    553 void SsaBuilder::VisitInstruction(HInstruction* instruction) {
    554   if (!instruction->NeedsEnvironment()) {
    555     return;
    556   }
    557   HEnvironment* environment = new (GetGraph()->GetArena()) HEnvironment(
    558       GetGraph()->GetArena(),
    559       current_locals_->Size(),
    560       GetGraph()->GetDexFile(),
    561       GetGraph()->GetMethodIdx(),
    562       instruction->GetDexPc());
    563   environment->CopyFrom(*current_locals_);
    564   instruction->SetRawEnvironment(environment);
    565 }
    566 
    567 void SsaBuilder::VisitTemporary(HTemporary* temp) {
    568   // Temporaries are only used by the baseline register allocator.
    569   temp->GetBlock()->RemoveInstruction(temp);
    570 }
    571 
    572 }  // namespace art
    573