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 "prepare_for_register_allocation.h"
18
19namespace art {
20
21void PrepareForRegisterAllocation::Run() {
22  // Order does not matter.
23  for (HReversePostOrderIterator it(*GetGraph()); !it.Done(); it.Advance()) {
24    HBasicBlock* block = it.Current();
25    // No need to visit the phis.
26    for (HInstructionIterator inst_it(block->GetInstructions()); !inst_it.Done();
27         inst_it.Advance()) {
28      inst_it.Current()->Accept(this);
29    }
30  }
31}
32
33void PrepareForRegisterAllocation::VisitNullCheck(HNullCheck* check) {
34  check->ReplaceWith(check->InputAt(0));
35}
36
37void PrepareForRegisterAllocation::VisitDivZeroCheck(HDivZeroCheck* check) {
38  check->ReplaceWith(check->InputAt(0));
39}
40
41void PrepareForRegisterAllocation::VisitBoundsCheck(HBoundsCheck* check) {
42  check->ReplaceWith(check->InputAt(0));
43}
44
45void PrepareForRegisterAllocation::VisitBoundType(HBoundType* bound_type) {
46  bound_type->ReplaceWith(bound_type->InputAt(0));
47  bound_type->GetBlock()->RemoveInstruction(bound_type);
48}
49
50void PrepareForRegisterAllocation::VisitClinitCheck(HClinitCheck* check) {
51  HLoadClass* cls = check->GetLoadClass();
52  check->ReplaceWith(cls);
53  if (check->GetPrevious() == cls) {
54    // Pass the initialization duty to the `HLoadClass` instruction,
55    // and remove the instruction from the graph.
56    cls->SetMustGenerateClinitCheck();
57    check->GetBlock()->RemoveInstruction(check);
58  }
59}
60
61void PrepareForRegisterAllocation::VisitCondition(HCondition* condition) {
62  bool needs_materialization = false;
63  if (!condition->GetUses().HasOnlyOneUse() || !condition->GetEnvUses().IsEmpty()) {
64    needs_materialization = true;
65  } else {
66    HInstruction* user = condition->GetUses().GetFirst()->GetUser();
67    if (!user->IsIf() && !user->IsDeoptimize()) {
68      needs_materialization = true;
69    } else {
70      // TODO: if there is no intervening instructions with side-effect between this condition
71      // and the If instruction, we should move the condition just before the If.
72      if (condition->GetNext() != user) {
73        needs_materialization = true;
74      }
75    }
76  }
77  if (!needs_materialization) {
78    condition->ClearNeedsMaterialization();
79  }
80}
81
82void PrepareForRegisterAllocation::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
83  if (invoke->IsStaticWithExplicitClinitCheck()) {
84    size_t last_input_index = invoke->InputCount() - 1;
85    HInstruction* last_input = invoke->InputAt(last_input_index);
86    DCHECK(last_input->IsLoadClass()) << last_input->DebugName();
87
88    // Remove a load class instruction as last input of a static
89    // invoke, which has been added (along with a clinit check,
90    // removed by PrepareForRegisterAllocation::VisitClinitCheck
91    // previously) by the graph builder during the creation of the
92    // static invoke instruction, but is no longer required at this
93    // stage (i.e., after inlining has been performed).
94    invoke->RemoveLoadClassAsLastInput();
95
96    // If the load class instruction is no longer used, remove it from
97    // the graph.
98    if (!last_input->HasUses()) {
99      last_input->GetBlock()->RemoveInstruction(last_input);
100    }
101  }
102}
103
104}  // namespace art
105