xref: /llvm-project/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp (revision af7bc39ba17d8c5250830e96881fb7211c7576bb)
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