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(
"Ite(" + 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();
1068 static const std::vector<std::tuple<ParserType, std::function<Result<std::vector<Token>>(
const std::string&)>>> parsers = {
1074 for (
const auto& [parser_type, parser] : parsers)
1076 std::string sanitized_expression = expression;
1079 if (parser_type == ParserType::LibertyNoSpace)
1081 sanitized_expression.erase(
1082 std::remove(sanitized_expression.begin(), sanitized_expression.end(),
' '),
1083 sanitized_expression.end()
1085 used_parser_type = ParserType::Liberty;
1088 auto tokens = parser(sanitized_expression);
1090 if (tokens.is_error())
1097 if (tokens.is_error())
1103 if (
function.is_error())
1109 return ERR(
"could not parse Boolean function from string: no parser available for '" + expression +
"'");
1118 return (simplified.is_ok()) ? simplified.get() : this->
clone();
1125 return (simplified.is_ok()) ? simplified.get() : this->
clone();
1130 auto function = this->
clone();
1131 for (
auto i = 0u; i < this->m_nodes.size(); i++)
1145 auto substitute_variable = [](
const auto& node,
auto&& operands,
auto var_name,
auto repl) ->
BooleanFunction {
1146 if (node.has_variable_name(var_name))
1148 return repl.
clone();
1153 std::vector<BooleanFunction> stack;
1154 for (
const auto& node : this->m_nodes)
1156 std::vector<BooleanFunction> operands;
1157 std::move(stack.end() -
static_cast<i64>(node.get_arity()), stack.end(), std::back_inserter(operands));
1158 stack.erase(stack.end() -
static_cast<i64>(node.get_arity()), stack.end());
1160 stack.emplace_back(substitute_variable(node, std::move(operands),
name, replacement));
1163 switch (stack.size())
1166 return OK(stack.back());
1168 return ERR(
"could not replace variable '" +
name +
"' with Boolean function '" + replacement.
to_string() +
"': validation failed, the operations may be imbalanced");
1174 auto function = this->
clone();
1175 for (
auto i = 0u; i < this->m_nodes.size(); i++)
1177 if (
const auto var_name_res = this->m_nodes[i].
get_variable_name(); var_name_res.is_ok())
1179 if (
const auto it = substitutions.find(var_name_res.get()); it != substitutions.end())
1181 function.m_nodes[i] =
Node::Variable(it->second, this->m_nodes[i].size);
1196 auto substitute_variable = [substitutions](
const auto& node,
auto&& operands) ->
BooleanFunction {
1197 if (node.is_variable())
1199 if (
auto repl_it = substitutions.find(node.variable); repl_it != substitutions.end())
1201 return repl_it->second.
clone();
1207 std::vector<BooleanFunction> stack;
1208 for (
const auto& node : this->m_nodes)
1210 std::vector<BooleanFunction> operands;
1211 std::move(stack.end() -
static_cast<i64>(node.get_arity()), stack.end(), std::back_inserter(operands));
1212 stack.erase(stack.end() -
static_cast<i64>(node.get_arity()), stack.end());
1214 stack.emplace_back(substitute_variable(node, std::move(operands)));
1217 switch (stack.size())
1220 return OK(stack.back());
1222 return ERR(
"could not carry out multiple substitutions: validation failed, the operations may be imbalanced");
1229 if (this->m_nodes.empty())
1231 return OK(BooleanFunction::Value::X);
1235 if (this->
size() != 1)
1237 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");
1241 auto generic_inputs = std::unordered_map<std::string, std::vector<Value>>();
1242 for (
const auto& [
name, value] : inputs)
1244 generic_inputs.emplace(
name, std::vector<Value>({value}));
1247 auto value = this->
evaluate(generic_inputs);
1251 return OK(value.get()[0]);
1254 return ERR(value.get_error());
1260 if (this->m_nodes.empty())
1262 return OK(std::vector<BooleanFunction::Value>({BooleanFunction::Value::X}));
1268 for (
const auto& node : this->m_nodes)
1270 if (!node.is_variable())
1275 if (
const auto it = inputs.find(node.variable); it != inputs.end() && node.size != it->second.size())
1277 return ERR(
"could not evaluate Boolean function '" + this->
to_string() +
"': as the size of vairbale " + node.variable +
" with size " + std::to_string(node.size)
1278 +
" does not match the size of the provided input (" + std::to_string(it->second.size()) +
")");
1284 for (
const auto& [
name, value] : inputs)
1291 auto result = symbolic_execution.evaluate(*
this);
1294 if (
auto value = result.get(); value.is_constant())
1296 return OK(value.get_top_level_node().constant);
1298 return OK(std::vector<BooleanFunction::Value>(this->
size(), BooleanFunction::Value::X));
1300 return ERR(result.get_error());
1306 if (this->
size() != 1)
1308 return ERR(
"not a single-bit function");
1315 const std::unordered_set<std::string> known_variables(variables.begin(), variables.end());
1316 for (
const auto& node : this->m_nodes)
1320 return ERR(
"not a single-bit function");
1330 if (node.constant.size() != 1 || (node.constant[0] != Value::ZERO && node.constant[0] != Value::ONE))
1332 return ERR(
"constant is not Boolean");
1336 if (known_variables.find(node.variable) == known_variables.end())
1338 return ERR(
"function has a variable that is not part of the truth table");
1342 return ERR(
"not a bitwise function");
1355 static constexpr
u64 PATTERN[6] = {
1356 0xAAAAAAAAAAAAAAAAull,
1357 0xCCCCCCCCCCCCCCCCull,
1358 0xF0F0F0F0F0F0F0F0ull,
1359 0xFF00FF00FF00FF00ull,
1360 0xFFFF0000FFFF0000ull,
1361 0xFFFFFFFF00000000ull,
1364 std::unordered_map<std::string, u32> variable_index;
1365 for (
u32 i = 0; i < variables.size(); i++)
1367 variable_index[variables[i]] = i;
1370 const u64 num_rows =
u64(1) << variables.size();
1371 std::vector<Value> result(num_rows, Value::ZERO);
1373 std::vector<u64> stack;
1374 stack.reserve(this->m_nodes.size());
1376 for (
u64 base = 0; base < num_rows; base += 64)
1378 const u64 rows_in_chunk = std::min<u64>(64, num_rows - base);
1379 const u64 chunk_mask = (rows_in_chunk == 64) ? ~
u64(0) : ((
u64(1) << rows_in_chunk) - 1);
1382 for (
const auto& node : this->m_nodes)
1386 const u32 i = variable_index.at(node.variable);
1387 stack.push_back((i < 6) ? PATTERN[i] : (((base >> i) & 1) ? ~
u64(0) :
u64(0)));
1393 stack.push_back((node.constant[0] == Value::ONE) ? ~
u64(0) :
u64(0));
1397 const u16 arity = node.get_arity();
1398 if (stack.size() < arity)
1400 return ERR(
"could not compute truth table: malformed node list");
1405 const u64 a = stack.back();
1407 stack.push_back(~a);
1411 const u64 b = stack.back();
1413 const u64 a = stack.back();
1418 stack.push_back(a & b);
1422 stack.push_back(a | b);
1426 stack.push_back(a ^ b);
1430 if (stack.size() != 1)
1432 return ERR(
"could not compute truth table: malformed node list");
1435 const u64 out = stack.back() & chunk_mask;
1436 for (
u64 bit = 0; bit < rows_in_chunk; bit++)
1438 result[base + bit] = (out & (
u64(1) << bit)) ? Value::ONE : Value::ZERO;
1442 return OK(std::vector<std::vector<Value>>({std::move(result)}));
1451 for (
const auto& node : this->m_nodes)
1453 if (node.is_variable() && node.size != 1)
1455 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");
1460 auto variables = ordered_variables;
1461 if (variables.empty())
1463 variables = std::vector<std::string>(variable_names_in_function.begin(), variable_names_in_function.end());
1467 if (remove_unknown_variables)
1470 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(); }),
1476 if (this->m_nodes.empty())
1478 return OK(std::vector<std::vector<Value>>(1, std::vector<Value>(1 << variables.size(), Value::X)));
1485 return ERR(
"could not compute truth table for Boolean function '" + this->
to_string() +
"': unable to generate truth-table with more than "
1492 if (
const auto res = compute_truth_table_bitwise(variables); res.is_ok())
1497 std::vector<std::vector<Value>> truth_table(this->
size(), std::vector<Value>(1 << variables.size(), Value::ZERO));
1500 for (
auto value = 0u; value < ((
u32)1 << variables.size()); value++)
1502 std::unordered_map<std::string, std::vector<Value>>
input;
1504 for (
const auto& variable : variables)
1506 input[variable] = ((tmp & 1) == 0) ? std::vector<Value>({Value::ZERO}) : std::vector<Value>({Value::ONE});
1509 auto result = this->
evaluate(input);
1510 if (result.is_error())
1512 return ERR(result.get_error());
1514 auto output = result.get();
1521 return OK(truth_table);
1526 std::vector<std::string> inputs;
1528 if (ordered_inputs.empty())
1530 inputs = std::vector<std::string>(inputs_set.begin(), inputs_set.end());
1534 inputs = ordered_inputs;
1537 if (remove_unknown_inputs)
1539 inputs.erase(std::remove_if(inputs.begin(), inputs.end(), [&inputs_set](
const auto& s) { return inputs_set.find(s) == inputs_set.end(); }), inputs.end());
1545 return ERR_APPEND(res.get_error(),
"could not print truth table for Boolean function '" + this->to_string() +
"': unable to compute truth table");
1547 const auto truth_table = res.get();
1549 std::stringstream str(
"");
1551 u32 num_inputs = inputs.size();
1552 u32 num_outputs = truth_table.size();
1555 std::vector<u32> in_widths;
1556 for (
const auto& var : inputs)
1558 in_widths.push_back(var.size());
1559 str <<
" " << var <<
" |";
1562 std::vector<u32> out_widths;
1563 if (function_name.empty())
1565 function_name =
"O";
1567 if (num_outputs == 1)
1569 str <<
"| " << function_name <<
" ";
1570 out_widths.push_back(function_name.size());
1574 for (
u32 i = 0; i < num_outputs; i++)
1576 std::string var = function_name +
"(" + std::to_string(i) +
")";
1577 str <<
"| " << var <<
" ";
1578 out_widths.push_back(var.size());
1584 for (
u32 i = 0; i < num_inputs; i++)
1586 str << std::setw(in_widths.at(i) + 3) << std::setfill(
'-') <<
"+";
1588 for (
u32 i = 0; i < num_outputs; i++)
1590 str <<
"+" << std::setw(out_widths.at(i) + 2) << std::setfill(
'-') <<
"-";
1595 for (
u32 i = 0; i < (
u32)(1 << num_inputs); i++)
1597 for (
u32 j = 0; j < num_inputs; j++)
1599 str <<
" " << std::left << std::setw(in_widths.at(j)) << std::setfill(
' ') << ((i >> j) & 1) <<
" |";
1602 for (
u32 k = 0; k < num_outputs; k++)
1604 str <<
"| " << std::left << std::setw(out_widths.at(k)) << std::setfill(
' ') << truth_table.at(k).at(i) <<
" ";
1608 return OK(str.str());
1619 auto reduce_to_z3 = [&context, &var2expr](
const auto& node,
auto&& p) -> std::tuple<bool, z3::expr> {
1620 if (node.get_arity() != p.size())
1622 return {
false, z3::expr(context)};
1628 return {
true, context.bv_val(node.index, node.size)};
1632 auto constant = context.bv_val(node.constant.front(), 1);
1633 for (
u32 i = 1; i < node.constant.size(); i++)
1635 const auto bit = node.constant.at(i);
1636 constant = z3::concat(context.bv_val(bit, 1), constant);
1638 return {
true, constant};
1641 if (
auto it = var2expr.find(node.variable); it != var2expr.end())
1643 return {
true, it->second};
1645 return {
true, context.bv_const(node.variable.c_str(), node.size)};
1649 return {
true, p[0] & p[1]};
1651 return {
true, p[0] | p[1]};
1653 return {
true, ~p[0]};
1655 return {
true, p[0] ^ p[1]};
1657 return {
true, p[0].extract(p[2].get_numeral_uint(), p[1].get_numeral_uint())};
1659 return {
true, z3::concat(p[0], p[1])};
1661 return {
true, z3::sext(p[0], p[1].get_numeral_uint())};
1664 log_error(
"netlist",
"Not implemented reached for nodetype {} in z3 conversion", node.type);
1665 return {
false, z3::expr(context)};
1669 std::vector<z3::expr> stack;
1670 for (
const auto& node : this->m_nodes)
1672 std::vector<z3::expr> operands;
1673 std::move(stack.end() -
static_cast<i64>(node.get_arity()), stack.end(), std::back_inserter(operands));
1674 stack.erase(stack.end() -
static_cast<i64>(node.get_arity()), stack.end());
1676 if (
auto [ok, reduction] = reduce_to_z3(node, std::move(operands)); ok)
1678 stack.emplace_back(reduction);
1682 return z3::expr(context);
1686 switch (stack.size())
1689 return stack.back();
1691 return z3::expr(context);
1702 for (
const auto& parameter : p)
1704 size += parameter.size();
1706 this->m_nodes.reserve(
size);
1708 for (
auto&& parameter : p)
1710 this->m_nodes.insert(this->m_nodes.end(), parameter.m_nodes.begin(), parameter.m_nodes.end());
1712 this->m_nodes.emplace_back(node);
1715 std::string BooleanFunction::to_string_in_reverse_polish_notation()
const
1718 for (
const auto& node : this->m_nodes)
1720 s += node.to_string() +
" ";
1725 Result<BooleanFunction> BooleanFunction::validate(BooleanFunction&&
function)
1731 if (
auto coverage =
function.compute_node_coverage(); coverage.back() !=
function.
length())
1733 auto str =
function.to_string_in_reverse_polish_notation();
1734 return ERR(
"could not validate '" + str +
"': imbalanced function with coverage '" + std::to_string(coverage.back()) +
" != " + std::to_string(
function.length()));
1737 return OK(std::move(
function));
1740 std::vector<u32> BooleanFunction::compute_node_coverage()
const
1742 auto coverage = std::vector<u32>(this->m_nodes.size(), (
u32)-1);
1749 auto get = [](
const auto& cov,
size_t index) ->
u32 {
return (
index < cov.size()) ? cov[
index] : -1; };
1760 for (
auto i = 0ul; i < this->m_nodes.size(); i++)
1762 auto arity = this->m_nodes[i].get_arity();
1771 auto x = get(coverage, i - 1);
1772 set(coverage, i,
x);
1776 auto x = get(coverage, i - 1);
1777 auto y = get(coverage, i - 1 -
x);
1778 set(coverage, i,
x,
y);
1782 auto x = get(coverage, i - 1);
1783 auto y = get(coverage, i - 1 -
x);
1784 auto z = get(coverage, i - 1 -
x -
y);
1785 set(coverage, i,
x,
y, z);
1796 return Node(_type, _size, {}, {}, {});
1821 return !(*
this == other);
1831 return Node(this->
type, this->
size, this->constant, this->index, this->variable);
1840 for (
const auto& value : this->constant)
1848 return std::to_string(this->index);
1850 return this->variable;
1910 return "unsupported node type '" + std::to_string(this->
type) +
"'.";
1921 static const std::map<u16, u16> type2arity = {
1932 return type2arity.at(
type);
1937 return this->
type == _type;
1947 return this->
is_constant() && (this->constant == value);
1957 auto bv_value = std::vector<BooleanFunction::Value>({});
1958 bv_value.reserve(this->
size);
1959 for (
auto i = 0u; i < this->constant.size(); i++)
1961 bv_value.emplace_back((value & (1 << i)) ? BooleanFunction::Value::ONE : BooleanFunction::Value::ZERO);
1963 return this->constant == bv_value;
1970 return ERR(
"Node is not a constant");
1973 return OK(this->constant);
1980 return ERR(
"Node is not a constant");
1983 if (this->
size > 64)
1985 return ERR(
"Node constant has size > 64");
1988 if (std::any_of(this->constant.begin(), this->constant.end(), [](
auto v) { return v != BooleanFunction::Value::ONE && v != BooleanFunction::Value::ZERO; }))
1990 return ERR(
"Node constant is undefined or high-impedance");
1994 for (
auto it = this->constant.rbegin(); it != this->constant.rend(); it++)
2010 return this->
is_index() && (this->index == value);
2017 return ERR(
"Node is not an index");
2020 return OK(this->index);
2030 return this->
is_variable() && (this->variable == value);
2037 return ERR(
"Node is not a variable");
2040 return OK(this->variable);
2045 return !this->is_operand();
2059 BooleanFunction::Node::Node(
u16 _type,
u16 _size, std::vector<BooleanFunction::Value> _constant,
u16 _index, std::string _variable)
2060 :
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)
Result< std::vector< Token > > parse_with_liberty_grammar(const std::string &expression)
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< 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.