CIRCT 23.0.0git
Loading...
Searching...
No Matches
DeseqUtils.h
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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
10#include "circt/Support/LLVM.h"
11#include "mlir/IR/Value.h"
12#include "llvm/ADT/APInt.h"
13#include "llvm/ADT/DenseMapInfo.h"
14#include "llvm/ADT/SmallVector.h"
15#include "llvm/Support/raw_ostream.h"
16
17namespace circt {
18namespace llhd {
19namespace deseq {
20
21//===----------------------------------------------------------------------===//
22// ValueField
23//===----------------------------------------------------------------------===//
24
25/// Identify a specific subfield (or the whole) of an SSA value using the HW
26/// field ID scheme. `fieldID == 0` means the whole value.
27struct ValueField {
28 /// The root SSA value being accessed (e.g. the full struct or array).
29 Value value;
30 /// The HW field ID describing which subfield is referenced. `0` means the
31 /// whole value.
32 uint64_t fieldID = 0;
33 /// Optional bit/slice projection within the selected field. `0` means the
34 /// whole field, otherwise this is `lowBit + 1` of a `comb.extract` applied to
35 /// the field (and can be chained by addition).
36 uint64_t bitID = 0;
37 /// Width (in bits) of the final extracted slice. `0` means no explicit slice
38 /// width is tracked.
39 uint64_t bitWidth = 0;
40 /// An optional SSA value that already materializes this specific subfield.
41 /// For non-projection values, this is identical to `value`.
43
44 ValueField() = default;
45 ValueField(Value value, uint64_t fieldID, Value projection = {},
46 uint64_t bitID = 0, uint64_t bitWidth = 0)
49
50 Value getProjected() const { return projection ? projection : value; }
51
52 bool operator==(const ValueField &other) const {
53 return value == other.value && fieldID == other.fieldID &&
54 bitID == other.bitID && bitWidth == other.bitWidth;
55 }
56 bool operator!=(const ValueField &other) const { return !(*this == other); }
57 operator bool() const { return static_cast<bool>(value); }
58};
59
60//===----------------------------------------------------------------------===//
61// Disjunctive Normal Form
62//===----------------------------------------------------------------------===//
63
64/// A single AND operation within a DNF.
65struct DNFTerm {
66 /// A mask with two bits for each possible term that may be present. Even bits
67 /// indicate a term is present, odd bits indicate a term's negation is
68 /// present.
69 uint32_t andTerms = 0;
70
71 bool isTrue() const { return andTerms == 0; }
72 bool isFalse() const {
73 // If any term has both the even and odd bits set, the term is false.
74 return (andTerms & 0x55555555UL) & (andTerms >> 1);
75 }
76
77 bool operator==(DNFTerm other) const { return andTerms == other.andTerms; }
78 bool operator!=(DNFTerm other) const { return !(*this == other); }
79};
80
81/// A boolean function expressed in canonical disjunctive normal form. Supports
82/// functions with up to 32 terms. Consists of AND operations nested inside an
83/// OR operation.
84struct DNF {
85 SmallVector<DNFTerm, 2> orTerms;
86 bool isPoison() const { return orTerms.size() == 1 && orTerms[0].isFalse(); }
87 bool isTrue() const { return orTerms.size() == 1 && orTerms[0].isTrue(); }
88 bool isFalse() const { return orTerms.empty(); }
89};
90
91llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const DNFTerm &term);
92llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const DNF &dnf);
93
94//===----------------------------------------------------------------------===//
95// Truth Table
96//===----------------------------------------------------------------------===//
97
98/// A boolean function expressed as a truth table. The first term is treated as
99/// a special "unknown" value marker with special semantics. Truth tables have
100/// exponential memory requirements. They are only useful to track a small
101/// number of terms, say up to 16, which already requires 64 kB of memory.
103 /// The value of the boolean function for each possible combination of input
104 /// term assignments. If the boolean function has N input terms, this `APInt`
105 /// lists all `2**N` possible combinations. The special "poison" value is
106 /// represented as a zero-width `bits`.
107 APInt bits;
108
109 /// Get the number of terms in the truth table. Since the width of `bits`
110 /// corresponds to `2**numInputs`, we count the number of trailing zeros in
111 /// the width of `bits` to determine `numInputs`.
112 unsigned getNumTerms() const {
113 if (isPoison())
114 return 0;
115 return llvm::countr_zero(bits.getBitWidth());
116 }
117
118 static TruthTable getPoison() { return TruthTable{APInt::getZero(0)}; }
119 bool isPoison() const { return bits.getBitWidth() == 0; }
120 bool isTrue() const { return bits.isAllOnes(); }
121 bool isFalse() const { return bits.isZero(); }
122
123 /// Create a boolean expression with a constant true or false value.
124 static TruthTable getConst(unsigned numTerms, bool value) {
125 assert(numTerms <= 16 && "excessive truth table");
126 return TruthTable{value ? APInt::getAllOnes(1 << numTerms)
127 : APInt::getZero(1 << numTerms)};
128 }
129
130 /// Create a boolean expression consisting of a single term.
131 static TruthTable getTerm(unsigned numTerms, unsigned term) {
132 assert(numTerms <= 16 && "excessive truth table");
133 assert(term < numTerms);
134 return TruthTable{getTermMask(1 << numTerms, term)};
135 }
136
137 // Boolean operations.
138 TruthTable operator~() const;
139 TruthTable operator&(const TruthTable &other) const;
140 TruthTable operator|(const TruthTable &other) const;
141 TruthTable operator^(const TruthTable &other) const;
142
144 TruthTable &operator&=(const TruthTable &other);
145 TruthTable &operator|=(const TruthTable &other);
146 TruthTable &operator^=(const TruthTable &other);
147
148 bool operator==(const TruthTable &other) const { return bits == other.bits; }
149 bool operator!=(const TruthTable &other) const { return !(*this == other); }
150
151 /// Convert the truth table into its canonical disjunctive normal form.
152 DNF canonicalize() const;
153
154private:
155 /// Return a mask that has a 1 in all truth table rows where `term` is 1,
156 /// and a 0 otherwise. This is equivalent to the truth table of a boolean
157 /// expression consisting of a single term.
158 static APInt getTermMask(unsigned bitWidth, unsigned term) {
159 return APInt::getSplat(bitWidth,
160 APInt::getHighBitsSet(2 << term, 1 << term));
161 }
162 APInt getTermMask(unsigned term) const {
163 return getTermMask(bits.getBitWidth(), term);
164 }
165
166 // Adjust any `!x` terms to be `x` terms.
167 void fixupUnknown();
168};
169
170llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const TruthTable &table);
171
172//===----------------------------------------------------------------------===//
173// Value Table
174//===----------------------------------------------------------------------===//
175
176/// A single entry in a value table. Tracks the condition under which a value
177/// appears. Can be set to a special "poison" and "unknown" marker.
179 Value value;
180
181 ValueEntry() = default;
183
184 bool isPoison() const { return *this == getPoison(); }
185 bool isUnknown() const { return *this == getUnknown(); }
187 return Value::getFromOpaquePointer((void *)(1));
188 }
189 static ValueEntry getUnknown() { return Value(); }
190
191 void merge(ValueEntry other);
192
193 bool operator==(ValueEntry other) const { return value == other.value; }
194 bool operator!=(ValueEntry other) const { return value != other.value; }
195};
196
197/// A table of SSA values and the conditions under which they appear. This
198/// struct can be used to track the various concrete values an SSA value may
199/// assume depending on how control flow reaches it.
201 SmallVector<std::pair<TruthTable, ValueEntry>, 1> entries;
202
203 ValueTable() = default;
205 : entries({{condition, entry}}) {}
206
207 void addCondition(TruthTable condition);
208 void merge(const ValueTable &other);
209 void minimize();
210};
211
212llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const ValueEntry &entry);
213llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
214 const std::pair<TruthTable, ValueEntry> &pair);
215llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const ValueTable &table);
216
217//===----------------------------------------------------------------------===//
218// Clock and Reset Analysis
219//===----------------------------------------------------------------------===//
220
221/// A single reset extracted from a process during trigger analysis.
222struct ResetInfo {
223 /// The value acting as the reset, causing the register to be set to `value`
224 /// when triggered.
225 Value reset;
226 /// The value the register is reset to.
227 Value value;
228 /// Whether the reset is active when high.
230
231 /// Check if this reset info is null.
232 operator bool() const { return bool(reset); }
233};
234
235/// A single clock extracted from a process during trigger analysis.
236struct ClockInfo {
237 /// The value acting as the clock, causing the register to be set to a value
238 /// in `valueTable` when triggered.
239 Value clock;
240 /// The value the register is set to when the clock is triggered.
241 Value value;
242 /// Whether the clock is sensitive to a rising or falling edge.
244 /// The optional value acting as an enable.
245 Value enable;
246
247 /// Check if this clock info is null.
248 operator bool() const { return bool(clock); }
249};
250
251/// A drive op and the clock and reset that resulted from trigger analysis. A
252/// process may describe multiple clock and reset triggers, but since the
253/// registers we lower to only allow a single clock and a single reset, this
254/// struct tracks a single clock and reset, respectively. Processes describing
255/// multiple clocks or resets are skipped.
256struct DriveInfo {
257 /// The drive operation.
258 DriveOp op;
259 /// The clock that triggers a change to the driven value. Guaranteed to be
260 /// non-null.
262 /// The optional reset that triggers a change of the driven value to a fixed
263 /// reset value. Null if no reset was detected.
265
267 explicit DriveInfo(DriveOp op) : op(op) {}
268};
269
270//===----------------------------------------------------------------------===//
271// Value Assignments for Process Specialization
272//===----------------------------------------------------------------------===//
273
274/// A single `i1` value that is fixed to a given value in the past and the
275/// present.
277 /// The IR value being fixed.
278 Value value;
279 /// The assigned value in the past, as transported into the presented via a
280 /// destination operand of a process' wait op.
281 bool past;
282 /// The assigned value in the present.
284
285 bool operator==(const FixedValue &other) const {
286 return value == other.value && past == other.past &&
287 present == other.present;
288 }
289
290 operator bool() const { return bool(value); }
291};
292
293/// A list of `i1` values that are fixed to a given value. These are used when
294/// specializing a process to compute the value and enable condition for a drive
295/// when a trigger occurs.
296using FixedValues = SmallVector<FixedValue, 2>;
297
298static inline llvm::hash_code hash_value(const FixedValue &arg) {
299 return llvm::hash_combine(arg.value, arg.past, arg.present);
300}
301
302static inline llvm::hash_code hash_value(const FixedValues &arg) {
303 return llvm::hash_combine_range(arg.begin(), arg.end());
304}
305
306} // namespace deseq
307} // namespace llhd
308} // namespace circt
309
310namespace llvm {
311
312// Allow `FixedValue` to be used as hash map key.
313template <>
314struct DenseMapInfo<circt::llhd::deseq::FixedValue> {
315 using Value = mlir::Value;
317 static inline FixedValue getEmptyKey() {
318 return FixedValue{DenseMapInfo<Value>::getEmptyKey(), false, false};
319 }
320 static inline FixedValue getTombstoneKey() {
321 return FixedValue{DenseMapInfo<Value>::getTombstoneKey(), false, false};
322 }
323 static unsigned getHashValue(const FixedValue &key) {
324 return hash_value(key);
325 }
326 static bool isEqual(const FixedValue &a, const FixedValue &b) {
327 return a == b;
328 }
329};
330
331// Allow `FixedValues` to be used as hash map key.
332template <>
333struct DenseMapInfo<circt::llhd::deseq::FixedValues> {
336 static inline FixedValues getEmptyKey() {
338 }
342 static unsigned getHashValue(const FixedValues &key) {
343 return hash_value(key);
344 }
345 static bool isEqual(const FixedValues &a, const FixedValues &b) {
346 return a == b;
347 }
348};
349
350// Allow `ValueField` to be used as a DenseMap key.
351template <>
352struct DenseMapInfo<circt::llhd::deseq::ValueField> {
354 static inline VF getEmptyKey() {
356 }
357 static inline VF getTombstoneKey() {
359 }
366 static bool isEqual(const VF &a, const VF &b) { return a == b; }
367};
368
369} // namespace llvm
assert(baseType &&"element must be base type")
llvm::raw_ostream & operator<<(llvm::raw_ostream &os, const DNFTerm &term)
SmallVector< FixedValue, 2 > FixedValues
A list of i1 values that are fixed to a given value.
Definition DeseqUtils.h:296
static llvm::hash_code hash_value(const FixedValue &arg)
Definition DeseqUtils.h:298
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
llvm::hash_code hash_value(const DenseSet< T > &set)
A single clock extracted from a process during trigger analysis.
Definition DeseqUtils.h:236
Value clock
The value acting as the clock, causing the register to be set to a value in valueTable when triggered...
Definition DeseqUtils.h:239
bool risingEdge
Whether the clock is sensitive to a rising or falling edge.
Definition DeseqUtils.h:243
Value value
The value the register is set to when the clock is triggered.
Definition DeseqUtils.h:241
Value enable
The optional value acting as an enable.
Definition DeseqUtils.h:245
A single AND operation within a DNF.
Definition DeseqUtils.h:65
uint32_t andTerms
A mask with two bits for each possible term that may be present.
Definition DeseqUtils.h:69
bool operator==(DNFTerm other) const
Definition DeseqUtils.h:77
bool operator!=(DNFTerm other) const
Definition DeseqUtils.h:78
A boolean function expressed in canonical disjunctive normal form.
Definition DeseqUtils.h:84
bool isPoison() const
Definition DeseqUtils.h:86
SmallVector< DNFTerm, 2 > orTerms
Definition DeseqUtils.h:85
A drive op and the clock and reset that resulted from trigger analysis.
Definition DeseqUtils.h:256
ClockInfo clock
The clock that triggers a change to the driven value.
Definition DeseqUtils.h:261
ResetInfo reset
The optional reset that triggers a change of the driven value to a fixed reset value.
Definition DeseqUtils.h:264
DriveOp op
The drive operation.
Definition DeseqUtils.h:258
A single i1 value that is fixed to a given value in the past and the present.
Definition DeseqUtils.h:276
bool present
The assigned value in the present.
Definition DeseqUtils.h:283
bool past
The assigned value in the past, as transported into the presented via a destination operand of a proc...
Definition DeseqUtils.h:281
bool operator==(const FixedValue &other) const
Definition DeseqUtils.h:285
Value value
The IR value being fixed.
Definition DeseqUtils.h:278
A single reset extracted from a process during trigger analysis.
Definition DeseqUtils.h:222
Value value
The value the register is reset to.
Definition DeseqUtils.h:227
Value reset
The value acting as the reset, causing the register to be set to value when triggered.
Definition DeseqUtils.h:225
bool activeHigh
Whether the reset is active when high.
Definition DeseqUtils.h:229
A boolean function expressed as a truth table.
Definition DeseqUtils.h:102
static APInt getTermMask(unsigned bitWidth, unsigned term)
Return a mask that has a 1 in all truth table rows where term is 1, and a 0 otherwise.
Definition DeseqUtils.h:158
bool operator!=(const TruthTable &other) const
Definition DeseqUtils.h:149
DNF canonicalize() const
Convert the truth table into its canonical disjunctive normal form.
static TruthTable getTerm(unsigned numTerms, unsigned term)
Create a boolean expression consisting of a single term.
Definition DeseqUtils.h:131
static TruthTable getPoison()
Definition DeseqUtils.h:118
bool operator==(const TruthTable &other) const
Definition DeseqUtils.h:148
APInt bits
The value of the boolean function for each possible combination of input term assignments.
Definition DeseqUtils.h:107
TruthTable operator~() const
APInt getTermMask(unsigned term) const
Definition DeseqUtils.h:162
unsigned getNumTerms() const
Get the number of terms in the truth table.
Definition DeseqUtils.h:112
TruthTable operator&(const TruthTable &other) const
TruthTable operator^(const TruthTable &other) const
static TruthTable getConst(unsigned numTerms, bool value)
Create a boolean expression with a constant true or false value.
Definition DeseqUtils.h:124
TruthTable operator|(const TruthTable &other) const
TruthTable & operator|=(const TruthTable &other)
TruthTable & operator&=(const TruthTable &other)
TruthTable & operator^=(const TruthTable &other)
A single entry in a value table.
Definition DeseqUtils.h:178
static ValueEntry getUnknown()
Definition DeseqUtils.h:189
bool operator!=(ValueEntry other) const
Definition DeseqUtils.h:194
static ValueEntry getPoison()
Definition DeseqUtils.h:186
void merge(ValueEntry other)
bool operator==(ValueEntry other) const
Definition DeseqUtils.h:193
Identify a specific subfield (or the whole) of an SSA value using the HW field ID scheme.
Definition DeseqUtils.h:27
uint64_t bitWidth
Width (in bits) of the final extracted slice.
Definition DeseqUtils.h:39
Value value
The root SSA value being accessed (e.g. the full struct or array).
Definition DeseqUtils.h:29
uint64_t fieldID
The HW field ID describing which subfield is referenced.
Definition DeseqUtils.h:32
ValueField(Value value, uint64_t fieldID, Value projection={}, uint64_t bitID=0, uint64_t bitWidth=0)
Definition DeseqUtils.h:45
uint64_t bitID
Optional bit/slice projection within the selected field.
Definition DeseqUtils.h:36
Value projection
An optional SSA value that already materializes this specific subfield.
Definition DeseqUtils.h:42
bool operator!=(const ValueField &other) const
Definition DeseqUtils.h:56
bool operator==(const ValueField &other) const
Definition DeseqUtils.h:52
A table of SSA values and the conditions under which they appear.
Definition DeseqUtils.h:200
SmallVector< std::pair< TruthTable, ValueEntry >, 1 > entries
Definition DeseqUtils.h:201
void addCondition(TruthTable condition)
ValueTable(TruthTable condition, ValueEntry entry)
Definition DeseqUtils.h:204
void merge(const ValueTable &other)
static bool isEqual(const FixedValue &a, const FixedValue &b)
Definition DeseqUtils.h:326
static unsigned getHashValue(const FixedValue &key)
Definition DeseqUtils.h:323
static unsigned getHashValue(const FixedValues &key)
Definition DeseqUtils.h:342
static bool isEqual(const FixedValues &a, const FixedValues &b)
Definition DeseqUtils.h:345
static bool isEqual(const VF &a, const VF &b)
Definition DeseqUtils.h:366