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 #ifndef ART_COMPILER_OPTIMIZING_SSA_BUILDER_H_ 18 #define ART_COMPILER_OPTIMIZING_SSA_BUILDER_H_ 19 20 #include "base/macros.h" 21 #include "base/scoped_arena_allocator.h" 22 #include "base/scoped_arena_containers.h" 23 #include "nodes.h" 24 #include "optimization.h" 25 26 namespace art HIDDEN { 27 28 /** 29 * Transforms a graph into SSA form. The liveness guarantees of 30 * this transformation are listed below. A DEX register 31 * being killed means its value at a given position in the code 32 * will not be available to its environment uses. A merge in the 33 * following text is materialized as a `HPhi`. 34 * 35 * (a) Dex registers that do not require merging (that is, they do not 36 * have different values at a join block) are available to all their 37 * environment uses. Note that it does not imply the instruction will 38 * have a physical location after register allocation. See the 39 * SsaLivenessAnalysis phase. 40 * 41 * (b) Dex registers that require merging, and the merging gives 42 * incompatible types, will be killed for environment uses of that merge. 43 * 44 * (c) When the `debuggable` flag is passed to the compiler, Dex registers 45 * that require merging and have a proper type after the merge, are 46 * available to all their environment uses. If the `debuggable` flag 47 * is not set, values of Dex registers only used by environments 48 * are killed. 49 */ 50 class SsaBuilder : public ValueObject { 51 public: SsaBuilder(HGraph * graph,Handle<mirror::ClassLoader> class_loader,Handle<mirror::DexCache> dex_cache,ScopedArenaAllocator * local_allocator)52 SsaBuilder(HGraph* graph, 53 Handle<mirror::ClassLoader> class_loader, 54 Handle<mirror::DexCache> dex_cache, 55 ScopedArenaAllocator* local_allocator) 56 : graph_(graph), 57 class_loader_(class_loader), 58 dex_cache_(dex_cache), 59 agets_fixed_(false), 60 local_allocator_(local_allocator), 61 ambiguous_agets_(local_allocator->Adapter(kArenaAllocGraphBuilder)), 62 ambiguous_asets_(local_allocator->Adapter(kArenaAllocGraphBuilder)), 63 uninitialized_strings_(local_allocator->Adapter(kArenaAllocGraphBuilder)), 64 uninitialized_string_phis_(local_allocator->Adapter(kArenaAllocGraphBuilder)) { 65 } 66 67 GraphAnalysisResult BuildSsa(); 68 69 HInstruction* GetFloatOrDoubleEquivalent(HInstruction* instruction, DataType::Type type); 70 HInstruction* GetReferenceTypeEquivalent(HInstruction* instruction); 71 MaybeAddAmbiguousArrayGet(HArrayGet * aget)72 void MaybeAddAmbiguousArrayGet(HArrayGet* aget) { 73 DataType::Type type = aget->GetType(); 74 DCHECK(!DataType::IsFloatingPointType(type)); 75 if (DataType::IsIntOrLongType(type)) { 76 ambiguous_agets_.push_back(aget); 77 } 78 } 79 MaybeAddAmbiguousArraySet(HArraySet * aset)80 void MaybeAddAmbiguousArraySet(HArraySet* aset) { 81 DataType::Type type = aset->GetValue()->GetType(); 82 if (DataType::IsIntOrLongType(type)) { 83 ambiguous_asets_.push_back(aset); 84 } 85 } 86 AddUninitializedString(HNewInstance * string)87 void AddUninitializedString(HNewInstance* string) { 88 // In some rare cases (b/27847265), the same NewInstance may be seen 89 // multiple times. We should only consider it once for removal, so we 90 // ensure it is not added more than once. 91 // Note that we cannot check whether this really is a NewInstance of String 92 // before RTP. We DCHECK that in RemoveRedundantUninitializedStrings. 93 if (!ContainsElement(uninitialized_strings_, string)) { 94 uninitialized_strings_.push_back(string); 95 } 96 } 97 AddUninitializedStringPhi(HInvoke * invoke)98 void AddUninitializedStringPhi(HInvoke* invoke) { 99 uninitialized_string_phis_.push_back(invoke); 100 } 101 102 private: 103 void SetLoopHeaderPhiInputs(); 104 void FixEnvironmentPhis(); 105 void FixNullConstantType(); 106 void EquivalentPhisCleanup(); 107 void RunPrimitiveTypePropagation(); 108 109 // Attempts to resolve types of aget(-wide) instructions and type values passed 110 // to aput(-wide) instructions from reference type information on the array 111 // input. Returns false if the type of an array is unknown. 112 bool FixAmbiguousArrayOps(); 113 114 bool TypeInputsOfPhi(HPhi* phi, ScopedArenaVector<HPhi*>* worklist); 115 bool UpdatePrimitiveType(HPhi* phi, ScopedArenaVector<HPhi*>* worklist); 116 void ProcessPrimitiveTypePropagationWorklist(ScopedArenaVector<HPhi*>* worklist); 117 118 HFloatConstant* GetFloatEquivalent(HIntConstant* constant); 119 HDoubleConstant* GetDoubleEquivalent(HLongConstant* constant); 120 HPhi* GetFloatDoubleOrReferenceEquivalentOfPhi(HPhi* phi, DataType::Type type); 121 HArrayGet* GetFloatOrDoubleEquivalentOfArrayGet(HArrayGet* aget); 122 123 void RemoveRedundantUninitializedStrings(); 124 bool ReplaceUninitializedStringPhis(); 125 bool HasAliasInEnvironments(HInstruction* instruction); 126 127 HGraph* const graph_; 128 Handle<mirror::ClassLoader> class_loader_; 129 Handle<mirror::DexCache> dex_cache_; 130 131 // True if types of ambiguous ArrayGets have been resolved. 132 bool agets_fixed_; 133 134 ScopedArenaAllocator* const local_allocator_; 135 ScopedArenaVector<HArrayGet*> ambiguous_agets_; 136 ScopedArenaVector<HArraySet*> ambiguous_asets_; 137 ScopedArenaVector<HNewInstance*> uninitialized_strings_; 138 ScopedArenaVector<HInvoke*> uninitialized_string_phis_; 139 140 DISALLOW_COPY_AND_ASSIGN(SsaBuilder); 141 }; 142 143 } // namespace art 144 145 #endif // ART_COMPILER_OPTIMIZING_SSA_BUILDER_H_ 146