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 <memory> 24 #include <utility> 25 26 namespace clang { 27 namespace dataflow { 28 29 /// Returns a map consisting of key-value entries that are present in both maps. 30 template <typename K, typename V> 31 llvm::DenseMap<K, V> intersectDenseMaps(const llvm::DenseMap<K, V> &Map1, 32 const llvm::DenseMap<K, V> &Map2) { 33 llvm::DenseMap<K, V> Result; 34 for (auto &Entry : Map1) { 35 auto It = Map2.find(Entry.first); 36 if (It != Map2.end() && Entry.second == It->second) 37 Result.insert({Entry.first, Entry.second}); 38 } 39 return Result; 40 } 41 42 bool Environment::operator==(const Environment &Other) const { 43 assert(DACtx == Other.DACtx); 44 return DeclToLoc == Other.DeclToLoc && LocToVal == Other.LocToVal; 45 } 46 47 LatticeJoinEffect Environment::join(const Environment &Other) { 48 assert(DACtx == Other.DACtx); 49 50 auto Effect = LatticeJoinEffect::Unchanged; 51 52 const unsigned DeclToLocSizeBefore = DeclToLoc.size(); 53 DeclToLoc = intersectDenseMaps(DeclToLoc, Other.DeclToLoc); 54 if (DeclToLocSizeBefore != DeclToLoc.size()) 55 Effect = LatticeJoinEffect::Changed; 56 57 // FIXME: Add support for joining distinct values that are assigned to the 58 // same storage locations in `LocToVal` and `Other.LocToVal`. 59 const unsigned LocToValSizeBefore = LocToVal.size(); 60 LocToVal = intersectDenseMaps(LocToVal, Other.LocToVal); 61 if (LocToValSizeBefore != LocToVal.size()) 62 Effect = LatticeJoinEffect::Changed; 63 64 return Effect; 65 } 66 67 StorageLocation &Environment::createStorageLocation(QualType Type) { 68 assert(!Type.isNull()); 69 if (Type->isStructureOrClassType()) { 70 // FIXME: Explore options to avoid eager initialization of fields as some of 71 // them might not be needed for a particular analysis. 72 llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs; 73 for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) { 74 FieldLocs.insert({Field, &createStorageLocation(Field->getType())}); 75 } 76 return DACtx->takeOwnership( 77 std::make_unique<AggregateStorageLocation>(Type, std::move(FieldLocs))); 78 } 79 return DACtx->takeOwnership(std::make_unique<ScalarStorageLocation>(Type)); 80 } 81 82 StorageLocation &Environment::createStorageLocation(const VarDecl &D) { 83 // Evaluated declarations are always assigned the same storage locations to 84 // ensure that the environment stabilizes across loop iterations. Storage 85 // locations for evaluated declarations are stored in the analysis context. 86 if (auto *Loc = DACtx->getStorageLocation(D)) 87 return *Loc; 88 auto &Loc = createStorageLocation(D.getType()); 89 DACtx->setStorageLocation(D, Loc); 90 return Loc; 91 } 92 93 void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) { 94 assert(DeclToLoc.find(&D) == DeclToLoc.end()); 95 DeclToLoc[&D] = &Loc; 96 } 97 98 StorageLocation *Environment::getStorageLocation(const ValueDecl &D) const { 99 auto It = DeclToLoc.find(&D); 100 return It == DeclToLoc.end() ? nullptr : It->second; 101 } 102 103 void Environment::setValue(const StorageLocation &Loc, Value &Value) { 104 LocToVal[&Loc] = &Value; 105 } 106 107 Value *Environment::getValue(const StorageLocation &Loc) const { 108 auto It = LocToVal.find(&Loc); 109 return It == LocToVal.end() ? nullptr : It->second; 110 } 111 112 Value *Environment::initValueInStorageLocation(const StorageLocation &Loc, 113 QualType Type) { 114 llvm::DenseSet<QualType> Visited; 115 return initValueInStorageLocationUnlessSelfReferential(Loc, Type, Visited); 116 } 117 118 Value *Environment::initValueInStorageLocationUnlessSelfReferential( 119 const StorageLocation &Loc, QualType Type, 120 llvm::DenseSet<QualType> &Visited) { 121 assert(!Type.isNull()); 122 123 if (Type->isIntegerType()) { 124 auto &Value = DACtx->takeOwnership(std::make_unique<IntegerValue>()); 125 setValue(Loc, Value); 126 return &Value; 127 } 128 129 if (Type->isReferenceType()) { 130 QualType PointeeType = Type->getAs<ReferenceType>()->getPointeeType(); 131 auto &PointeeLoc = createStorageLocation(PointeeType); 132 133 if (!Visited.contains(PointeeType.getCanonicalType())) { 134 Visited.insert(PointeeType.getCanonicalType()); 135 initValueInStorageLocationUnlessSelfReferential(PointeeLoc, PointeeType, 136 Visited); 137 Visited.erase(PointeeType.getCanonicalType()); 138 } 139 140 auto &Value = 141 DACtx->takeOwnership(std::make_unique<ReferenceValue>(PointeeLoc)); 142 setValue(Loc, Value); 143 return &Value; 144 } 145 146 if (Type->isPointerType()) { 147 QualType PointeeType = Type->getAs<PointerType>()->getPointeeType(); 148 auto &PointeeLoc = createStorageLocation(PointeeType); 149 150 if (!Visited.contains(PointeeType.getCanonicalType())) { 151 Visited.insert(PointeeType.getCanonicalType()); 152 initValueInStorageLocationUnlessSelfReferential(PointeeLoc, PointeeType, 153 Visited); 154 Visited.erase(PointeeType.getCanonicalType()); 155 } 156 157 auto &Value = 158 DACtx->takeOwnership(std::make_unique<PointerValue>(PointeeLoc)); 159 setValue(Loc, Value); 160 return &Value; 161 } 162 163 if (Type->isStructureOrClassType()) { 164 auto *AggregateLoc = cast<AggregateStorageLocation>(&Loc); 165 166 llvm::DenseMap<const ValueDecl *, Value *> FieldValues; 167 for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) { 168 assert(Field != nullptr); 169 170 QualType FieldType = Field->getType(); 171 if (Visited.contains(FieldType.getCanonicalType())) 172 continue; 173 174 Visited.insert(FieldType.getCanonicalType()); 175 FieldValues.insert( 176 {Field, initValueInStorageLocationUnlessSelfReferential( 177 AggregateLoc->getChild(*Field), FieldType, Visited)}); 178 Visited.erase(FieldType.getCanonicalType()); 179 } 180 181 auto &Value = DACtx->takeOwnership( 182 std::make_unique<StructValue>(std::move(FieldValues))); 183 setValue(Loc, Value); 184 return &Value; 185 } 186 187 return nullptr; 188 } 189 190 } // namespace dataflow 191 } // namespace clang 192