xref: /aosp_15_r20/art/compiler/optimizing/ssa_builder.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 "ssa_builder.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/logging.h"
22*795d594fSAndroid Build Coastguard Worker #include "data_type-inl.h"
23*795d594fSAndroid Build Coastguard Worker #include "dex/bytecode_utils.h"
24*795d594fSAndroid Build Coastguard Worker #include "mirror/class-inl.h"
25*795d594fSAndroid Build Coastguard Worker #include "nodes.h"
26*795d594fSAndroid Build Coastguard Worker #include "reference_type_propagation.h"
27*795d594fSAndroid Build Coastguard Worker #include "scoped_thread_state_change-inl.h"
28*795d594fSAndroid Build Coastguard Worker #include "ssa_phi_elimination.h"
29*795d594fSAndroid Build Coastguard Worker 
30*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
31*795d594fSAndroid Build Coastguard Worker 
FixNullConstantType()32*795d594fSAndroid Build Coastguard Worker void SsaBuilder::FixNullConstantType() {
33*795d594fSAndroid Build Coastguard Worker   // The order doesn't matter here.
34*795d594fSAndroid Build Coastguard Worker   for (HBasicBlock* block : graph_->GetReversePostOrder()) {
35*795d594fSAndroid Build Coastguard Worker     for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
36*795d594fSAndroid Build Coastguard Worker       HInstruction* equality_instr = it.Current();
37*795d594fSAndroid Build Coastguard Worker       if (!equality_instr->IsEqual() && !equality_instr->IsNotEqual()) {
38*795d594fSAndroid Build Coastguard Worker         continue;
39*795d594fSAndroid Build Coastguard Worker       }
40*795d594fSAndroid Build Coastguard Worker       HInstruction* left = equality_instr->InputAt(0);
41*795d594fSAndroid Build Coastguard Worker       HInstruction* right = equality_instr->InputAt(1);
42*795d594fSAndroid Build Coastguard Worker       HInstruction* int_operand = nullptr;
43*795d594fSAndroid Build Coastguard Worker 
44*795d594fSAndroid Build Coastguard Worker       if ((left->GetType() == DataType::Type::kReference) &&
45*795d594fSAndroid Build Coastguard Worker           (right->GetType() == DataType::Type::kInt32)) {
46*795d594fSAndroid Build Coastguard Worker         int_operand = right;
47*795d594fSAndroid Build Coastguard Worker       } else if ((right->GetType() == DataType::Type::kReference) &&
48*795d594fSAndroid Build Coastguard Worker                  (left->GetType() == DataType::Type::kInt32)) {
49*795d594fSAndroid Build Coastguard Worker         int_operand = left;
50*795d594fSAndroid Build Coastguard Worker       } else {
51*795d594fSAndroid Build Coastguard Worker         continue;
52*795d594fSAndroid Build Coastguard Worker       }
53*795d594fSAndroid Build Coastguard Worker 
54*795d594fSAndroid Build Coastguard Worker       // If we got here, we are comparing against a reference and the int constant
55*795d594fSAndroid Build Coastguard Worker       // should be replaced with a null constant.
56*795d594fSAndroid Build Coastguard Worker       // Both type propagation and redundant phi elimination ensure `int_operand`
57*795d594fSAndroid Build Coastguard Worker       // can only be the 0 constant.
58*795d594fSAndroid Build Coastguard Worker       DCHECK(int_operand->IsIntConstant()) << int_operand->DebugName();
59*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(0, int_operand->AsIntConstant()->GetValue());
60*795d594fSAndroid Build Coastguard Worker       equality_instr->ReplaceInput(graph_->GetNullConstant(), int_operand == right ? 1 : 0);
61*795d594fSAndroid Build Coastguard Worker     }
62*795d594fSAndroid Build Coastguard Worker   }
63*795d594fSAndroid Build Coastguard Worker }
64*795d594fSAndroid Build Coastguard Worker 
EquivalentPhisCleanup()65*795d594fSAndroid Build Coastguard Worker void SsaBuilder::EquivalentPhisCleanup() {
66*795d594fSAndroid Build Coastguard Worker   // The order doesn't matter here.
67*795d594fSAndroid Build Coastguard Worker   for (HBasicBlock* block : graph_->GetReversePostOrder()) {
68*795d594fSAndroid Build Coastguard Worker     for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
69*795d594fSAndroid Build Coastguard Worker       HPhi* phi = it.Current()->AsPhi();
70*795d594fSAndroid Build Coastguard Worker       HPhi* next = phi->GetNextEquivalentPhiWithSameType();
71*795d594fSAndroid Build Coastguard Worker       if (next != nullptr) {
72*795d594fSAndroid Build Coastguard Worker         // Make sure we do not replace a live phi with a dead phi. A live phi
73*795d594fSAndroid Build Coastguard Worker         // has been handled by the type propagation phase, unlike a dead phi.
74*795d594fSAndroid Build Coastguard Worker         if (next->IsLive()) {
75*795d594fSAndroid Build Coastguard Worker           phi->ReplaceWith(next);
76*795d594fSAndroid Build Coastguard Worker           phi->SetDead();
77*795d594fSAndroid Build Coastguard Worker         } else {
78*795d594fSAndroid Build Coastguard Worker           next->ReplaceWith(phi);
79*795d594fSAndroid Build Coastguard Worker         }
80*795d594fSAndroid Build Coastguard Worker         DCHECK(next->GetNextEquivalentPhiWithSameType() == nullptr)
81*795d594fSAndroid Build Coastguard Worker             << "More then one phi equivalent with type " << phi->GetType()
82*795d594fSAndroid Build Coastguard Worker             << " found for phi" << phi->GetId();
83*795d594fSAndroid Build Coastguard Worker       }
84*795d594fSAndroid Build Coastguard Worker     }
85*795d594fSAndroid Build Coastguard Worker   }
86*795d594fSAndroid Build Coastguard Worker }
87*795d594fSAndroid Build Coastguard Worker 
FixEnvironmentPhis()88*795d594fSAndroid Build Coastguard Worker void SsaBuilder::FixEnvironmentPhis() {
89*795d594fSAndroid Build Coastguard Worker   for (HBasicBlock* block : graph_->GetReversePostOrder()) {
90*795d594fSAndroid Build Coastguard Worker     for (HInstructionIterator it_phis(block->GetPhis()); !it_phis.Done(); it_phis.Advance()) {
91*795d594fSAndroid Build Coastguard Worker       HPhi* phi = it_phis.Current()->AsPhi();
92*795d594fSAndroid Build Coastguard Worker       // If the phi is not dead, or has no environment uses, there is nothing to do.
93*795d594fSAndroid Build Coastguard Worker       if (!phi->IsDead() || !phi->HasEnvironmentUses()) continue;
94*795d594fSAndroid Build Coastguard Worker       HInstruction* next = phi->GetNext();
95*795d594fSAndroid Build Coastguard Worker       if (!phi->IsVRegEquivalentOf(next)) continue;
96*795d594fSAndroid Build Coastguard Worker       if (next->AsPhi()->IsDead()) {
97*795d594fSAndroid Build Coastguard Worker         // If the phi equivalent is dead, check if there is another one.
98*795d594fSAndroid Build Coastguard Worker         next = next->GetNext();
99*795d594fSAndroid Build Coastguard Worker         if (!phi->IsVRegEquivalentOf(next)) continue;
100*795d594fSAndroid Build Coastguard Worker         // There can be at most two phi equivalents.
101*795d594fSAndroid Build Coastguard Worker         DCHECK(!phi->IsVRegEquivalentOf(next->GetNext()));
102*795d594fSAndroid Build Coastguard Worker         if (next->AsPhi()->IsDead()) continue;
103*795d594fSAndroid Build Coastguard Worker       }
104*795d594fSAndroid Build Coastguard Worker       // We found a live phi equivalent. Update the environment uses of `phi` with it.
105*795d594fSAndroid Build Coastguard Worker       phi->ReplaceWith(next);
106*795d594fSAndroid Build Coastguard Worker     }
107*795d594fSAndroid Build Coastguard Worker   }
108*795d594fSAndroid Build Coastguard Worker }
109*795d594fSAndroid Build Coastguard Worker 
AddDependentInstructionsToWorklist(HInstruction * instruction,ScopedArenaVector<HPhi * > * worklist)110*795d594fSAndroid Build Coastguard Worker static void AddDependentInstructionsToWorklist(HInstruction* instruction,
111*795d594fSAndroid Build Coastguard Worker                                                ScopedArenaVector<HPhi*>* worklist) {
112*795d594fSAndroid Build Coastguard Worker   // If `instruction` is a dead phi, type conflict was just identified. All its
113*795d594fSAndroid Build Coastguard Worker   // live phi users, and transitively users of those users, therefore need to be
114*795d594fSAndroid Build Coastguard Worker   // marked dead/conflicting too, so we add them to the worklist. Otherwise we
115*795d594fSAndroid Build Coastguard Worker   // add users whose type does not match and needs to be updated.
116*795d594fSAndroid Build Coastguard Worker   bool add_all_live_phis = instruction->IsPhi() && instruction->AsPhi()->IsDead();
117*795d594fSAndroid Build Coastguard Worker   for (const HUseListNode<HInstruction*>& use : instruction->GetUses()) {
118*795d594fSAndroid Build Coastguard Worker     HInstruction* user = use.GetUser();
119*795d594fSAndroid Build Coastguard Worker     if (user->IsPhi() && user->AsPhi()->IsLive()) {
120*795d594fSAndroid Build Coastguard Worker       if (add_all_live_phis || user->GetType() != instruction->GetType()) {
121*795d594fSAndroid Build Coastguard Worker         worklist->push_back(user->AsPhi());
122*795d594fSAndroid Build Coastguard Worker       }
123*795d594fSAndroid Build Coastguard Worker     }
124*795d594fSAndroid Build Coastguard Worker   }
125*795d594fSAndroid Build Coastguard Worker }
126*795d594fSAndroid Build Coastguard Worker 
127*795d594fSAndroid Build Coastguard Worker // Find a candidate primitive type for `phi` by merging the type of its inputs.
128*795d594fSAndroid Build Coastguard Worker // Return false if conflict is identified.
TypePhiFromInputs(HPhi * phi)129*795d594fSAndroid Build Coastguard Worker static bool TypePhiFromInputs(HPhi* phi) {
130*795d594fSAndroid Build Coastguard Worker   DataType::Type common_type = phi->GetType();
131*795d594fSAndroid Build Coastguard Worker 
132*795d594fSAndroid Build Coastguard Worker   for (HInstruction* input : phi->GetInputs()) {
133*795d594fSAndroid Build Coastguard Worker     if (input->IsPhi() && input->AsPhi()->IsDead()) {
134*795d594fSAndroid Build Coastguard Worker       // Phis are constructed live so if an input is a dead phi, it must have
135*795d594fSAndroid Build Coastguard Worker       // been made dead due to type conflict. Mark this phi conflicting too.
136*795d594fSAndroid Build Coastguard Worker       return false;
137*795d594fSAndroid Build Coastguard Worker     }
138*795d594fSAndroid Build Coastguard Worker 
139*795d594fSAndroid Build Coastguard Worker     DataType::Type input_type = HPhi::ToPhiType(input->GetType());
140*795d594fSAndroid Build Coastguard Worker     if (common_type == input_type) {
141*795d594fSAndroid Build Coastguard Worker       // No change in type.
142*795d594fSAndroid Build Coastguard Worker     } else if (DataType::Is64BitType(common_type) != DataType::Is64BitType(input_type)) {
143*795d594fSAndroid Build Coastguard Worker       // Types are of different sizes, e.g. int vs. long. Must be a conflict.
144*795d594fSAndroid Build Coastguard Worker       return false;
145*795d594fSAndroid Build Coastguard Worker     } else if (DataType::IsIntegralType(common_type)) {
146*795d594fSAndroid Build Coastguard Worker       // Previous inputs were integral, this one is not but is of the same size.
147*795d594fSAndroid Build Coastguard Worker       // This does not imply conflict since some bytecode instruction types are
148*795d594fSAndroid Build Coastguard Worker       // ambiguous. TypeInputsOfPhi will either type them or detect a conflict.
149*795d594fSAndroid Build Coastguard Worker       DCHECK(DataType::IsFloatingPointType(input_type) ||
150*795d594fSAndroid Build Coastguard Worker              input_type == DataType::Type::kReference);
151*795d594fSAndroid Build Coastguard Worker       common_type = input_type;
152*795d594fSAndroid Build Coastguard Worker     } else if (DataType::IsIntegralType(input_type)) {
153*795d594fSAndroid Build Coastguard Worker       // Input is integral, common type is not. Same as in the previous case, if
154*795d594fSAndroid Build Coastguard Worker       // there is a conflict, it will be detected during TypeInputsOfPhi.
155*795d594fSAndroid Build Coastguard Worker       DCHECK(DataType::IsFloatingPointType(common_type) ||
156*795d594fSAndroid Build Coastguard Worker              common_type == DataType::Type::kReference);
157*795d594fSAndroid Build Coastguard Worker     } else {
158*795d594fSAndroid Build Coastguard Worker       // Combining float and reference types. Clearly a conflict.
159*795d594fSAndroid Build Coastguard Worker       DCHECK(
160*795d594fSAndroid Build Coastguard Worker           (common_type == DataType::Type::kFloat32 && input_type == DataType::Type::kReference) ||
161*795d594fSAndroid Build Coastguard Worker           (common_type == DataType::Type::kReference && input_type == DataType::Type::kFloat32));
162*795d594fSAndroid Build Coastguard Worker       return false;
163*795d594fSAndroid Build Coastguard Worker     }
164*795d594fSAndroid Build Coastguard Worker   }
165*795d594fSAndroid Build Coastguard Worker 
166*795d594fSAndroid Build Coastguard Worker   // We have found a candidate type for the phi. Set it and return true. We may
167*795d594fSAndroid Build Coastguard Worker   // still discover conflict whilst typing the individual inputs in TypeInputsOfPhi.
168*795d594fSAndroid Build Coastguard Worker   phi->SetType(common_type);
169*795d594fSAndroid Build Coastguard Worker   return true;
170*795d594fSAndroid Build Coastguard Worker }
171*795d594fSAndroid Build Coastguard Worker 
172*795d594fSAndroid Build Coastguard Worker // Replace inputs of `phi` to match its type. Return false if conflict is identified.
TypeInputsOfPhi(HPhi * phi,ScopedArenaVector<HPhi * > * worklist)173*795d594fSAndroid Build Coastguard Worker bool SsaBuilder::TypeInputsOfPhi(HPhi* phi, ScopedArenaVector<HPhi*>* worklist) {
174*795d594fSAndroid Build Coastguard Worker   DataType::Type common_type = phi->GetType();
175*795d594fSAndroid Build Coastguard Worker   if (DataType::IsIntegralType(common_type)) {
176*795d594fSAndroid Build Coastguard Worker     // We do not need to retype ambiguous inputs because they are always constructed
177*795d594fSAndroid Build Coastguard Worker     // with the integral type candidate.
178*795d594fSAndroid Build Coastguard Worker     if (kIsDebugBuild) {
179*795d594fSAndroid Build Coastguard Worker       for (HInstruction* input : phi->GetInputs()) {
180*795d594fSAndroid Build Coastguard Worker         DCHECK(HPhi::ToPhiType(input->GetType()) == common_type);
181*795d594fSAndroid Build Coastguard Worker       }
182*795d594fSAndroid Build Coastguard Worker     }
183*795d594fSAndroid Build Coastguard Worker     // Inputs did not need to be replaced, hence no conflict. Report success.
184*795d594fSAndroid Build Coastguard Worker     return true;
185*795d594fSAndroid Build Coastguard Worker   } else {
186*795d594fSAndroid Build Coastguard Worker     DCHECK(common_type == DataType::Type::kReference ||
187*795d594fSAndroid Build Coastguard Worker            DataType::IsFloatingPointType(common_type));
188*795d594fSAndroid Build Coastguard Worker     HInputsRef inputs = phi->GetInputs();
189*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0; i < inputs.size(); ++i) {
190*795d594fSAndroid Build Coastguard Worker       HInstruction* input = inputs[i];
191*795d594fSAndroid Build Coastguard Worker       if (input->GetType() != common_type) {
192*795d594fSAndroid Build Coastguard Worker         // Input type does not match phi's type. Try to retype the input or
193*795d594fSAndroid Build Coastguard Worker         // generate a suitably typed equivalent.
194*795d594fSAndroid Build Coastguard Worker         HInstruction* equivalent = (common_type == DataType::Type::kReference)
195*795d594fSAndroid Build Coastguard Worker             ? GetReferenceTypeEquivalent(input)
196*795d594fSAndroid Build Coastguard Worker             : GetFloatOrDoubleEquivalent(input, common_type);
197*795d594fSAndroid Build Coastguard Worker         if (equivalent == nullptr) {
198*795d594fSAndroid Build Coastguard Worker           // Input could not be typed. Report conflict.
199*795d594fSAndroid Build Coastguard Worker           return false;
200*795d594fSAndroid Build Coastguard Worker         }
201*795d594fSAndroid Build Coastguard Worker         // Make sure the input did not change its type and we do not need to
202*795d594fSAndroid Build Coastguard Worker         // update its users.
203*795d594fSAndroid Build Coastguard Worker         DCHECK_NE(input, equivalent);
204*795d594fSAndroid Build Coastguard Worker 
205*795d594fSAndroid Build Coastguard Worker         phi->ReplaceInput(equivalent, i);
206*795d594fSAndroid Build Coastguard Worker         if (equivalent->IsPhi()) {
207*795d594fSAndroid Build Coastguard Worker           worklist->push_back(equivalent->AsPhi());
208*795d594fSAndroid Build Coastguard Worker         }
209*795d594fSAndroid Build Coastguard Worker       }
210*795d594fSAndroid Build Coastguard Worker     }
211*795d594fSAndroid Build Coastguard Worker     // All inputs either matched the type of the phi or we successfully replaced
212*795d594fSAndroid Build Coastguard Worker     // them with a suitable equivalent. Report success.
213*795d594fSAndroid Build Coastguard Worker     return true;
214*795d594fSAndroid Build Coastguard Worker   }
215*795d594fSAndroid Build Coastguard Worker }
216*795d594fSAndroid Build Coastguard Worker 
217*795d594fSAndroid Build Coastguard Worker // Attempt to set the primitive type of `phi` to match its inputs. Return whether
218*795d594fSAndroid Build Coastguard Worker // it was changed by the algorithm or not.
UpdatePrimitiveType(HPhi * phi,ScopedArenaVector<HPhi * > * worklist)219*795d594fSAndroid Build Coastguard Worker bool SsaBuilder::UpdatePrimitiveType(HPhi* phi, ScopedArenaVector<HPhi*>* worklist) {
220*795d594fSAndroid Build Coastguard Worker   DCHECK(phi->IsLive());
221*795d594fSAndroid Build Coastguard Worker   DataType::Type original_type = phi->GetType();
222*795d594fSAndroid Build Coastguard Worker 
223*795d594fSAndroid Build Coastguard Worker   // Try to type the phi in two stages:
224*795d594fSAndroid Build Coastguard Worker   // (1) find a candidate type for the phi by merging types of all its inputs,
225*795d594fSAndroid Build Coastguard Worker   // (2) try to type the phi's inputs to that candidate type.
226*795d594fSAndroid Build Coastguard Worker   // Either of these stages may detect a type conflict and fail, in which case
227*795d594fSAndroid Build Coastguard Worker   // we immediately abort.
228*795d594fSAndroid Build Coastguard Worker   if (!TypePhiFromInputs(phi) || !TypeInputsOfPhi(phi, worklist)) {
229*795d594fSAndroid Build Coastguard Worker     // Conflict detected. Mark the phi dead and return true because it changed.
230*795d594fSAndroid Build Coastguard Worker     phi->SetDead();
231*795d594fSAndroid Build Coastguard Worker     return true;
232*795d594fSAndroid Build Coastguard Worker   }
233*795d594fSAndroid Build Coastguard Worker 
234*795d594fSAndroid Build Coastguard Worker   // Return true if the type of the phi has changed.
235*795d594fSAndroid Build Coastguard Worker   return phi->GetType() != original_type;
236*795d594fSAndroid Build Coastguard Worker }
237*795d594fSAndroid Build Coastguard Worker 
RunPrimitiveTypePropagation()238*795d594fSAndroid Build Coastguard Worker void SsaBuilder::RunPrimitiveTypePropagation() {
239*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<HPhi*> worklist(local_allocator_->Adapter(kArenaAllocGraphBuilder));
240*795d594fSAndroid Build Coastguard Worker 
241*795d594fSAndroid Build Coastguard Worker   for (HBasicBlock* block : graph_->GetReversePostOrder()) {
242*795d594fSAndroid Build Coastguard Worker     if (block->IsLoopHeader()) {
243*795d594fSAndroid Build Coastguard Worker       for (HInstructionIterator phi_it(block->GetPhis()); !phi_it.Done(); phi_it.Advance()) {
244*795d594fSAndroid Build Coastguard Worker         HPhi* phi = phi_it.Current()->AsPhi();
245*795d594fSAndroid Build Coastguard Worker         if (phi->IsLive()) {
246*795d594fSAndroid Build Coastguard Worker           worklist.push_back(phi);
247*795d594fSAndroid Build Coastguard Worker         }
248*795d594fSAndroid Build Coastguard Worker       }
249*795d594fSAndroid Build Coastguard Worker     } else {
250*795d594fSAndroid Build Coastguard Worker       for (HInstructionIterator phi_it(block->GetPhis()); !phi_it.Done(); phi_it.Advance()) {
251*795d594fSAndroid Build Coastguard Worker         // Eagerly compute the type of the phi, for quicker convergence. Note
252*795d594fSAndroid Build Coastguard Worker         // that we don't need to add users to the worklist because we are
253*795d594fSAndroid Build Coastguard Worker         // doing a reverse post-order visit, therefore either the phi users are
254*795d594fSAndroid Build Coastguard Worker         // non-loop phi and will be visited later in the visit, or are loop-phis,
255*795d594fSAndroid Build Coastguard Worker         // and they are already in the work list.
256*795d594fSAndroid Build Coastguard Worker         HPhi* phi = phi_it.Current()->AsPhi();
257*795d594fSAndroid Build Coastguard Worker         if (phi->IsLive()) {
258*795d594fSAndroid Build Coastguard Worker           UpdatePrimitiveType(phi, &worklist);
259*795d594fSAndroid Build Coastguard Worker         }
260*795d594fSAndroid Build Coastguard Worker       }
261*795d594fSAndroid Build Coastguard Worker     }
262*795d594fSAndroid Build Coastguard Worker   }
263*795d594fSAndroid Build Coastguard Worker 
264*795d594fSAndroid Build Coastguard Worker   ProcessPrimitiveTypePropagationWorklist(&worklist);
265*795d594fSAndroid Build Coastguard Worker   EquivalentPhisCleanup();
266*795d594fSAndroid Build Coastguard Worker }
267*795d594fSAndroid Build Coastguard Worker 
ProcessPrimitiveTypePropagationWorklist(ScopedArenaVector<HPhi * > * worklist)268*795d594fSAndroid Build Coastguard Worker void SsaBuilder::ProcessPrimitiveTypePropagationWorklist(ScopedArenaVector<HPhi*>* worklist) {
269*795d594fSAndroid Build Coastguard Worker   // Process worklist
270*795d594fSAndroid Build Coastguard Worker   while (!worklist->empty()) {
271*795d594fSAndroid Build Coastguard Worker     HPhi* phi = worklist->back();
272*795d594fSAndroid Build Coastguard Worker     worklist->pop_back();
273*795d594fSAndroid Build Coastguard Worker     // The phi could have been made dead as a result of conflicts while in the
274*795d594fSAndroid Build Coastguard Worker     // worklist. If it is now dead, there is no point in updating its type.
275*795d594fSAndroid Build Coastguard Worker     if (phi->IsLive() && UpdatePrimitiveType(phi, worklist)) {
276*795d594fSAndroid Build Coastguard Worker       AddDependentInstructionsToWorklist(phi, worklist);
277*795d594fSAndroid Build Coastguard Worker     }
278*795d594fSAndroid Build Coastguard Worker   }
279*795d594fSAndroid Build Coastguard Worker }
280*795d594fSAndroid Build Coastguard Worker 
FindFloatOrDoubleEquivalentOfArrayGet(HArrayGet * aget)281*795d594fSAndroid Build Coastguard Worker static HArrayGet* FindFloatOrDoubleEquivalentOfArrayGet(HArrayGet* aget) {
282*795d594fSAndroid Build Coastguard Worker   DataType::Type type = aget->GetType();
283*795d594fSAndroid Build Coastguard Worker   DCHECK(DataType::IsIntOrLongType(type));
284*795d594fSAndroid Build Coastguard Worker   HInstruction* next = aget->GetNext();
285*795d594fSAndroid Build Coastguard Worker   if (next != nullptr && next->IsArrayGet()) {
286*795d594fSAndroid Build Coastguard Worker     HArrayGet* next_aget = next->AsArrayGet();
287*795d594fSAndroid Build Coastguard Worker     if (next_aget->IsEquivalentOf(aget)) {
288*795d594fSAndroid Build Coastguard Worker       return next_aget;
289*795d594fSAndroid Build Coastguard Worker     }
290*795d594fSAndroid Build Coastguard Worker   }
291*795d594fSAndroid Build Coastguard Worker   return nullptr;
292*795d594fSAndroid Build Coastguard Worker }
293*795d594fSAndroid Build Coastguard Worker 
CreateFloatOrDoubleEquivalentOfArrayGet(HArrayGet * aget)294*795d594fSAndroid Build Coastguard Worker static HArrayGet* CreateFloatOrDoubleEquivalentOfArrayGet(HArrayGet* aget) {
295*795d594fSAndroid Build Coastguard Worker   DataType::Type type = aget->GetType();
296*795d594fSAndroid Build Coastguard Worker   DCHECK(DataType::IsIntOrLongType(type));
297*795d594fSAndroid Build Coastguard Worker   DCHECK(FindFloatOrDoubleEquivalentOfArrayGet(aget) == nullptr);
298*795d594fSAndroid Build Coastguard Worker 
299*795d594fSAndroid Build Coastguard Worker   HArrayGet* equivalent = new (aget->GetBlock()->GetGraph()->GetAllocator()) HArrayGet(
300*795d594fSAndroid Build Coastguard Worker       aget->GetArray(),
301*795d594fSAndroid Build Coastguard Worker       aget->GetIndex(),
302*795d594fSAndroid Build Coastguard Worker       type == DataType::Type::kInt32 ? DataType::Type::kFloat32 : DataType::Type::kFloat64,
303*795d594fSAndroid Build Coastguard Worker       aget->GetDexPc());
304*795d594fSAndroid Build Coastguard Worker   aget->GetBlock()->InsertInstructionAfter(equivalent, aget);
305*795d594fSAndroid Build Coastguard Worker   return equivalent;
306*795d594fSAndroid Build Coastguard Worker }
307*795d594fSAndroid Build Coastguard Worker 
GetPrimitiveArrayComponentType(HInstruction * array)308*795d594fSAndroid Build Coastguard Worker static DataType::Type GetPrimitiveArrayComponentType(HInstruction* array)
309*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
310*795d594fSAndroid Build Coastguard Worker   ReferenceTypeInfo array_type = array->GetReferenceTypeInfo();
311*795d594fSAndroid Build Coastguard Worker   DCHECK(array_type.IsPrimitiveArrayClass());
312*795d594fSAndroid Build Coastguard Worker   return DataTypeFromPrimitive(
313*795d594fSAndroid Build Coastguard Worker       array_type.GetTypeHandle()->GetComponentType()->GetPrimitiveType());
314*795d594fSAndroid Build Coastguard Worker }
315*795d594fSAndroid Build Coastguard Worker 
FixAmbiguousArrayOps()316*795d594fSAndroid Build Coastguard Worker bool SsaBuilder::FixAmbiguousArrayOps() {
317*795d594fSAndroid Build Coastguard Worker   if (ambiguous_agets_.empty() && ambiguous_asets_.empty()) {
318*795d594fSAndroid Build Coastguard Worker     return true;
319*795d594fSAndroid Build Coastguard Worker   }
320*795d594fSAndroid Build Coastguard Worker 
321*795d594fSAndroid Build Coastguard Worker   // The wrong ArrayGet equivalent may still have Phi uses coming from ArraySet
322*795d594fSAndroid Build Coastguard Worker   // uses (because they are untyped) and environment uses (if --debuggable).
323*795d594fSAndroid Build Coastguard Worker   // After resolving all ambiguous ArrayGets, we will re-run primitive type
324*795d594fSAndroid Build Coastguard Worker   // propagation on the Phis which need to be updated.
325*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<HPhi*> worklist(local_allocator_->Adapter(kArenaAllocGraphBuilder));
326*795d594fSAndroid Build Coastguard Worker 
327*795d594fSAndroid Build Coastguard Worker   {
328*795d594fSAndroid Build Coastguard Worker     ScopedObjectAccess soa(Thread::Current());
329*795d594fSAndroid Build Coastguard Worker 
330*795d594fSAndroid Build Coastguard Worker     for (HArrayGet* aget_int : ambiguous_agets_) {
331*795d594fSAndroid Build Coastguard Worker       HInstruction* array = aget_int->GetArray();
332*795d594fSAndroid Build Coastguard Worker       if (!array->GetReferenceTypeInfo().IsPrimitiveArrayClass()) {
333*795d594fSAndroid Build Coastguard Worker         // RTP did not type the input array. Bail.
334*795d594fSAndroid Build Coastguard Worker         VLOG(compiler) << "Not compiled: Could not infer an array type for array operation at "
335*795d594fSAndroid Build Coastguard Worker                        << aget_int->GetDexPc();
336*795d594fSAndroid Build Coastguard Worker         return false;
337*795d594fSAndroid Build Coastguard Worker       }
338*795d594fSAndroid Build Coastguard Worker 
339*795d594fSAndroid Build Coastguard Worker       HArrayGet* aget_float = FindFloatOrDoubleEquivalentOfArrayGet(aget_int);
340*795d594fSAndroid Build Coastguard Worker       DataType::Type array_type = GetPrimitiveArrayComponentType(array);
341*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(DataType::Is64BitType(aget_int->GetType()), DataType::Is64BitType(array_type));
342*795d594fSAndroid Build Coastguard Worker 
343*795d594fSAndroid Build Coastguard Worker       if (DataType::IsIntOrLongType(array_type)) {
344*795d594fSAndroid Build Coastguard Worker         if (aget_float != nullptr) {
345*795d594fSAndroid Build Coastguard Worker           // There is a float/double equivalent. We must replace it and re-run
346*795d594fSAndroid Build Coastguard Worker           // primitive type propagation on all dependent instructions.
347*795d594fSAndroid Build Coastguard Worker           aget_float->ReplaceWith(aget_int);
348*795d594fSAndroid Build Coastguard Worker           aget_float->GetBlock()->RemoveInstruction(aget_float);
349*795d594fSAndroid Build Coastguard Worker           AddDependentInstructionsToWorklist(aget_int, &worklist);
350*795d594fSAndroid Build Coastguard Worker         }
351*795d594fSAndroid Build Coastguard Worker       } else {
352*795d594fSAndroid Build Coastguard Worker         DCHECK(DataType::IsFloatingPointType(array_type));
353*795d594fSAndroid Build Coastguard Worker         if (aget_float == nullptr) {
354*795d594fSAndroid Build Coastguard Worker           // This is a float/double ArrayGet but there were no typed uses which
355*795d594fSAndroid Build Coastguard Worker           // would create the typed equivalent. Create it now.
356*795d594fSAndroid Build Coastguard Worker           aget_float = CreateFloatOrDoubleEquivalentOfArrayGet(aget_int);
357*795d594fSAndroid Build Coastguard Worker         }
358*795d594fSAndroid Build Coastguard Worker         // Replace the original int/long instruction. Note that it may have phi
359*795d594fSAndroid Build Coastguard Worker         // uses, environment uses, as well as real uses (from untyped ArraySets).
360*795d594fSAndroid Build Coastguard Worker         // We need to re-run primitive type propagation on its dependent instructions.
361*795d594fSAndroid Build Coastguard Worker         aget_int->ReplaceWith(aget_float);
362*795d594fSAndroid Build Coastguard Worker         aget_int->GetBlock()->RemoveInstruction(aget_int);
363*795d594fSAndroid Build Coastguard Worker         AddDependentInstructionsToWorklist(aget_float, &worklist);
364*795d594fSAndroid Build Coastguard Worker       }
365*795d594fSAndroid Build Coastguard Worker     }
366*795d594fSAndroid Build Coastguard Worker 
367*795d594fSAndroid Build Coastguard Worker     // Set a flag stating that types of ArrayGets have been resolved. Requesting
368*795d594fSAndroid Build Coastguard Worker     // equivalent of the wrong type with GetFloatOrDoubleEquivalentOfArrayGet
369*795d594fSAndroid Build Coastguard Worker     // will fail from now on.
370*795d594fSAndroid Build Coastguard Worker     agets_fixed_ = true;
371*795d594fSAndroid Build Coastguard Worker 
372*795d594fSAndroid Build Coastguard Worker     for (HArraySet* aset : ambiguous_asets_) {
373*795d594fSAndroid Build Coastguard Worker       HInstruction* array = aset->GetArray();
374*795d594fSAndroid Build Coastguard Worker       if (!array->GetReferenceTypeInfo().IsPrimitiveArrayClass()) {
375*795d594fSAndroid Build Coastguard Worker         // RTP did not type the input array. Bail.
376*795d594fSAndroid Build Coastguard Worker         VLOG(compiler) << "Not compiled: Could not infer an array type for array operation at "
377*795d594fSAndroid Build Coastguard Worker                        << aset->GetDexPc();
378*795d594fSAndroid Build Coastguard Worker         return false;
379*795d594fSAndroid Build Coastguard Worker       }
380*795d594fSAndroid Build Coastguard Worker 
381*795d594fSAndroid Build Coastguard Worker       HInstruction* value = aset->GetValue();
382*795d594fSAndroid Build Coastguard Worker       DataType::Type value_type = value->GetType();
383*795d594fSAndroid Build Coastguard Worker       DataType::Type array_type = GetPrimitiveArrayComponentType(array);
384*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(DataType::Is64BitType(value_type), DataType::Is64BitType(array_type));
385*795d594fSAndroid Build Coastguard Worker 
386*795d594fSAndroid Build Coastguard Worker       if (DataType::IsFloatingPointType(array_type)) {
387*795d594fSAndroid Build Coastguard Worker         if (!DataType::IsFloatingPointType(value_type)) {
388*795d594fSAndroid Build Coastguard Worker           DCHECK(DataType::IsIntegralType(value_type));
389*795d594fSAndroid Build Coastguard Worker           // Array elements are floating-point but the value has not been replaced
390*795d594fSAndroid Build Coastguard Worker           // with its floating-point equivalent. The replacement must always
391*795d594fSAndroid Build Coastguard Worker           // succeed in code validated by the verifier.
392*795d594fSAndroid Build Coastguard Worker           HInstruction* equivalent = GetFloatOrDoubleEquivalent(value, array_type);
393*795d594fSAndroid Build Coastguard Worker           DCHECK(equivalent != nullptr);
394*795d594fSAndroid Build Coastguard Worker           aset->ReplaceInput(equivalent, /* index= */ 2);
395*795d594fSAndroid Build Coastguard Worker           if (equivalent->IsPhi()) {
396*795d594fSAndroid Build Coastguard Worker             // Returned equivalent is a phi which may not have had its inputs
397*795d594fSAndroid Build Coastguard Worker             // replaced yet. We need to run primitive type propagation on it.
398*795d594fSAndroid Build Coastguard Worker             worklist.push_back(equivalent->AsPhi());
399*795d594fSAndroid Build Coastguard Worker           }
400*795d594fSAndroid Build Coastguard Worker         }
401*795d594fSAndroid Build Coastguard Worker         // Refine the side effects of this floating point aset. Note that we do this even if
402*795d594fSAndroid Build Coastguard Worker         // no replacement occurs, since the right-hand-side may have been corrected already.
403*795d594fSAndroid Build Coastguard Worker         aset->SetSideEffects(HArraySet::ComputeSideEffects(aset->GetComponentType()));
404*795d594fSAndroid Build Coastguard Worker       } else {
405*795d594fSAndroid Build Coastguard Worker         // Array elements are integral and the value assigned to it initially
406*795d594fSAndroid Build Coastguard Worker         // was integral too. Nothing to do.
407*795d594fSAndroid Build Coastguard Worker         DCHECK(DataType::IsIntegralType(array_type));
408*795d594fSAndroid Build Coastguard Worker         DCHECK(DataType::IsIntegralType(value_type));
409*795d594fSAndroid Build Coastguard Worker       }
410*795d594fSAndroid Build Coastguard Worker     }
411*795d594fSAndroid Build Coastguard Worker   }
412*795d594fSAndroid Build Coastguard Worker 
413*795d594fSAndroid Build Coastguard Worker   if (!worklist.empty()) {
414*795d594fSAndroid Build Coastguard Worker     ProcessPrimitiveTypePropagationWorklist(&worklist);
415*795d594fSAndroid Build Coastguard Worker     EquivalentPhisCleanup();
416*795d594fSAndroid Build Coastguard Worker   }
417*795d594fSAndroid Build Coastguard Worker 
418*795d594fSAndroid Build Coastguard Worker   return true;
419*795d594fSAndroid Build Coastguard Worker }
420*795d594fSAndroid Build Coastguard Worker 
HasAliasInEnvironments(HInstruction * instruction)421*795d594fSAndroid Build Coastguard Worker bool SsaBuilder::HasAliasInEnvironments(HInstruction* instruction) {
422*795d594fSAndroid Build Coastguard Worker   ScopedArenaHashSet<size_t> seen_users(
423*795d594fSAndroid Build Coastguard Worker       local_allocator_->Adapter(kArenaAllocGraphBuilder));
424*795d594fSAndroid Build Coastguard Worker   for (const HUseListNode<HEnvironment*>& use : instruction->GetEnvUses()) {
425*795d594fSAndroid Build Coastguard Worker     DCHECK(use.GetUser() != nullptr);
426*795d594fSAndroid Build Coastguard Worker     size_t id = use.GetUser()->GetHolder()->GetId();
427*795d594fSAndroid Build Coastguard Worker     if (seen_users.find(id) != seen_users.end()) {
428*795d594fSAndroid Build Coastguard Worker       return true;
429*795d594fSAndroid Build Coastguard Worker     }
430*795d594fSAndroid Build Coastguard Worker     seen_users.insert(id);
431*795d594fSAndroid Build Coastguard Worker   }
432*795d594fSAndroid Build Coastguard Worker   return false;
433*795d594fSAndroid Build Coastguard Worker }
434*795d594fSAndroid Build Coastguard Worker 
ReplaceUninitializedStringPhis()435*795d594fSAndroid Build Coastguard Worker bool SsaBuilder::ReplaceUninitializedStringPhis() {
436*795d594fSAndroid Build Coastguard Worker   for (HInvoke* invoke : uninitialized_string_phis_) {
437*795d594fSAndroid Build Coastguard Worker     HInstruction* str = invoke->InputAt(invoke->InputCount() - 1);
438*795d594fSAndroid Build Coastguard Worker     if (str->IsPhi()) {
439*795d594fSAndroid Build Coastguard Worker       // If after redundant phi and dead phi elimination, it's still a phi that feeds
440*795d594fSAndroid Build Coastguard Worker       // the invoke, then we must be compiling a method with irreducible loops. Just bail.
441*795d594fSAndroid Build Coastguard Worker       DCHECK(graph_->HasIrreducibleLoops());
442*795d594fSAndroid Build Coastguard Worker       return false;
443*795d594fSAndroid Build Coastguard Worker     }
444*795d594fSAndroid Build Coastguard Worker     DCHECK(str->IsNewInstance());
445*795d594fSAndroid Build Coastguard Worker     AddUninitializedString(str->AsNewInstance());
446*795d594fSAndroid Build Coastguard Worker     str->ReplaceUsesDominatedBy(invoke, invoke);
447*795d594fSAndroid Build Coastguard Worker     str->ReplaceEnvUsesDominatedBy(invoke, invoke);
448*795d594fSAndroid Build Coastguard Worker     invoke->RemoveInputAt(invoke->InputCount() - 1);
449*795d594fSAndroid Build Coastguard Worker   }
450*795d594fSAndroid Build Coastguard Worker   return true;
451*795d594fSAndroid Build Coastguard Worker }
452*795d594fSAndroid Build Coastguard Worker 
RemoveRedundantUninitializedStrings()453*795d594fSAndroid Build Coastguard Worker void SsaBuilder::RemoveRedundantUninitializedStrings() {
454*795d594fSAndroid Build Coastguard Worker   if (graph_->IsDebuggable()) {
455*795d594fSAndroid Build Coastguard Worker     // Do not perform the optimization for consistency with the interpreter
456*795d594fSAndroid Build Coastguard Worker     // which always allocates an object for new-instance of String.
457*795d594fSAndroid Build Coastguard Worker     return;
458*795d594fSAndroid Build Coastguard Worker   }
459*795d594fSAndroid Build Coastguard Worker 
460*795d594fSAndroid Build Coastguard Worker   for (HNewInstance* new_instance : uninitialized_strings_) {
461*795d594fSAndroid Build Coastguard Worker     DCHECK(new_instance->IsInBlock());
462*795d594fSAndroid Build Coastguard Worker     DCHECK(new_instance->IsStringAlloc());
463*795d594fSAndroid Build Coastguard Worker 
464*795d594fSAndroid Build Coastguard Worker     // Replace NewInstance of String with NullConstant if not used prior to
465*795d594fSAndroid Build Coastguard Worker     // calling StringFactory. We check for alias environments in case of deoptimization.
466*795d594fSAndroid Build Coastguard Worker     // The interpreter is expected to skip null check on the `this` argument of the
467*795d594fSAndroid Build Coastguard Worker     // StringFactory call.
468*795d594fSAndroid Build Coastguard Worker     if (!new_instance->HasNonEnvironmentUses() && !HasAliasInEnvironments(new_instance)) {
469*795d594fSAndroid Build Coastguard Worker       new_instance->ReplaceWith(graph_->GetNullConstant());
470*795d594fSAndroid Build Coastguard Worker       new_instance->GetBlock()->RemoveInstruction(new_instance);
471*795d594fSAndroid Build Coastguard Worker 
472*795d594fSAndroid Build Coastguard Worker       // Remove LoadClass if not needed any more.
473*795d594fSAndroid Build Coastguard Worker       HInstruction* input = new_instance->InputAt(0);
474*795d594fSAndroid Build Coastguard Worker       HLoadClass* load_class = nullptr;
475*795d594fSAndroid Build Coastguard Worker 
476*795d594fSAndroid Build Coastguard Worker       // If the class was not present in the dex cache at the point of building
477*795d594fSAndroid Build Coastguard Worker       // the graph, the builder inserted a HClinitCheck in between. Since the String
478*795d594fSAndroid Build Coastguard Worker       // class is always initialized at the point of running Java code, we can remove
479*795d594fSAndroid Build Coastguard Worker       // that check.
480*795d594fSAndroid Build Coastguard Worker       if (input->IsClinitCheck()) {
481*795d594fSAndroid Build Coastguard Worker         load_class = input->InputAt(0)->AsLoadClass();
482*795d594fSAndroid Build Coastguard Worker         input->ReplaceWith(load_class);
483*795d594fSAndroid Build Coastguard Worker         input->GetBlock()->RemoveInstruction(input);
484*795d594fSAndroid Build Coastguard Worker       } else {
485*795d594fSAndroid Build Coastguard Worker         load_class = input->AsLoadClass();
486*795d594fSAndroid Build Coastguard Worker         DCHECK(new_instance->IsStringAlloc());
487*795d594fSAndroid Build Coastguard Worker         DCHECK(!load_class->NeedsAccessCheck()) << "String class is always accessible";
488*795d594fSAndroid Build Coastguard Worker       }
489*795d594fSAndroid Build Coastguard Worker       DCHECK(load_class != nullptr);
490*795d594fSAndroid Build Coastguard Worker       if (!load_class->HasUses()) {
491*795d594fSAndroid Build Coastguard Worker         // Even if the HLoadClass needs access check, we can remove it, as we know the
492*795d594fSAndroid Build Coastguard Worker         // String class does not need it.
493*795d594fSAndroid Build Coastguard Worker         load_class->GetBlock()->RemoveInstruction(load_class);
494*795d594fSAndroid Build Coastguard Worker       }
495*795d594fSAndroid Build Coastguard Worker     }
496*795d594fSAndroid Build Coastguard Worker   }
497*795d594fSAndroid Build Coastguard Worker }
498*795d594fSAndroid Build Coastguard Worker 
HasPhiEquivalentAtLoopEntry(HGraph * graph)499*795d594fSAndroid Build Coastguard Worker static bool HasPhiEquivalentAtLoopEntry(HGraph* graph) {
500*795d594fSAndroid Build Coastguard Worker   // Phi equivalents for a dex register do not work with OSR, as the phis will
501*795d594fSAndroid Build Coastguard Worker   // receive two different stack slots but only one is recorded in the stack
502*795d594fSAndroid Build Coastguard Worker   // map.
503*795d594fSAndroid Build Coastguard Worker   for (HBasicBlock* block : graph->GetReversePostOrder()) {
504*795d594fSAndroid Build Coastguard Worker     if (block->IsLoopHeader()) {
505*795d594fSAndroid Build Coastguard Worker       for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
506*795d594fSAndroid Build Coastguard Worker         if (it.Current()->AsPhi()->HasEquivalentPhi()) {
507*795d594fSAndroid Build Coastguard Worker           return true;
508*795d594fSAndroid Build Coastguard Worker         }
509*795d594fSAndroid Build Coastguard Worker       }
510*795d594fSAndroid Build Coastguard Worker     }
511*795d594fSAndroid Build Coastguard Worker   }
512*795d594fSAndroid Build Coastguard Worker   return false;
513*795d594fSAndroid Build Coastguard Worker }
514*795d594fSAndroid Build Coastguard Worker 
BuildSsa()515*795d594fSAndroid Build Coastguard Worker GraphAnalysisResult SsaBuilder::BuildSsa() {
516*795d594fSAndroid Build Coastguard Worker   DCHECK(!graph_->IsInSsaForm());
517*795d594fSAndroid Build Coastguard Worker 
518*795d594fSAndroid Build Coastguard Worker   // Propagate types of phis. At this point, phis are typed void in the general
519*795d594fSAndroid Build Coastguard Worker   // case, or float/double/reference if we created an equivalent phi. So we need
520*795d594fSAndroid Build Coastguard Worker   // to propagate the types across phis to give them a correct type. If a type
521*795d594fSAndroid Build Coastguard Worker   // conflict is detected in this stage, the phi is marked dead.
522*795d594fSAndroid Build Coastguard Worker   RunPrimitiveTypePropagation();
523*795d594fSAndroid Build Coastguard Worker 
524*795d594fSAndroid Build Coastguard Worker   // Now that the correct primitive types have been assigned, we can get rid
525*795d594fSAndroid Build Coastguard Worker   // of redundant phis. Note that we cannot do this phase before type propagation,
526*795d594fSAndroid Build Coastguard Worker   // otherwise we could get rid of phi equivalents, whose presence is a requirement
527*795d594fSAndroid Build Coastguard Worker   // for the type propagation phase. Note that this is to satisfy statement (a)
528*795d594fSAndroid Build Coastguard Worker   // of the SsaBuilder (see ssa_builder.h).
529*795d594fSAndroid Build Coastguard Worker   SsaRedundantPhiElimination(graph_).Run();
530*795d594fSAndroid Build Coastguard Worker 
531*795d594fSAndroid Build Coastguard Worker   // Fix the type for null constants which are part of an equality comparison.
532*795d594fSAndroid Build Coastguard Worker   // We need to do this after redundant phi elimination, to ensure the only cases
533*795d594fSAndroid Build Coastguard Worker   // that we can see are reference comparison against 0. The redundant phi
534*795d594fSAndroid Build Coastguard Worker   // elimination ensures we do not see a phi taking two 0 constants in a HEqual
535*795d594fSAndroid Build Coastguard Worker   // or HNotEqual.
536*795d594fSAndroid Build Coastguard Worker   FixNullConstantType();
537*795d594fSAndroid Build Coastguard Worker 
538*795d594fSAndroid Build Coastguard Worker   // Compute type of reference type instructions. The pass assumes that
539*795d594fSAndroid Build Coastguard Worker   // NullConstant has been fixed up.
540*795d594fSAndroid Build Coastguard Worker   ReferenceTypePropagation(graph_,
541*795d594fSAndroid Build Coastguard Worker                            dex_cache_,
542*795d594fSAndroid Build Coastguard Worker                            /* is_first_run= */ true).Run();
543*795d594fSAndroid Build Coastguard Worker 
544*795d594fSAndroid Build Coastguard Worker   // HInstructionBuilder duplicated ArrayGet instructions with ambiguous type
545*795d594fSAndroid Build Coastguard Worker   // (int/float or long/double) and marked ArraySets with ambiguous input type.
546*795d594fSAndroid Build Coastguard Worker   // Now that RTP computed the type of the array input, the ambiguity can be
547*795d594fSAndroid Build Coastguard Worker   // resolved and the correct equivalents kept.
548*795d594fSAndroid Build Coastguard Worker   if (!FixAmbiguousArrayOps()) {
549*795d594fSAndroid Build Coastguard Worker     return kAnalysisFailAmbiguousArrayOp;
550*795d594fSAndroid Build Coastguard Worker   }
551*795d594fSAndroid Build Coastguard Worker 
552*795d594fSAndroid Build Coastguard Worker   // Mark dead phis. This will mark phis which are not used by instructions
553*795d594fSAndroid Build Coastguard Worker   // or other live phis. If compiling as debuggable code, phis will also be kept
554*795d594fSAndroid Build Coastguard Worker   // live if they have an environment use.
555*795d594fSAndroid Build Coastguard Worker   SsaDeadPhiElimination dead_phi_elimimation(graph_);
556*795d594fSAndroid Build Coastguard Worker   dead_phi_elimimation.MarkDeadPhis();
557*795d594fSAndroid Build Coastguard Worker 
558*795d594fSAndroid Build Coastguard Worker   // Make sure environments use the right phi equivalent: a phi marked dead
559*795d594fSAndroid Build Coastguard Worker   // can have a phi equivalent that is not dead. In that case we have to replace
560*795d594fSAndroid Build Coastguard Worker   // it with the live equivalent because deoptimization and try/catch rely on
561*795d594fSAndroid Build Coastguard Worker   // environments containing values of all live vregs at that point. Note that
562*795d594fSAndroid Build Coastguard Worker   // there can be multiple phis for the same Dex register that are live
563*795d594fSAndroid Build Coastguard Worker   // (for example when merging constants), in which case it is okay for the
564*795d594fSAndroid Build Coastguard Worker   // environments to just reference one.
565*795d594fSAndroid Build Coastguard Worker   FixEnvironmentPhis();
566*795d594fSAndroid Build Coastguard Worker 
567*795d594fSAndroid Build Coastguard Worker   // Now that the right phis are used for the environments, we can eliminate
568*795d594fSAndroid Build Coastguard Worker   // phis we do not need. Regardless of the debuggable status, this phase is
569*795d594fSAndroid Build Coastguard Worker   /// necessary for statement (b) of the SsaBuilder (see ssa_builder.h), as well
570*795d594fSAndroid Build Coastguard Worker   // as for the code generation, which does not deal with phis of conflicting
571*795d594fSAndroid Build Coastguard Worker   // input types.
572*795d594fSAndroid Build Coastguard Worker   dead_phi_elimimation.EliminateDeadPhis();
573*795d594fSAndroid Build Coastguard Worker 
574*795d594fSAndroid Build Coastguard Worker   // Replace Phis that feed in a String.<init> during instruction building. We
575*795d594fSAndroid Build Coastguard Worker   // run this after redundant and dead phi elimination to make sure the phi will have
576*795d594fSAndroid Build Coastguard Worker   // been replaced by the actual allocation. Only with an irreducible loop
577*795d594fSAndroid Build Coastguard Worker   // a phi can still be the input, in which case we bail.
578*795d594fSAndroid Build Coastguard Worker   if (!ReplaceUninitializedStringPhis()) {
579*795d594fSAndroid Build Coastguard Worker     return kAnalysisFailIrreducibleLoopAndStringInit;
580*795d594fSAndroid Build Coastguard Worker   }
581*795d594fSAndroid Build Coastguard Worker 
582*795d594fSAndroid Build Coastguard Worker   // HInstructionBuidler replaced uses of NewInstances of String with the
583*795d594fSAndroid Build Coastguard Worker   // results of their corresponding StringFactory calls. Unless the String
584*795d594fSAndroid Build Coastguard Worker   // objects are used before they are initialized, they can be replaced with
585*795d594fSAndroid Build Coastguard Worker   // NullConstant. Note that this optimization is valid only if unsimplified
586*795d594fSAndroid Build Coastguard Worker   // code does not use the uninitialized value because we assume execution can
587*795d594fSAndroid Build Coastguard Worker   // be deoptimized at any safepoint. We must therefore perform it before any
588*795d594fSAndroid Build Coastguard Worker   // other optimizations.
589*795d594fSAndroid Build Coastguard Worker   RemoveRedundantUninitializedStrings();
590*795d594fSAndroid Build Coastguard Worker 
591*795d594fSAndroid Build Coastguard Worker   if (graph_->IsCompilingOsr() && HasPhiEquivalentAtLoopEntry(graph_)) {
592*795d594fSAndroid Build Coastguard Worker     return kAnalysisFailPhiEquivalentInOsr;
593*795d594fSAndroid Build Coastguard Worker   }
594*795d594fSAndroid Build Coastguard Worker 
595*795d594fSAndroid Build Coastguard Worker   graph_->SetInSsaForm();
596*795d594fSAndroid Build Coastguard Worker   return kAnalysisSuccess;
597*795d594fSAndroid Build Coastguard Worker }
598*795d594fSAndroid Build Coastguard Worker 
599*795d594fSAndroid Build Coastguard Worker /**
600*795d594fSAndroid Build Coastguard Worker  * Constants in the Dex format are not typed. So the builder types them as
601*795d594fSAndroid Build Coastguard Worker  * integers, but when doing the SSA form, we might realize the constant
602*795d594fSAndroid Build Coastguard Worker  * is used for floating point operations. We create a floating-point equivalent
603*795d594fSAndroid Build Coastguard Worker  * constant to make the operations correctly typed.
604*795d594fSAndroid Build Coastguard Worker  */
GetFloatEquivalent(HIntConstant * constant)605*795d594fSAndroid Build Coastguard Worker HFloatConstant* SsaBuilder::GetFloatEquivalent(HIntConstant* constant) {
606*795d594fSAndroid Build Coastguard Worker   // We place the floating point constant next to this constant.
607*795d594fSAndroid Build Coastguard Worker   HFloatConstant* result = constant->GetNext()->AsFloatConstantOrNull();
608*795d594fSAndroid Build Coastguard Worker   if (result == nullptr) {
609*795d594fSAndroid Build Coastguard Worker     float value = bit_cast<float, int32_t>(constant->GetValue());
610*795d594fSAndroid Build Coastguard Worker     result = new (graph_->GetAllocator()) HFloatConstant(value);
611*795d594fSAndroid Build Coastguard Worker     constant->GetBlock()->InsertInstructionBefore(result, constant->GetNext());
612*795d594fSAndroid Build Coastguard Worker     graph_->CacheFloatConstant(result);
613*795d594fSAndroid Build Coastguard Worker   } else {
614*795d594fSAndroid Build Coastguard Worker     // If there is already a constant with the expected type, we know it is
615*795d594fSAndroid Build Coastguard Worker     // the floating point equivalent of this constant.
616*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ((bit_cast<int32_t, float>(result->GetValue())), constant->GetValue());
617*795d594fSAndroid Build Coastguard Worker   }
618*795d594fSAndroid Build Coastguard Worker   return result;
619*795d594fSAndroid Build Coastguard Worker }
620*795d594fSAndroid Build Coastguard Worker 
621*795d594fSAndroid Build Coastguard Worker /**
622*795d594fSAndroid Build Coastguard Worker  * Wide constants in the Dex format are not typed. So the builder types them as
623*795d594fSAndroid Build Coastguard Worker  * longs, but when doing the SSA form, we might realize the constant
624*795d594fSAndroid Build Coastguard Worker  * is used for floating point operations. We create a floating-point equivalent
625*795d594fSAndroid Build Coastguard Worker  * constant to make the operations correctly typed.
626*795d594fSAndroid Build Coastguard Worker  */
GetDoubleEquivalent(HLongConstant * constant)627*795d594fSAndroid Build Coastguard Worker HDoubleConstant* SsaBuilder::GetDoubleEquivalent(HLongConstant* constant) {
628*795d594fSAndroid Build Coastguard Worker   // We place the floating point constant next to this constant.
629*795d594fSAndroid Build Coastguard Worker   HDoubleConstant* result = constant->GetNext()->AsDoubleConstantOrNull();
630*795d594fSAndroid Build Coastguard Worker   if (result == nullptr) {
631*795d594fSAndroid Build Coastguard Worker     double value = bit_cast<double, int64_t>(constant->GetValue());
632*795d594fSAndroid Build Coastguard Worker     result = new (graph_->GetAllocator()) HDoubleConstant(value);
633*795d594fSAndroid Build Coastguard Worker     constant->GetBlock()->InsertInstructionBefore(result, constant->GetNext());
634*795d594fSAndroid Build Coastguard Worker     graph_->CacheDoubleConstant(result);
635*795d594fSAndroid Build Coastguard Worker   } else {
636*795d594fSAndroid Build Coastguard Worker     // If there is already a constant with the expected type, we know it is
637*795d594fSAndroid Build Coastguard Worker     // the floating point equivalent of this constant.
638*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ((bit_cast<int64_t, double>(result->GetValue())), constant->GetValue());
639*795d594fSAndroid Build Coastguard Worker   }
640*795d594fSAndroid Build Coastguard Worker   return result;
641*795d594fSAndroid Build Coastguard Worker }
642*795d594fSAndroid Build Coastguard Worker 
643*795d594fSAndroid Build Coastguard Worker /**
644*795d594fSAndroid Build Coastguard Worker  * Because of Dex format, we might end up having the same phi being
645*795d594fSAndroid Build Coastguard Worker  * used for non floating point operations and floating point / reference operations.
646*795d594fSAndroid Build Coastguard Worker  * Because we want the graph to be correctly typed (and thereafter avoid moves between
647*795d594fSAndroid Build Coastguard Worker  * floating point registers and core registers), we need to create a copy of the
648*795d594fSAndroid Build Coastguard Worker  * phi with a floating point / reference type.
649*795d594fSAndroid Build Coastguard Worker  */
GetFloatDoubleOrReferenceEquivalentOfPhi(HPhi * phi,DataType::Type type)650*795d594fSAndroid Build Coastguard Worker HPhi* SsaBuilder::GetFloatDoubleOrReferenceEquivalentOfPhi(HPhi* phi, DataType::Type type) {
651*795d594fSAndroid Build Coastguard Worker   DCHECK(phi->IsLive()) << "Cannot get equivalent of a dead phi since it would create a live one.";
652*795d594fSAndroid Build Coastguard Worker 
653*795d594fSAndroid Build Coastguard Worker   // We place the floating point /reference phi next to this phi.
654*795d594fSAndroid Build Coastguard Worker   HInstruction* next = phi->GetNext();
655*795d594fSAndroid Build Coastguard Worker   if (next != nullptr &&
656*795d594fSAndroid Build Coastguard Worker       next->AsPhi()->GetRegNumber() == phi->GetRegNumber() &&
657*795d594fSAndroid Build Coastguard Worker       next->GetType() != type) {
658*795d594fSAndroid Build Coastguard Worker     // Move to the next phi to see if it is the one we are looking for.
659*795d594fSAndroid Build Coastguard Worker     next = next->GetNext();
660*795d594fSAndroid Build Coastguard Worker   }
661*795d594fSAndroid Build Coastguard Worker 
662*795d594fSAndroid Build Coastguard Worker   if (next == nullptr ||
663*795d594fSAndroid Build Coastguard Worker       (next->AsPhi()->GetRegNumber() != phi->GetRegNumber()) ||
664*795d594fSAndroid Build Coastguard Worker       (next->GetType() != type)) {
665*795d594fSAndroid Build Coastguard Worker     ArenaAllocator* allocator = graph_->GetAllocator();
666*795d594fSAndroid Build Coastguard Worker     HInputsRef inputs = phi->GetInputs();
667*795d594fSAndroid Build Coastguard Worker     HPhi* new_phi = new (allocator) HPhi(allocator, phi->GetRegNumber(), inputs.size(), type);
668*795d594fSAndroid Build Coastguard Worker     // Copy the inputs. Note that the graph may not be correctly typed
669*795d594fSAndroid Build Coastguard Worker     // by doing this copy, but the type propagation phase will fix it.
670*795d594fSAndroid Build Coastguard Worker     ArrayRef<HUserRecord<HInstruction*>> new_input_records = new_phi->GetInputRecords();
671*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0; i < inputs.size(); ++i) {
672*795d594fSAndroid Build Coastguard Worker       new_input_records[i] = HUserRecord<HInstruction*>(inputs[i]);
673*795d594fSAndroid Build Coastguard Worker     }
674*795d594fSAndroid Build Coastguard Worker     phi->GetBlock()->InsertPhiAfter(new_phi, phi);
675*795d594fSAndroid Build Coastguard Worker     DCHECK(new_phi->IsLive());
676*795d594fSAndroid Build Coastguard Worker     return new_phi;
677*795d594fSAndroid Build Coastguard Worker   } else {
678*795d594fSAndroid Build Coastguard Worker     // An existing equivalent was found. If it is dead, conflict was previously
679*795d594fSAndroid Build Coastguard Worker     // identified and we return nullptr instead.
680*795d594fSAndroid Build Coastguard Worker     HPhi* next_phi = next->AsPhi();
681*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(next_phi->GetType(), type);
682*795d594fSAndroid Build Coastguard Worker     return next_phi->IsLive() ? next_phi : nullptr;
683*795d594fSAndroid Build Coastguard Worker   }
684*795d594fSAndroid Build Coastguard Worker }
685*795d594fSAndroid Build Coastguard Worker 
GetFloatOrDoubleEquivalentOfArrayGet(HArrayGet * aget)686*795d594fSAndroid Build Coastguard Worker HArrayGet* SsaBuilder::GetFloatOrDoubleEquivalentOfArrayGet(HArrayGet* aget) {
687*795d594fSAndroid Build Coastguard Worker   DCHECK(DataType::IsIntegralType(aget->GetType()));
688*795d594fSAndroid Build Coastguard Worker 
689*795d594fSAndroid Build Coastguard Worker   if (!DataType::IsIntOrLongType(aget->GetType())) {
690*795d594fSAndroid Build Coastguard Worker     // Cannot type boolean, char, byte, short to float/double.
691*795d594fSAndroid Build Coastguard Worker     return nullptr;
692*795d594fSAndroid Build Coastguard Worker   }
693*795d594fSAndroid Build Coastguard Worker 
694*795d594fSAndroid Build Coastguard Worker   DCHECK(ContainsElement(ambiguous_agets_, aget));
695*795d594fSAndroid Build Coastguard Worker   if (agets_fixed_) {
696*795d594fSAndroid Build Coastguard Worker     // This used to be an ambiguous ArrayGet but its type has been resolved to
697*795d594fSAndroid Build Coastguard Worker     // int/long. Requesting a float/double equivalent should lead to a conflict.
698*795d594fSAndroid Build Coastguard Worker     if (kIsDebugBuild) {
699*795d594fSAndroid Build Coastguard Worker       ScopedObjectAccess soa(Thread::Current());
700*795d594fSAndroid Build Coastguard Worker       DCHECK(DataType::IsIntOrLongType(GetPrimitiveArrayComponentType(aget->GetArray())));
701*795d594fSAndroid Build Coastguard Worker     }
702*795d594fSAndroid Build Coastguard Worker     return nullptr;
703*795d594fSAndroid Build Coastguard Worker   } else {
704*795d594fSAndroid Build Coastguard Worker     // This is an ambiguous ArrayGet which has not been resolved yet. Return an
705*795d594fSAndroid Build Coastguard Worker     // equivalent float/double instruction to use until it is resolved.
706*795d594fSAndroid Build Coastguard Worker     HArrayGet* equivalent = FindFloatOrDoubleEquivalentOfArrayGet(aget);
707*795d594fSAndroid Build Coastguard Worker     return (equivalent == nullptr) ? CreateFloatOrDoubleEquivalentOfArrayGet(aget) : equivalent;
708*795d594fSAndroid Build Coastguard Worker   }
709*795d594fSAndroid Build Coastguard Worker }
710*795d594fSAndroid Build Coastguard Worker 
GetFloatOrDoubleEquivalent(HInstruction * value,DataType::Type type)711*795d594fSAndroid Build Coastguard Worker HInstruction* SsaBuilder::GetFloatOrDoubleEquivalent(HInstruction* value, DataType::Type type) {
712*795d594fSAndroid Build Coastguard Worker   if (value->IsArrayGet()) {
713*795d594fSAndroid Build Coastguard Worker     return GetFloatOrDoubleEquivalentOfArrayGet(value->AsArrayGet());
714*795d594fSAndroid Build Coastguard Worker   } else if (value->IsLongConstant()) {
715*795d594fSAndroid Build Coastguard Worker     return GetDoubleEquivalent(value->AsLongConstant());
716*795d594fSAndroid Build Coastguard Worker   } else if (value->IsIntConstant()) {
717*795d594fSAndroid Build Coastguard Worker     return GetFloatEquivalent(value->AsIntConstant());
718*795d594fSAndroid Build Coastguard Worker   } else if (value->IsPhi()) {
719*795d594fSAndroid Build Coastguard Worker     return GetFloatDoubleOrReferenceEquivalentOfPhi(value->AsPhi(), type);
720*795d594fSAndroid Build Coastguard Worker   } else {
721*795d594fSAndroid Build Coastguard Worker     return nullptr;
722*795d594fSAndroid Build Coastguard Worker   }
723*795d594fSAndroid Build Coastguard Worker }
724*795d594fSAndroid Build Coastguard Worker 
GetReferenceTypeEquivalent(HInstruction * value)725*795d594fSAndroid Build Coastguard Worker HInstruction* SsaBuilder::GetReferenceTypeEquivalent(HInstruction* value) {
726*795d594fSAndroid Build Coastguard Worker   if (value->IsIntConstant() && value->AsIntConstant()->GetValue() == 0) {
727*795d594fSAndroid Build Coastguard Worker     return graph_->GetNullConstant();
728*795d594fSAndroid Build Coastguard Worker   } else if (value->IsPhi()) {
729*795d594fSAndroid Build Coastguard Worker     return GetFloatDoubleOrReferenceEquivalentOfPhi(value->AsPhi(), DataType::Type::kReference);
730*795d594fSAndroid Build Coastguard Worker   } else {
731*795d594fSAndroid Build Coastguard Worker     return nullptr;
732*795d594fSAndroid Build Coastguard Worker   }
733*795d594fSAndroid Build Coastguard Worker }
734*795d594fSAndroid Build Coastguard Worker 
735*795d594fSAndroid Build Coastguard Worker }  // namespace art
736