/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/include/clang/Analysis/FlowSensitive/Arena.h
Line | Count | Source |
1 | | //===-- Arena.h -------------------------------*- 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 | | #ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE__ARENA_H |
9 | | #define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE__ARENA_H |
10 | | |
11 | | #include "clang/Analysis/FlowSensitive/Formula.h" |
12 | | #include "clang/Analysis/FlowSensitive/StorageLocation.h" |
13 | | #include "clang/Analysis/FlowSensitive/Value.h" |
14 | | #include "llvm/ADT/StringRef.h" |
15 | | #include <vector> |
16 | | |
17 | | namespace clang::dataflow { |
18 | | |
19 | | /// The Arena owns the objects that model data within an analysis. |
20 | | /// For example, `Value`, `StorageLocation`, `Atom`, and `Formula`. |
21 | | class Arena { |
22 | | public: |
23 | 658 | Arena() : True(makeAtom()), False(makeAtom()) {} |
24 | | Arena(const Arena &) = delete; |
25 | | Arena &operator=(const Arena &) = delete; |
26 | | |
27 | | /// Creates a `T` (some subclass of `StorageLocation`), forwarding `args` to |
28 | | /// the constructor, and returns a reference to it. |
29 | | /// |
30 | | /// The `DataflowAnalysisContext` takes ownership of the created object. The |
31 | | /// object will be destroyed when the `DataflowAnalysisContext` is destroyed. |
32 | | template <typename T, typename... Args> |
33 | | std::enable_if_t<std::is_base_of<StorageLocation, T>::value, T &> |
34 | 5.13k | create(Args &&...args) { |
35 | | // Note: If allocation of individual `StorageLocation`s turns out to be |
36 | | // costly, consider creating specializations of `create<T>` for commonly |
37 | | // used `StorageLocation` subclasses and make them use a `BumpPtrAllocator`. |
38 | 5.13k | return *cast<T>( |
39 | 5.13k | Locs.emplace_back(std::make_unique<T>(std::forward<Args>(args)...)) |
40 | 5.13k | .get()); |
41 | 5.13k | } std::__1::enable_if<std::is_base_of<clang::dataflow::StorageLocation, clang::dataflow::RecordStorageLocation>::value, clang::dataflow::RecordStorageLocation&>::type clang::dataflow::Arena::create<clang::dataflow::RecordStorageLocation, clang::QualType&, llvm::DenseMap<clang::ValueDecl const*, clang::dataflow::StorageLocation*, llvm::DenseMapInfo<clang::ValueDecl const*, void>, llvm::detail::DenseMapPair<clang::ValueDecl const*, clang::dataflow::StorageLocation*> > >(clang::QualType&, llvm::DenseMap<clang::ValueDecl const*, clang::dataflow::StorageLocation*, llvm::DenseMapInfo<clang::ValueDecl const*, void>, llvm::detail::DenseMapPair<clang::ValueDecl const*, clang::dataflow::StorageLocation*> >&&) Line | Count | Source | 34 | 2.47k | create(Args &&...args) { | 35 | | // Note: If allocation of individual `StorageLocation`s turns out to be | 36 | | // costly, consider creating specializations of `create<T>` for commonly | 37 | | // used `StorageLocation` subclasses and make them use a `BumpPtrAllocator`. | 38 | 2.47k | return *cast<T>( | 39 | 2.47k | Locs.emplace_back(std::make_unique<T>(std::forward<Args>(args)...)) | 40 | 2.47k | .get()); | 41 | 2.47k | } |
std::__1::enable_if<std::is_base_of<clang::dataflow::StorageLocation, clang::dataflow::ScalarStorageLocation>::value, clang::dataflow::ScalarStorageLocation&>::type clang::dataflow::Arena::create<clang::dataflow::ScalarStorageLocation, clang::QualType&>(clang::QualType&) Line | Count | Source | 34 | 2.65k | create(Args &&...args) { | 35 | | // Note: If allocation of individual `StorageLocation`s turns out to be | 36 | | // costly, consider creating specializations of `create<T>` for commonly | 37 | | // used `StorageLocation` subclasses and make them use a `BumpPtrAllocator`. | 38 | 2.65k | return *cast<T>( | 39 | 2.65k | Locs.emplace_back(std::make_unique<T>(std::forward<Args>(args)...)) | 40 | 2.65k | .get()); | 41 | 2.65k | } |
|
42 | | |
43 | | /// Creates a `T` (some subclass of `Value`), forwarding `args` to the |
44 | | /// constructor, and returns a reference to it. |
45 | | /// |
46 | | /// The `DataflowAnalysisContext` takes ownership of the created object. The |
47 | | /// object will be destroyed when the `DataflowAnalysisContext` is destroyed. |
48 | | template <typename T, typename... Args> |
49 | | std::enable_if_t<std::is_base_of<Value, T>::value, T &> |
50 | 11.0k | create(Args &&...args) { |
51 | | // Note: If allocation of individual `Value`s turns out to be costly, |
52 | | // consider creating specializations of `create<T>` for commonly used |
53 | | // `Value` subclasses and make them use a `BumpPtrAllocator`. |
54 | 11.0k | return *cast<T>( |
55 | 11.0k | Vals.emplace_back(std::make_unique<T>(std::forward<Args>(args)...)) |
56 | 11.0k | .get()); |
57 | 11.0k | } std::__1::enable_if<std::is_base_of<clang::dataflow::Value, clang::dataflow::IntegerValue>::value, clang::dataflow::IntegerValue&>::type clang::dataflow::Arena::create<clang::dataflow::IntegerValue>() Line | Count | Source | 50 | 1.63k | create(Args &&...args) { | 51 | | // Note: If allocation of individual `Value`s turns out to be costly, | 52 | | // consider creating specializations of `create<T>` for commonly used | 53 | | // `Value` subclasses and make them use a `BumpPtrAllocator`. | 54 | 1.63k | return *cast<T>( | 55 | 1.63k | Vals.emplace_back(std::make_unique<T>(std::forward<Args>(args)...)) | 56 | 1.63k | .get()); | 57 | 1.63k | } |
std::__1::enable_if<std::is_base_of<clang::dataflow::Value, clang::dataflow::AtomicBoolValue>::value, clang::dataflow::AtomicBoolValue&>::type clang::dataflow::Arena::create<clang::dataflow::AtomicBoolValue, clang::dataflow::Formula const&>(clang::dataflow::Formula const&) Line | Count | Source | 50 | 2.03k | create(Args &&...args) { | 51 | | // Note: If allocation of individual `Value`s turns out to be costly, | 52 | | // consider creating specializations of `create<T>` for commonly used | 53 | | // `Value` subclasses and make them use a `BumpPtrAllocator`. | 54 | 2.03k | return *cast<T>( | 55 | 2.03k | Vals.emplace_back(std::make_unique<T>(std::forward<Args>(args)...)) | 56 | 2.03k | .get()); | 57 | 2.03k | } |
std::__1::enable_if<std::is_base_of<clang::dataflow::Value, clang::dataflow::FormulaBoolValue>::value, clang::dataflow::FormulaBoolValue&>::type clang::dataflow::Arena::create<clang::dataflow::FormulaBoolValue, clang::dataflow::Formula const&>(clang::dataflow::Formula const&) Line | Count | Source | 50 | 708 | create(Args &&...args) { | 51 | | // Note: If allocation of individual `Value`s turns out to be costly, | 52 | | // consider creating specializations of `create<T>` for commonly used | 53 | | // `Value` subclasses and make them use a `BumpPtrAllocator`. | 54 | 708 | return *cast<T>( | 55 | 708 | Vals.emplace_back(std::make_unique<T>(std::forward<Args>(args)...)) | 56 | 708 | .get()); | 57 | 708 | } |
std::__1::enable_if<std::is_base_of<clang::dataflow::Value, clang::dataflow::TopBoolValue>::value, clang::dataflow::TopBoolValue&>::type clang::dataflow::Arena::create<clang::dataflow::TopBoolValue, clang::dataflow::Formula const&>(clang::dataflow::Formula const&) Line | Count | Source | 50 | 49 | create(Args &&...args) { | 51 | | // Note: If allocation of individual `Value`s turns out to be costly, | 52 | | // consider creating specializations of `create<T>` for commonly used | 53 | | // `Value` subclasses and make them use a `BumpPtrAllocator`. | 54 | 49 | return *cast<T>( | 55 | 49 | Vals.emplace_back(std::make_unique<T>(std::forward<Args>(args)...)) | 56 | 49 | .get()); | 57 | 49 | } |
std::__1::enable_if<std::is_base_of<clang::dataflow::Value, clang::dataflow::PointerValue>::value, clang::dataflow::PointerValue&>::type clang::dataflow::Arena::create<clang::dataflow::PointerValue, clang::dataflow::StorageLocation&>(clang::dataflow::StorageLocation&) Line | Count | Source | 50 | 2.05k | create(Args &&...args) { | 51 | | // Note: If allocation of individual `Value`s turns out to be costly, | 52 | | // consider creating specializations of `create<T>` for commonly used | 53 | | // `Value` subclasses and make them use a `BumpPtrAllocator`. | 54 | 2.05k | return *cast<T>( | 55 | 2.05k | Vals.emplace_back(std::make_unique<T>(std::forward<Args>(args)...)) | 56 | 2.05k | .get()); | 57 | 2.05k | } |
std::__1::enable_if<std::is_base_of<clang::dataflow::Value, clang::dataflow::RecordValue>::value, clang::dataflow::RecordValue&>::type clang::dataflow::Arena::create<clang::dataflow::RecordValue, clang::dataflow::RecordStorageLocation&>(clang::dataflow::RecordStorageLocation&) Line | Count | Source | 50 | 4.49k | create(Args &&...args) { | 51 | | // Note: If allocation of individual `Value`s turns out to be costly, | 52 | | // consider creating specializations of `create<T>` for commonly used | 53 | | // `Value` subclasses and make them use a `BumpPtrAllocator`. | 54 | 4.49k | return *cast<T>( | 55 | 4.49k | Vals.emplace_back(std::make_unique<T>(std::forward<Args>(args)...)) | 56 | 4.49k | .get()); | 57 | 4.49k | } |
std::__1::enable_if<std::is_base_of<clang::dataflow::Value, clang::dataflow::PointerValue>::value, clang::dataflow::PointerValue&>::type clang::dataflow::Arena::create<clang::dataflow::PointerValue, clang::dataflow::RecordStorageLocation&>(clang::dataflow::RecordStorageLocation&) Line | Count | Source | 50 | 58 | create(Args &&...args) { | 51 | | // Note: If allocation of individual `Value`s turns out to be costly, | 52 | | // consider creating specializations of `create<T>` for commonly used | 53 | | // `Value` subclasses and make them use a `BumpPtrAllocator`. | 54 | 58 | return *cast<T>( | 55 | 58 | Vals.emplace_back(std::make_unique<T>(std::forward<Args>(args)...)) | 56 | 58 | .get()); | 57 | 58 | } |
|
58 | | |
59 | | /// Creates a BoolValue wrapping a particular formula. |
60 | | /// |
61 | | /// Passing in the same formula will result in the same BoolValue. |
62 | | /// FIXME: Interning BoolValues but not other Values is inconsistent. |
63 | | /// Decide whether we want Value interning or not. |
64 | | BoolValue &makeBoolValue(const Formula &); |
65 | | |
66 | | /// Creates a fresh atom and wraps in in an AtomicBoolValue. |
67 | | /// FIXME: For now, identical-address AtomicBoolValue <=> identical atom. |
68 | | /// Stop relying on pointer identity and remove this guarantee. |
69 | 1.52k | AtomicBoolValue &makeAtomValue() { |
70 | 1.52k | return cast<AtomicBoolValue>(makeBoolValue(makeAtomRef(makeAtom()))); |
71 | 1.52k | } |
72 | | |
73 | | /// Creates a fresh Top boolean value. |
74 | 49 | TopBoolValue &makeTopValue() { |
75 | | // No need for deduplicating: there's no way to create aliasing Tops. |
76 | 49 | return create<TopBoolValue>(makeAtomRef(makeAtom())); |
77 | 49 | } |
78 | | |
79 | | /// Returns a symbolic integer value that models an integer literal equal to |
80 | | /// `Value`. These literals are the same every time. |
81 | | /// Integer literals are not typed; the type is determined by the `Expr` that |
82 | | /// an integer literal is associated with. |
83 | | IntegerValue &makeIntLiteral(llvm::APInt Value); |
84 | | |
85 | | // Factories for boolean formulas. |
86 | | // Formulas are interned: passing the same arguments return the same result. |
87 | | // For commutative operations like And/Or, interning ignores order. |
88 | | // Simplifications are applied: makeOr(X, X) => X, etc. |
89 | | |
90 | | /// Returns a formula for the conjunction of `LHS` and `RHS`. |
91 | | const Formula &makeAnd(const Formula &LHS, const Formula &RHS); |
92 | | |
93 | | /// Returns a formula for the disjunction of `LHS` and `RHS`. |
94 | | const Formula &makeOr(const Formula &LHS, const Formula &RHS); |
95 | | |
96 | | /// Returns a formula for the negation of `Val`. |
97 | | const Formula &makeNot(const Formula &Val); |
98 | | |
99 | | /// Returns a formula for `LHS => RHS`. |
100 | | const Formula &makeImplies(const Formula &LHS, const Formula &RHS); |
101 | | |
102 | | /// Returns a formula for `LHS <=> RHS`. |
103 | | const Formula &makeEquals(const Formula &LHS, const Formula &RHS); |
104 | | |
105 | | /// Returns a formula for the variable A. |
106 | | const Formula &makeAtomRef(Atom A); |
107 | | |
108 | | /// Returns a formula for a literal true/false. |
109 | 3.74k | const Formula &makeLiteral(bool Value) { |
110 | 3.74k | return makeAtomRef(Value ? True1.90k : False1.84k ); |
111 | 3.74k | } |
112 | | |
113 | | // Parses a formula from its textual representation. |
114 | | // This may refer to atoms that were not produced by makeAtom() yet! |
115 | | llvm::Expected<const Formula &> parseFormula(llvm::StringRef); |
116 | | |
117 | | /// Returns a new atomic boolean variable, distinct from any other. |
118 | 11.7k | Atom makeAtom() { return static_cast<Atom>(NextAtom++); }; |
119 | | |
120 | | /// Creates a fresh flow condition and returns a token that identifies it. The |
121 | | /// token can be used to perform various operations on the flow condition such |
122 | | /// as adding constraints to it, forking it, joining it with another flow |
123 | | /// condition, or checking implications. |
124 | 8.70k | Atom makeFlowConditionToken() { return makeAtom(); } |
125 | | |
126 | | private: |
127 | | llvm::BumpPtrAllocator Alloc; |
128 | | |
129 | | // Storage for the state of a program. |
130 | | std::vector<std::unique_ptr<StorageLocation>> Locs; |
131 | | std::vector<std::unique_ptr<Value>> Vals; |
132 | | |
133 | | // Indices that are used to avoid recreating the same integer literals and |
134 | | // composite boolean values. |
135 | | llvm::DenseMap<llvm::APInt, IntegerValue *> IntegerLiterals; |
136 | | using FormulaPair = std::pair<const Formula *, const Formula *>; |
137 | | llvm::DenseMap<FormulaPair, const Formula *> Ands; |
138 | | llvm::DenseMap<FormulaPair, const Formula *> Ors; |
139 | | llvm::DenseMap<const Formula *, const Formula *> Nots; |
140 | | llvm::DenseMap<FormulaPair, const Formula *> Implies; |
141 | | llvm::DenseMap<FormulaPair, const Formula *> Equals; |
142 | | llvm::DenseMap<Atom, const Formula *> AtomRefs; |
143 | | |
144 | | llvm::DenseMap<const Formula *, BoolValue *> FormulaValues; |
145 | | unsigned NextAtom = 0; |
146 | | |
147 | | Atom True, False; |
148 | | }; |
149 | | |
150 | | } // namespace clang::dataflow |
151 | | |
152 | | #endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE__ARENA_H |