15#include "llvm/ADT/APInt.h"
16#include "llvm/ADT/STLExtras.h"
17#include "llvm/Support/MathExtras.h"
34 const llvm::APInt &output) {
37 assert(input.getBitWidth() < 32 &&
"Input width too large");
38 unsigned offset = input.getZExtValue() *
numOutputs;
40 table.setBitVal(offset + i, output[i]);
48 for (
unsigned i = 0; i < (1u <<
numInputs); ++i) {
50 llvm::APInt permutedInput = input;
53 for (
unsigned j = 0; j <
numInputs; ++j) {
54 if (permutation[j] != j)
55 permutedInput.setBitVal(j, input[permutation[j]]);
67 for (
unsigned i = 0; i < (1u <<
numInputs); ++i) {
71 llvm::APInt negatedInput = input ^ llvm::APInt(
numInputs, mask);
83 for (
unsigned i = 0; i < (1u <<
numInputs); ++i) {
88 llvm::APInt negatedOutput = output ^ llvm::APInt(
numOutputs, negation);
110 os <<
table <<
")\n";
113 for (
unsigned i = 0; i <
numInputs; ++i) {
114 os <<
"i" << i <<
" ";
117 os <<
"o" << i <<
" ";
128 for (
unsigned i = 0; i < (1u <<
numInputs); ++i) {
130 for (
unsigned j = 0; j <
numInputs; ++j) {
131 os << ((i >> j) & 1) <<
" ";
139 os << output[j] <<
" ";
155llvm::SmallVector<unsigned> identityPermutation(
unsigned size) {
156 llvm::SmallVector<unsigned> identity(size);
157 for (
unsigned i = 0; i < size; ++i)
165unsigned permuteNegationMask(
unsigned negationMask,
166 ArrayRef<unsigned> permutation) {
168 for (
unsigned i = 0; i < permutation.size(); ++i) {
169 if (negationMask & (1u << i)) {
170 result |= (1u << permutation[i]);
178llvm::SmallVector<unsigned> invertPermutation(ArrayRef<unsigned> permutation) {
179 llvm::SmallVector<unsigned> inverse(permutation.size());
180 for (
unsigned i = 0; i < permutation.size(); ++i) {
181 inverse[permutation[i]] = i;
190 llvm::SmallVectorImpl<unsigned> &permutation)
const {
192 "NPN classes must have the same number of inputs");
194 "NPN classes must be equivalent for input mapping");
207 permutation.push_back(thisInverse[canonicalPos]);
220 for (uint32_t negMask = 0; negMask < (1u << tt.
numInputs); ++negMask) {
224 auto permutation = identityPermutation(tt.
numInputs);
230 unsigned currentNegMask = permuteNegationMask(negMask, permutation);
233 for (
unsigned outputNegMask = 0; outputNegMask < (1u << tt.
numOutputs);
240 NPNClass candidate(candidateTT, permutation, currentNegMask,
246 canonical = std::move(candidate);
248 }
while (std::next_permutation(permutation.begin(), permutation.end()));
256 os <<
" Input permutation: [";
263 os <<
" Input negation: 0b";
268 os <<
" Output negation: 0b";
273 os <<
" Canonical truth table:\n";
287 {0x5555555555555555ULL, 0x3333333333333333ULL, 0x0F0F0F0F0F0F0F0FULL,
288 0x00FF00FF00FF00FFULL, 0x0000FFFF0000FFFFULL,
289 0x00000000FFFFFFFFULL},
290 {0xAAAAAAAAAAAAAAAAULL, 0xCCCCCCCCCCCCCCCCULL, 0xF0F0F0F0F0F0F0F0ULL,
291 0xFF00FF00FF00FF00ULL, 0xFFFF0000FFFF0000ULL,
292 0xFFFFFFFF00000000ULL},
298template <
bool positive>
300 assert(numVars <= 64 &&
"Number of variables too large");
301 assert(varIndex < numVars &&
"Variable index out of bounds");
302 uint64_t numBits = 1u << numVars;
307 uint64_t maskValue =
kVarMasks[positive][varIndex];
310 maskValue &= (1ULL << numBits) - 1;
311 return APInt(numBits, maskValue);
316 uint64_t patternWidth = 1u << (varIndex + 1);
317 APInt
pattern(patternWidth, 0);
320 uint64_t shift = 1u << varIndex;
321 if constexpr (positive) {
323 pattern.setBits(shift, patternWidth);
329 return APInt::getSplat(numBits,
pattern);
334 return createVarMaskImpl<true>(numVars, varIndex);
335 return createVarMaskImpl<false>(numVars, varIndex);
353std::pair<APInt, APInt>
355 assert(numVars <= 64 &&
"Number of variables too large");
356 assert(var < numVars &&
"Variable index out of bounds");
357 assert(f.getBitWidth() == (1u << numVars) &&
"Truth table size mismatch");
358 uint64_t numBits = 1u << numVars;
359 uint64_t shift = 1u << var;
365 APInt blockPattern = APInt::getLowBitsSet(2 * shift, shift);
366 APInt mask0 = APInt::getSplat(numBits, blockPattern);
367 APInt mask1 = mask0.shl(shift);
370 APInt selected0 = f & mask0;
371 APInt selected1 = f & mask1;
374 APInt cof0 = selected0 | selected0.shl(shift);
375 APInt cof1 = selected1 | selected1.lshr(shift);
386 for (
const auto &cube :
cubes) {
387 APInt cubeTT = ~APInt(1 <<
numVars, 0);
388 for (
unsigned i = 0; i <
numVars; ++i) {
389 if (cube.hasLiteral(i))
399 os <<
"SOPForm: " <<
numVars <<
" vars, " <<
cubes.size() <<
" cubes\n";
400 for (
const auto &cube :
cubes) {
402 for (
unsigned i = 0; i <
numVars; ++i) {
403 if (cube.mask & (1ULL << i)) {
404 os << ((cube.inverted & (1ULL << i)) ?
"!" :
"");
405 os <<
"x" << i <<
" ";
454APInt isopImpl(
const APInt &tt,
const APInt &dc,
unsigned numVars,
455 unsigned varIndex,
SOPForm &result) {
456 assert((tt & ~dc).isZero() &&
"tt must be subset of dc");
463 if (dc.isAllOnes()) {
464 result.
cubes.emplace_back();
475 APInt negCof, posCof, negDC, posDC;
476 for (
int i = varIndex - 1; i >= 0; --i) {
479 if (negCof != posCof || negDC != posDC) {
484 assert(var >= 0 &&
"No variable found in support");
487 size_t negBegin = result.
cubes.size();
488 APInt negCover = isopImpl(negCof & ~posDC, negDC, numVars, var, result);
489 size_t negEnd = result.
cubes.size();
492 APInt posCover = isopImpl(posCof & ~negDC, posDC, numVars, var, result);
493 size_t posEnd = result.
cubes.size();
496 APInt remaining = (negCof & ~negCover) | (posCof & ~posCover);
497 APInt sharedCover = isopImpl(remaining, negDC & posDC, numVars, var, result);
500 APInt negMask = createVarMaskImpl<false>(numVars, var);
501 APInt totalCover = sharedCover | (negCover & negMask) | (posCover & ~negMask);
504 for (
size_t i = negBegin; i < negEnd; ++i)
505 result.
cubes[i].setLiteral(var,
true);
507 for (
size_t i = negEnd; i < posEnd; ++i)
508 result.
cubes[i].setLiteral(var,
false);
516 assert((1u << numVars) == truthTable.getBitWidth() &&
517 "Truth table size must match 2^numVars");
520 if (numVars == 0 || truthTable.isZero())
523 (void)isopImpl(truthTable, truthTable, numVars, numVars, sop);
assert(baseType &&"element must be base type")
RewritePatternSet pattern
static APInt createVarMaskImpl(unsigned numVars, unsigned varIndex)
Create a mask for a variable in the truth table.
static constexpr uint64_t kVarMasks[2][6]
Precomputed masks for variables in truth tables up to 6 variables (64 bits).
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
SOPForm extractISOP(const llvm::APInt &truthTable, unsigned numVars)
Extract ISOP (Irredundant Sum-of-Products) from a truth table.
std::pair< llvm::APInt, llvm::APInt > computeCofactors(const llvm::APInt &f, unsigned numVars, unsigned varIndex)
Compute cofactor of a Boolean function for a given variable.
llvm::APInt createVarMask(unsigned numVars, unsigned varIndex, bool positive)
Create a mask for a variable in the truth table.
Represents a boolean function as a truth table.
BinaryTruthTable applyOutputNegation(unsigned negation) const
Apply output negation to create a new truth table.
llvm::APInt table
Truth table data as a packed bit vector.
BinaryTruthTable applyInputNegation(unsigned mask) const
Apply input negation to create a new truth table.
unsigned numInputs
Number of inputs for this boolean function.
void dump(llvm::raw_ostream &os=llvm::errs()) const
Debug dump method for truth tables.
bool isLexicographicallySmaller(const BinaryTruthTable &other) const
Check if this truth table is lexicographically smaller than another.
bool operator==(const BinaryTruthTable &other) const
Equality comparison for truth tables.
llvm::APInt getOutput(const llvm::APInt &input) const
Get the output value for a given input combination.
BinaryTruthTable applyPermutation(ArrayRef< unsigned > permutation) const
Apply input permutation to create a new truth table.
void setOutput(const llvm::APInt &input, const llvm::APInt &output)
Set the output value for a given input combination.
unsigned numOutputs
Number of outputs for this boolean function.
Represents the canonical form of a boolean function under NPN equivalence.
unsigned outputNegation
Output negation mask.
static NPNClass computeNPNCanonicalForm(const BinaryTruthTable &tt)
Compute the canonical NPN form for a given truth table.
void getInputPermutation(const NPNClass &targetNPN, llvm::SmallVectorImpl< unsigned > &permutation) const
Get input permutation from this NPN class to another equivalent NPN class.
BinaryTruthTable truthTable
Canonical truth table.
void dump(llvm::raw_ostream &os=llvm::errs()) const
Debug dump method for NPN classes.
bool equivalentOtherThanPermutation(const NPNClass &other) const
Equality comparison for NPN classes.
llvm::SmallVector< unsigned > inputPermutation
Input permutation applied.
unsigned inputNegation
Input negation mask.
bool isLexicographicallySmaller(const NPNClass &other) const