clang 18.0.0git
Arena.cpp
Go to the documentation of this file.
1//===-- Arena.cpp ---------------------------------------------------------===//
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
12#include "llvm/Support/Error.h"
13#include <string>
14
15namespace clang::dataflow {
16
17static std::pair<const Formula *, const Formula *>
18canonicalFormulaPair(const Formula &LHS, const Formula &RHS) {
19 auto Res = std::make_pair(&LHS, &RHS);
20 if (&RHS < &LHS) // FIXME: use a deterministic order instead
21 std::swap(Res.first, Res.second);
22 return Res;
23}
24
26 auto [It, Inserted] = AtomRefs.try_emplace(A);
27 if (Inserted)
28 It->second =
29 &Formula::create(Alloc, Formula::AtomRef, {}, static_cast<unsigned>(A));
30 return *It->second;
31}
32
33const Formula &Arena::makeAnd(const Formula &LHS, const Formula &RHS) {
34 if (&LHS == &RHS)
35 return LHS;
36
37 auto [It, Inserted] =
38 Ands.try_emplace(canonicalFormulaPair(LHS, RHS), nullptr);
39 if (Inserted)
40 It->second = &Formula::create(Alloc, Formula::And, {&LHS, &RHS});
41 return *It->second;
42}
43
44const Formula &Arena::makeOr(const Formula &LHS, const Formula &RHS) {
45 if (&LHS == &RHS)
46 return LHS;
47
48 auto [It, Inserted] =
49 Ors.try_emplace(canonicalFormulaPair(LHS, RHS), nullptr);
50 if (Inserted)
51 It->second = &Formula::create(Alloc, Formula::Or, {&LHS, &RHS});
52 return *It->second;
53}
54
55const Formula &Arena::makeNot(const Formula &Val) {
56 auto [It, Inserted] = Nots.try_emplace(&Val, nullptr);
57 if (Inserted)
58 It->second = &Formula::create(Alloc, Formula::Not, {&Val});
59 return *It->second;
60}
61
62const Formula &Arena::makeImplies(const Formula &LHS, const Formula &RHS) {
63 if (&LHS == &RHS)
64 return makeLiteral(true);
65
66 auto [It, Inserted] =
67 Implies.try_emplace(std::make_pair(&LHS, &RHS), nullptr);
68 if (Inserted)
69 It->second = &Formula::create(Alloc, Formula::Implies, {&LHS, &RHS});
70 return *It->second;
71}
72
73const Formula &Arena::makeEquals(const Formula &LHS, const Formula &RHS) {
74 if (&LHS == &RHS)
75 return makeLiteral(true);
76
77 auto [It, Inserted] =
78 Equals.try_emplace(canonicalFormulaPair(LHS, RHS), nullptr);
79 if (Inserted)
80 It->second = &Formula::create(Alloc, Formula::Equal, {&LHS, &RHS});
81 return *It->second;
82}
83
85 auto [It, Inserted] = IntegerLiterals.try_emplace(Value, nullptr);
86
87 if (Inserted)
88 It->second = &create<IntegerValue>();
89 return *It->second;
90}
91
93 auto [It, Inserted] = FormulaValues.try_emplace(&F);
94 if (Inserted)
95 It->second = (F.kind() == Formula::AtomRef)
96 ? (BoolValue *)&create<AtomicBoolValue>(F)
97 : &create<FormulaBoolValue>(F);
98 return *It->second;
99}
100
101namespace {
102const Formula *parse(Arena &A, llvm::StringRef &In) {
103 auto EatSpaces = [&] { In = In.ltrim(' '); };
104 EatSpaces();
105
106 if (In.consume_front("!")) {
107 if (auto *Arg = parse(A, In))
108 return &A.makeNot(*Arg);
109 return nullptr;
110 }
111
112 if (In.consume_front("(")) {
113 auto *Arg1 = parse(A, In);
114 if (!Arg1)
115 return nullptr;
116
117 EatSpaces();
118 decltype(&Arena::makeOr) Op;
119 if (In.consume_front("|"))
120 Op = &Arena::makeOr;
121 else if (In.consume_front("&"))
122 Op = &Arena::makeAnd;
123 else if (In.consume_front("=>"))
124 Op = &Arena::makeImplies;
125 else if (In.consume_front("="))
126 Op = &Arena::makeEquals;
127 else
128 return nullptr;
129
130 auto *Arg2 = parse(A, In);
131 if (!Arg2)
132 return nullptr;
133
134 EatSpaces();
135 if (!In.consume_front(")"))
136 return nullptr;
137
138 return &(A.*Op)(*Arg1, *Arg2);
139 }
140
141 // For now, only support unnamed variables V0, V1 etc.
142 // FIXME: parse e.g. "X" by allocating an atom and storing a name somewhere.
143 if (In.consume_front("V")) {
144 std::underlying_type_t<Atom> At;
145 if (In.consumeInteger(10, At))
146 return nullptr;
147 return &A.makeAtomRef(static_cast<Atom>(At));
148 }
149
150 if (In.consume_front("true"))
151 return &A.makeLiteral(true);
152 if (In.consume_front("false"))
153 return &A.makeLiteral(false);
154
155 return nullptr;
156}
157
158class FormulaParseError : public llvm::ErrorInfo<FormulaParseError> {
159 std::string Formula;
160 unsigned Offset;
161
162public:
163 static char ID;
164 FormulaParseError(llvm::StringRef Formula, unsigned Offset)
165 : Formula(Formula), Offset(Offset) {}
166
167 void log(raw_ostream &OS) const override {
168 OS << "bad formula at offset " << Offset << "\n";
169 OS << Formula << "\n";
170 OS.indent(Offset) << "^";
171 }
172
173 std::error_code convertToErrorCode() const override {
174 return std::make_error_code(std::errc::invalid_argument);
175 }
176};
177
178char FormulaParseError::ID = 0;
179
180} // namespace
181
183 llvm::StringRef Rest = In;
184 auto *Result = parse(*this, Rest);
185 if (!Result) // parse() hit something unparseable
186 return llvm::make_error<FormulaParseError>(In, In.size() - Rest.size());
187 Rest = Rest.ltrim();
188 if (!Rest.empty()) // parse didn't consume all the input
189 return llvm::make_error<FormulaParseError>(In, In.size() - Rest.size());
190 return *Result;
191}
192
193} // namespace clang::dataflow
The Arena owns the objects that model data within an analysis.
Definition: Arena.h:21
const Formula & makeEquals(const Formula &LHS, const Formula &RHS)
Returns a formula for LHS <=> RHS.
Definition: Arena.cpp:73
const Formula & makeAtomRef(Atom A)
Returns a formula for the variable A.
Definition: Arena.cpp:25
IntegerValue & makeIntLiteral(llvm::APInt Value)
Returns a symbolic integer value that models an integer literal equal to Value.
Definition: Arena.cpp:84
const Formula & makeNot(const Formula &Val)
Returns a formula for the negation of Val.
Definition: Arena.cpp:55
const Formula & makeOr(const Formula &LHS, const Formula &RHS)
Returns a formula for the disjunction of LHS and RHS.
Definition: Arena.cpp:44
BoolValue & makeBoolValue(const Formula &)
Creates a BoolValue wrapping a particular formula.
Definition: Arena.cpp:92
const Formula & makeAnd(const Formula &LHS, const Formula &RHS)
Returns a formula for the conjunction of LHS and RHS.
Definition: Arena.cpp:33
const Formula & makeImplies(const Formula &LHS, const Formula &RHS)
Returns a formula for LHS => RHS.
Definition: Arena.cpp:62
const Formula & makeLiteral(bool Value)
Returns a formula for a literal true/false.
Definition: Arena.h:109
llvm::Expected< const Formula & > parseFormula(llvm::StringRef)
Definition: Arena.cpp:182
Models a boolean.
Definition: Value.h:92
@ Equal
True if LHS is false or RHS is true.
Definition: Formula.h:64
@ Implies
True if either LHS or RHS is true.
Definition: Formula.h:63
@ AtomRef
A reference to an atomic boolean variable.
Definition: Formula.h:55
@ Or
True if LHS and RHS are both true.
Definition: Formula.h:62
@ And
True if its only operand is false.
Definition: Formula.h:61
Kind kind() const
Definition: Formula.h:66
static Formula & create(llvm::BumpPtrAllocator &Alloc, Kind K, ArrayRef< const Formula * > Operands, unsigned Value=0)
Definition: Formula.cpp:20
Models an integer.
Definition: Value.h:158
Base class for all values computed by abstract interpretation.
Definition: Value.h:33
Dataflow Directional Tag Classes.
Definition: Arena.h:17
Atom
Identifies an atomic boolean variable such as "V1".
Definition: Formula.h:35
static std::pair< const Formula *, const Formula * > canonicalFormulaPair(const Formula &LHS, const Formula &RHS)
Definition: Arena.cpp:18
@ Result
The result type of a method or function.
#define log(__x)
Definition: tgmath.h:460