1 /** 2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef COMPILER_OPTIMIZER_ANALYSIS_ALIAS_ANALYSIS_H_ 17 #define COMPILER_OPTIMIZER_ANALYSIS_ALIAS_ANALYSIS_H_ 18 19 #include <unordered_map> 20 #include "optimizer/ir/graph_visitor.h" 21 #include "optimizer/pass.h" 22 #include "utils/arena_containers.h" 23 #include "utils/hash.h" 24 25 namespace panda::compiler { 26 class BasicBlock; 27 class Graph; 28 29 enum AliasType : uint8_t { 30 // Proved that references are not aliases 31 NO_ALIAS, 32 // References may or may not alias each other (cannot be proven statically) 33 MAY_ALIAS, 34 // References are proven aliases 35 MUST_ALIAS 36 }; 37 38 enum PointerType { 39 // Reference to unknown object. 40 // Valid fields: base 41 OBJECT, 42 // Constant from pool 43 // Valid fields: imm 44 POOL_CONSTANT, 45 // Object's field 46 // Valid fields: base, imm, type_ptr 47 OBJECT_FIELD, 48 // Static field of the object 49 // Valid fields: imm, type_ptr 50 STATIC_FIELD, 51 // Array pointer 52 // Valid fields: base, idx 53 ARRAY_ELEMENT 54 }; 55 56 class Pointer { 57 public: 58 Pointer() = default; Pointer(PointerType type,const Inst * base,const Inst * idx,uint64_t imm,const void * type_ptr)59 Pointer(PointerType type, const Inst *base, const Inst *idx, uint64_t imm, const void *type_ptr) 60 : type_(type), base_(base), idx_(idx), imm_(imm), type_ptr_(type_ptr), volatile_(false) 61 { 62 local_ = false; 63 }; 64 CreateObject(const Inst * base)65 static Pointer CreateObject(const Inst *base) 66 { 67 return Pointer(OBJECT, base, nullptr, 0, nullptr); 68 } 69 70 static Pointer CreateObjectField(const Inst *base, uint32_t type_id, const void *type_ptr = nullptr) 71 { 72 return Pointer(OBJECT_FIELD, base, nullptr, type_id, type_ptr); 73 } 74 75 static Pointer CreateArrayElement(const Inst *array, const Inst *idx, uint64_t imm = 0) 76 { 77 return Pointer(ARRAY_ELEMENT, array, idx, imm, nullptr); 78 } 79 GetType()80 PointerType GetType() const 81 { 82 return type_; 83 } 84 GetBase()85 const Inst *GetBase() const 86 { 87 return base_; 88 } 89 GetIdx()90 const Inst *GetIdx() const 91 { 92 return idx_; 93 } 94 GetImm()95 uint64_t GetImm() const 96 { 97 return imm_; 98 } 99 GetTypePtr()100 const void *GetTypePtr() const 101 { 102 return type_ptr_; 103 } 104 IsLocal()105 bool IsLocal() const 106 { 107 return local_; 108 } 109 SetLocalVolatile(bool local,bool is_volatile)110 void SetLocalVolatile(bool local, bool is_volatile) 111 { 112 local_ = local; 113 volatile_ = is_volatile; 114 } 115 IsVolatile()116 bool IsVolatile() const 117 { 118 return volatile_; 119 } 120 121 void Dump(std::ostream *out) const; 122 HasSameOffset(const Pointer & p)123 bool HasSameOffset(const Pointer &p) const 124 { 125 if (type_ptr_ == nullptr && p.type_ptr_ == nullptr) { 126 return imm_ == p.imm_; 127 } 128 return type_ptr_ == p.type_ptr_; 129 } 130 131 private: 132 PointerType type_; 133 const Inst *base_; 134 const Inst *idx_; 135 uint64_t imm_; 136 const void *type_ptr_; 137 bool local_; 138 bool volatile_; 139 }; 140 141 struct PointerEqual { operatorPointerEqual142 bool operator()(Pointer const &p1, Pointer const &p2) const 143 { 144 return p1.GetType() == p2.GetType() && p1.GetBase() == p2.GetBase() && p1.GetIdx() == p2.GetIdx() && 145 p1.HasSameOffset(p2); 146 } 147 }; 148 149 struct PointerHash { operatorPointerHash150 uint32_t operator()(Pointer const &p) const 151 { 152 auto inst_hasher = std::hash<const Inst *> {}; 153 uint32_t hash = inst_hasher(p.GetBase()); 154 hash += inst_hasher(p.GetIdx()); 155 if (p.GetTypePtr() == nullptr) { 156 hash += std::hash<uint64_t> {}(p.GetImm()); 157 } else { 158 hash += std::hash<const void *> {}(p.GetTypePtr()); 159 } 160 return hash; 161 } 162 }; 163 164 // NOLINTNEXTLINE(fuchsia-multiple-inheritance) 165 class AliasAnalysis : public Analysis, public GraphVisitor { 166 public: 167 enum class Trilean { 168 TRUE, 169 UNKNOWN, 170 FALSE, 171 }; 172 173 using PointerPairVector = ArenaVector<std::pair<Pointer, Pointer>>; 174 175 explicit AliasAnalysis(Graph *graph); 176 NO_MOVE_SEMANTIC(AliasAnalysis); 177 NO_COPY_SEMANTIC(AliasAnalysis); 178 ~AliasAnalysis() override = default; 179 180 bool RunImpl() override; 181 GetPassName()182 const char *GetPassName() const override 183 { 184 return "AliasAnalysis"; 185 } 186 187 AliasType CheckInstAlias(Inst *mem1, Inst *mem2) const; 188 void Dump(std::ostream *out) const; 189 190 /** 191 * Sort IR instructions into two constraint groups: 192 * Direct: introduce the alias 193 * Copy: copy one alias to another 194 */ 195 const ArenaVector<BasicBlock *> &GetBlocksToVisit() const override; 196 197 /** 198 * Instructions that introduce aliases. 199 */ 200 static void VisitCastAnyTypeValue(GraphVisitor *v, Inst *inst); 201 AddDirectEdge(const Pointer & p)202 void AddDirectEdge(const Pointer &p) 203 { 204 direct_->push_back({p, p}); 205 } 206 GetClearInputsSet()207 ArenaSet<Inst *> *GetClearInputsSet() 208 { 209 inputs_set_->clear(); 210 return inputs_set_; 211 } 212 213 #include "optimizer/ir/visitor.inc" 214 215 private: 216 void Init(); 217 using PointerSet = ArenaUnorderedSet<Pointer, PointerHash, PointerEqual>; 218 template <class T> 219 using PointerMap = ArenaUnorderedMap<Pointer, T, PointerHash, PointerEqual>; 220 221 void SolveConstraints(); 222 223 void DumpChains(std::ostream *out) const; 224 225 private: 226 PointerMap<PointerSet> points_to_; 227 228 // Local containers: 229 PointerMap<ArenaVector<Pointer>> *chains_ {nullptr}; 230 PointerPairVector *direct_ {nullptr}; 231 ArenaSet<Inst *> *inputs_set_ {nullptr}; 232 }; 233 } // namespace panda::compiler 234 235 #endif // COMPILER_OPTIMIZER_ANALYSIS_ALIAS_ANALYSIS_H_ 236