3 #include <unordered_set>
13 #include <boost/spirit/home/x3.hpp>
22 {BooleanFunction::Value::ONE,
"1"},
23 {BooleanFunction::Value::X,
"X"},
24 {BooleanFunction::Value::Z,
"Z"}};
31 return std::string(
"0");
33 return std::string(
"1");
35 return std::string(
"X");
37 return std::string(
"Z");
40 return std::string(
"X");
45 static std::vector<char> char_map = {
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'A',
'B',
'C',
'D',
'E',
'F'};
48 static Result<std::string> to_bin(
const std::vector<BooleanFunction::Value>& value)
50 if (value.size() == 0)
52 return ERR(
"could not convert bit-vector to binary string: bit-vector is empty");
56 res.reserve(value.size());
60 res += enum_to_string<BooleanFunction::Value>(v);
66 static Result<std::string> to_oct(
const std::vector<BooleanFunction::Value>& value)
68 int bitsize = value.size();
71 return ERR(
"could not convert bit-vector to octal string: bit-vector is empty");
74 u8 first_bits = bitsize % 3;
83 res.reserve((bitsize + 2) / 3);
86 for (
u8 i = 0; i < first_bits; i++)
95 if ((mask & 0x80) > 0)
98 res += (char_map[
index]);
102 for (
int i = bitsize % 3; i < bitsize; i += 3)
108 index = (v1 << 2) | (v2 << 1) | v3;
109 mask = (v1 | v2 | v3);
111 if ((mask & 0x80) > 0)
114 res += (char_map[
index]);
119 static Result<std::string> to_dec(
const std::vector<BooleanFunction::Value>& value)
121 int bitsize = value.size();
124 return ERR(
"could not convert bit-vector to decimal string: bit-vector is empty");
129 return ERR(
"could not convert bit-vector to decimal string: bit-vector has length " + std::to_string(bitsize) +
", but only up to 64 bits are supported for decimal conversion");
135 for (
auto it = value.rbegin(); it != value.rend(); it++)
144 return OK(std::string(
"X"));
146 return OK(std::to_string(tmp));
149 static Result<std::string> to_hex(
const std::vector<BooleanFunction::Value>& value)
151 int bitsize = value.size();
154 return ERR(
"could not convert bit-vector to hexadecimal string: bit-vector is empty");
157 u8 first_bits = bitsize & 0x3;
165 std::string res =
"";
166 res.reserve((bitsize + 3) / 4);
169 for (
u8 i = 0; i < first_bits; i++)
178 if ((mask & 0x80) > 0)
181 res += (char_map[
index]);
185 for (
int i = bitsize & 0x3; i < bitsize; i += 4)
192 index = ((v1 << 3) | (v2 << 2) | (v3 << 1) | v4) & 0xF;
193 mask = (v1 | v2 | v3 | v4);
195 if ((mask & 0x80) > 0)
198 res += (char_map[
index]);
210 return to_bin(value);
212 return to_oct(value);
214 return to_dec(value);
216 return to_hex(value);
218 return ERR(
"could not convert bit-vector to string: invalid value '" + std::to_string(base) +
"' given for base");
224 if (value.size() > 64)
226 return ERR(
"cannot translate vector of values to u64 numeral: can only support vectors up to 64 bits and got vector of size " + std::to_string(value.size()) +
".");
230 for (
auto it = value.rbegin(); it != value.rend(); it++)
232 if ((*it != BooleanFunction::Value::ZERO) && (*it != BooleanFunction::Value::ONE))
234 return ERR(
"cannot translate vector of values to u64 numeral: found value other than ZERO or ONE: " +
BooleanFunction::to_string(*it) +
".");
255 if (
auto res = BooleanFunction::validate(
BooleanFunction(std::move(nodes))); res.is_error())
257 return ERR_APPEND(res.get_error(),
"could not build Boolean function from vector of nodes: failed to validate Boolean function");
282 auto values = std::vector<BooleanFunction::Value>();
283 values.reserve(
size);
284 for (
auto i = 0; i <
size; i++)
286 values.emplace_back(((value >> i) & 1) ? BooleanFunction::Value::ONE : BooleanFunction::Value::ZERO);
299 if ((p0.size() != p1.size()) || (p0.size() !=
size))
301 return ERR(
"could not join Boolean functions using AND operation: bit-sizes do not match (p0 = " + std::to_string(p0.size()) +
", p1 = " + std::to_string(p1.size())
302 +
", size = " + std::to_string(
size) +
")");
310 if ((p0.size() != p1.size()) || (p0.size() !=
size))
312 return ERR(
"could not join Boolean functions using OR operation: bit-sizes do not match (p0 = " + std::to_string(p0.size()) +
", p1 = " + std::to_string(p1.size())
313 +
", size = " + std::to_string(
size) +
").");
321 if (p0.size() !=
size)
323 return ERR(
"could not invert Boolean function using NOT operation: bit-sizes do not match (p0 = " + std::to_string(p0.size()) +
", size = " + std::to_string(
size) +
").");
331 if ((p0.size() != p1.size()) || (p0.size() !=
size))
333 return ERR(
"could not join Boolean functions using XOR operation: bit-sizes do not match (p0 = " + std::to_string(p0.size()) +
", p1 = " + std::to_string(p1.size())
334 +
", size = " + std::to_string(
size) +
").");
342 if ((p0.size() != p1.size()) || (p0.size() !=
size))
344 return ERR(
"could not join Boolean functions using ADD operation: bit-sizes do not match (p0 = " + std::to_string(p0.size()) +
", p1 = " + std::to_string(p1.size())
345 +
", size = " + std::to_string(
size) +
").");
353 if ((p0.size() != p1.size()) || (p0.size() !=
size))
355 return ERR(
"could not join Boolean functions using SUB operation: bit-sizes do not match (p0 = " + std::to_string(p0.size()) +
", p1 = " + std::to_string(p1.size())
356 +
", size = " + std::to_string(
size) +
").");
364 if ((p0.size() != p1.size()) || (p0.size() !=
size))
366 return ERR(
"could not join Boolean functions using MUL operation: bit-sizes do not match (p0 = " + std::to_string(p0.size()) +
", p1 = " + std::to_string(p1.size())
367 +
", size = " + std::to_string(
size) +
").");
375 if ((p0.size() != p1.size()) || (p0.size() !=
size))
377 return ERR(
"could not join Boolean functions using SDIV operation: bit-sizes do not match (p0 = " + std::to_string(p0.size()) +
", p1 = " + std::to_string(p1.size())
378 +
", size = " + std::to_string(
size) +
").");
386 if ((p0.size() != p1.size()) || (p0.size() !=
size))
388 return ERR(
"could not join Boolean functions using UDIV operation: bit-sizes do not match (p0 = " + std::to_string(p0.size()) +
", p1 = " + std::to_string(p1.size())
389 +
", size = " + std::to_string(
size) +
").");
397 if ((p0.size() != p1.size()) || (p0.size() !=
size))
399 return ERR(
"could not join Boolean functions using SREM operation: bit-sizes do not match (p0 = " + std::to_string(p0.size()) +
", p1 = " + std::to_string(p1.size())
400 +
", size = " + std::to_string(
size) +
").");
408 if ((p0.size() != p1.size()) || (p0.size() !=
size))
410 return ERR(
"could not join Boolean functions using UREM operation: bit-sizes do not match (p0 = " + std::to_string(p0.size()) +
", p1 = " + std::to_string(p1.size())
411 +
", size = " + std::to_string(
size) +
").");
419 if (!p1.is_index() || !p2.is_index())
421 return ERR(
"could not apply slice operation: function types do not match (p1 and p2 must be of type 'BooleanFunction::Index')");
423 if ((p0.size() != p1.size()) || (p1.size() != p2.size()))
425 return ERR(
"could not apply slice operation: bit-sizes do not match (p0 = " + std::to_string(p0.size()) +
", p1 = " + std::to_string(p1.size()) +
", p2 = " + std::to_string(p2.size())
426 +
" - sizes must be equal)");
429 auto start = p1.get_index_value().get();
430 auto end = p2.get_index_value().get();
431 if ((start > end) || (start >= p0.size()) || (end >= p0.size()) || (end - start + 1) !=
size)
433 return ERR(
"could not apply SLICE operation: bit indices are not valid, p1 must be larger or equal than p1 and smaller than p0 (p0 = " + std::to_string(p0.size())
434 +
", p1 = " + std::to_string(start) +
", p2 = " + std::to_string(end) +
")");
442 if ((p0.size() + p1.size()) !=
size)
444 return ERR(
"could not apply CONCAT operation: function input widths do not match (p0 = " + std::to_string(p0.size()) +
"-bit, p1 = " + std::to_string(p1.size())
445 +
"-bit, size = " + std::to_string(
size) +
").");
453 if (p0.size() >
size || p1.size() !=
size)
455 return ERR(
"could not apply ZEXT operation: function input width does not match (p0 = " + std::to_string(p0.size()) +
"-bit, p1 = " + std::to_string(p1.size())
456 +
"-bit, size = " + std::to_string(
size) +
").");
459 if (!p1.has_index_value(
size))
461 return ERR(
"could not apply ZEXT operation: p1 does not encode size (p1 = " + p1.to_string() +
", size = " + std::to_string(
size) +
").");
469 if (p0.size() >
size || p1.size() !=
size)
471 return ERR(
"could not apply SEXT operation: function input width does not match (p0 = " + std::to_string(p0.size()) +
"-bit, p1 = " + std::to_string(p1.size())
472 +
"-bit, size = " + std::to_string(
size) +
").");
475 if (!p1.has_index_value(
size))
477 return ERR(
"could not apply SEXT operation: p1 does not encode size (p1 = " + p1.to_string() +
", size = " + std::to_string(
size) +
").");
485 if (p0.size() !=
size || p1.size() !=
size)
487 return ERR(
"could not apply SHL operation: function input width does not match (p0 = " + std::to_string(p0.size()) +
"-bit, p1 = " + std::to_string(p1.size())
488 +
"-bit, size = " + std::to_string(
size) +
").");
493 return ERR(
"could not apply SHL operation: p1 is not an index.");
501 if (p0.size() !=
size || p1.size() !=
size)
503 return ERR(
"could not apply LSHR operation: function input width does not match (p0 = " + std::to_string(p0.size()) +
"-bit, p1 = " + std::to_string(p1.size())
504 +
"-bit, size = " + std::to_string(
size) +
").");
509 return ERR(
"could not apply LSHR operation: p1 is not an index.");
517 if (p0.size() !=
size || p1.size() !=
size)
519 return ERR(
"could not apply ASHR operation: function input width does not match (p0 = " + std::to_string(p0.size()) +
"-bit, p1 = " + std::to_string(p1.size())
520 +
"-bit, size = " + std::to_string(
size) +
").");
525 return ERR(
"could not apply ASHR operation: p1 is not an index.");
533 if (p0.size() !=
size || p1.size() !=
size)
535 return ERR(
"could not apply ROL operation: function input width does not match (p0 = " + std::to_string(p0.size()) +
"-bit, p1 = " + std::to_string(p1.size())
536 +
"-bit, size = " + std::to_string(
size) +
").");
541 return ERR(
"could not apply ROL operation: p1 is not an index.");
549 if (p0.size() !=
size || p1.size() !=
size)
551 return ERR(
"could not apply ROR operation: function input width does not match (p0 = " + std::to_string(p0.size()) +
"-bit, p1 = " + std::to_string(p1.size())
552 +
"-bit, size = " + std::to_string(
size) +
").");
557 return ERR(
"could not apply ROR operation: p1 is not an index.");
565 if (p0.size() != p1.size() ||
size != 1)
567 return ERR(
"could not apply EQ operation: function input width does not match (p0 = " + std::to_string(p0.size()) +
"-bit, p1 = " + std::to_string(p1.size())
568 +
"-bit, size = " + std::to_string(
size) +
").");
576 if (p0.size() != p1.size() ||
size != 1)
578 return ERR(
"could not apply SLE operation: function input width does not match (p0 = " + std::to_string(p0.size()) +
"-bit, p1 = " + std::to_string(p1.size())
579 +
"-bit, size = " + std::to_string(
size) +
").");
587 if (p0.size() != p1.size() ||
size != 1)
589 return ERR(
"could not apply SLT operation: function input width does not match (p0 = " + std::to_string(p0.size()) +
"-bit, p1 = " + std::to_string(p1.size())
590 +
"-bit, size = " + std::to_string(
size) +
").");
598 if (p0.size() != p1.size() ||
size != 1)
600 return ERR(
"could not apply ULE operation: function input width does not match (p0 = " + std::to_string(p0.size()) +
"-bit, p1 = " + std::to_string(p1.size())
601 +
"-bit, size = " + std::to_string(
size) +
").");
609 if (p0.size() != p1.size() ||
size != 1)
611 return ERR(
"could not apply ULT operation: function input width does not match (p0 = " + std::to_string(p0.size()) +
"-bit, p1 = " + std::to_string(p1.size())
612 +
"-bit, size = " + std::to_string(
size) +
").");
620 if (p0.size() != 1 || p1.size() !=
size || p2.size() !=
size)
622 return ERR(
"could not apply ITE operation: function input width does not match (p0 = " + std::to_string(p0.size()) +
"-bit, p1 = " + std::to_string(p1.size())
623 +
"-bit, p2 = " + std::to_string(p2.size()) +
"-bit, size = " + std::to_string(
size) +
").");
707 if (this->m_nodes.size() != other.m_nodes.size())
712 for (
auto i = 0ul; i < this->m_nodes.size(); i++)
714 if (this->m_nodes[i] != other.m_nodes[i])
724 return !(*
this == other);
729 if (this->m_nodes.size() < other.m_nodes.size())
733 if (this->m_nodes.size() > other.m_nodes.size())
740 return std::lexicographical_compare(this->m_nodes.begin(), this->m_nodes.end(), other.m_nodes.begin(), other.m_nodes.end());
745 return this->m_nodes.empty();
751 function.m_nodes.reserve(this->m_nodes.size());
753 for (
const auto& node : this->m_nodes)
755 function.m_nodes.emplace_back(node);
785 return ERR(
"Boolean function is empty");
810 return ERR(
"Boolean function is empty");
820 return ERR(
"Boolean function is empty");
840 return ERR(
"Boolean function is empty");
848 return this->m_nodes.back();
853 return this->m_nodes.size();
858 return this->m_nodes;
870 auto coverage = this->compute_node_coverage();
877 return {
BooleanFunction(std::vector<Node>({this->m_nodes.begin(), this->m_nodes.end() - 1}))};
882 return {
BooleanFunction(std::vector<Node>({this->m_nodes.begin(), this->m_nodes.begin() +
index})),
886 auto index0 = this->
length() - coverage[this->
length() - 3] - coverage[this->
length() - 2] - 1;
887 auto index1 = this->
length() - coverage[this->
length() - 2] - 1;
889 return {
BooleanFunction(std::vector<Node>({this->m_nodes.begin(), this->m_nodes.begin() + index0})),
890 BooleanFunction(std::vector<Node>({this->m_nodes.begin() + index0, this->m_nodes.begin() + index1})),
891 BooleanFunction(std::vector<Node>({this->m_nodes.begin() + index1, this->m_nodes.end() - 1}))};
895 assert(
false &&
"not implemented reached.");
903 auto variable_names = std::set<std::string>();
904 for (
const auto& node : this->m_nodes)
906 if (node.is_variable())
908 variable_names.insert(node.variable);
911 return variable_names;
918 return ERR(
"could not print Boolean function: node arity of " + std::to_string(node.
get_arity()) +
" does not match number of operands of " + std::to_string(operands.size()));
929 return OK(
"(" + operands[0] +
" & " + operands[1] +
")");
931 return OK(
"(! " + operands[0] +
")");
933 return OK(
"(" + operands[0] +
" | " + operands[1] +
")");
935 return OK(
"(" + operands[0] +
" ^ " + operands[1] +
")");
938 return OK(
"(" + operands[0] +
" + " + operands[1] +
")");
940 return OK(
"(" + operands[0] +
" - " + operands[1] +
")");
942 return OK(
"(" + operands[0] +
" * " + operands[1] +
")");
944 return OK(
"(" + operands[0] +
" /s " + operands[1] +
")");
946 return OK(
"(" + operands[0] +
" / " + operands[1] +
")");
948 return OK(
"(" + operands[0] +
" \%s " + operands[1] +
")");
950 return OK(
"(" + operands[0] +
" \% " + operands[1] +
")");
953 return OK(
"(" + operands[0] +
" ++ " + operands[1] +
")");
955 return OK(
"Slice(" + operands[0] +
", " + operands[1] +
", " + operands[2] +
")");
957 return OK(
"Zext(" + operands[0] +
", " + operands[1] +
")");
959 return OK(
"Sext(" + operands[0] +
", " + operands[1] +
")");
962 return OK(
"(" + operands[0] +
" << " + operands[1] +
")");
964 return OK(
"(" + operands[0] +
" >> " + operands[1] +
")");
966 return OK(
"(" + operands[0] +
" >>a " + operands[1] +
")");
968 return OK(
"(" + operands[0] +
" <<r " + operands[1] +
")");
970 return OK(
"(" + operands[0] +
" >>r " + operands[1] +
")");
973 return OK(
"(" + operands[0] +
" == " + operands[1] +
")");
975 return OK(
"(" + operands[0] +
" <s " + operands[1] +
")");
977 return OK(
"(" + operands[0] +
" <=s " + operands[1] +
")");
979 return OK(
"(" + operands[0] +
" < " + operands[1] +
")");
981 return OK(
"(" + operands[0] +
" <= " + operands[1] +
")");
983 return OK(
"(" + operands[0] +
" ? " + operands[1] +
" : " + operands[2] +
")");
986 return ERR(
"could not print Boolean function: unsupported node type '" + std::to_string(node.
type) +
"'");
990 Result<std::string> BooleanFunction::algebraic_printer(
const BooleanFunction::Node& node, std::vector<std::string>&& operands)
992 if (node.get_arity() != operands.size())
994 return ERR(
"could not print Boolean function: node arity of " + std::to_string(node.get_arity()) +
" does not match number of operands of " + std::to_string(operands.size()));
1001 return OK(node.to_string());
1004 return OK(
"CONST" + std::string(node.has_constant_value(0) ?
"0" :
"1"));
1007 return OK(
"(" + operands[0] +
"*" + operands[1] +
")");
1009 return OK(
"(! " + operands[0] +
")");
1011 return OK(
"(" + operands[0] +
"+" + operands[1] +
")");
1014 return ERR(
"could not print Boolean function: unsupported node type '" + std::to_string(node.type) +
"'");
1021 if (this->m_nodes.empty())
1027 std::vector<std::string> stack;
1028 for (
const auto& node : this->m_nodes)
1030 std::vector<std::string> operands;
1038 std::move(stack.end() -
static_cast<u64>(node.
get_arity()), stack.end(), std::back_inserter(operands));
1039 stack.erase(stack.end() -
static_cast<u64>(node.
get_arity()), stack.end());
1041 if (
auto res = printer(node, std::move(operands)); res.is_ok())
1043 stack.emplace_back(res.get());
1047 log_error(
"netlist",
"Cannot translate BooleanFunction::Node '{}' to a string: {}.", node.
to_string(), res.get_error().get());
1052 switch (stack.size())
1055 return stack.back();
1073 using ParserFn = std::function<Result<std::vector<Token>>(
const std::string&,
const std::map<std::string, u16>&)>;
1074 static const std::vector<std::tuple<ParserType, ParserFn>> parsers = {
1080 for (
const auto& [parser_type, parser] : parsers)
1082 std::string sanitized_expression = expression;
1085 if (parser_type == ParserType::LibertyNoSpace)
1087 sanitized_expression.erase(
1088 std::remove(sanitized_expression.begin(), sanitized_expression.end(),
' '),
1089 sanitized_expression.end()
1091 used_parser_type = ParserType::Liberty;
1094 auto tokens = parser(sanitized_expression, var_sizes);
1096 if (tokens.is_error())
1103 if (tokens.is_error())
1109 if (
function.is_error())
1115 return ERR(
"could not parse Boolean function from string: no parser available for '" + expression +
"'");
1124 return (simplified.is_ok()) ? simplified.get() : this->
clone();
1131 return (simplified.is_ok()) ? simplified.get() : this->
clone();
1136 auto function = this->
clone();
1137 for (
auto i = 0u; i < this->m_nodes.size(); i++)
1151 auto substitute_variable = [](
const auto& node,
auto&& operands,
auto var_name,
auto repl) ->
BooleanFunction {
1152 if (node.has_variable_name(var_name))
1154 return repl.
clone();
1159 std::vector<BooleanFunction> stack;
1160 for (
const auto& node : this->m_nodes)
1162 std::vector<BooleanFunction> operands;
1163 std::move(stack.end() -
static_cast<i64>(node.get_arity()), stack.end(), std::back_inserter(operands));
1164 stack.erase(stack.end() -
static_cast<i64>(node.get_arity()), stack.end());
1166 stack.emplace_back(substitute_variable(node, std::move(operands),
name, replacement));
1169 switch (stack.size())
1172 return OK(stack.back());
1174 return ERR(
"could not replace variable '" +
name +
"' with Boolean function '" + replacement.
to_string() +
"': validation failed, the operations may be imbalanced");
1180 auto function = this->
clone();
1181 for (
auto i = 0u; i < this->m_nodes.size(); i++)
1183 if (
const auto var_name_res = this->m_nodes[i].
get_variable_name(); var_name_res.is_ok())
1185 if (
const auto it = substitutions.find(var_name_res.get()); it != substitutions.end())
1187 function.m_nodes[i] =
Node::Variable(it->second, this->m_nodes[i].size);
1202 auto substitute_variable = [substitutions](
const auto& node,
auto&& operands) ->
BooleanFunction {
1203 if (node.is_variable())
1205 if (
auto repl_it = substitutions.find(node.variable); repl_it != substitutions.end())
1207 return repl_it->second.
clone();
1213 std::vector<BooleanFunction> stack;
1214 for (
const auto& node : this->m_nodes)
1216 std::vector<BooleanFunction> operands;
1217 std::move(stack.end() -
static_cast<i64>(node.get_arity()), stack.end(), std::back_inserter(operands));
1218 stack.erase(stack.end() -
static_cast<i64>(node.get_arity()), stack.end());
1220 stack.emplace_back(substitute_variable(node, std::move(operands)));
1223 switch (stack.size())
1226 return OK(stack.back());
1228 return ERR(
"could not carry out multiple substitutions: validation failed, the operations may be imbalanced");
1235 if (this->m_nodes.empty())
1237 return OK(BooleanFunction::Value::X);
1241 if (this->
size() != 1)
1243 return ERR(
"could not evaluate Boolean function '" + this->
to_string() +
"': using single-bit evaluation on a Boolean function of size " + std::to_string(this->
size()) +
" is illegal");
1247 auto generic_inputs = std::unordered_map<std::string, std::vector<Value>>();
1248 for (
const auto& [
name, value] : inputs)
1250 generic_inputs.emplace(
name, std::vector<Value>({value}));
1253 auto value = this->
evaluate(generic_inputs);
1257 return OK(value.get()[0]);
1260 return ERR(value.get_error());
1266 if (this->m_nodes.empty())
1268 return OK(std::vector<BooleanFunction::Value>({BooleanFunction::Value::X}));
1274 for (
const auto& node : this->m_nodes)
1276 if (!node.is_variable())
1281 if (
const auto it = inputs.find(node.variable); it != inputs.end() && node.size != it->second.size())
1283 return ERR(
"could not evaluate Boolean function '" + this->
to_string() +
"': as the size of vairbale " + node.variable +
" with size " + std::to_string(node.size)
1284 +
" does not match the size of the provided input (" + std::to_string(it->second.size()) +
")");
1290 for (
const auto& [
name, value] : inputs)
1297 auto result = symbolic_execution.evaluate(*
this);
1300 if (
auto value = result.get(); value.is_constant())
1302 return OK(value.get_top_level_node().constant);
1304 return OK(std::vector<BooleanFunction::Value>(this->
size(), BooleanFunction::Value::X));
1306 return ERR(result.get_error());
1312 if (this->
size() != 1)
1314 return ERR(
"not a single-bit function");
1321 const std::unordered_set<std::string> known_variables(variables.begin(), variables.end());
1322 for (
const auto& node : this->m_nodes)
1326 return ERR(
"not a single-bit function");
1336 if (node.constant.size() != 1 || (node.constant[0] != Value::ZERO && node.constant[0] != Value::ONE))
1338 return ERR(
"constant is not Boolean");
1342 if (known_variables.find(node.variable) == known_variables.end())
1344 return ERR(
"function has a variable that is not part of the truth table");
1348 return ERR(
"not a bitwise function");
1361 static constexpr
u64 PATTERN[6] = {
1362 0xAAAAAAAAAAAAAAAAull,
1363 0xCCCCCCCCCCCCCCCCull,
1364 0xF0F0F0F0F0F0F0F0ull,
1365 0xFF00FF00FF00FF00ull,
1366 0xFFFF0000FFFF0000ull,
1367 0xFFFFFFFF00000000ull,
1370 std::unordered_map<std::string, u32> variable_index;
1371 for (
u32 i = 0; i < variables.size(); i++)
1373 variable_index[variables[i]] = i;
1376 const u64 num_rows =
u64(1) << variables.size();
1377 std::vector<Value> result(num_rows, Value::ZERO);
1379 std::vector<u64> stack;
1380 stack.reserve(this->m_nodes.size());
1382 for (
u64 base = 0; base < num_rows; base += 64)
1384 const u64 rows_in_chunk = std::min<u64>(64, num_rows - base);
1385 const u64 chunk_mask = (rows_in_chunk == 64) ? ~
u64(0) : ((
u64(1) << rows_in_chunk) - 1);
1388 for (
const auto& node : this->m_nodes)
1392 const u32 i = variable_index.at(node.variable);
1393 stack.push_back((i < 6) ? PATTERN[i] : (((base >> i) & 1) ? ~
u64(0) :
u64(0)));
1399 stack.push_back((node.constant[0] == Value::ONE) ? ~
u64(0) :
u64(0));
1403 const u16 arity = node.get_arity();
1404 if (stack.size() < arity)
1406 return ERR(
"could not compute truth table: malformed node list");
1411 const u64 a = stack.back();
1413 stack.push_back(~a);
1417 const u64 b = stack.back();
1419 const u64 a = stack.back();
1424 stack.push_back(a & b);
1428 stack.push_back(a | b);
1432 stack.push_back(a ^ b);
1436 if (stack.size() != 1)
1438 return ERR(
"could not compute truth table: malformed node list");
1441 const u64 out = stack.back() & chunk_mask;
1442 for (
u64 bit = 0; bit < rows_in_chunk; bit++)
1444 result[base + bit] = (out & (
u64(1) << bit)) ? Value::ONE : Value::ZERO;
1448 return OK(std::vector<std::vector<Value>>({std::move(result)}));
1457 for (
const auto& node : this->m_nodes)
1459 if (node.is_variable() && node.size != 1)
1461 return ERR(
"could not compute truth table for Boolean function '" + this->
to_string() +
"': unable to generate a truth-table for Boolean function with variables of > 1-bit");
1466 auto variables = ordered_variables;
1467 if (variables.empty())
1469 variables = std::vector<std::string>(variable_names_in_function.begin(), variable_names_in_function.end());
1473 if (remove_unknown_variables)
1476 std::remove_if(variables.begin(), variables.end(), [&variable_names_in_function](
const auto& s) { return variable_names_in_function.find(s) == variable_names_in_function.end(); }),
1482 if (this->m_nodes.empty())
1484 return OK(std::vector<std::vector<Value>>(1, std::vector<Value>(1 << variables.size(), Value::X)));
1491 return ERR(
"could not compute truth table for Boolean function '" + this->
to_string() +
"': unable to generate truth-table with more than "
1498 if (
const auto res = compute_truth_table_bitwise(variables); res.is_ok())
1503 std::vector<std::vector<Value>> truth_table(this->
size(), std::vector<Value>(1 << variables.size(), Value::ZERO));
1506 for (
auto value = 0u; value < ((
u32)1 << variables.size()); value++)
1508 std::unordered_map<std::string, std::vector<Value>>
input;
1510 for (
const auto& variable : variables)
1512 input[variable] = ((tmp & 1) == 0) ? std::vector<Value>({Value::ZERO}) : std::vector<Value>({Value::ONE});
1515 auto result = this->
evaluate(input);
1516 if (result.is_error())
1518 return ERR(result.get_error());
1520 auto output = result.get();
1527 return OK(truth_table);
1532 std::vector<std::string> inputs;
1534 if (ordered_inputs.empty())
1536 inputs = std::vector<std::string>(inputs_set.begin(), inputs_set.end());
1540 inputs = ordered_inputs;
1543 if (remove_unknown_inputs)
1545 inputs.erase(std::remove_if(inputs.begin(), inputs.end(), [&inputs_set](
const auto& s) { return inputs_set.find(s) == inputs_set.end(); }), inputs.end());
1551 return ERR_APPEND(res.get_error(),
"could not print truth table for Boolean function '" + this->to_string() +
"': unable to compute truth table");
1553 const auto truth_table = res.get();
1555 std::stringstream str(
"");
1557 u32 num_inputs = inputs.size();
1558 u32 num_outputs = truth_table.size();
1561 std::vector<u32> in_widths;
1562 for (
const auto& var : inputs)
1564 in_widths.push_back(var.size());
1565 str <<
" " << var <<
" |";
1568 std::vector<u32> out_widths;
1569 if (function_name.empty())
1571 function_name =
"O";
1573 if (num_outputs == 1)
1575 str <<
"| " << function_name <<
" ";
1576 out_widths.push_back(function_name.size());
1580 for (
u32 i = 0; i < num_outputs; i++)
1582 std::string var = function_name +
"(" + std::to_string(i) +
")";
1583 str <<
"| " << var <<
" ";
1584 out_widths.push_back(var.size());
1590 for (
u32 i = 0; i < num_inputs; i++)
1592 str << std::setw(in_widths.at(i) + 3) << std::setfill(
'-') <<
"+";
1594 for (
u32 i = 0; i < num_outputs; i++)
1596 str <<
"+" << std::setw(out_widths.at(i) + 2) << std::setfill(
'-') <<
"-";
1601 for (
u32 i = 0; i < (
u32)(1 << num_inputs); i++)
1603 for (
u32 j = 0; j < num_inputs; j++)
1605 str <<
" " << std::left << std::setw(in_widths.at(j)) << std::setfill(
' ') << ((i >> j) & 1) <<
" |";
1608 for (
u32 k = 0; k < num_outputs; k++)
1610 str <<
"| " << std::left << std::setw(out_widths.at(k)) << std::setfill(
' ') << truth_table.at(k).at(i) <<
" ";
1614 return OK(str.str());
1625 auto reduce_to_z3 = [&context, &var2expr](
const auto& node,
auto&& p) -> std::tuple<bool, z3::expr> {
1626 if (node.get_arity() != p.size())
1628 return {
false, z3::expr(context)};
1634 return {
true, context.bv_val(node.index, node.size)};
1638 auto constant = context.bv_val(node.constant.front(), 1);
1639 for (
u32 i = 1; i < node.constant.size(); i++)
1641 const auto bit = node.constant.at(i);
1642 constant = z3::concat(context.bv_val(bit, 1), constant);
1644 return {
true, constant};
1647 if (
auto it = var2expr.find(node.variable); it != var2expr.end())
1649 return {
true, it->second};
1651 return {
true, context.bv_const(node.variable.c_str(), node.size)};
1655 return {
true, p[0] & p[1]};
1657 return {
true, p[0] | p[1]};
1659 return {
true, ~p[0]};
1661 return {
true, p[0] ^ p[1]};
1663 return {
true, p[0].extract(p[2].get_numeral_uint(), p[1].get_numeral_uint())};
1665 return {
true, z3::concat(p[0], p[1])};
1667 return {
true, z3::sext(p[0], p[1].get_numeral_uint())};
1670 log_error(
"netlist",
"Not implemented reached for nodetype {} in z3 conversion", node.type);
1671 return {
false, z3::expr(context)};
1675 std::vector<z3::expr> stack;
1676 for (
const auto& node : this->m_nodes)
1678 std::vector<z3::expr> operands;
1679 std::move(stack.end() -
static_cast<i64>(node.get_arity()), stack.end(), std::back_inserter(operands));
1680 stack.erase(stack.end() -
static_cast<i64>(node.get_arity()), stack.end());
1682 if (
auto [ok, reduction] = reduce_to_z3(node, std::move(operands)); ok)
1684 stack.emplace_back(reduction);
1688 return z3::expr(context);
1692 switch (stack.size())
1695 return stack.back();
1697 return z3::expr(context);
1708 for (
const auto& parameter : p)
1710 size += parameter.size();
1712 this->m_nodes.reserve(
size);
1714 for (
auto&& parameter : p)
1716 this->m_nodes.insert(this->m_nodes.end(), parameter.m_nodes.begin(), parameter.m_nodes.end());
1718 this->m_nodes.emplace_back(node);
1721 std::string BooleanFunction::to_string_in_reverse_polish_notation()
const
1724 for (
const auto& node : this->m_nodes)
1726 s += node.to_string() +
" ";
1731 Result<BooleanFunction> BooleanFunction::validate(BooleanFunction&&
function)
1737 const auto coverage =
function.compute_node_coverage();
1738 if (coverage.back() !=
function.length())
1740 auto str =
function.to_string_in_reverse_polish_notation();
1741 return ERR(
"could not validate '" + str +
"': imbalanced function with coverage '" + std::to_string(coverage.back()) +
" != " + std::to_string(
function.length()));
1747 const auto& nodes =
function.m_nodes;
1748 for (
size_t i = 0; i < nodes.size(); ++i)
1750 const auto& n = nodes[i];
1751 const u16 arity = n.get_arity();
1757 std::vector<size_t> op_idx(arity);
1758 size_t cursor = i - 1;
1759 for (
int k =
static_cast<int>(arity) - 1; k >= 0; --k)
1764 cursor -= coverage[cursor];
1768 const auto op_size = [&](
size_t k) ->
u16 {
return nodes[op_idx[k]].size; };
1783 if (op_size(0) != n.size || op_size(1) != n.size)
1785 return ERR(
"could not validate Boolean function: bit-size mismatch in '" + std::to_string(n.type) +
"' node (operands " + std::to_string(op_size(0)) +
", "
1786 + std::to_string(op_size(1)) +
" vs result " + std::to_string(n.size) +
")");
1792 if (op_size(0) != n.size)
1794 return ERR(
"could not validate Boolean function: bit-size mismatch in 'Not' node (operand " + std::to_string(op_size(0)) +
" vs result " + std::to_string(n.size) +
")");
1804 if (op_size(0) != op_size(1) || n.size != 1)
1806 return ERR(
"could not validate Boolean function: bit-size mismatch in comparison node (operands " + std::to_string(op_size(0)) +
", " + std::to_string(op_size(1))
1807 +
" vs result " + std::to_string(n.size) +
")");
1813 if (op_size(0) != 1 || op_size(1) != n.size || op_size(2) != n.size)
1815 return ERR(
"could not validate Boolean function: bit-size mismatch in 'Ite' node (cond " + std::to_string(op_size(0)) +
", then " + std::to_string(op_size(1)) +
", else "
1816 + std::to_string(op_size(2)) +
" vs result " + std::to_string(n.size) +
")");
1828 return OK(std::move(
function));
1831 std::vector<u32> BooleanFunction::compute_node_coverage()
const
1833 auto coverage = std::vector<u32>(this->m_nodes.size(), (
u32)-1);
1840 auto get = [](
const auto& cov,
size_t index) ->
u32 {
return (
index < cov.size()) ? cov[
index] : -1; };
1851 for (
auto i = 0ul; i < this->m_nodes.size(); i++)
1853 auto arity = this->m_nodes[i].get_arity();
1862 auto x = get(coverage, i - 1);
1863 set(coverage, i,
x);
1867 auto x = get(coverage, i - 1);
1868 auto y = get(coverage, i - 1 -
x);
1869 set(coverage, i,
x,
y);
1873 auto x = get(coverage, i - 1);
1874 auto y = get(coverage, i - 1 -
x);
1875 auto z = get(coverage, i - 1 -
x -
y);
1876 set(coverage, i,
x,
y, z);
1887 return Node(_type, _size, {}, {}, {});
1912 return !(*
this == other);
1922 return Node(this->
type, this->
size, this->constant, this->index, this->variable);
1931 for (
const auto& value : this->constant)
1939 return std::to_string(this->index);
1941 return this->variable;
2001 return "unsupported node type '" + std::to_string(this->
type) +
"'.";
2012 static const std::map<u16, u16> type2arity = {
2023 return type2arity.at(
type);
2028 return this->
type == _type;
2038 return this->
is_constant() && (this->constant == value);
2048 auto bv_value = std::vector<BooleanFunction::Value>({});
2049 bv_value.reserve(this->
size);
2050 for (
auto i = 0u; i < this->constant.size(); i++)
2052 bv_value.emplace_back((value & (1 << i)) ? BooleanFunction::Value::ONE : BooleanFunction::Value::ZERO);
2054 return this->constant == bv_value;
2061 return ERR(
"Node is not a constant");
2064 return OK(this->constant);
2071 return ERR(
"Node is not a constant");
2074 if (this->
size > 64)
2076 return ERR(
"Node constant has size > 64");
2079 if (std::any_of(this->constant.begin(), this->constant.end(), [](
auto v) { return v != BooleanFunction::Value::ONE && v != BooleanFunction::Value::ZERO; }))
2081 return ERR(
"Node constant is undefined or high-impedance");
2085 for (
auto it = this->constant.rbegin(); it != this->constant.rend(); it++)
2101 return this->
is_index() && (this->index == value);
2108 return ERR(
"Node is not an index");
2111 return OK(this->index);
2121 return this->
is_variable() && (this->variable == value);
2128 return ERR(
"Node is not a variable");
2131 return OK(this->variable);
2136 return !this->is_operand();
2150 BooleanFunction::Node::Node(
u16 _type,
u16 _size, std::vector<BooleanFunction::Value> _constant,
u16 _index, std::string _variable)
2151 :
type(_type),
size(_size), constant(_constant),
index(_index), variable(_variable)
static Result< BooleanFunction > Slt(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
bool has_index_value(u16 index) const
BooleanFunction operator+(const BooleanFunction &other) const
static Result< BooleanFunction > Ite(BooleanFunction &&p0, BooleanFunction &&p1, BooleanFunction &&p2, u16 size)
BooleanFunction operator&(const BooleanFunction &other) const
static Result< BooleanFunction > Eq(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static BooleanFunction Var(const std::string &name, u16 size=1)
static constexpr u32 MAX_TRUTH_TABLE_VARIABLES
static Result< BooleanFunction > Xor(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
bool operator==(const BooleanFunction &other) const
Result< std::string > get_variable_name() const
BooleanFunction operator^(const BooleanFunction &other) const
const BooleanFunction::Node & get_top_level_node() const
static Result< BooleanFunction > Add(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
std::set< std::string > get_variable_names() const
static Result< BooleanFunction > Lshr(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
bool has_constant_value(const std::vector< Value > &value) const
static Result< BooleanFunction > Zext(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
Result< std::vector< Value > > get_constant_value() const
static Result< BooleanFunction > Mul(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
bool has_variable_name(const std::string &variable_name) const
static Result< BooleanFunction > Ule(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Sub(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Sext(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Udiv(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
BooleanFunction operator~() const
static Result< BooleanFunction > Concat(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Ult(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static BooleanFunction Index(u16 index, u16 size)
z3::expr to_z3(z3::context &context, const std::map< std::string, z3::expr > &var2expr={}) const
Result< std::vector< std::vector< Value > > > compute_truth_table(const std::vector< std::string > &ordered_variables={}, bool remove_unknown_variables=false) const
BooleanFunction & operator-=(const BooleanFunction &other)
Result< Value > evaluate(const std::unordered_map< std::string, Value > &inputs) const
static Result< BooleanFunction > Sle(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > build(std::vector< Node > &&nodes)
BooleanFunction operator|(const BooleanFunction &other) const
static Result< BooleanFunction > from_string(const std::string &expression)
static Result< BooleanFunction > Slice(BooleanFunction &&p0, BooleanFunction &&p1, BooleanFunction &&p2, u16 size)
const std::vector< BooleanFunction::Node > & get_nodes() const
BooleanFunction & operator*=(const BooleanFunction &other)
BooleanFunction simplify() const
BooleanFunction operator-(const BooleanFunction &other) const
Result< std::string > get_truth_table_as_string(const std::vector< std::string > &ordered_variables={}, std::string function_name="", bool remove_unknown_variables=false) const
bool operator<(const BooleanFunction &other) const
BooleanFunction & operator&=(const BooleanFunction &other)
BooleanFunction clone() const
Value
represents the type of the node
static Result< BooleanFunction > Or(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
bool operator!=(const BooleanFunction &other) const
static Result< BooleanFunction > Urem(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
BooleanFunction & operator^=(const BooleanFunction &other)
static Result< BooleanFunction > Ror(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
BooleanFunction & operator+=(const BooleanFunction &other)
static Result< BooleanFunction > Sdiv(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
BooleanFunction & operator|=(const BooleanFunction &other)
static std::string to_string(Value value)
BooleanFunction simplify_local() const
static BooleanFunction Const(const BooleanFunction::Value &value)
BooleanFunction operator*(const BooleanFunction &other) const
static Result< BooleanFunction > Ashr(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< u64 > to_u64(const std::vector< BooleanFunction::Value > &value)
static Result< BooleanFunction > Not(BooleanFunction &&p0, u16 size)
static Result< BooleanFunction > And(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
std::vector< BooleanFunction > get_parameters() const
Result< u16 > get_index_value() const
BooleanFunction substitute(const std::string &old_variable_name, const std::string &new_variable_name) const
static Result< BooleanFunction > Shl(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
Result< u64 > get_constant_value_u64() const
static Result< BooleanFunction > Rol(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Srem(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
#define log_error(channel,...)
#define ERR_APPEND(prev_error, message)
Result< std::vector< Token > > parse_with_standard_grammar(const std::string &expression, const std::map< std::string, u16 > &var_sizes={})
ParserType
ParserType refers to the parser identifier.
Result< BooleanFunction > translate(std::vector< Token > &&tokens, const std::string &expression)
Result< std::vector< Token > > reverse_polish_notation(std::vector< Token > &&tokens, const std::string &expression, const ParserType &parser)
Result< std::vector< Token > > parse_with_liberty_grammar(const std::string &expression, const std::map< std::string, u16 > &var_sizes={})
Result< BooleanFunction > local_simplification(const BooleanFunction &function)
void remove(std::filesystem::path file_path)
std::ostream & operator<<(std::ostream &os, T e)
std::string enum_to_string(T e)
std::vector< BooleanFunction::Value > constant
The (optional) constant value of the node.
u16 type
The type of the node.
bool is_operation() const
u16 size
The bit-size of the node.
static u16 get_arity_of_type(u16 type)
static Node Constant(const std::vector< BooleanFunction::Value > value)
bool has_index_value(u16 value) const
std::string variable
The (optional) variable name of the node.
bool has_variable_name(const std::string &variable_name) const
static Node Operation(u16 type, u16 size)
bool has_constant_value(const std::vector< Value > &value) const
bool is_commutative() const
std::string to_string() const
Result< std::vector< Value > > get_constant_value() const
static Node Index(u16 index, u16 size)
Result< u16 > get_index_value() const
bool operator!=(const Node &other) const
bool operator==(const Node &other) const
bool operator<(const Node &other) const
u16 index
The (optional) index value of the node.
static Node Variable(const std::string variable, u16 size)
Result< std::string > get_variable_name() const
Result< u64 > get_constant_value_u64() const
static constexpr u16 Constant
static constexpr u16 Srem
static constexpr u16 Udiv
static constexpr u16 Sdiv
static constexpr u16 Urem
static constexpr u16 Lshr
static constexpr u16 Sext
static constexpr u16 Ashr
static constexpr u16 Index
static constexpr u16 Concat
static constexpr u16 Slice
static constexpr u16 Zext
static constexpr u16 Variable
Token refers to a token identifier and accompanied data.