From c6e1d461faa0e845fa2306ca9015aed0d37e83e6 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Fri, 11 Jul 2025 23:09:30 +0200 Subject: [PATCH] libparse: support space ANDs --- passes/techmap/dfflibmap.cc | 5 +---- passes/techmap/libparse.cc | 43 ++++++++++++++++++++++++------------- passes/techmap/libparse.h | 3 +++ 3 files changed, 32 insertions(+), 19 deletions(-) diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc index ae9498a9c..ade155791 100644 --- a/passes/techmap/dfflibmap.cc +++ b/passes/techmap/dfflibmap.cc @@ -92,9 +92,6 @@ static bool parse_next_state(const LibertyAst *cell, const LibertyAst *attr, std auto expr = attr->value; auto cell_name = cell->args[0]; - for (size_t pos = expr.find_first_of("\" \t"); pos != std::string::npos; pos = expr.find_first_of("\" \t")) - expr.erase(pos, 1); - // if this isn't an enable flop, the next_state variable is usually just the input pin name. if (expr[expr.size()-1] == '\'') { data_name = expr.substr(0, expr.size()-1); @@ -117,7 +114,7 @@ static bool parse_next_state(const LibertyAst *cell, const LibertyAst *attr, std // the next_state variable isn't just a pin name; perhaps this is an enable? auto helper = LibertyExpression::Lexer(expr); auto tree = LibertyExpression::parse(helper); - log_debug("liberty expression:\n%s\n", tree.str().c_str()); + // log_debug("liberty expression:\n%s\n", tree.str().c_str()); if (tree.kind == LibertyExpression::Kind::EMPTY) { if (!warned_cells.count(cell_name)) { diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index 0df7af347..957a529b9 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -163,6 +163,12 @@ void LibertyAst::dump(FILE *f, sieve &blacklist, sieve &whitelist, std::string i } #ifndef FILTERLIB + +// binary operators excluding ' ' +bool LibertyExpression::is_nice_binop(char c) { + return c == '*' || c == '&' || c == '^' || c == '+' || c == '|'; +} + // https://matklad.github.io/2020/04/13/simple-but-powerful-pratt-parsing.html LibertyExpression LibertyExpression::parse(Lexer &s, int min_prio) { if (s.empty()) @@ -201,15 +207,8 @@ LibertyExpression LibertyExpression::parse(Lexer &s, int min_prio) { while (true) { if (s.empty()) break; - - c = s.peek(); - while (isspace(c)) { - if (s.empty()) - return lhs; - s.next(); - c = s.peek(); - } + c = s.peek(); if (c == '\'') { // postfix NOT if (min_prio > 7) @@ -235,11 +234,27 @@ LibertyExpression LibertyExpression::parse(Lexer &s, int min_prio) { lhs = std::move(n); continue; - } else if (c == '&' || c == '*') { // infix AND - // technically space should be considered infix AND. it seems rare in practice. + } else if (c == '&' || c == '*' || isspace(c)) { // infix AND if (min_prio > 3) break; - s.next(); + + if (isspace(c)) { + // Rewind past this space and any further spaces + while (isspace(c) && !s.empty()) { + if (s.empty()) + return lhs; + s.next(); + c = s.peek(); + } + if (is_nice_binop(c)) { + // We found a real binop, so this space wasn't an AND + // and we just discard it as meaningless whitespace + continue; + } + } else { + // Rewind past this op + s.next(); + } auto rhs = parse(s, 4); auto n = LibertyExpression{}; @@ -310,7 +325,6 @@ bool LibertyExpression::eval(dict& values) { std::string LibertyExpression::str(int indent) { std::string prefix; - prefix = std::string(indent, ' '); switch (kind) { case AND: prefix += "(and "; @@ -337,10 +351,9 @@ std::string LibertyExpression::str(int indent) bool first = true; for (auto child : children) { if (!first) { - prefix += "\n" + child.str(indent + add_indent); - } else { - prefix += child.str(0); + prefix += "\n" + std::string(indent + add_indent, ' '); } + prefix += child.str(indent + add_indent); first = false; } prefix += ")"; diff --git a/passes/techmap/libparse.h b/passes/techmap/libparse.h index 8a2ab22e0..ee0f3db42 100644 --- a/passes/techmap/libparse.h +++ b/passes/techmap/libparse.h @@ -93,6 +93,9 @@ namespace Yosys static LibertyExpression parse(Lexer &s, int min_prio = 0); void get_pin_names(pool& names); bool eval(dict& values); + std::string str(int indent = 0); + private: + static bool is_nice_binop(char c); }; class LibertyInputStream {