clang 22.0.0git
FormulaSerialization.cpp
Go to the documentation of this file.
1//===- FormulaSerialization.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
12#include "clang/Basic/LLVM.h"
13#include "llvm/ADT/DenseMap.h"
14#include "llvm/ADT/STLExtras.h"
15#include "llvm/ADT/StringRef.h"
16#include "llvm/Support/Allocator.h"
17#include "llvm/Support/Error.h"
18#include "llvm/Support/ErrorHandling.h"
19#include <cassert>
20
21namespace clang::dataflow {
22
23// Returns the leading indicator of operation formulas. `AtomRef` and `Literal`
24// are handled differently.
26 switch (K) {
29 // No sigil.
30 return '\0';
31 case Formula::Not:
32 return '!';
33 case Formula::And:
34 return '&';
35 case Formula::Or:
36 return '|';
38 return '>';
39 case Formula::Equal:
40 return '=';
41 }
42 llvm_unreachable("unhandled formula kind");
43}
44
45void serializeFormula(const Formula &F, llvm::raw_ostream &OS) {
46 switch (Formula::numOperands(F.kind())) {
47 case 0:
48 switch (F.kind()) {
50 OS << F.getAtom();
51 break;
53 OS << (F.literal() ? 'T' : 'F');
54 break;
55 default:
56 llvm_unreachable("unhandled formula kind");
57 }
58 break;
59 case 1:
60 OS << compactSigil(F.kind());
61 serializeFormula(*F.operands()[0], OS);
62 break;
63 case 2:
64 OS << compactSigil(F.kind());
65 serializeFormula(*F.operands()[0], OS);
66 serializeFormula(*F.operands()[1], OS);
67 break;
68 default:
69 llvm_unreachable("unhandled formula arity");
70 }
71}
72
74parsePrefix(llvm::StringRef &Str, Arena &A,
75 llvm::DenseMap<unsigned, Atom> &AtomMap) {
76 if (Str.empty())
77 return llvm::createStringError(llvm::inconvertibleErrorCode(),
78 "unexpected end of input");
79
80 char Prefix = Str[0];
81 Str = Str.drop_front();
82
83 switch (Prefix) {
84 case 'T':
85 return &A.makeLiteral(true);
86 case 'F':
87 return &A.makeLiteral(false);
88 case 'V': {
89 unsigned AtomID;
90 if (Str.consumeInteger(10, AtomID))
91 return llvm::createStringError(llvm::inconvertibleErrorCode(),
92 "expected atom id");
93 auto [It, Inserted] = AtomMap.try_emplace(AtomID, Atom());
94 if (Inserted)
95 It->second = A.makeAtom();
96 return &A.makeAtomRef(It->second);
97 }
98 case '!': {
99 auto OperandOrErr = parsePrefix(Str, A, AtomMap);
100 if (!OperandOrErr)
101 return OperandOrErr.takeError();
102 return &A.makeNot(**OperandOrErr);
103 }
104 case '&':
105 case '|':
106 case '>':
107 case '=': {
108 auto LeftOrErr = parsePrefix(Str, A, AtomMap);
109 if (!LeftOrErr)
110 return LeftOrErr.takeError();
111
112 auto RightOrErr = parsePrefix(Str, A, AtomMap);
113 if (!RightOrErr)
114 return RightOrErr.takeError();
115
116 const Formula &LHS = **LeftOrErr;
117 const Formula &RHS = **RightOrErr;
118
119 switch (Prefix) {
120 case '&':
121 return &A.makeAnd(LHS, RHS);
122 case '|':
123 return &A.makeOr(LHS, RHS);
124 case '>':
125 return &A.makeImplies(LHS, RHS);
126 case '=':
127 return &A.makeEquals(LHS, RHS);
128 default:
129 llvm_unreachable("unexpected binary op");
130 }
131 }
132 default:
133 return llvm::createStringError(llvm::inconvertibleErrorCode(),
134 "unexpected prefix character: %c", Prefix);
135 }
136}
137
139parseFormula(llvm::StringRef Str, Arena &A,
140 llvm::DenseMap<unsigned, Atom> &AtomMap) {
141 size_t OriginalSize = Str.size();
142 llvm::Expected<const Formula *> F = parsePrefix(Str, A, AtomMap);
143 if (!F)
144 return F.takeError();
145 if (!Str.empty())
146 return llvm::createStringError(llvm::inconvertibleErrorCode(),
147 ("unexpected suffix of length: " +
148 llvm::Twine(Str.size() - OriginalSize))
149 .str());
150 return F;
151}
152
153} // namespace clang::dataflow
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
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:91
const Formula & makeAtomRef(Atom A)
Returns a formula for the variable A.
Definition Arena.cpp:34
Atom makeAtom()
Returns a new atomic boolean variable, distinct from any other.
Definition Arena.h:118
const Formula & makeNot(const Formula &Val)
Returns a formula for the negation of Val.
Definition Arena.cpp:67
const Formula & makeOr(const Formula &LHS, const Formula &RHS)
Returns a formula for the disjunction of LHS and RHS.
Definition Arena.cpp:54
const Formula & makeAnd(const Formula &LHS, const Formula &RHS)
Returns a formula for the conjunction of LHS and RHS.
Definition Arena.cpp:41
const Formula & makeImplies(const Formula &LHS, const Formula &RHS)
Returns a formula for LHS => RHS.
Definition Arena.cpp:78
const Formula & makeLiteral(bool Value)
Returns a formula for a literal true/false.
Definition Arena.h:111
ArrayRef< const Formula * > operands() const
Definition Formula.h:82
Atom getAtom() const
Definition Formula.h:68
@ 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:54
@ Literal
Constant true or false.
Definition Formula.h:56
@ 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
bool literal() const
Definition Formula.h:73
Kind kind() const
Definition Formula.h:66
static unsigned numOperands(Kind K)
Count of operands (sub-formulas) associated with Formulas of kind K.
Definition Formula.h:99
Dataflow Directional Tag Classes.
Definition AdornedCFG.h:29
static llvm::Expected< const Formula * > parsePrefix(llvm::StringRef &Str, Arena &A, llvm::DenseMap< unsigned, Atom > &AtomMap)
Atom
Identifies an atomic boolean variable such as "V1".
Definition Formula.h:34
void serializeFormula(const Formula &F, llvm::raw_ostream &OS)
Prints F to OS in a compact format, optimized for easy parsing (deserialization) rather than human us...
llvm::Expected< const Formula * > parseFormula(llvm::StringRef Str, Arena &A, llvm::DenseMap< unsigned, Atom > &AtomMap)
Parses Str to build a serialized Formula.
static char compactSigil(Formula::Kind K)