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