1 //===-- DataflowEnvironment.cpp ---------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines an Environment class that is used by dataflow analyses 10 // that run over Control-Flow Graphs (CFGs) to keep track of the state of the 11 // program at given program points. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" 16 #include "clang/AST/Decl.h" 17 #include "clang/AST/Type.h" 18 #include "clang/Analysis/FlowSensitive/DataflowLattice.h" 19 #include "clang/Analysis/FlowSensitive/StorageLocation.h" 20 #include "clang/Analysis/FlowSensitive/Value.h" 21 #include "llvm/ADT/DenseMap.h" 22 #include "llvm/ADT/DenseSet.h" 23 #include "llvm/Support/ErrorHandling.h" 24 #include <memory> 25 #include <utility> 26 27 namespace clang { 28 namespace dataflow { 29 30 /// Returns a map consisting of key-value entries that are present in both maps. 31 template <typename K, typename V> 32 llvm::DenseMap<K, V> intersectDenseMaps(const llvm::DenseMap<K, V> &Map1, 33 const llvm::DenseMap<K, V> &Map2) { 34 llvm::DenseMap<K, V> Result; 35 for (auto &Entry : Map1) { 36 auto It = Map2.find(Entry.first); 37 if (It != Map2.end() && Entry.second == It->second) 38 Result.insert({Entry.first, Entry.second}); 39 } 40 return Result; 41 } 42 43 bool Environment::operator==(const Environment &Other) const { 44 assert(DACtx == Other.DACtx); 45 return DeclToLoc == Other.DeclToLoc && LocToVal == Other.LocToVal; 46 } 47 48 LatticeJoinEffect Environment::join(const Environment &Other) { 49 assert(DACtx == Other.DACtx); 50 51 auto Effect = LatticeJoinEffect::Unchanged; 52 53 const unsigned DeclToLocSizeBefore = DeclToLoc.size(); 54 DeclToLoc = intersectDenseMaps(DeclToLoc, Other.DeclToLoc); 55 if (DeclToLocSizeBefore != DeclToLoc.size()) 56 Effect = LatticeJoinEffect::Changed; 57 58 // FIXME: Add support for joining distinct values that are assigned to the 59 // same storage locations in `LocToVal` and `Other.LocToVal`. 60 const unsigned LocToValSizeBefore = LocToVal.size(); 61 LocToVal = intersectDenseMaps(LocToVal, Other.LocToVal); 62 if (LocToValSizeBefore != LocToVal.size()) 63 Effect = LatticeJoinEffect::Changed; 64 65 return Effect; 66 } 67 68 StorageLocation &Environment::createStorageLocation(QualType Type) { 69 assert(!Type.isNull()); 70 if (Type->isStructureOrClassType()) { 71 // FIXME: Explore options to avoid eager initialization of fields as some of 72 // them might not be needed for a particular analysis. 73 llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs; 74 for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) { 75 FieldLocs.insert({Field, &createStorageLocation(Field->getType())}); 76 } 77 return takeOwnership( 78 std::make_unique<AggregateStorageLocation>(Type, std::move(FieldLocs))); 79 } 80 return takeOwnership(std::make_unique<ScalarStorageLocation>(Type)); 81 } 82 83 StorageLocation &Environment::createStorageLocation(const VarDecl &D) { 84 // Evaluated declarations are always assigned the same storage locations to 85 // ensure that the environment stabilizes across loop iterations. Storage 86 // locations for evaluated declarations are stored in the analysis context. 87 if (auto *Loc = DACtx->getStorageLocation(D)) 88 return *Loc; 89 auto &Loc = createStorageLocation(D.getType()); 90 DACtx->setStorageLocation(D, Loc); 91 return Loc; 92 } 93 94 StorageLocation &Environment::createStorageLocation(const Expr &E) { 95 // Evaluated expressions are always assigned the same storage locations to 96 // ensure that the environment stabilizes across loop iterations. Storage 97 // locations for evaluated expressions are stored in the analysis context. 98 if (auto *Loc = DACtx->getStorageLocation(E)) 99 return *Loc; 100 auto &Loc = createStorageLocation(E.getType()); 101 DACtx->setStorageLocation(E, Loc); 102 return Loc; 103 } 104 105 void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) { 106 assert(DeclToLoc.find(&D) == DeclToLoc.end()); 107 DeclToLoc[&D] = &Loc; 108 } 109 110 StorageLocation *Environment::getStorageLocation(const ValueDecl &D, 111 SkipPast SP) const { 112 auto It = DeclToLoc.find(&D); 113 return It == DeclToLoc.end() ? nullptr : &skip(*It->second, SP); 114 } 115 116 void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) { 117 assert(ExprToLoc.find(&E) == ExprToLoc.end()); 118 ExprToLoc[&E] = &Loc; 119 } 120 121 StorageLocation *Environment::getStorageLocation(const Expr &E, 122 SkipPast SP) const { 123 auto It = ExprToLoc.find(&E); 124 return It == ExprToLoc.end() ? nullptr : &skip(*It->second, SP); 125 } 126 127 void Environment::setValue(const StorageLocation &Loc, Value &Value) { 128 LocToVal[&Loc] = &Value; 129 } 130 131 Value *Environment::getValue(const StorageLocation &Loc) const { 132 auto It = LocToVal.find(&Loc); 133 return It == LocToVal.end() ? nullptr : It->second; 134 } 135 136 Value *Environment::getValue(const ValueDecl &D, SkipPast SP) const { 137 auto *Loc = getStorageLocation(D, SP); 138 if (Loc == nullptr) 139 return nullptr; 140 return getValue(*Loc); 141 } 142 143 Value *Environment::getValue(const Expr &E, SkipPast SP) const { 144 auto *Loc = getStorageLocation(E, SP); 145 if (Loc == nullptr) 146 return nullptr; 147 return getValue(*Loc); 148 } 149 150 Value *Environment::initValueInStorageLocation(const StorageLocation &Loc, 151 QualType Type) { 152 llvm::DenseSet<QualType> Visited; 153 return initValueInStorageLocationUnlessSelfReferential(Loc, Type, Visited); 154 } 155 156 Value *Environment::initValueInStorageLocationUnlessSelfReferential( 157 const StorageLocation &Loc, QualType Type, 158 llvm::DenseSet<QualType> &Visited) { 159 assert(!Type.isNull()); 160 161 if (Type->isIntegerType()) { 162 auto &Val = takeOwnership(std::make_unique<IntegerValue>()); 163 setValue(Loc, Val); 164 return &Val; 165 } 166 167 if (Type->isReferenceType()) { 168 QualType PointeeType = Type->getAs<ReferenceType>()->getPointeeType(); 169 auto &PointeeLoc = createStorageLocation(PointeeType); 170 171 if (!Visited.contains(PointeeType.getCanonicalType())) { 172 Visited.insert(PointeeType.getCanonicalType()); 173 initValueInStorageLocationUnlessSelfReferential(PointeeLoc, PointeeType, 174 Visited); 175 Visited.erase(PointeeType.getCanonicalType()); 176 } 177 178 auto &Val = takeOwnership(std::make_unique<ReferenceValue>(PointeeLoc)); 179 setValue(Loc, Val); 180 return &Val; 181 } 182 183 if (Type->isPointerType()) { 184 QualType PointeeType = Type->getAs<PointerType>()->getPointeeType(); 185 auto &PointeeLoc = createStorageLocation(PointeeType); 186 187 if (!Visited.contains(PointeeType.getCanonicalType())) { 188 Visited.insert(PointeeType.getCanonicalType()); 189 initValueInStorageLocationUnlessSelfReferential(PointeeLoc, PointeeType, 190 Visited); 191 Visited.erase(PointeeType.getCanonicalType()); 192 } 193 194 auto &Val = takeOwnership(std::make_unique<PointerValue>(PointeeLoc)); 195 setValue(Loc, Val); 196 return &Val; 197 } 198 199 if (Type->isStructureOrClassType()) { 200 auto *AggregateLoc = cast<AggregateStorageLocation>(&Loc); 201 202 llvm::DenseMap<const ValueDecl *, Value *> FieldValues; 203 for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) { 204 assert(Field != nullptr); 205 206 QualType FieldType = Field->getType(); 207 if (Visited.contains(FieldType.getCanonicalType())) 208 continue; 209 210 Visited.insert(FieldType.getCanonicalType()); 211 FieldValues.insert( 212 {Field, initValueInStorageLocationUnlessSelfReferential( 213 AggregateLoc->getChild(*Field), FieldType, Visited)}); 214 Visited.erase(FieldType.getCanonicalType()); 215 } 216 217 auto &Val = 218 takeOwnership(std::make_unique<StructValue>(std::move(FieldValues))); 219 setValue(Loc, Val); 220 return &Val; 221 } 222 223 return nullptr; 224 } 225 226 StorageLocation & 227 Environment::takeOwnership(std::unique_ptr<StorageLocation> Loc) { 228 return DACtx->takeOwnership(std::move(Loc)); 229 } 230 231 Value &Environment::takeOwnership(std::unique_ptr<Value> Val) { 232 return DACtx->takeOwnership(std::move(Val)); 233 } 234 235 StorageLocation &Environment::skip(StorageLocation &Loc, SkipPast SP) const { 236 switch (SP) { 237 case SkipPast::None: 238 return Loc; 239 case SkipPast::Reference: 240 // References cannot be chained so we only need to skip past one level of 241 // indirection. 242 if (auto *Val = dyn_cast_or_null<ReferenceValue>(getValue(Loc))) 243 return Val->getPointeeLoc(); 244 return Loc; 245 } 246 llvm_unreachable("bad SkipPast kind"); 247 } 248 249 const StorageLocation &Environment::skip(const StorageLocation &Loc, 250 SkipPast SP) const { 251 return skip(*const_cast<StorageLocation *>(&Loc), SP); 252 } 253 254 } // namespace dataflow 255 } // namespace clang 256