xref: /freebsd/contrib/llvm-project/clang/include/clang/Analysis/FlowSensitive/CNFFormula.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1 //===- CNFFormula.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 //
9 //  A representation of a boolean formula in 3-CNF.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CNFFORMULA_H
14 #define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CNFFORMULA_H
15 
16 #include <cstdint>
17 #include <vector>
18 
19 #include "clang/Analysis/FlowSensitive/Formula.h"
20 
21 namespace clang {
22 namespace dataflow {
23 
24 /// Boolean variables are represented as positive integers.
25 using Variable = uint32_t;
26 
27 /// A null boolean variable is used as a placeholder in various data structures
28 /// and algorithms.
29 constexpr Variable NullVar = 0;
30 
31 /// Literals are represented as positive integers. Specifically, for a boolean
32 /// variable `V` that is represented as the positive integer `I`, the positive
33 /// literal `V` is represented as the integer `2*I` and the negative literal
34 /// `!V` is represented as the integer `2*I+1`.
35 using Literal = uint32_t;
36 
37 /// A null literal is used as a placeholder in various data structures and
38 /// algorithms.
39 constexpr Literal NullLit = 0;
40 
41 /// Clause identifiers are represented as positive integers.
42 using ClauseID = uint32_t;
43 
44 /// A null clause identifier is used as a placeholder in various data structures
45 /// and algorithms.
46 constexpr ClauseID NullClause = 0;
47 
48 /// Returns the positive literal `V`.
posLit(Variable V)49 inline constexpr Literal posLit(Variable V) { return 2 * V; }
50 
51 /// Returns the negative literal `!V`.
negLit(Variable V)52 inline constexpr Literal negLit(Variable V) { return 2 * V + 1; }
53 
54 /// Returns whether `L` is a positive literal.
isPosLit(Literal L)55 inline constexpr bool isPosLit(Literal L) { return 0 == (L & 1); }
56 
57 /// Returns whether `L` is a negative literal.
isNegLit(Literal L)58 inline constexpr bool isNegLit(Literal L) { return 1 == (L & 1); }
59 
60 /// Returns the negated literal `!L`.
notLit(Literal L)61 inline constexpr Literal notLit(Literal L) { return L ^ 1; }
62 
63 /// Returns the variable of `L`.
var(Literal L)64 inline constexpr Variable var(Literal L) { return L >> 1; }
65 
66 /// A boolean formula in 3-CNF (conjunctive normal form with at most 3 literals
67 /// per clause).
68 class CNFFormula {
69   /// `LargestVar` is equal to the largest positive integer that represents a
70   /// variable in the formula.
71   const Variable LargestVar;
72 
73   /// Literals of all clauses in the formula.
74   ///
75   /// The element at index 0 stands for the literal in the null clause. It is
76   /// set to 0 and isn't used. Literals of clauses in the formula start from the
77   /// element at index 1.
78   ///
79   /// For example, for the formula `(L1 v L2) ^ (L2 v L3 v L4)` the elements of
80   /// `Clauses` will be `[0, L1, L2, L2, L3, L4]`.
81   std::vector<Literal> Clauses;
82 
83   /// Start indices of clauses of the formula in `Clauses`.
84   ///
85   /// The element at index 0 stands for the start index of the null clause. It
86   /// is set to 0 and isn't used. Start indices of clauses in the formula start
87   /// from the element at index 1.
88   ///
89   /// For example, for the formula `(L1 v L2) ^ (L2 v L3 v L4)` the elements of
90   /// `ClauseStarts` will be `[0, 1, 3]`. Note that the literals of the first
91   /// clause always start at index 1. The start index for the literals of the
92   /// second clause depends on the size of the first clause and so on.
93   std::vector<size_t> ClauseStarts;
94 
95   /// Indicates that we already know the formula is unsatisfiable.
96   /// During construction, we catch simple cases of conflicting unit-clauses.
97   bool KnownContradictory;
98 
99 public:
100   explicit CNFFormula(Variable LargestVar);
101 
102   /// Adds the `L1 v ... v Ln` clause to the formula.
103   /// Requirements:
104   ///
105   ///  `Li` must not be `NullLit`.
106   ///
107   ///  All literals in the input that are not `NullLit` must be distinct.
108   void addClause(ArrayRef<Literal> lits);
109 
110   /// Returns whether the formula is known to be contradictory.
111   /// This is the case if any of the clauses is empty.
knownContradictory()112   bool knownContradictory() const { return KnownContradictory; }
113 
114   /// Returns the largest variable in the formula.
largestVar()115   Variable largestVar() const { return LargestVar; }
116 
117   /// Returns the number of clauses in the formula.
118   /// Valid clause IDs are in the range [1, `numClauses()`].
numClauses()119   ClauseID numClauses() const { return ClauseStarts.size() - 1; }
120 
121   /// Returns the number of literals in clause `C`.
clauseSize(ClauseID C)122   size_t clauseSize(ClauseID C) const {
123     return C == ClauseStarts.size() - 1 ? Clauses.size() - ClauseStarts[C]
124                                         : ClauseStarts[C + 1] - ClauseStarts[C];
125   }
126 
127   /// Returns the literals of clause `C`.
128   /// If `knownContradictory()` is false, each clause has at least one literal.
clauseLiterals(ClauseID C)129   llvm::ArrayRef<Literal> clauseLiterals(ClauseID C) const {
130     size_t S = clauseSize(C);
131     if (S == 0)
132       return llvm::ArrayRef<Literal>();
133     return llvm::ArrayRef<Literal>(&Clauses[ClauseStarts[C]], S);
134   }
135 
136   /// An iterator over all literals of all clauses in the formula.
137   /// The iterator allows mutation of the literal through the `*` operator.
138   /// This is to support solvers that mutate the formula during solving.
139   class Iterator {
140     friend class CNFFormula;
141     CNFFormula *CNF;
142     size_t Idx;
Iterator(CNFFormula * CNF,size_t Idx)143     Iterator(CNFFormula *CNF, size_t Idx) : CNF(CNF), Idx(Idx) {}
144 
145   public:
146     Iterator(const Iterator &) = default;
147     Iterator &operator=(const Iterator &) = default;
148 
149     Iterator &operator++() {
150       ++Idx;
151       assert(Idx < CNF->Clauses.size() && "Iterator out of bounds");
152       return *this;
153     }
154 
next()155     Iterator next() const {
156       Iterator I = *this;
157       ++I;
158       return I;
159     }
160 
161     Literal &operator*() const { return CNF->Clauses[Idx]; }
162   };
163   friend class Iterator;
164 
165   /// Returns an iterator to the first literal of clause `C`.
startOfClause(ClauseID C)166   Iterator startOfClause(ClauseID C) { return Iterator(this, ClauseStarts[C]); }
167 };
168 
169 /// Converts the conjunction of `Vals` into a formula in conjunctive normal
170 /// form where each clause has at least one and at most three literals.
171 /// `Atomics` is populated with a mapping from `Variables` to the corresponding
172 /// `Atom`s for atomic booleans in the input formulas.
173 CNFFormula buildCNF(const llvm::ArrayRef<const Formula *> &Formulas,
174                     llvm::DenseMap<Variable, Atom> &Atomics);
175 
176 } // namespace dataflow
177 } // namespace clang
178 
179 #endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CNFFORMULA_H
180