From e0822c048ec051be216b972fdea2dba15929e1c5 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 10 Jul 2025 21:13:28 +0200 Subject: [PATCH 01/38] Revert "verilog: fix parser "if" memory errors." This reverts commit 34a2abeddb5054df29140baf1c6d5af02a9aac63. --- frontends/verilog/verilog_parser.y | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 17edc357d..7e53005f3 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -2874,7 +2874,6 @@ behavioral_stmt: } | if_attr TOK_IF '(' expr ')' { AstNode *node = 0; - AstNode *block = new AstNode(AST_BLOCK); AstNode *context = ast_stack.back(); if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if)) { AstNode *outer = ast_stack[ast_stack.size() - 2]; @@ -2883,10 +2882,8 @@ behavioral_stmt: // parallel "else if": append condition to outer "if" node = outer; log_assert (node->children.size()); - ast_stack.pop_back(); delete node->children.back(); node->children.pop_back(); - ast_stack.push_back(block); } else if (outer->get_bool_attribute(ID::full_case)) (*$1)[ID::full_case] = AstNode::mkconst_int(1, false); } @@ -2897,8 +2894,8 @@ behavioral_stmt: append_attr(node, $1); ast_stack.back()->children.push_back(node); node->children.push_back(node->get_bool_attribute(ID::parallel_case) ? AstNode::mkconst_int(1, false, 1) : expr); - } else - free_attr($1); + } + AstNode *block = new AstNode(AST_BLOCK); AstNode *cond = new AstNode(AST_COND, node->get_bool_attribute(ID::parallel_case) ? expr : AstNode::mkconst_int(1, false, 1), block); SET_AST_NODE_LOC(cond, @4, @4); node->children.push_back(cond); From dc204dc9095135a16cbb4713e311f08a7ceca629 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 10 Jul 2025 21:14:38 +0200 Subject: [PATCH 02/38] Revert "verilog: add support for SystemVerilog string literals." This reverts commit 5feb1a1752a7469fd5a02ec8afdb68794e55ef8f. --- docs/source/yosys_internals/verilog.rst | 3 - frontends/verilog/verilog_lexer.l | 168 ++++------------ tests/verilog/bug5160.v | 5 + tests/verilog/string-literals.ys | 257 ------------------------ 4 files changed, 47 insertions(+), 386 deletions(-) create mode 100644 tests/verilog/bug5160.v delete mode 100644 tests/verilog/string-literals.ys diff --git a/docs/source/yosys_internals/verilog.rst b/docs/source/yosys_internals/verilog.rst index d67553aa9..0039aaab7 100644 --- a/docs/source/yosys_internals/verilog.rst +++ b/docs/source/yosys_internals/verilog.rst @@ -381,6 +381,3 @@ from SystemVerilog: will process conditionals using these keywords by annotating their representation with the appropriate ``full_case`` and/or ``parallel_case`` attributes, which are described above.) - -- SystemVerilog string literals are supported (triple-quoted strings and - escape sequences such as line continuations and hex escapes). diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index e2d7a2cd9..40162b8d3 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -112,129 +112,6 @@ static bool isUserType(std::string &s) return false; } -static bool is_hex_dig(char c, int *val) -{ - if ('0' <= c && c <= '9') { - *val = c - '0'; - return true; - } else if ('a' <= c && c <= 'f') { - *val = c - 'a' + 0xA; - return true; - } else if ('A' <= c && c <= 'F') { - *val = c - 'A' + 0xA; - return true; - } else if (c == 'x' || c == 'X' || c == 'z' || c == 'Z' || c == '?') { - log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "'%c' not a valid digit in hex escape sequence.\n", c); - *val = 0; // not semantically valid in hex escape... - return true; // ...but still processed as part of hex token - } - - return false; -} - -static bool is_oct_dig(char c, int *val) -{ - if ('0' <= c && c <= '7') { - *val = c - '0'; - return true; - } else if (c == 'x' || c == 'X' || c == 'z' || c == 'Z' || c == '?') { - log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "'%c' not a valid digit in octal escape sequence.\n", c); - *val = 0; // not semantically valid in octal escape... - return true; // ...but still processed as part of octal token - } - - return false; -} - -static std::string *process_str(char *str, int len, bool triple) -{ - char *in, *out; // Overwrite input buffer: flex manual states "Actions - // are free to modify 'yytext' except for lengthening it". - - for (in = str, out = str; in < str + len; in++) - switch (*in) { - case '\n': - case '\r': - if (in + 1 < str + len && (in[1] ^ *in) == ('\n' ^ '\r')) - in++; - if (!triple) - log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "Multi-line string literals should be triple-quoted or escaped.\n"); - *out++ = '\n'; - break; - case '\\': - in++; - log_assert(in < str + len); - switch (*in) { - case 'a': - *out++ = '\a'; - break; - case 'f': - *out++ = '\f'; - break; - case 'n': - *out++ = '\n'; - break; - case 'r': /* not part of IEEE-1800 2023, but seems - like a good idea to support it anyway */ - *out++ = '\r'; - break; - case 't': - *out++ = '\t'; - break; - case 'v': - *out++ = '\v'; - break; - case 'x': - int val; - if (in + 1 < str + len && is_hex_dig(in[1], &val)) { - *out = val; - in++; - if (in + 1 < str + len && is_hex_dig(in[1], &val)) { - *out = *out * 0x10 + val; - in++; - } - out++; - } else - log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "ignoring invalid hex escape.\n"); - break; - case '\\': - *out++ = '\\'; - break; - case '"': - *out++ = '"'; - break; - case '\n': - case '\r': - if (in + 1 < str + len && (in[1] ^ *in) == ('\n' ^ '\r')) - in++; - break; - default: - if ('0' <= *in && *in <= '7') { - int val; - - *out = *in - '0'; - if (in + 1 < str + len && is_oct_dig(in[1], &val)) { - *out = *out * 010 + val; - in++; - if (in + 1 < str + len && is_oct_dig(in[1], &val)) { - if (*out >= 040) - log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "octal escape exceeds \\377\n"); - *out = *out * 010 + val; - in++; - } - } - out++; - } else - *out++ = *in; - } - break; - default: - *out++ = *in; - } - - return new std::string(str, out - str); -} - %} %option yylineno @@ -245,6 +122,7 @@ static std::string *process_str(char *str, int len, bool triple) %option prefix="frontend_verilog_yy" %x COMMENT +%x STRING %x SYNOPSYS_TRANSLATE_OFF %x SYNOPSYS_FLAGS %x IMPORT_DPI @@ -457,9 +335,47 @@ TIME_SCALE_SUFFIX [munpf]?s return TOK_REALVAL; } -\"([^\\"]|\\.|\\\n)*\" { yylval->string = process_str(yytext + 1, yyleng - 2, false); return TOK_STRING; } - -\"{3}(\"{0,2}([^\\"]|\\.|\\\n))*\"{3} { yylval->string = process_str(yytext + 3, yyleng - 6, true); return TOK_STRING; } +\" { BEGIN(STRING); } +([^\\"]|\\.)+ { yymore(); real_location = old_location; } +\" { + BEGIN(0); + char *yystr = strdup(yytext); + yystr[strlen(yytext) - 1] = 0; + int i = 0, j = 0; + while (yystr[i]) { + if (yystr[i] == '\\' && yystr[i + 1]) { + i++; + if (yystr[i] == 'a') + yystr[i] = '\a'; + else if (yystr[i] == 'f') + yystr[i] = '\f'; + else if (yystr[i] == 'n') + yystr[i] = '\n'; + else if (yystr[i] == 'r') + yystr[i] = '\r'; + else if (yystr[i] == 't') + yystr[i] = '\t'; + else if (yystr[i] == 'v') + yystr[i] = '\v'; + else if ('0' <= yystr[i] && yystr[i] <= '7') { + yystr[i] = yystr[i] - '0'; + if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') { + yystr[i + 1] = yystr[i] * 8 + yystr[i + 1] - '0'; + i++; + } + if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') { + yystr[i + 1] = yystr[i] * 8 + yystr[i + 1] - '0'; + i++; + } + } + } + yystr[j++] = yystr[i++]; + } + yystr[j] = 0; + yylval->string = new std::string(yystr, j); + free(yystr); + return TOK_STRING; +} and|nand|or|nor|xor|xnor|not|buf|bufif0|bufif1|notif0|notif1 { yylval->string = new std::string(yytext); diff --git a/tests/verilog/bug5160.v b/tests/verilog/bug5160.v new file mode 100644 index 000000000..5b141a360 --- /dev/null +++ b/tests/verilog/bug5160.v @@ -0,0 +1,5 @@ +// Regression test for bug mentioned in #5160: +// https://github.com/YosysHQ/yosys/pull/5160#issuecomment-2983643084 +module top; + initial $display( "\\" ); +endmodule diff --git a/tests/verilog/string-literals.ys b/tests/verilog/string-literals.ys deleted file mode 100644 index a0f0f0460..000000000 --- a/tests/verilog/string-literals.ys +++ /dev/null @@ -1,257 +0,0 @@ -# Test valid escape sequences yield correct results: -logger -expect-no-warnings -read_verilog << EOF -module top; - wire[7:0] sp = "\ "; - wire[7:0] spval = 32; - wire[7:0] ex = "\!"; - wire[7:0] exval = 33; - wire[7:0] dq = "\""; - wire[7:0] dqval = 34; - wire[7:0] ha = "\#"; - wire[7:0] haval = 35; - wire[7:0] do = "\$"; - wire[7:0] doval = 36; - wire[7:0] pc = "\%"; - wire[7:0] pcval = 37; - wire[7:0] am = "\&"; - wire[7:0] amval = 38; - wire[7:0] sq = "\'"; - wire[7:0] sqval = 39; - wire[7:0] op = "\("; - wire[7:0] opval = 40; - wire[7:0] cp = "\)"; - wire[7:0] cpval = 41; - wire[7:0] as = "\*"; - wire[7:0] asval = 42; - wire[7:0] pl = "\+"; - wire[7:0] plval = 43; - wire[7:0] co = "\,"; - wire[7:0] coval = 44; - wire[7:0] mi = "\-"; - wire[7:0] mival = 45; - wire[7:0] do = "\."; - wire[7:0] doval = 46; - wire[7:0] sl = "\/"; - wire[7:0] slval = 47; - - wire[7:0] dig0 = "\012"; - wire[7:0] dig0val = 10; - wire[7:0] dig8 = "\8"; // not octal, a literal '8' - wire[7:0] dig8val = 56; - wire[7:0] dig9 = "\9"; // not octal, a literal '9' - wire[7:0] dig9val = 57; - - wire[7:0] cl = "\:"; - wire[7:0] clval = 58; - wire[7:0] sc = "\;"; - wire[7:0] scval = 59; - wire[7:0] lt = "\<"; - wire[7:0] ltval = 60; - wire[7:0] eq = "\="; - wire[7:0] eqval = 61; - wire[7:0] gt = "\>"; - wire[7:0] gtval = 62; - wire[7:0] qu = "\?"; - wire[7:0] quval = 63; - wire[7:0] at = "\@"; - wire[7:0] atval = 64; - - wire[7:0] A = "\A"; - wire[7:0] Aval = 65; // etc. etc. - - wire[7:0] os = "\["; - wire[7:0] osval = 91; - wire[7:0] bs = "\\"; - wire[7:0] bsval = 92; - wire[7:0] cs = "\]"; - wire[7:0] csval = 93; - wire[7:0] ca = "\^"; - wire[7:0] caval = 94; - wire[7:0] us = "\_"; - wire[7:0] usval = 95; - wire[7:0] bq = "\`"; - wire[7:0] bqval = 96; - - wire[7:0] a = "\a"; // alert, ASCII BEL=7 - wire[7:0] aval = 7; - wire[7:0] b = "\b"; - wire[7:0] bval = 98; - wire[7:0] c = "\c"; - wire[7:0] cval = 99; - wire[7:0] d = "\d"; - wire[7:0] dval = 100; - wire[7:0] e = "\e"; - wire[7:0] eval = 101; - wire[7:0] f = "\f"; // form feed, ASCII FF=12 - wire[7:0] fval = 12; - wire[7:0] g = "\g"; - wire[7:0] gval = 103; - wire[7:0] h = "\h"; - wire[7:0] hval = 104; - wire[7:0] i = "\i"; - wire[7:0] ival = 105; - wire[7:0] j = "\j"; - wire[7:0] jval = 106; - wire[7:0] k = "\k"; - wire[7:0] kval = 107; - wire[7:0] l = "\l"; - wire[7:0] lval = 108; - wire[7:0] m = "\m"; - wire[7:0] mval = 109; - wire[7:0] n = "\n"; // new line, ASCII LF=10 - wire[7:0] nval = 10; - wire[7:0] o = "\o"; - wire[7:0] oval = 111; - wire[7:0] p = "\p"; - wire[7:0] pval = 112; - wire[7:0] q = "\q"; - wire[7:0] qval = 113; - wire[7:0] r = "\r"; // carriage return, ASCII CR=13, not IEEE 1800-2023 - wire[7:0] rval = 13; - wire[7:0] s = "\s"; - wire[7:0] sval = 115; - wire[7:0] t = "\t"; // tab, ASCII HT=9 - wire[7:0] tval = 9; - wire[7:0] u = "\u"; - wire[7:0] uval = 117; - wire[7:0] v = "\v"; // vertical tab, ASCII VT=11 - wire[7:0] vval = 11; - wire[7:0] w = "\w"; - wire[7:0] wval = 119; - wire[7:0] x = "\x2A"; // hex escape - wire[7:0] xval = 42; - wire[7:0] y = "\y"; - wire[7:0] yval = 121; - wire[7:0] z = "\z"; - wire[7:0] zval = 122; - - wire[7:0] ob = "\{"; - wire[7:0] obval = 123; - wire[7:0] vb = "\|"; - wire[7:0] vbval = 124; - wire[7:0] cb = "\}"; - wire[7:0] cbval = 125; - wire[7:0] ti = "\~"; - wire[7:0] tival = 126; -endmodule -EOF -sat -prove sp spval -prove ex exval -prove dq dqval -prove ha haval -prove do doval -prove pc pcval -prove am amval -prove sq sqval -prove op opval -prove cp cpval -prove as asval -prove pl plval -prove co coval -prove mi mival -prove do doval -prove sl slval -verify -sat -prove dig0 dig0val -prove dig8 dig8val -prove dig9 dig9val -verify -sat -prove cl clval -prove sc scval -prove lt ltval -prove eq eqval -prove gt gtval -prove qu quval -prove at atval -prove A Aval -verify -sat -prove os osval -prove bs bsval -prove cs csval -prove ca caval -prove us usval -prove bq bqval -verify -sat -prove a aval -prove b bval -prove c cval -prove d dval -prove e eval -prove f fval -prove g gval -prove h hval -prove i ival -prove j jval -prove k kval -prove l lval -prove m mval -prove n nval -prove o oval -prove p pval -prove q qval -prove r rval -prove s sval -prove t tval -prove u uval -prove v vval -prove w wval -prove x xval -prove y yval -prove z zval -verify -sat -prove ob obval -prove vb vbval -prove cb cbval -prove ti tival -verify -logger -check-expected -design -reset - -# Test octal escape out of range. -logger -expect warning "octal escape exceeds \\377" 1 -read_verilog << EOF -module top; - wire[7:0] x = "\400"; -endmodule -EOF -logger -check-expected -design -reset - -# Test invalid octal digit. -logger -expect warning "'\?' not a valid digit in octal escape sequence" 1 -read_verilog << EOF -module top; - wire[7:0] x = "\0?"; -endmodule -EOF -logger -check-expected -design -reset - -# Test invalid hex digit. -logger -expect warning "'X' not a valid digit in hex escape sequence" 1 -read_verilog << EOF -module top; - wire[7:0] x = "\x0X"; -endmodule -EOF -logger -check-expected -design -reset - -# Test hex escape with no hex digits at all. -logger -expect warning "ignoring invalid hex escape" 1 -read_verilog << EOF -module top; - wire[7:0] x = "\xy"; -endmodule -EOF -logger -check-expected -design -reset - -# Test hex escape interrupted by end of string. -logger -expect warning "ignoring invalid hex escape" 1 -read_verilog << EOF -module top; - wire[7:0] x = "\x"; -endmodule -EOF -logger -check-expected -design -reset - -# Test multi-line string. -logger -expect warning "Multi-line string literals should be triple-quoted or escaped" 1 -read_verilog << EOF -module top; - wire[31:0] x = "A -BC"; - wire[31:0] xval = 32'h410A4243; -endmodule -EOF -logger -check-expected -design -reset - -# Test multi-line triple-quoted string. -logger -expect-no-warnings -read_verilog << EOF -module top; - wire[31:0] x = """A -BC"""; - wire[31:0] xval = 32'h410A4243; -endmodule -EOF -logger -check-expected -sat -prove x xval -verify -design -reset - -# Test escaped multi-line string. -logger -expect-no-warnings -read_verilog << EOF -module top; - wire[31:0] x = "AB\ -CD"; - wire[31:0] xval = 32'h41424344; -endmodule -EOF -logger -check-expected -sat -prove x xval -verify -design -reset - -# Test octal escape with surrounding data. -logger -expect-no-warnings -read_verilog << EOF -module top; - wire[31:0] x = "AB\234C"; - wire[31:0] xval = 32'h41429C43; -endmodule -EOF -logger -check-expected -sat -prove x xval -verify -design -reset - -# Test hex escape with surrounding data. -logger -expect-no-warnings -read_verilog << EOF -module top; - wire[31:0] x = "A\xBCDE"; - wire[31:0] xval = 32'h41BC4445; -endmodule -EOF -logger -check-expected -sat -prove x xval -verify From bb08919105c5e1da4710becb4e4d087c5314003f Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 10 Jul 2025 21:15:38 +0200 Subject: [PATCH 03/38] Revert "verilog: fix string literal regular expression (#5187)" This reverts commit 834a7294b7c790612e9d1a686b374130b43d814e. --- frontends/verilog/verilog_lexer.l | 2 +- tests/verilog/bug5160.v | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) delete mode 100644 tests/verilog/bug5160.v diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 40162b8d3..8148748d8 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -336,7 +336,7 @@ TIME_SCALE_SUFFIX [munpf]?s } \" { BEGIN(STRING); } -([^\\"]|\\.)+ { yymore(); real_location = old_location; } +([^\"]|\\.)+ { yymore(); real_location = old_location; } \" { BEGIN(0); char *yystr = strdup(yytext); diff --git a/tests/verilog/bug5160.v b/tests/verilog/bug5160.v deleted file mode 100644 index 5b141a360..000000000 --- a/tests/verilog/bug5160.v +++ /dev/null @@ -1,5 +0,0 @@ -// Regression test for bug mentioned in #5160: -// https://github.com/YosysHQ/yosys/pull/5160#issuecomment-2983643084 -module top; - initial $display( "\\" ); -endmodule From 8a873a7724e9c33a88cccc7464cf108166b3733c Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 16 Jun 2025 22:55:24 +0200 Subject: [PATCH 04/38] ast, read_verilog: ownership in AST, use C++ styles for parser and lexer --- frontends/ast/ast.cc | 340 ++- frontends/ast/ast.h | 61 +- frontends/ast/dpicall.cc | 8 +- frontends/ast/genrtlil.cc | 206 +- frontends/ast/simplify.cc | 1433 +++++----- frontends/verilog/.gitignore | 3 + frontends/verilog/Makefile.inc | 1 + frontends/verilog/const2ast.cc | 52 +- frontends/verilog/preproc.cc | 9 +- frontends/verilog/preproc.h | 9 +- frontends/verilog/verilog_frontend.cc | 171 +- frontends/verilog/verilog_frontend.h | 86 +- frontends/verilog/verilog_lexer.h | 48 + frontends/verilog/verilog_lexer.l | 559 ++-- frontends/verilog/verilog_parser.y | 3595 ++++++++++++------------- kernel/rtlil.cc | 16 +- kernel/rtlil.h | 2 +- passes/cmds/design.cc | 6 - passes/memory/memlib.h | 2 +- 19 files changed, 3295 insertions(+), 3312 deletions(-) create mode 100644 frontends/verilog/verilog_lexer.h diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 431f7b4f8..2844f96b7 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -39,8 +39,7 @@ using namespace AST_INTERNAL; // instantiate global variables (public API) namespace AST { std::string current_filename; - void (*set_line_num)(int) = NULL; - int (*get_line_num)() = NULL; + bool sv_mode; unsigned long long astnodes = 0; unsigned long long astnode_count() { return astnodes; } } @@ -192,16 +191,16 @@ bool AstNode::get_bool_attribute(RTLIL::IdString id) if (attributes.count(id) == 0) return false; - AstNode *attr = attributes.at(id); - if (attr->type != AST_CONSTANT) - attr->input_error("Attribute `%s' with non-constant value!\n", id.c_str()); + AstNode& attr = *(attributes.at(id)); + if (attr.type != AST_CONSTANT) + attr.input_error("Attribute `%s' with non-constant value!\n", id.c_str()); - return attr->integer != 0; + return attr.integer != 0; } // create new node (AstNode constructor) // (the optional child arguments make it easier to create AST trees) -AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *child3, AstNode *child4) +AstNode::AstNode(AstNodeType type, std::unique_ptr child1, std::unique_ptr child2, std::unique_ptr child3, std::unique_ptr child4) { static unsigned int hashidx_count = 123456789; hashidx_count = mkhash_xorshift(hashidx_count); @@ -239,56 +238,74 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch in_param = false; if (child1) - children.push_back(child1); + children.push_back(std::move(child1)); if (child2) - children.push_back(child2); + children.push_back(std::move(child2)); if (child3) - children.push_back(child3); + children.push_back(std::move(child3)); if (child4) - children.push_back(child4); + children.push_back(std::move(child4)); fixup_hierarchy_flags(); } // create a (deep recursive) copy of a node -AstNode *AstNode::clone() const +std::unique_ptr AstNode::clone() const { - AstNode *that = new AstNode; - *that = *this; - for (auto &it : that->children) - it = it->clone(); - for (auto &it : that->attributes) - it.second = it.second->clone(); - - that->set_in_lvalue_flag(false); - that->set_in_param_flag(false); - that->fixup_hierarchy_flags(); // fixup to set flags on cloned children + auto that = std::make_unique(this->type); + cloneInto(*that.get()); return that; } // create a (deep recursive) copy of a node use 'other' as target root node -void AstNode::cloneInto(AstNode *other) const +void AstNode::cloneInto(AstNode &other) const { - AstNode *tmp = clone(); - tmp->in_lvalue_from_above = other->in_lvalue_from_above; - tmp->in_param_from_above = other->in_param_from_above; - other->delete_children(); - *other = *tmp; - tmp->children.clear(); - tmp->attributes.clear(); - other->fixup_hierarchy_flags(); - delete tmp; + other.type = type; + other.str = str; + other.bits = bits; + other.is_input = is_input; + other.is_output = is_output; + other.is_reg = is_reg; + other.is_logic = is_logic; + other.is_signed = is_signed; + other.is_string = is_string; + other.is_wand = is_wand; + other.is_wor = is_wor; + other.range_valid = range_valid; + other.range_swapped = range_swapped; + other.was_checked = was_checked; + other.is_unsized = is_unsized; + other.is_custom_type = is_custom_type; + other.port_id = port_id, + other.range_left = range_left, + other.range_right = range_right; + other.integer = integer; + other.realvalue = realvalue; + other.is_enum = is_enum; + other.dimensions = dimensions; + other.unpacked_dimensions = unpacked_dimensions; + other.id2ast = id2ast; + other.basic_prep = basic_prep; + other.lookahead = lookahead; + other.filename = filename; + other.location = location; + other.in_lvalue = in_lvalue; + other.in_param = in_param; + // Keep in_lvalue_from_above and in_param_from_above untouched + + other.delete_children(); + for (auto& child : this->children) + other.children.push_back(child->clone()); + for (auto& [key, val] : this->attributes) + other.attributes[key] = (val->clone()); + // fixup to set flags on cloned children + other.fixup_hierarchy_flags(); } // delete all children in this node void AstNode::delete_children() { - for (auto &it : children) - delete it; children.clear(); - - for (auto &it : attributes) - delete it.second; attributes.clear(); } @@ -423,18 +440,18 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const { case AST_MODULE: fprintf(f, "%s" "module %s(", indent.c_str(), id2vl(str).c_str()); - for (auto child : children) + for (const auto& child : children) if (child->type == AST_WIRE && (child->is_input || child->is_output)) { fprintf(f, "%s%s", first ? "" : ", ", id2vl(child->str).c_str()); first = false; } fprintf(f, ");\n"); - for (auto child : children) + for (const auto& child : children) if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM || child->type == AST_DEFPARAM) child->dumpVlog(f, indent + " "); else - rem_children1.push_back(child); + rem_children1.push_back(child.get()); for (auto child : rem_children1) if (child->type == AST_WIRE || child->type == AST_AUTOWIRE || child->type == AST_MEMORY) @@ -470,7 +487,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const fprintf(f, "%s" "reg", (is_input || is_output) ? " " : indent.c_str()); if (is_signed) fprintf(f, " signed"); - for (auto child : children) { + for (const auto& child : children) { fprintf(f, " "); child->dumpVlog(f, ""); } @@ -486,7 +503,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const fprintf(f, "%s" "memory", indent.c_str()); if (is_signed) fprintf(f, " signed"); - for (auto child : children) { + for (const auto& child : children) { fprintf(f, " "); child->dumpVlog(f, ""); if (first) @@ -500,7 +517,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const if (0) { case AST_MEMINIT: txt = "@meminit@"; } if (0) { case AST_MEMWR: txt = "@memwr@"; } fprintf(f, "%s%s", indent.c_str(), txt.c_str()); - for (auto child : children) { + for (const auto& child : children) { fprintf(f, first ? "(" : ", "); child->dumpVlog(f, ""); first = false; @@ -517,7 +534,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const else fprintf(f, "[%d:%d]", range_left, range_right); } else { - for (auto child : children) { + for (const auto& child : children) { fprintf(f, "%c", first ? '[' : ':'); child->dumpVlog(f, ""); first = false; @@ -527,13 +544,13 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const break; case AST_MULTIRANGE: - for (auto child : children) + for (const auto& child : children) child->dumpVlog(f, ""); break; case AST_ALWAYS: fprintf(f, "%s" "always @", indent.c_str()); - for (auto child : children) { + for (const auto& child : children) { if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE) continue; fprintf(f, first ? "(" : ", "); @@ -541,7 +558,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const first = false; } fprintf(f, first ? "*\n" : ")\n"); - for (auto child : children) { + for (const auto& child : children) { if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE) child->dumpVlog(f, indent + " "); } @@ -549,7 +566,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const case AST_INITIAL: fprintf(f, "%s" "initial\n", indent.c_str()); - for (auto child : children) { + for (const auto& child : children) { if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE) child->dumpVlog(f, indent + " "); } @@ -562,7 +579,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const fprintf(f, "posedge "); if (type == AST_NEGEDGE) fprintf(f, "negedge "); - for (auto child : children) + for (const auto& child : children) child->dumpVlog(f, ""); break; @@ -574,7 +591,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const else fprintf(f, "%s", id2vl(str).c_str()); } - for (auto child : children) + for (const auto& child : children) child->dumpVlog(f, ""); break; @@ -602,7 +619,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const children[0]->dumpVlog(f, indent); } else { fprintf(f, "%s" "begin\n", indent.c_str()); - for (auto child : children) + for (const auto& child : children) child->dumpVlog(f, indent + " "); fprintf(f, "%s" "end\n", indent.c_str()); } @@ -618,7 +635,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const children[0]->dumpVlog(f, ""); fprintf(f, ")\n"); for (size_t i = 1; i < children.size(); i++) { - AstNode *child = children[i]; + const auto& child = children[i]; child->dumpVlog(f, indent + " "); } fprintf(f, "%s" "endcase\n", indent.c_str()); @@ -627,7 +644,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const case AST_COND: case AST_CONDX: case AST_CONDZ: - for (auto child : children) { + for (const auto& child : children) { if (child->type == AST_BLOCK) { fprintf(f, ":\n"); child->dumpVlog(f, indent + " "); @@ -663,7 +680,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const case AST_CONCAT: fprintf(f, "{"); for (int i = GetSize(children)-1; i >= 0; i--) { - auto child = children[i]; + const auto& child = children[i]; if (!first) fprintf(f, ", "); child->dumpVlog(f, ""); @@ -818,16 +835,16 @@ bool AstNode::contains(const AstNode *other) const { if (this == other) return true; - for (auto child : children) + for (const auto& child : children) if (child->contains(other)) return true; return false; } // create an AST node for a constant (using a 32 bit int as value) -AstNode *AstNode::mkconst_int(uint32_t v, bool is_signed, int width) +std::unique_ptr AstNode::mkconst_int(uint32_t v, bool is_signed, int width) { - AstNode *node = new AstNode(AST_CONSTANT); + auto node = std::make_unique(AST_CONSTANT); node->integer = v; node->is_signed = is_signed; for (int i = 0; i < width; i++) { @@ -841,9 +858,9 @@ AstNode *AstNode::mkconst_int(uint32_t v, bool is_signed, int width) } // create an AST node for a constant (using a bit vector as value) -AstNode *AstNode::mkconst_bits(const std::vector &v, bool is_signed, bool is_unsized) +std::unique_ptr AstNode::mkconst_bits(const std::vector &v, bool is_signed, bool is_unsized) { - AstNode *node = new AstNode(AST_CONSTANT); + auto node = std::make_unique(AST_CONSTANT); node->is_signed = is_signed; node->bits = v; for (size_t i = 0; i < 32; i++) { @@ -859,15 +876,15 @@ AstNode *AstNode::mkconst_bits(const std::vector &v, bool is_signe return node; } -AstNode *AstNode::mkconst_bits(const std::vector &v, bool is_signed) +std::unique_ptr AstNode::mkconst_bits(const std::vector &v, bool is_signed) { return mkconst_bits(v, is_signed, false); } // create an AST node for a constant (using a string in bit vector form as value) -AstNode *AstNode::mkconst_str(const std::vector &v) +std::unique_ptr AstNode::mkconst_str(const std::vector &v) { - AstNode *node = mkconst_str(RTLIL::Const(v).decode_string()); + auto node = mkconst_str(RTLIL::Const(v).decode_string()); while (GetSize(node->bits) < GetSize(v)) node->bits.push_back(RTLIL::State::S0); log_assert(node->bits == v); @@ -875,9 +892,9 @@ AstNode *AstNode::mkconst_str(const std::vector &v) } // create an AST node for a constant (using a string as value) -AstNode *AstNode::mkconst_str(const std::string &str) +std::unique_ptr AstNode::mkconst_str(const std::string &str) { - AstNode *node; + std::unique_ptr node; // LRM 1364-2005 5.2.3.3 The empty string literal ("") shall be considered // equivalent to the ASCII NUL ("\0") @@ -902,18 +919,19 @@ AstNode *AstNode::mkconst_str(const std::string &str) } // create a temporary register -AstNode *AstNode::mktemp_logic(const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed) +std::unique_ptr AstNode::mktemp_logic(const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed) { - AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(range_left, true), mkconst_int(range_right, true))); + auto wire_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(range_left, true), mkconst_int(range_right, true))); + auto* wire = wire_owned.get(); wire->str = stringf("%s%s:%d$%d", name.c_str(), RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); if (nosync) wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); wire->is_signed = is_signed; wire->is_logic = true; - mod->children.push_back(wire); + mod->children.push_back(std::move(wire_owned)); while (wire->simplify(true, 1, -1, false)) { } - AstNode *ident = new AstNode(AST_IDENTIFIER); + auto ident = std::make_unique(AST_IDENTIFIER); ident->str = wire->str; ident->id2ast = wire; @@ -967,10 +985,9 @@ RTLIL::Const AstNode::asParaConst() const { if (type == AST_REALVALUE) { - AstNode *strnode = AstNode::mkconst_str(stringf("%f", realvalue)); + auto strnode = AstNode::mkconst_str(stringf("%f", realvalue)); RTLIL::Const val = strnode->asAttrConst(); val.flags |= RTLIL::CONST_FLAG_REAL; - delete strnode; return val; } @@ -1078,7 +1095,7 @@ void AST::set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast) obj->attributes[ID::src] = ast->loc_string(); } -static bool param_has_no_default(const AstNode *param) { +static bool param_has_no_default(const std::unique_ptr ¶m) { const auto &children = param->children; log_assert(param->type == AST_PARAMETER); log_assert(children.size() <= 2); @@ -1086,7 +1103,7 @@ static bool param_has_no_default(const AstNode *param) { (children.size() == 1 && children[0]->type == AST_RANGE); } -static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool defer, AstNode *original_ast = NULL, bool quiet = false) +static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool defer, std::unique_ptr original_ast = NULL, bool quiet = false) { log_assert(current_scope.empty()); log_assert(ast->type == AST_MODULE || ast->type == AST_INTERFACE); @@ -1100,15 +1117,15 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d AstModule *module = new AstModule; current_module = module; - module->ast = NULL; + module->ast = nullptr; module->name = ast->str; set_src_attr(module, ast); module->set_bool_attribute(ID::cells_not_processed); current_ast_mod = ast; - AstNode *ast_before_simplify; + std::unique_ptr ast_before_simplify; if (original_ast != NULL) - ast_before_simplify = original_ast; + ast_before_simplify = std::move(original_ast); else ast_before_simplify = ast->clone(); @@ -1125,7 +1142,7 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d if (!defer) { - for (const AstNode *node : ast->children) + for (auto& node : ast->children) if (node->type == AST_PARAMETER && param_has_no_default(node)) node->input_error("Parameter `%s' has no default value and has not been overridden!\n", node->str.c_str()); @@ -1133,7 +1150,7 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d if (!blackbox_module && !flag_noblackbox) { blackbox_module = true; - for (auto child : ast->children) { + for (const auto& child : ast->children) { if (child->type == AST_WIRE && (child->is_input || child->is_output)) continue; if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM) @@ -1163,36 +1180,33 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d ast->dumpVlog(NULL, " "); log("--- END OF AST DUMP ---\n"); } - + for (auto &attr: ast->attributes) + log_assert((bool)attr.second.get()); if (flag_nowb && ast->attributes.count(ID::whitebox)) { - delete ast->attributes.at(ID::whitebox); ast->attributes.erase(ID::whitebox); } - + for (auto &attr: ast->attributes) + log_assert((bool)attr.second.get()); if (ast->attributes.count(ID::lib_whitebox)) { - if (!flag_lib || flag_nowb) { - delete ast->attributes.at(ID::lib_whitebox); - ast->attributes.erase(ID::lib_whitebox); - } else { - if (ast->attributes.count(ID::whitebox)) { - delete ast->attributes.at(ID::whitebox); - ast->attributes.erase(ID::whitebox); - } - AstNode *n = ast->attributes.at(ID::lib_whitebox); - ast->set_attribute(ID::whitebox, n); - ast->attributes.erase(ID::lib_whitebox); + if (flag_lib && !flag_nowb) { + ast->attributes[ID::whitebox] = std::move( + ast->attributes[ID::lib_whitebox] + ); } + ast->attributes.erase(ID::lib_whitebox); } + for (auto &attr: ast->attributes) + log_assert((bool)attr.second.get()); if (!blackbox_module && ast->attributes.count(ID::blackbox)) { - AstNode *n = ast->attributes.at(ID::blackbox); + auto& n = ast->attributes.at(ID::blackbox); if (n->type != AST_CONSTANT) ast->input_error("Got blackbox attribute with non-constant value!\n"); blackbox_module = n->asBool(); } if (blackbox_module && ast->attributes.count(ID::whitebox)) { - AstNode *n = ast->attributes.at(ID::whitebox); + auto& n = ast->attributes.at(ID::whitebox); if (n->type != AST_CONSTANT) ast->input_error("Got whitebox attribute with non-constant value!\n"); blackbox_module = !n->asBool(); @@ -1200,38 +1214,34 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d if (ast->attributes.count(ID::noblackbox)) { if (blackbox_module) { - AstNode *n = ast->attributes.at(ID::noblackbox); + auto& n = ast->attributes.at(ID::noblackbox); if (n->type != AST_CONSTANT) ast->input_error("Got noblackbox attribute with non-constant value!\n"); blackbox_module = !n->asBool(); } - delete ast->attributes.at(ID::noblackbox); ast->attributes.erase(ID::noblackbox); } - + for (auto &attr: ast->attributes) + log_assert((bool)attr.second.get()); if (blackbox_module) { if (ast->attributes.count(ID::whitebox)) { - delete ast->attributes.at(ID::whitebox); ast->attributes.erase(ID::whitebox); } if (ast->attributes.count(ID::lib_whitebox)) { - delete ast->attributes.at(ID::lib_whitebox); ast->attributes.erase(ID::lib_whitebox); } - std::vector new_children; - for (auto child : ast->children) { + std::vector> new_children; + for (auto& child : ast->children) { if (child->type == AST_WIRE && (child->is_input || child->is_output)) { - new_children.push_back(child); + new_children.push_back(std::move(child)); } else if (child->type == AST_PARAMETER) { - new_children.push_back(child); + new_children.push_back(std::move(child)); } else if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE && (child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule")) { - new_children.push_back(child); - } else { - delete child; + new_children.push_back(std::move(child)); } } @@ -1245,17 +1255,18 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d ignoreThisSignalsInInitial = RTLIL::SigSpec(); for (auto &attr : ast->attributes) { + log_assert((bool)attr.second.get()); if (attr.second->type != AST_CONSTANT) ast->input_error("Attribute `%s' with non-constant value!\n", attr.first.c_str()); module->attributes[attr.first] = attr.second->asAttrConst(); } for (size_t i = 0; i < ast->children.size(); i++) { - AstNode *node = ast->children[i]; + const auto& node = ast->children[i]; if (node->type == AST_WIRE || node->type == AST_MEMORY) node->genRTLIL(); } for (size_t i = 0; i < ast->children.size(); i++) { - AstNode *node = ast->children[i]; + const auto& node = ast->children[i]; if (node->type != AST_WIRE && node->type != AST_MEMORY && node->type != AST_INITIAL) node->genRTLIL(); } @@ -1263,7 +1274,7 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d ignoreThisSignalsInInitial.sort_and_unify(); for (size_t i = 0; i < ast->children.size(); i++) { - AstNode *node = ast->children[i]; + const auto& node = ast->children[i]; if (node->type == AST_INITIAL) node->genRTLIL(); } @@ -1277,14 +1288,14 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d continue; module->attributes[attr.first] = attr.second->asAttrConst(); } - for (const AstNode *node : ast->children) + for (const auto& node : ast->children) if (node->type == AST_PARAMETER) current_module->avail_parameters(node->str); } if (ast->type == AST_INTERFACE) module->set_bool_attribute(ID::is_interface); - module->ast = ast_before_simplify; + module->ast = std::move(ast_before_simplify); module->nolatches = flag_nolatches; module->nomeminit = flag_nomeminit; module->nomem2reg = flag_nomem2reg; @@ -1311,8 +1322,8 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d RTLIL::Module * AST_INTERNAL::process_and_replace_module(RTLIL::Design *design, RTLIL::Module *old_module, - AstNode *new_ast, - AstNode *original_ast) + AST::AstNode *new_ast, + std::unique_ptr original_ast) { // The old module will be deleted. Rename and mark for deletion, using // a static counter to make sure we get a unique name. @@ -1335,7 +1346,7 @@ AST_INTERNAL::process_and_replace_module(RTLIL::Design *design, } // Generate RTLIL from AST for the new module and add to the design: - RTLIL::Module* new_module = process_module(design, new_ast, false, original_ast); + RTLIL::Module* new_module = process_module(design, new_ast, false, std::move(original_ast)); if (is_top) new_module->set_bool_attribute(ID::top); @@ -1347,17 +1358,17 @@ AST_INTERNAL::process_and_replace_module(RTLIL::Design *design, static void rename_in_package_stmts(AstNode *pkg) { std::unordered_set idents; - for (AstNode *item : pkg->children) + for (auto& item : pkg->children) idents.insert(item->str); - std::function rename = - [&rename, &idents, pkg](AstNode *node) { - for (AstNode *child : node->children) { + std::function&)> rename = + [&rename, &idents, pkg](std::unique_ptr& node) { + for (auto& child : node->children) { if (idents.count(child->str)) child->str = pkg->str + "::" + child->str.substr(1); rename(child); } }; - for (AstNode *item : pkg->children) + for (auto& item : pkg->children) if (item->type == AST_FUNCTION || item->type == AST_TASK) rename(item); } @@ -1390,17 +1401,17 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump ast->fixup_hierarchy_flags(true); log_assert(current_ast->type == AST_DESIGN); - for (AstNode *child : current_ast->children) + for (const auto& child : current_ast->children) { if (child->type == AST_MODULE || child->type == AST_INTERFACE) { - for (auto n : design->verilog_globals) + for (auto& n : design->verilog_globals) child->children.push_back(n->clone()); // append nodes from previous packages using package-qualified names - for (auto &n : design->verilog_packages) { + for (auto& n : design->verilog_packages) { for (auto &o : n->children) { - AstNode *cloned_node = o->clone(); + auto cloned_node = o->clone(); // log("cloned node %s\n", type2str(cloned_node->type).c_str()); if (cloned_node->type == AST_ENUM) { for (auto &e : cloned_node->children) { @@ -1410,7 +1421,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump } else { cloned_node->str = n->str + std::string("::") + cloned_node->str.substr(1); } - child->children.push_back(cloned_node); + child->children.push_back(std::move(cloned_node)); } } @@ -1419,7 +1430,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump bool defer_local = defer; if (!defer_local) - for (const AstNode *node : child->children) + for (const auto& node : child->children) if (node->type == AST_PARAMETER && param_has_no_default(node)) { log("Deferring `%s' because it contains parameter(s) without defaults.\n", child->str.c_str()); @@ -1447,13 +1458,13 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump } } - process_module(design, child, defer_local); + process_module(design, child.get(), defer_local); current_ast_mod = nullptr; } else if (child->type == AST_PACKAGE) { // process enum/other declarations child->simplify(true, 1, -1, false); - rename_in_package_stmts(child); + rename_in_package_stmts(child.get()); design->verilog_packages.push_back(child->clone()); current_scope.clear(); } @@ -1470,16 +1481,9 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump current_scope.clear(); } } -} -// AstModule destructor -AstModule::~AstModule() -{ - if (ast != NULL) - delete ast; } - // An interface port with modport is specified like this: // . // This function splits the interface_name from the modport_name, and fails if it is not a valid combination @@ -1516,7 +1520,7 @@ AstNode * AST::find_modport(AstNode *intf, std::string name) for (auto &ch : intf->children) if (ch->type == AST_MODPORT) if (ch->str == name) // Modport found - return ch; + return ch.get(); return NULL; } @@ -1524,7 +1528,7 @@ AstNode * AST::find_modport(AstNode *intf, std::string name) void AST::explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule, std::string intfname, AstNode *modport) { for (auto w : intfmodule->wires()){ - AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(w->width -1, true), AstNode::mkconst_int(0, true))); + auto wire = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, AstNode::mkconst_int(w->width -1, true), AstNode::mkconst_int(0, true))); std::string origname = log_id(w->name); std::string newname = intfname + "." + origname; wire->str = newname; @@ -1543,16 +1547,13 @@ void AST::explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule } } if (found_in_modport) { - module_ast->children.push_back(wire); - } - else { // If not found in modport, do not create port - delete wire; + module_ast->children.push_back(std::move(wire)); } } else { // If no modport, set inout wire->is_input = true; wire->is_output = true; - module_ast->children.push_back(wire); + module_ast->children.push_back(std::move(wire)); } } } @@ -1570,7 +1571,7 @@ bool AstModule::reprocess_if_necessary(RTLIL::Design *design) log("Reprocessing module %s because instantiated module %s has become available.\n", log_id(name), log_id(modname)); loadconfig(); - process_and_replace_module(design, this, ast, NULL); + process_and_replace_module(design, this, ast.get(), NULL); return true; } } @@ -1583,32 +1584,32 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dictclone(); + auto new_ast = ast->clone(); for (auto &intf : local_interfaces) { std::string intfname = intf.first.str(); RTLIL::Module *intfmodule = intf.second; for (auto w : intfmodule->wires()){ - AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(w->width -1, true), AstNode::mkconst_int(0, true))); + auto wire = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, AstNode::mkconst_int(w->width -1, true), AstNode::mkconst_int(0, true))); std::string newname = log_id(w->name); newname = intfname + "." + newname; wire->str = newname; - new_ast->children.push_back(wire); + new_ast->children.push_back(std::move(wire)); } } - AstNode *ast_before_replacing_interface_ports = new_ast->clone(); + auto ast_before_replacing_interface_ports = new_ast->clone(); // Explode all interface ports. Note this will only have an effect on 'top // level' modules. Other sub-modules will have their interface ports // exploded via the derive(..) function for (size_t i =0; ichildren.size(); i++) { - AstNode *ch2 = new_ast->children[i]; + const auto& ch2 = new_ast->children[i]; if (ch2->type == AST_INTERFACEPORT) { // Is an interface port std::string name_port = ch2->str; // Name of the interface port if (ch2->children.size() > 0) { for(size_t j=0; jchildren.size();j++) { - AstNode *ch = ch2->children[j]; + const auto& ch = ch2->children[j]; if(ch->type == AST_INTERFACEPORTTYPE) { // Found the AST node containing the type of the interface std::pair res = split_modport_from_type(ch->str); std::string interface_type = res.first; @@ -1616,11 +1617,11 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dictmodule(interface_type) != nullptr) { // Add a cell to the module corresponding to the interface port such that // it can further propagated down if needed: - AstNode *celltype_for_intf = new AstNode(AST_CELLTYPE); + auto celltype_for_intf = std::make_unique(AST_CELLTYPE); celltype_for_intf->str = interface_type; - AstNode *cell_for_intf = new AstNode(AST_CELL, celltype_for_intf); + auto cell_for_intf = std::make_unique(AST_CELL, std::move(celltype_for_intf)); cell_for_intf->str = name_port + "_inst_from_top_dummy"; - new_ast->children.push_back(cell_for_intf); + new_ast->children.push_back(std::move(cell_for_intf)); // Get all members of this non-overridden dummy interface instance: RTLIL::Module *intfmodule = design->module(interface_type); // All interfaces should at this point in time (assuming @@ -1628,9 +1629,9 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dictmodules_ AstModule *ast_module_of_interface = (AstModule*)intfmodule; std::string interface_modport_compare_str = "\\" + interface_modport; - AstNode *modport = find_modport(ast_module_of_interface->ast, interface_modport_compare_str); // modport == NULL if no modport + AstNode *modport = find_modport(ast_module_of_interface->ast.get(), interface_modport_compare_str); // modport == NULL if no modport // Iterate over all wires in the interface and add them to the module: - explode_interface_port(new_ast, intfmodule, name_port, modport); + explode_interface_port(new_ast.get(), intfmodule, name_port, modport); } break; } @@ -1642,9 +1643,7 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dictset_bool_attribute(ID::interfaces_replaced_in_module); @@ -1654,7 +1653,7 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dict ¶meters, const dict &interfaces, const dict &modports, bool /*mayfail*/) { - AstNode *new_ast = NULL; + std::unique_ptr new_ast = NULL; std::string modname = derive_common(design, parameters, &new_ast); // Since interfaces themselves may be instantiated with different parameters, @@ -1690,14 +1689,14 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, const dict 0) { std::string interface_modport = modports.at(intfname).str(); AstModule *ast_module_of_interface = (AstModule*)intfmodule; - AstNode *ast_node_of_interface = ast_module_of_interface->ast; + AstNode *ast_node_of_interface = ast_module_of_interface->ast.get(); modport = find_modport(ast_node_of_interface, interface_modport); } // Iterate over all wires in the interface and add them to the module: - explode_interface_port(new_ast, intfmodule, intfname, modport); + explode_interface_port(new_ast.get(), intfmodule, intfname, modport); } - process_module(design, new_ast, false); + process_module(design, new_ast.get(), false); design->module(modname)->check(); RTLIL::Module* mod = design->module(modname); @@ -1734,7 +1733,6 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, const dict new_ast = NULL; std::string modname = derive_common(design, parameters, &new_ast, quiet); if (!design->has(modname) && new_ast) { new_ast->str = modname; - process_module(design, new_ast, false, NULL, quiet); + process_module(design, new_ast.get(), false, NULL, quiet); design->module(modname)->check(); } else if (!quiet) { log("Found cached RTLIL representation for module `%s'.\n", modname.c_str()); } - delete new_ast; return modname; } @@ -1784,7 +1781,7 @@ std::string AST::derived_module_name(std::string stripped_name, const std::vecto } // create a new parametric module (when needed) and return the name of the generated module -std::string AstModule::derive_common(RTLIL::Design *design, const dict ¶meters, AstNode **new_ast_out, bool quiet) +std::string AstModule::derive_common(RTLIL::Design *design, const dict ¶meters, std::unique_ptr* new_ast_out, bool quiet) { std::string stripped_name = name.str(); (*new_ast_out) = nullptr; @@ -1794,7 +1791,7 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict> named_parameters; - for (const auto child : ast->children) { + for (const auto& child : ast->children) { if (child->type != AST_PARAMETER) continue; para_counter++; @@ -1828,12 +1825,12 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict rewritten; rewritten.reserve(GetSize(parameters)); - AstNode *new_ast = ast->clone(); + auto new_ast = ast->clone(); if (!new_ast->attributes.count(ID::hdlname)) new_ast->set_attribute(ID::hdlname, AstNode::mkconst_str(stripped_name.substr(1))); para_counter = 0; - for (auto child : new_ast->children) { + for (auto& child : new_ast->children) { if (child->type != AST_PARAMETER) continue; para_counter++; @@ -1853,9 +1850,8 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dictchildren.insert(child->children.begin(), nullptr); - delete child->children.at(0); if ((it->second.flags & RTLIL::CONST_FLAG_REAL) != 0) { - child->children[0] = new AstNode(AST_REALVALUE); + child->children[0] = std::make_unique(AST_REALVALUE); child->children[0]->realvalue = std::stod(it->second.decode_string()); } else if ((it->second.flags & RTLIL::CONST_FLAG_STRING) != 0) child->children[0] = AstNode::mkconst_str(it->second.decode_string()); @@ -1868,17 +1864,17 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict(AST_DEFPARAM, std::make_unique(AST_IDENTIFIER)); defparam->children[0]->str = param.first.str(); if ((param.second.flags & RTLIL::CONST_FLAG_STRING) != 0) defparam->children.push_back(AstNode::mkconst_str(param.second.decode_string())); else defparam->children.push_back(AstNode::mkconst_bits(param.second.to_bits(), (param.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0)); - new_ast->children.push_back(defparam); + new_ast->children.push_back(std::move(defparam)); } new_ast->fixup_hierarchy_flags(true); - (*new_ast_out) = new_ast; + new_ast_out->reset(new_ast.release()); return modname; } diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 2c2d408ce..4c75b6dfa 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -183,10 +183,10 @@ namespace AST AstNodeType type; // the list of child nodes for this node - std::vector children; + std::vector> children; // the list of attributes assigned to this node - std::map attributes; + std::map> attributes; bool get_bool_attribute(RTLIL::IdString id); // node content - most of it is unused in most node types @@ -212,7 +212,7 @@ namespace AST int unpacked_dimensions; // this is set by simplify and used during RTLIL generation - AstNode *id2ast; + AstNode* id2ast; // this is used by simplify to detect if basic analysis has been performed already on the node bool basic_prep; @@ -234,9 +234,9 @@ namespace AST bool in_param_from_above; // creating and deleting nodes - AstNode(AstNodeType type = AST_NONE, AstNode *child1 = nullptr, AstNode *child2 = nullptr, AstNode *child3 = nullptr, AstNode *child4 = nullptr); - AstNode *clone() const; - void cloneInto(AstNode *other) const; + AstNode(AstNodeType type = AST_NONE, std::unique_ptr child1 = nullptr, std::unique_ptr child2 = nullptr, std::unique_ptr child3 = nullptr, std::unique_ptr child4 = nullptr); + std::unique_ptr clone() const; + void cloneInto(AstNode &other) const; void delete_children(); ~AstNode(); @@ -264,15 +264,16 @@ namespace AST // simplify() creates a simpler AST by unrolling for-loops, expanding generate blocks, etc. // it also sets the id2ast pointers so that identifier lookups are fast in genRTLIL() bool simplify(bool const_fold, int stage, int width_hint, bool sign_hint); + void null_check(); void replace_result_wire_name_in_function(const std::string &from, const std::string &to); - AstNode *readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init); + std::unique_ptr readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init); void expand_genblock(const std::string &prefix); void label_genblks(std::set& existing, int &counter); void mem2reg_as_needed_pass1(dict> &mem2reg_places, dict &mem2reg_flags, dict &proc_flags, uint32_t &status_flags); - bool mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, AstNode *block, AstNode *&async_block); + bool mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, AstNode *block, AstNode* async_block); bool mem2reg_check(pool &mem2reg_set); - void mem2reg_remove(pool &mem2reg_set, vector &delnodes); + void mem2reg_remove(pool &mem2reg_set); void meminfo(int &mem_width, int &mem_size, int &addr_bits); bool detect_latch(const std::string &var); const RTLIL::Module* lookup_cell_module(); @@ -288,7 +289,7 @@ namespace AST }; bool has_const_only_constructs(); bool replace_variables(std::map &variables, AstNode *fcall, bool must_succeed); - AstNode *eval_const_function(AstNode *fcall, bool must_succeed); + std::unique_ptr eval_const_function(AstNode *fcall, bool must_succeed); bool is_simple_const_expr(); // helper for parsing format strings @@ -305,29 +306,30 @@ namespace AST std::vector genBindings() const; // used by genRTLIL() for detecting expression width and sign - void detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *found_real = NULL); - void detectSignWidth(int &width_hint, bool &sign_hint, bool *found_real = NULL); + void detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *found_real = nullptr); + void detectSignWidth(int &width_hint, bool &sign_hint, bool *found_real = nullptr); // create RTLIL code for this AST node // for expressions the resulting signal vector is returned // all generated cell instances, etc. are written to the RTLIL::Module pointed to by AST_INTERNAL::current_module RTLIL::SigSpec genRTLIL(int width_hint = -1, bool sign_hint = false); - RTLIL::SigSpec genWidthRTLIL(int width, bool sgn, const dict *new_subst_ptr = NULL); + RTLIL::SigSpec genWidthRTLIL(int width, bool sgn, const dict *new_subst_ptr = nullptr); // compare AST nodes bool operator==(const AstNode &other) const; bool operator!=(const AstNode &other) const; bool contains(const AstNode *other) const; + AstNode operator=(AstNode) = delete; // helper functions for creating AST nodes for constants - static AstNode *mkconst_int(uint32_t v, bool is_signed, int width = 32); - static AstNode *mkconst_bits(const std::vector &v, bool is_signed, bool is_unsized); - static AstNode *mkconst_bits(const std::vector &v, bool is_signed); - static AstNode *mkconst_str(const std::vector &v); - static AstNode *mkconst_str(const std::string &str); + static std::unique_ptr mkconst_int(uint32_t v, bool is_signed, int width = 32); + static std::unique_ptr mkconst_bits(const std::vector &v, bool is_signed, bool is_unsized); + static std::unique_ptr mkconst_bits(const std::vector &v, bool is_signed); + static std::unique_ptr mkconst_str(const std::vector &v); + static std::unique_ptr mkconst_str(const std::string &str); // helper function to create an AST node for a temporary register - AstNode *mktemp_logic(const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed); + std::unique_ptr mktemp_logic(const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed); // helper function for creating sign-extended const objects RTLIL::Const bitsAsConst(int width, bool is_signed); @@ -356,12 +358,12 @@ namespace AST // helper to clone the node with some of its subexpressions replaced with zero (this is used // to evaluate widths of dynamic ranges) - AstNode *clone_at_zero(); + std::unique_ptr clone_at_zero(); - void set_attribute(RTLIL::IdString key, AstNode *node) + void set_attribute(RTLIL::IdString key, std::unique_ptr node) { - attributes[key] = node; node->set_in_param_flag(true); + attributes[key] = std::move(node); } // helper to set in_lvalue/in_param flags from the hierarchy context (the actual flag @@ -377,7 +379,7 @@ namespace AST void fixup_hierarchy_flags(bool force_descend = false); // helpers for indexing - AstNode *make_index_range(AstNode *node, bool unpacked_range = false); + std::unique_ptr make_index_range(AstNode *node, bool unpacked_range = false); AstNode *get_struct_member() const; // helper to print errors from simplify/genrtlil code @@ -391,12 +393,11 @@ namespace AST // parametric modules are supported directly by the AST library // therefore we need our own derivate of RTLIL::Module with overloaded virtual functions struct AstModule : RTLIL::Module { - AstNode *ast; + std::unique_ptr ast; bool nolatches, nomeminit, nomem2reg, mem2reg, noblackbox, lib, nowb, noopt, icells, pwires, autowire; - ~AstModule() override; RTLIL::IdString derive(RTLIL::Design *design, const dict ¶meters, bool mayfail) override; RTLIL::IdString derive(RTLIL::Design *design, const dict ¶meters, const dict &interfaces, const dict &modports, bool mayfail) override; - std::string derive_common(RTLIL::Design *design, const dict ¶meters, AstNode **new_ast_out, bool quiet = false); + std::string derive_common(RTLIL::Design *design, const dict ¶meters, std::unique_ptr* new_ast_out, bool quiet = false); void expand_interfaces(RTLIL::Design *design, const dict &local_interfaces) override; bool reprocess_if_necessary(RTLIL::Design *design) override; RTLIL::Module *clone() const override; @@ -407,8 +408,8 @@ namespace AST // the AstNode constructor then uses current_filename and get_line_num() // to initialize the filename and linenum properties of new nodes extern std::string current_filename; - extern void (*set_line_num)(int); - extern int (*get_line_num)(); + // also set by the language frontend to control some AST processing + extern bool sv_mode; // for stats unsigned long long astnode_count(); @@ -418,7 +419,7 @@ namespace AST void use_internal_line_num(); // call a DPI function - AstNode *dpi_call(const std::string &rtype, const std::string &fname, const std::vector &argtypes, const std::vector &args); + std::unique_ptr dpi_call(const std::string &rtype, const std::string &fname, const std::vector &argtypes, const std::vector> &args); // Helper functions related to handling SystemVerilog interfaces std::pair split_modport_from_type(std::string name_type); @@ -464,7 +465,7 @@ namespace AST_INTERNAL process_and_replace_module(RTLIL::Design *design, RTLIL::Module *old_module, AST::AstNode *new_ast, - AST::AstNode *original_ast = nullptr); + std::unique_ptr original_ast = nullptr); } YOSYS_NAMESPACE_END diff --git a/frontends/ast/dpicall.cc b/frontends/ast/dpicall.cc index d6fcc26bd..4fa375df7 100644 --- a/frontends/ast/dpicall.cc +++ b/frontends/ast/dpicall.cc @@ -64,9 +64,9 @@ static ffi_fptr resolve_fn (std::string symbol_name) log_error("unable to resolve '%s'.\n", symbol_name.c_str()); } -AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname, const std::vector &argtypes, const std::vector &args) +std::unique_ptr AST::dpi_call(const std::string &rtype, const std::string &fname, const std::vector &argtypes, const std::vector> &args) { - AST::AstNode *newNode = nullptr; + std::unique_ptr newNode = nullptr; union value { double f64; float f32; int32_t i32; void *ptr; }; std::vector value_store(args.size() + 1); std::vector types(args.size() + 1); @@ -125,11 +125,11 @@ AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname, ffi_call(&cif, resolve_fn(fname.c_str()), values[args.size()], values.data()); if (rtype == "real") { - newNode = new AstNode(AST_REALVALUE); + newNode = std::make_unique(AST_REALVALUE); newNode->realvalue = value_store[args.size()].f64; log(" return realvalue: %g\n", newNode->asReal(true)); } else if (rtype == "shortreal") { - newNode = new AstNode(AST_REALVALUE); + newNode = std::make_unique(AST_REALVALUE); newNode->realvalue = value_store[args.size()].f32; log(" return realvalue: %g\n", newNode->asReal(true)); } else if (rtype == "chandle") { diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 26ed0e3e4..fcc91adfc 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -85,7 +85,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s set_src_attr(wire, that); wire->is_signed = that->is_signed; - if (that != NULL) + if (that != nullptr) for (auto &attr : that->attributes) { if (attr.second->type != AST_CONSTANT) that->input_error("Attribute `%s' with non-constant value!\n", attr.first.c_str()); @@ -195,22 +195,22 @@ struct AST_INTERNAL::LookaheadRewriter if (node->lookahead) { log_assert(node->type == AST_IDENTIFIER); if (!lookaheadids.count(node->str)) { - AstNode *wire = new AstNode(AST_WIRE); - for (auto c : node->id2ast->children) + auto wire = std::make_unique(AST_WIRE); + for (auto& c : node->id2ast->children) wire->children.push_back(c->clone()); wire->fixup_hierarchy_flags(); wire->str = stringf("$lookahead%s$%d", node->str.c_str(), autoidx++); wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); wire->is_logic = true; while (wire->simplify(true, 1, -1, false)) { } - current_ast_mod->children.push_back(wire); - lookaheadids[node->str] = make_pair(node->id2ast, wire); + lookaheadids[node->str] = make_pair(node->id2ast, wire.get()); wire->genRTLIL(); + current_ast_mod->children.push_back(std::move(wire)); } } - for (auto child : node->children) - collect_lookaheadids(child); + for (auto& child : node->children) + collect_lookaheadids(child.get()); } bool has_lookaheadids(AstNode *node) @@ -218,8 +218,8 @@ struct AST_INTERNAL::LookaheadRewriter if (node->type == AST_IDENTIFIER && lookaheadids.count(node->str) != 0) return true; - for (auto child : node->children) - if (has_lookaheadids(child)) + for (auto& child : node->children) + if (has_lookaheadids(child.get())) return true; return false; @@ -230,8 +230,8 @@ struct AST_INTERNAL::LookaheadRewriter if (node->type == AST_IDENTIFIER && lookaheadids.count(node->str) == 0) return true; - for (auto child : node->children) - if (has_nonlookaheadids(child)) + for (auto& child : node->children) + if (has_nonlookaheadids(child.get())) return true; return false; @@ -241,16 +241,16 @@ struct AST_INTERNAL::LookaheadRewriter { if (node->type == AST_ASSIGN_LE) { - if (has_lookaheadids(node->children[0])) + if (has_lookaheadids(node->children[0].get())) { - if (has_nonlookaheadids(node->children[0])) + if (has_nonlookaheadids(node->children[0].get())) log_error("incompatible mix of lookahead and non-lookahead IDs in LHS expression.\n"); - rewrite_lookaheadids(node->children[0], true); + rewrite_lookaheadids(node->children[0].get(), true); node->type = AST_ASSIGN_EQ; } - rewrite_lookaheadids(node->children[1], lhs); + rewrite_lookaheadids(node->children[1].get(), lhs); return; } @@ -261,21 +261,21 @@ struct AST_INTERNAL::LookaheadRewriter lhs = false; } - for (auto child : node->children) - rewrite_lookaheadids(child, lhs); + for (auto& child : node->children) + rewrite_lookaheadids(child.get(), lhs); } LookaheadRewriter(AstNode *top) { - // top->dumpAst(NULL, "REWRITE-BEFORE> "); - // top->dumpVlog(NULL, "REWRITE-BEFORE> "); + // top->dumpAst(nullptr, "REWRITE-BEFORE> "); + // top->dumpVlog(nullptr, "REWRITE-BEFORE> "); AstNode *block = nullptr; - for (auto c : top->children) + for (auto& c : top->children) if (c->type == AST_BLOCK) { log_assert(block == nullptr); - block = c; + block = c.get(); } log_assert(block != nullptr); @@ -284,25 +284,25 @@ struct AST_INTERNAL::LookaheadRewriter for (auto it : lookaheadids) { - AstNode *ref_orig = new AstNode(AST_IDENTIFIER); + auto ref_orig = std::make_unique(AST_IDENTIFIER); ref_orig->str = it.second.first->str; ref_orig->id2ast = it.second.first; ref_orig->was_checked = true; - AstNode *ref_temp = new AstNode(AST_IDENTIFIER); + auto ref_temp = std::make_unique(AST_IDENTIFIER); ref_temp->str = it.second.second->str; ref_temp->id2ast = it.second.second; ref_temp->was_checked = true; - AstNode *init_assign = new AstNode(AST_ASSIGN_EQ, ref_temp->clone(), ref_orig->clone()); - AstNode *final_assign = new AstNode(AST_ASSIGN_LE, ref_orig, ref_temp); + auto init_assign = std::make_unique(AST_ASSIGN_EQ, ref_temp->clone(), ref_orig->clone()); + auto final_assign = std::make_unique(AST_ASSIGN_LE, std::move(ref_orig), std::move(ref_temp)); - block->children.insert(block->children.begin(), init_assign); - block->children.push_back(final_assign); + block->children.insert(block->children.begin(), std::move(init_assign)); + block->children.push_back(std::move(final_assign)); } - // top->dumpAst(NULL, "REWRITE-AFTER> "); - // top->dumpVlog(NULL, "REWRITE-AFTER> "); + // top->dumpAst(nullptr, "REWRITE-AFTER> "); + // top->dumpVlog(nullptr, "REWRITE-AFTER> "); } }; @@ -310,7 +310,7 @@ struct AST_INTERNAL::LookaheadRewriter struct AST_INTERNAL::ProcessGenerator { // input and output structures - AstNode *always; + std::unique_ptr always; RTLIL::SigSpec initSyncSignals; RTLIL::Process *proc; RTLIL::SigSpec outputSignals; @@ -341,14 +341,14 @@ struct AST_INTERNAL::ProcessGenerator // The most recently assigned $print or $check cell \PRIORITY. int last_effect_priority; - ProcessGenerator(AstNode *always, RTLIL::SigSpec initSyncSignalsArg = RTLIL::SigSpec()) : always(always), initSyncSignals(initSyncSignalsArg), last_effect_priority(0) + ProcessGenerator(std::unique_ptr a, RTLIL::SigSpec initSyncSignalsArg = RTLIL::SigSpec()) : always(std::move(a)), initSyncSignals(initSyncSignalsArg), last_effect_priority(0) { // rewrite lookahead references - LookaheadRewriter la_rewriter(always); + LookaheadRewriter la_rewriter(always.get()); // generate process and simple root case proc = current_module->addProcess(stringf("$proc$%s:%d$%d", RTLIL::encode_filename(always->filename).c_str(), always->location.first_line, autoidx++)); - set_src_attr(proc, always); + set_src_attr(proc, always.get()); for (auto &attr : always->attributes) { if (attr.second->type != AST_CONSTANT) always->input_error("Attribute `%s' with non-constant value!\n", attr.first.c_str()); @@ -358,13 +358,13 @@ struct AST_INTERNAL::ProcessGenerator // create initial temporary signal for all output registers RTLIL::SigSpec subst_lvalue_from, subst_lvalue_to; - collect_lvalues(subst_lvalue_from, always, true, true); + collect_lvalues(subst_lvalue_from, always.get(), true, true); subst_lvalue_to = new_temp_signal(subst_lvalue_from); subst_lvalue_map = subst_lvalue_from.to_sigbit_map(subst_lvalue_to); bool found_global_syncs = false; bool found_anyedge_syncs = false; - for (auto child : always->children) + for (auto& child : always->children) { if ((child->type == AST_POSEDGE || child->type == AST_NEGEDGE) && GetSize(child->children) == 1 && child->children.at(0)->type == AST_IDENTIFIER && child->children.at(0)->id2ast && child->children.at(0)->id2ast->type == AST_WIRE && child->children.at(0)->id2ast->get_bool_attribute(ID::gclk)) { @@ -388,7 +388,7 @@ struct AST_INTERNAL::ProcessGenerator // create syncs for the process bool found_clocked_sync = false; - for (auto child : always->children) + for (auto& child : always->children) if (child->type == AST_POSEDGE || child->type == AST_NEGEDGE) { if (GetSize(child->children) == 1 && child->children.at(0)->type == AST_IDENTIFIER && child->children.at(0)->id2ast && child->children.at(0)->id2ast->type == AST_WIRE && child->children.at(0)->id2ast->get_bool_attribute(ID::gclk)) @@ -420,9 +420,9 @@ struct AST_INTERNAL::ProcessGenerator } // process the AST - for (auto child : always->children) + for (auto& child : always->children) if (child->type == AST_BLOCK) - processAst(child); + processAst(child.get()); for (auto sync: proc->syncs) processMemWrites(sync); @@ -472,7 +472,7 @@ struct AST_INTERNAL::ProcessGenerator for (int i = 0; i < GetSize(chunks); i++) { RTLIL::SigChunk &chunk = chunks[i]; - if (chunk.wire == NULL) + if (chunk.wire == nullptr) continue; std::string wire_name; @@ -484,7 +484,7 @@ struct AST_INTERNAL::ProcessGenerator } while (current_module->wires_.count(wire_name) > 0); RTLIL::Wire *wire = current_module->addWire(wire_name, chunk.width); - set_src_attr(wire, always); + set_src_attr(wire, always.get()); chunk.wire = wire; chunk.offset = 0; @@ -499,10 +499,10 @@ struct AST_INTERNAL::ProcessGenerator switch (ast->type) { case AST_CASE: - for (auto child : ast->children) + for (auto& child : ast->children) if (child != ast->children[0]) { log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ); - collect_lvalues(reg, child, type_eq, type_le, false); + collect_lvalues(reg, child.get(), type_eq, type_le, false); } break; @@ -511,19 +511,19 @@ struct AST_INTERNAL::ProcessGenerator case AST_CONDZ: case AST_ALWAYS: case AST_INITIAL: - for (auto child : ast->children) + for (auto& child : ast->children) if (child->type == AST_BLOCK) - collect_lvalues(reg, child, type_eq, type_le, false); + collect_lvalues(reg, child.get(), type_eq, type_le, false); break; case AST_BLOCK: - for (auto child : ast->children) { + for (auto& child : ast->children) { if (child->type == AST_ASSIGN_EQ && type_eq) reg.append(child->children[0]->genRTLIL()); if (child->type == AST_ASSIGN_LE && type_le) reg.append(child->children[0]->genRTLIL()); if (child->type == AST_CASE || child->type == AST_BLOCK) - collect_lvalues(reg, child, type_eq, type_le, false); + collect_lvalues(reg, child.get(), type_eq, type_le, false); } break; @@ -583,8 +583,8 @@ struct AST_INTERNAL::ProcessGenerator switch (ast->type) { case AST_BLOCK: - for (auto child : ast->children) - processAst(child); + for (auto& child : ast->children) + processAst(child.get()); break; case AST_ASSIGN_EQ: @@ -641,9 +641,9 @@ struct AST_INTERNAL::ProcessGenerator RTLIL::SigSpec this_case_eq_rvalue = this_case_eq_lvalue; this_case_eq_rvalue.replace(subst_rvalue_map.stdmap()); - RTLIL::CaseRule *default_case = NULL; - RTLIL::CaseRule *last_generated_case = NULL; - for (auto child : ast->children) + RTLIL::CaseRule *default_case = nullptr; + RTLIL::CaseRule *last_generated_case = nullptr; + for (auto& child : ast->children) { if (child == ast->children[0]) continue; @@ -657,14 +657,14 @@ struct AST_INTERNAL::ProcessGenerator RTLIL::CaseRule *backup_case = current_case; current_case = new RTLIL::CaseRule; - set_src_attr(current_case, child); + set_src_attr(current_case, child.get()); last_generated_case = current_case; addChunkActions(current_case->actions, this_case_eq_ltemp, this_case_eq_rvalue); - for (auto node : child->children) { + for (auto& node : child->children) { if (node->type == AST_DEFAULT) default_case = current_case; else if (node->type == AST_BLOCK) - processAst(node); + processAst(node.get()); else current_case->compare.push_back(node->genWidthRTLIL(width_hint, sign_hint, &subst_rvalue_map.stdmap())); } @@ -678,7 +678,7 @@ struct AST_INTERNAL::ProcessGenerator subst_rvalue_map.restore(); } - if (last_generated_case != NULL && ast->get_bool_attribute(ID::full_case) && default_case == NULL) { + if (last_generated_case != nullptr && ast->get_bool_attribute(ID::full_case) && default_case == nullptr) { #if 0 // this is a valid transformation, but as optimization it is premature. // better: add a default case that assigns 'x' to everything, and let later @@ -690,7 +690,7 @@ struct AST_INTERNAL::ProcessGenerator sw->cases.push_back(default_case); #endif } else { - if (default_case == NULL) { + if (default_case == nullptr) { default_case = new RTLIL::CaseRule; addChunkActions(default_case->actions, this_case_eq_ltemp, this_case_eq_rvalue); } @@ -760,7 +760,7 @@ struct AST_INTERNAL::ProcessGenerator default_base = 16; std::vector args; - for (auto node : ast->children) { + for (auto& node : ast->children) { int width; bool is_signed; node->detectSignWidth(width, is_signed, nullptr); @@ -866,8 +866,8 @@ struct AST_INTERNAL::ProcessGenerator break; default: - // ast->dumpAst(NULL, "ast> "); - // current_ast_mod->dumpAst(NULL, "mod> "); + // ast->dumpAst(nullptr, "ast> "); + // current_ast_mod->dumpAst(nullptr, "mod> "); log_abort(); } } @@ -876,14 +876,14 @@ struct AST_INTERNAL::ProcessGenerator { // Maps per-memid AST_MEMWR IDs to indices in the mem_write_actions array. dict, int> port_map; - for (auto child : always->children) + for (auto& child : always->children) if (child->type == AST_MEMWR) { std::string memid = child->str; int portid = child->children[3]->asInt(false); int cur_idx = GetSize(sync->mem_write_actions); RTLIL::MemWriteAction action; - set_src_attr(&action, child); + set_src_attr(&action, child.get()); action.memid = memid; action.address = child->children[0]->genWidthRTLIL(-1, true, &subst_rvalue_map.stdmap()); action.data = child->children[1]->genWidthRTLIL(current_module->memories[memid]->width, true, &subst_rvalue_map.stdmap()); @@ -971,11 +971,11 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun bool sub_sign_hint = true; int sub_width_hint = -1; int this_width = 0; - AstNode *range = NULL; - AstNode *id_ast = NULL; + AstNode *range = nullptr; + AstNode *id_ast = nullptr; bool local_found_real = false; - if (found_real == NULL) + if (found_real == nullptr) found_real = &local_found_real; switch (type) @@ -1019,22 +1019,22 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun input_error("Failed to detect width for parameter %s!\n", str.c_str()); } if (children.size() != 0) - range = children[0]; + range = children[0].get(); } else if (id_ast->type == AST_WIRE || id_ast->type == AST_AUTOWIRE) { if (!id_ast->range_valid) { if (id_ast->type == AST_AUTOWIRE) this_width = 1; else { - // current_ast_mod->dumpAst(NULL, "mod> "); + // current_ast_mod->dumpAst(nullptr, "mod> "); // log("---\n"); - // id_ast->dumpAst(NULL, "decl> "); - // dumpAst(NULL, "ref> "); + // id_ast->dumpAst(nullptr, "decl> "); + // dumpAst(nullptr, "ref> "); input_error("Failed to detect width of signal access `%s'!\n", str.c_str()); } } else { this_width = id_ast->range_left - id_ast->range_right + 1; if (children.size() != 0) - range = children[0]; + range = children[0].get(); } } else if (id_ast->type == AST_GENVAR) { this_width = 32; @@ -1043,26 +1043,23 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun input_error("Failed to detect width of memory access `%s'!\n", str.c_str()); this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1; if (children.size() > 1) - range = children[1]; + range = children[1].get(); } else if (id_ast->type == AST_STRUCT_ITEM || id_ast->type == AST_STRUCT || id_ast->type == AST_UNION) { - AstNode *tmp_range = make_index_range(id_ast); + auto tmp_range = make_index_range(id_ast); this_width = tmp_range->range_left - tmp_range->range_right + 1; - delete tmp_range; } else input_error("Failed to detect width for identifier %s!\n", str.c_str()); if (range) { if (range->children.size() == 1) this_width = 1; else if (!range->range_valid) { - AstNode *left_at_zero_ast = children[0]->children[0]->clone_at_zero(); - AstNode *right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone_at_zero() : left_at_zero_ast->clone(); + auto left_at_zero_ast = children[0]->children[0]->clone_at_zero(); + auto right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone_at_zero() : left_at_zero_ast->clone(); while (left_at_zero_ast->simplify(true, 1, -1, false)) { } while (right_at_zero_ast->simplify(true, 1, -1, false)) { } if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) input_error("Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); this_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; - delete left_at_zero_ast; - delete right_at_zero_ast; } else this_width = range->range_left - range->range_right + 1; sign_hint = false; @@ -1106,7 +1103,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun break; case AST_CONCAT: - for (auto child : children) { + for (auto& child : children) { sub_width_hint = 0; sub_sign_hint = true; child->detectSignWidthWorker(sub_width_hint, sub_sign_hint); @@ -1135,7 +1132,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun case AST_BIT_OR: case AST_BIT_XOR: case AST_BIT_XNOR: - for (auto child : children) + for (auto& child : children) child->detectSignWidthWorker(width_hint, sign_hint, found_real); break; @@ -1175,7 +1172,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun case AST_MUL: case AST_DIV: case AST_MOD: - for (auto child : children) + for (auto& child : children) child->detectSignWidthWorker(width_hint, sign_hint, found_real); break; @@ -1216,12 +1213,13 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun width_hint = max(width_hint, sub_width_hint); sign_hint &= sub_sign_hint; }; - visit_case_expr(children[0]); + visit_case_expr(children[0].get()); for (size_t i = 1; i < children.size(); i++) { - AstNode *child = children[i]; - for (AstNode *v : child->children) + AstNode *child = children[i].get(); + for (auto& v : child->children) { if (v->type != AST_DEFAULT && v->type != AST_BLOCK) - visit_case_expr(v); + visit_case_expr(v.get()); + } } break; } @@ -1269,9 +1267,9 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun if (func->type != AST_FUNCTION) input_error("Function call to %s resolved to something that isn't a function!\n", RTLIL::unescape_id(str).c_str()); const AstNode *wire = nullptr; - for (const AstNode *child : func->children) + for (const auto& child : func->children) if (child->str == func->str) { - wire = child; + wire = child.get(); break; } log_assert(wire && wire->type == AST_WIRE); @@ -1280,10 +1278,10 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun if (!wire->children.empty()) { log_assert(wire->children.size() == 1); - const AstNode *range = wire->children.at(0); + const AstNode *range = wire->children.at(0).get(); log_assert(range->type == AST_RANGE && range->children.size() == 2); - AstNode *left = range->children.at(0)->clone(); - AstNode *right = range->children.at(1)->clone(); + auto left = range->children.at(0)->clone(); + auto right = range->children.at(1)->clone(); left->set_in_param_flag(true); right->set_in_param_flag(true); while (left->simplify(true, 1, -1, false)) { } @@ -1292,8 +1290,6 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun input_error("Function %s has non-constant width!", RTLIL::unescape_id(str).c_str()); result_width = abs(int(left->asInt(true) - right->asInt(true))); - delete left; - delete right; } width_hint = max(width_hint, result_width); break; @@ -1306,6 +1302,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun for (auto f : log_files) current_scope_ast->dumpAst(f, "verilog-ast> "); input_error("Don't know how to detect sign and width for %s node!\n", type2str(type).c_str()); + } if (*found_real) @@ -1517,11 +1514,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) // shifter cell is created and the output signal of this cell is returned case AST_IDENTIFIER: { - RTLIL::Wire *wire = NULL; + RTLIL::Wire *wire = nullptr; RTLIL::SigChunk chunk; bool is_interface = false; - AST::AstNode *member_node = NULL; + AST::AstNode *member_node = nullptr; int add_undef_bits_msb = 0; int add_undef_bits_lsb = 0; @@ -1608,14 +1605,14 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) } if (!children[0]->range_valid) { - AstNode *left_at_zero_ast = children[0]->children[0]->clone_at_zero(); - AstNode *right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone_at_zero() : left_at_zero_ast->clone(); + auto left_at_zero_ast = children[0]->children[0]->clone_at_zero(); + auto right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone_at_zero() : left_at_zero_ast->clone(); while (left_at_zero_ast->simplify(true, 1, -1, false)) { } while (right_at_zero_ast->simplify(true, 1, -1, false)) { } if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) input_error("Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; - AstNode *fake_ast = new AstNode(AST_NONE, clone(), children[0]->children.size() >= 2 ? + auto fake_ast = new AstNode(AST_NONE, clone(), children[0]->children.size() >= 2 ? children[0]->children[1]->clone() : children[0]->children[0]->clone()); fake_ast->children[0]->delete_children(); if (member_node) @@ -1637,9 +1634,6 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (GetSize(shift_val) >= 32) fake_ast->children[1]->is_signed = true; RTLIL::SigSpec sig = binop2rtlil(fake_ast, ID($shiftx), width, fake_ast->children[0]->genRTLIL(), shift_val); - delete left_at_zero_ast; - delete right_at_zero_ast; - delete fake_ast; return sig; } else { chunk.width = children[0]->range_left - children[0]->range_right + 1; @@ -2092,7 +2086,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) cell->set_bool_attribute(ID::module_not_derived); for (auto it = children.begin(); it != children.end(); it++) { - AstNode *child = *it; + AstNode *child = it->get(); if (child->type == AST_CELLTYPE) { cell->type = child->str; if (flag_icells && cell->type.begins_with("\\$")) @@ -2101,7 +2095,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) } if (child->type == AST_PARASET) { IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str; - const AstNode *value = child->children[0]; + const AstNode *value = child->children[0].get(); if (value->type == AST_REALVALUE) log_file_warning(filename, location.first_line, "Replacing floating point parameter %s.%s = %f with string.\n", log_id(cell), log_id(paraname), value->realvalue); @@ -2114,7 +2108,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (child->type == AST_ARGUMENT) { RTLIL::SigSpec sig; if (child->children.size() > 0) { - AstNode *arg = child->children[0]; + AstNode *arg = child->children[0].get(); int local_width_hint = -1; bool local_sign_hint = false; // don't inadvertently attempt to detect the width of interfaces @@ -2186,16 +2180,14 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) // use ProcessGenerator for always blocks case AST_ALWAYS: { - AstNode *always = this->clone(); - ProcessGenerator generator(always); + auto always = this->clone(); + ProcessGenerator generator(std::move(always)); ignoreThisSignalsInInitial.append(generator.outputSignals); - delete always; } break; case AST_INITIAL: { - AstNode *always = this->clone(); - ProcessGenerator generator(always, ignoreThisSignalsInInitial); - delete always; + auto always = this->clone(); + ProcessGenerator generator(std::move(always), ignoreThisSignalsInInitial); } break; case AST_TECALL: { diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 05621d857..d306c6022 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -35,6 +35,7 @@ #include #include #include +#include // For std::gcd in C++17 // #include @@ -87,7 +88,7 @@ void AstNode::fixup_hierarchy_flags(bool force_descend) case AST_PARASET: case AST_PREFIX: in_param = true; - for (auto child : children) + for (auto& child : children) child->set_in_param_flag(true, force_descend); break; @@ -95,7 +96,7 @@ void AstNode::fixup_hierarchy_flags(bool force_descend) case AST_WIRE: case AST_GENIF: case AST_GENCASE: - for (auto child : children) + for (auto& child : children) child->set_in_param_flag(in_param, force_descend); if (children.size() >= 1) children[0]->set_in_param_flag(true, force_descend); @@ -103,19 +104,21 @@ void AstNode::fixup_hierarchy_flags(bool force_descend) case AST_GENFOR: case AST_FOR: - for (auto child : children) + for (auto& child : children) { + log_assert((bool)child); child->set_in_param_flag(in_param, force_descend); + } if (children.size() >= 2) children[1]->set_in_param_flag(true, force_descend); break; default: in_param = in_param_from_above; - for (auto child : children) + for (auto& child : children) child->set_in_param_flag(in_param, force_descend); } - for (auto attr : attributes) + for (auto& attr : attributes) attr.second->set_in_param_flag(true, force_descend); in_lvalue = in_lvalue_from_above; @@ -131,14 +134,14 @@ void AstNode::fixup_hierarchy_flags(bool force_descend) break; default: - for (auto child : children) + for (auto& child : children) child->set_in_lvalue_flag(in_lvalue, force_descend); } if (force_descend) { - for (auto child : children) + for (auto& child : children) child->fixup_hierarchy_flags(true); - for (auto attr : attributes) + for (auto& attr : attributes) attr.second->fixup_hierarchy_flags(true); } } @@ -148,7 +151,7 @@ void AstNode::fixup_hierarchy_flags(bool force_descend) Fmt AstNode::processFormat(int stage, bool sformat_like, int default_base, size_t first_arg_at, bool may_fail) { std::vector args; for (size_t index = first_arg_at; index < children.size(); index++) { - AstNode *node_arg = children[index]; + AstNode *node_arg = children[index].get(); while (node_arg->simplify(true, stage, -1, false)) { } VerilogFmtArg arg = {}; @@ -199,7 +202,7 @@ void AstNode::annotateTypedEnums(AstNode *template_node) while (enum_node->simplify(true, 1, -1, false)) { } //get width from 1st enum item: log_assert(enum_node->children.size() >= 1); - AstNode *enum_item0 = enum_node->children[0]; + AstNode *enum_item0 = enum_node->children[0].get(); log_assert(enum_item0->type == AST_ENUM_ITEM); int width; if (!enum_item0->range_valid) @@ -210,7 +213,7 @@ void AstNode::annotateTypedEnums(AstNode *template_node) width = enum_item0->range_left - enum_item0->range_right + 1; log_assert(width > 0); //add declared enum items: - for (auto enum_item : enum_node->children){ + for (auto& enum_item : enum_node->children){ log_assert(enum_item->type == AST_ENUM_ITEM); //get is_signed bool is_signed; @@ -242,10 +245,10 @@ void AstNode::annotateTypedEnums(AstNode *template_node) } } -static AstNode *make_range(int left, int right, bool is_signed = false) +static std::unique_ptr make_range(int left, int right, bool is_signed = false) { // generate a pre-validated range node for a fixed signal range. - auto range = new AstNode(AST_RANGE); + auto range = std::make_unique(AST_RANGE); range->range_left = left; range->range_right = right; range->range_valid = true; @@ -287,7 +290,7 @@ static int size_packed_struct(AstNode *snode, int base_offset) int packed_width = -1; // examine members from last to first for (auto it = snode->children.rbegin(); it != snode->children.rend(); ++it) { - auto node = *it; + auto node = it->get(); int width; if (node->type == AST_STRUCT || node->type == AST_UNION) { // embedded struct or union @@ -297,14 +300,14 @@ static int size_packed_struct(AstNode *snode, int base_offset) log_assert(node->type == AST_STRUCT_ITEM); if (node->children.size() > 0 && node->children[0]->type == AST_RANGE) { // member width e.g. bit [7:0] a - width = range_width(node, node->children[0]); + width = range_width(node, node->children[0].get()); if (node->children.size() == 2) { // Unpacked array. Note that this is a Yosys extension; only packed data types // and integer data types are allowed in packed structs / unions in SystemVerilog. if (node->children[1]->type == AST_RANGE) { // Unpacked array, e.g. bit [63:0] a [0:3] // Pretend it's declared as a packed array, e.g. bit [0:3][63:0] a - auto rnode = node->children[1]; + auto rnode = node->children[1].get(); if (rnode->children.size() == 1) { // C-style array size, e.g. bit [63:0] a [4] node->dimensions.push_back({ 0, rnode->range_left, true }); @@ -312,7 +315,7 @@ static int size_packed_struct(AstNode *snode, int base_offset) } else { width *= add_dimension(node, rnode); } - add_dimension(node, node->children[0]); + add_dimension(node, node->children[0].get()); } else { // The Yosys extension for unpacked arrays in packed structs / unions @@ -321,11 +324,9 @@ static int size_packed_struct(AstNode *snode, int base_offset) } } else { // Vector - add_dimension(node, node->children[0]); + add_dimension(node, node->children[0].get()); } // range nodes are now redundant - for (AstNode *child : node->children) - delete child; node->children.clear(); } else if (node->children.size() > 0 && node->children[0]->type == AST_MULTIRANGE) { @@ -336,12 +337,10 @@ static int size_packed_struct(AstNode *snode, int base_offset) struct_array_packing_error(node); } width = 1; - for (auto rnode : node->children[0]->children) { - width *= add_dimension(node, rnode); + for (auto& rnode : node->children[0]->children) { + width *= add_dimension(node, rnode.get()); } // range nodes are now redundant - for (AstNode *child : node->children) - delete child; node->children.clear(); } else if (node->range_left < 0) { @@ -389,49 +388,49 @@ static int size_packed_struct(AstNode *snode, int base_offset) return width; } -static AstNode *node_int(int ival) +static std::unique_ptr node_int(int ival) { return AstNode::mkconst_int(ival, true); } -static AstNode *multiply_by_const(AstNode *expr_node, int stride) +static std::unique_ptr multiply_by_const(std::unique_ptr expr_node, int stride) { - return new AstNode(AST_MUL, expr_node, node_int(stride)); + return std::make_unique(AST_MUL, std::move(expr_node), node_int(stride)); } -static AstNode *normalize_index(AstNode *expr, AstNode *decl_node, int dimension) +static std::unique_ptr normalize_index(AstNode *expr, AstNode *decl_node, int dimension) { - expr = expr->clone(); + auto new_expr = expr->clone(); int offset = decl_node->dimensions[dimension].range_right; if (offset) { - expr = new AstNode(AST_SUB, expr, node_int(offset)); + new_expr = std::make_unique(AST_SUB, std::move(new_expr), node_int(offset)); } // Packed dimensions are normally indexed by lsb, while unpacked dimensions are normally indexed by msb. if ((dimension < decl_node->unpacked_dimensions) ^ decl_node->dimensions[dimension].range_swapped) { // Swap the index if the dimension is declared the "wrong" way. int left = decl_node->dimensions[dimension].range_width - 1; - expr = new AstNode(AST_SUB, node_int(left), expr); + new_expr = std::make_unique(AST_SUB, node_int(left), std::move(new_expr)); } - return expr; + return new_expr; } -static AstNode *index_offset(AstNode *offset, AstNode *rnode, AstNode *decl_node, int dimension, int &stride) +static std::unique_ptr index_offset(std::unique_ptr offset, AstNode *rnode, AstNode *decl_node, int dimension, int &stride) { stride /= decl_node->dimensions[dimension].range_width; - auto right = normalize_index(rnode->children.back(), decl_node, dimension); - auto add_offset = stride > 1 ? multiply_by_const(right, stride) : right; - return offset ? new AstNode(AST_ADD, offset, add_offset) : add_offset; + auto right = normalize_index(rnode->children.back().get(), decl_node, dimension); + auto add_offset = stride > 1 ? multiply_by_const(std::move(right), stride) : std::move(right); + return offset ? std::make_unique(AST_ADD, std::move(offset), std::move(add_offset)) : std::move(add_offset); } -static AstNode *index_msb_offset(AstNode *lsb_offset, AstNode *rnode, AstNode *decl_node, int dimension, int stride) +static std::unique_ptr index_msb_offset(std::unique_ptr lsb_offset, AstNode *rnode, AstNode *decl_node, int dimension, int stride) { log_assert(rnode->children.size() <= 2); // Offset to add to LSB - AstNode *add_offset; + std::unique_ptr add_offset; if (rnode->children.size() == 1) { // Index, e.g. s.a[i] add_offset = node_int(stride - 1); @@ -439,21 +438,21 @@ static AstNode *index_msb_offset(AstNode *lsb_offset, AstNode *rnode, AstNode *d else { // rnode->children.size() == 2 // Slice, e.g. s.a[i:j] - auto left = normalize_index(rnode->children[0], decl_node, dimension); - auto right = normalize_index(rnode->children[1], decl_node, dimension); - add_offset = new AstNode(AST_SUB, left, right); + auto left = normalize_index(rnode->children[0].get(), decl_node, dimension); + auto right = normalize_index(rnode->children[1].get(), decl_node, dimension); + add_offset = std::make_unique(AST_SUB, std::move(left), std::move(right)); if (stride > 1) { // offset = (msb - lsb + 1)*stride - 1 - auto slice_width = new AstNode(AST_ADD, add_offset, node_int(1)); - add_offset = new AstNode(AST_SUB, multiply_by_const(slice_width, stride), node_int(1)); + auto slice_width = std::make_unique(AST_ADD, std::move(add_offset), node_int(1)); + add_offset = std::make_unique(AST_SUB, multiply_by_const(std::move(slice_width), stride), node_int(1)); } } - return new AstNode(AST_ADD, lsb_offset, add_offset); + return std::make_unique(AST_ADD, std::move(lsb_offset), std::move(add_offset)); } -AstNode *AstNode::make_index_range(AstNode *decl_node, bool unpacked_range) +std::unique_ptr AstNode::make_index_range(AstNode *decl_node, bool unpacked_range) { // Work out the range in the packed array that corresponds to a struct member // taking into account any range operations applicable to the current node @@ -466,8 +465,8 @@ AstNode *AstNode::make_index_range(AstNode *decl_node, bool unpacked_range) log_assert(children.size() == 1); // Range operations - AstNode *rnode = children[0]; - AstNode *offset = NULL; + AstNode *rnode = children[0].get(); + std::unique_ptr offset = nullptr; int dim = unpacked_range ? 0 : decl_node->unpacked_dimensions; int max_dim = unpacked_range ? decl_node->unpacked_dimensions : GetSize(decl_node->dimensions); @@ -478,15 +477,15 @@ AstNode *AstNode::make_index_range(AstNode *decl_node, bool unpacked_range) // Calculate LSB offset for the final index / slice if (rnode->type == AST_RANGE) { - offset = index_offset(offset, rnode, decl_node, dim, stride); + offset = index_offset(std::move(offset), rnode, decl_node, dim, stride); } else if (rnode->type == AST_MULTIRANGE) { // Add offset for each dimension AstNode *mrnode = rnode; int stop_dim = std::min(GetSize(mrnode->children), max_dim); for (; dim < stop_dim; dim++) { - rnode = mrnode->children[dim]; - offset = index_offset(offset, rnode, decl_node, dim, stride); + rnode = mrnode->children[dim].get(); + offset = index_offset(std::move(offset), rnode, decl_node, dim, stride); } dim--; // Step back to the final index / slice } @@ -494,15 +493,15 @@ AstNode *AstNode::make_index_range(AstNode *decl_node, bool unpacked_range) input_error("Unsupported range operation for %s\n", str.c_str()); } - AstNode *index_range = new AstNode(AST_RANGE); + std::unique_ptrindex_range = std::make_unique(AST_RANGE); if (!unpacked_range && (stride > 1 || GetSize(rnode->children) == 2)) { // Calculate MSB offset for the final index / slice of packed dimensions. - AstNode *msb_offset = index_msb_offset(offset->clone(), rnode, decl_node, dim, stride); - index_range->children.push_back(msb_offset); + std::unique_ptrmsb_offset = index_msb_offset(offset->clone(), rnode, decl_node, dim, stride); + index_range->children.push_back(std::move(msb_offset)); } - index_range->children.push_back(offset); + index_range->children.push_back(std::move(offset)); return index_range; } @@ -510,8 +509,8 @@ AstNode *AstNode::make_index_range(AstNode *decl_node, bool unpacked_range) AstNode *AstNode::get_struct_member() const { AstNode *member_node; - if (attributes.count(ID::wiretype) && (member_node = attributes.at(ID::wiretype)) && - (member_node->type == AST_STRUCT_ITEM || member_node->type == AST_STRUCT || member_node->type == AST_UNION)) + if (attributes.count(ID::wiretype) && (member_node = attributes.at(ID::wiretype).get()) && + (member_node->type == AST_STRUCT_ITEM || member_node->type == AST_STRUCT || member_node->type == AST_UNION)) { return member_node; } @@ -523,20 +522,20 @@ static void add_members_to_scope(AstNode *snode, std::string name) // add all the members in a struct or union to local scope // in case later referenced in assignments log_assert(snode->type==AST_STRUCT || snode->type==AST_UNION); - for (auto *node : snode->children) { + for (auto &node : snode->children) { auto member_name = name + "." + node->str; - current_scope[member_name] = node; + current_scope[member_name] = node.get(); if (node->type != AST_STRUCT_ITEM) { // embedded struct or union - add_members_to_scope(node, name + "." + node->str); + add_members_to_scope(node.get(), name + "." + node->str); } } } -static AstNode *make_packed_struct(AstNode *template_node, std::string &name, decltype(AstNode::attributes) &attributes) +std::unique_ptr make_packed_struct(AstNode *template_node, std::string &name, decltype(AstNode::attributes) &attributes) { // create a wire for the packed struct - auto wnode = new AstNode(AST_WIRE, make_range(template_node->range_left, 0)); + auto wnode = std::make_unique(AST_WIRE, make_range(template_node->range_left, 0)); wnode->str = name; wnode->is_logic = true; wnode->range_valid = true; @@ -547,24 +546,24 @@ static AstNode *make_packed_struct(AstNode *template_node, std::string &name, de // resolve packed dimension while (wnode->simplify(true, 1, -1, false)) {} // make sure this node is the one in scope for this name - current_scope[name] = wnode; + current_scope[name] = wnode.get(); // add all the struct members to scope under the wire's name add_members_to_scope(template_node, name); return wnode; } -static void prepend_ranges(AstNode *&range, AstNode *range_add) +static void prepend_ranges(std::unique_ptr &range, AstNode *range_add) { // Convert range to multirange. if (range->type == AST_RANGE) - range = new AstNode(AST_MULTIRANGE, range); + range = std::make_unique(AST_MULTIRANGE, std::move(range)); // Add range or ranges. if (range_add->type == AST_RANGE) range->children.insert(range->children.begin(), range_add->clone()); else { int i = 0; - for (auto child : range_add->children) + for (auto& child : range_add->children) range->children.insert(range->children.begin() + i++, child->clone()); } } @@ -575,16 +574,16 @@ static bool node_contains_assignment_to(const AstNode* node, const AstNode* var) if (node->type == AST_ASSIGN_EQ || node->type == AST_ASSIGN_LE) { // current node is iteslf an assignment log_assert(node->children.size() >= 2); - const AstNode* lhs = node->children[0]; + const AstNode* lhs = node->children[0].get(); if (lhs->type == AST_IDENTIFIER && lhs->str == var->str) return false; } - for (const AstNode* child : node->children) { + for (auto& child : node->children) { // if this child shadows the given variable - if (child != var && child->str == var->str && child->type == AST_WIRE) + if (child.get() != var && child->str == var->str && child->type == AST_WIRE) break; // skip the remainder of this block/scope // depth-first short circuit - if (!node_contains_assignment_to(child, var)) + if (!node_contains_assignment_to(child.get(), var)) return false; } return true; @@ -625,9 +624,9 @@ const RTLIL::Module* AstNode::lookup_cell_module() }; const AstNode *celltype = nullptr; - for (const AstNode *child : children) + for (auto& child : children) if (child->type == AST_CELLTYPE) { - celltype = child; + celltype = child.get(); break; } log_assert(celltype != nullptr); @@ -644,7 +643,7 @@ const RTLIL::Module* AstNode::lookup_cell_module() // build a mapping from true param name to param value size_t para_counter = 0; dict cell_params_map; - for (AstNode *child : children) { + for (auto& child : children) { if (child->type != AST_PARASET) continue; @@ -652,7 +651,7 @@ const RTLIL::Module* AstNode::lookup_cell_module() return nullptr; // let hierarchy handle this error IdString paraname = child->str.empty() ? module->avail_parameters[para_counter++] : child->str; - const AstNode *value = child->children[0]; + const AstNode *value = child->children[0].get(); if (value->type != AST_REALVALUE && value->type != AST_CONSTANT) return nullptr; // let genrtlil handle this error cell_params_map[paraname] = value->asParaConst(); @@ -684,8 +683,8 @@ static bool contains_unbased_unsized(const AstNode *node) { if (node->type == AST_CONSTANT) return node->is_unsized; - for (const AstNode *child : node->children) - if (contains_unbased_unsized(child)) + for (auto& child : node->children) + if (contains_unbased_unsized(child.get())) return true; return false; } @@ -694,19 +693,19 @@ static bool contains_unbased_unsized(const AstNode *node) // dimensions of the given wire reference void add_wire_for_ref(const RTLIL::Wire *ref, const std::string &str) { - AstNode *left = AstNode::mkconst_int(ref->width - 1 + ref->start_offset, true); - AstNode *right = AstNode::mkconst_int(ref->start_offset, true); + std::unique_ptr left = AstNode::mkconst_int(ref->width - 1 + ref->start_offset, true); + std::unique_ptr right = AstNode::mkconst_int(ref->start_offset, true); if (ref->upto) std::swap(left, right); - AstNode *range = new AstNode(AST_RANGE, left, right); + std::unique_ptr range = std::make_unique(AST_RANGE, std::move(left), std::move(right)); - AstNode *wire = new AstNode(AST_WIRE, range); + std::unique_ptr wire = std::make_unique(AST_WIRE, std::move(range)); wire->is_signed = ref->is_signed; wire->is_logic = true; wire->str = str; - current_ast_mod->children.push_back(wire); - current_scope[str] = wire; + current_scope[str] = wire.get(); + current_ast_mod->children.push_back(std::move(wire)); } enum class IdentUsage { @@ -733,10 +732,10 @@ static IdentUsage always_asgn_before_use(const AstNode *node, const std::string bool all_defined = true; bool any_used = false; bool has_default = false; - for (const AstNode *child : node->children) { + for (auto& child : node->children) { if (child->type == AST_COND && child->children.at(0)->type == AST_DEFAULT) has_default = true; - IdentUsage nested = always_asgn_before_use(child, target); + IdentUsage nested = always_asgn_before_use(child.get(), target); if (nested != IdentUsage::Assigned && child->type == AST_COND) all_defined = false; if (nested == IdentUsage::SyncRequired) @@ -753,20 +752,20 @@ static IdentUsage always_asgn_before_use(const AstNode *node, const std::string // Check if this is an assignment to the target variable. For simplicity, we // don't analyze sub-ranges of the variable. if (node->type == AST_ASSIGN_EQ) { - const AstNode *ident = node->children.at(0); + auto& ident = node->children.at(0); if (ident->type == AST_IDENTIFIER && ident->str == target) return IdentUsage::Assigned; } - for (const AstNode *child : node->children) { - IdentUsage nested = always_asgn_before_use(child, target); + for (auto& child : node->children) { + IdentUsage nested = always_asgn_before_use(child.get(), target); if (nested != IdentUsage::NotReferenced) return nested; } return IdentUsage::NotReferenced; } -AstNode *AstNode::clone_at_zero() +std::unique_ptr AstNode::clone_at_zero() { int width_hint; bool sign_hint; @@ -795,8 +794,7 @@ AstNode *AstNode::clone_at_zero() break; } - AstNode *that = new AstNode; - *that = *this; + auto that = clone(); for (auto &it : that->children) it = it->clone_at_zero(); for (auto &it : that->attributes) @@ -818,8 +816,8 @@ static bool try_determine_range_width(AstNode *range, int &result_width) return true; } - AstNode *left_at_zero_ast = range->children[0]->clone_at_zero(); - AstNode *right_at_zero_ast = range->children[1]->clone_at_zero(); + std::unique_ptr left_at_zero_ast = range->children[0]->clone_at_zero(); + std::unique_ptr right_at_zero_ast = range->children[1]->clone_at_zero(); while (left_at_zero_ast->simplify(true, 1, -1, false)) {} while (right_at_zero_ast->simplify(true, 1, -1, false)) {} @@ -831,8 +829,6 @@ static bool try_determine_range_width(AstNode *range, int &result_width) result_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; } - delete left_at_zero_ast; - delete right_at_zero_ast; return ok; } @@ -891,13 +887,22 @@ static void check_auto_nosync(AstNode *node) // remove the attributes we've "consumed" for (const RTLIL::IdString &str : attrs_to_drop) { auto it = node->attributes.find(str); - delete it->second; node->attributes.erase(it); } // check local variables in any nested blocks - for (AstNode *child : node->children) - check_auto_nosync(child); + for (auto& child : node->children) + check_auto_nosync(child.get()); +} + +void AstNode::null_check() +{ + for (auto& child : children) { + // if (!child) + // VALGRIND_PRINTF_BACKTRACE("null child"); + log_assert((bool) child); + child->null_check(); + } } // convert the AST into a simpler AST that has all parameters substituted by their @@ -908,6 +913,7 @@ static void check_auto_nosync(AstNode *node) // nodes that link to a different node using names and lexical scoping. bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hint) { + // null_check(); static int recursion_counter = 0; static bool deep_recursion_warning = false; @@ -918,7 +924,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin static bool unevaluated_tern_branch = false; - AstNode *newNode = NULL; + std::unique_ptr newNode = nullptr; bool did_something = false; #if 0 @@ -926,7 +932,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin log("AST simplify[%d] depth %d at %s:%d on %s %p:\n", stage, recursion_counter, filename.c_str(), location.first_line, type2str(type).c_str(), this); log("const_fold=%d, stage=%d, width_hint=%d, sign_hint=%d\n", int(const_fold), int(stage), int(width_hint), int(sign_hint)); - // dumpAst(NULL, "> "); + // dumpAst(nullptr, "> "); #endif if (stage == 0) @@ -1006,7 +1012,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin std::swap(data_range_left, data_range_right); for (int i = 0; i < mem_size; i++) { - AstNode *reg = new AstNode(AST_WIRE, new AstNode(AST_RANGE, + auto reg = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(data_range_left, true), mkconst_int(data_range_right, true))); reg->str = stringf("%s[%d]", node->str.c_str(), i); reg->is_reg = true; @@ -1016,19 +1022,15 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin reg->set_attribute(it.first, it.second->clone()); reg->filename = node->filename; reg->location = node->location; - children.push_back(reg); while (reg->simplify(true, 1, -1, false)) { } + children.push_back(std::move(reg)); } } - AstNode *async_block = NULL; - while (mem2reg_as_needed_pass2(mem2reg_set, this, NULL, async_block)) { } + AstNode* async_block = nullptr; + while (mem2reg_as_needed_pass2(mem2reg_set, this, nullptr, async_block)) { } - vector delnodes; - mem2reg_remove(mem2reg_set, delnodes); - - for (auto node : delnodes) - delete node; + mem2reg_remove(mem2reg_set); } while (simplify(const_fold, 2, width_hint, sign_hint)) { } @@ -1055,8 +1057,8 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } if ((type == AST_TCALL) && - (str == "$display" || str == "$displayb" || str == "$displayh" || str == "$displayo" || - str == "$write" || str == "$writeb" || str == "$writeh" || str == "$writeo")) + (str == "$display" || str == "$displayb" || str == "$displayh" || str == "$displayo" || + str == "$write" || str == "$writeb" || str == "$writeh" || str == "$writeo")) { if (!current_always) { log_file_warning(filename, location.first_line, "System task `%s' outside initial or always block is unsupported.\n", str.c_str()); @@ -1064,7 +1066,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin str = std::string(); } else { // simplify the expressions and convert them to a special cell later in genrtlil - for (auto node : children) + for (auto& node : children) while (node->simplify(true, stage, -1, false)) {} if (current_always->type == AST_INITIAL && !flag_nodisplay && stage == 2) { @@ -1104,16 +1106,13 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin label_genblks(existing, counter); std::map this_wire_scope; for (size_t i = 0; i < children.size(); i++) { - AstNode *node = children[i]; + AstNode* node = children[i].get(); if (node->type == AST_WIRE) { if (node->children.size() == 1 && node->children[0]->type == AST_RANGE) { - for (auto c : node->children[0]->children) { - if (!c->is_simple_const_expr()) { - if (attributes.count(ID::dynports)) - delete attributes.at(ID::dynports); + for (auto& c : node->children[0]->children) { + if (!c->is_simple_const_expr()) set_attribute(ID::dynports, AstNode::mkconst_int(1, true)); - } } } if (this_wire_scope.count(node->str) > 0) { @@ -1123,16 +1122,15 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (!node->is_input && !node->is_output && node->is_reg && node->children.size() == 0) goto wires_are_compatible; if (first_node->children.size() == 0 && node->children.size() == 1 && node->children[0]->type == AST_RANGE) { - AstNode *r = node->children[0]; + AstNode* r = node->children[0].get(); if (r->range_valid && r->range_left == 0 && r->range_right == 0) { - delete r; node->children.pop_back(); } } if (first_node->children.size() != node->children.size()) goto wires_are_incompatible; for (size_t j = 0; j < node->children.size(); j++) { - AstNode *n1 = first_node->children[j], *n2 = node->children[j]; + auto &n1 = first_node->children[j], &n2 = node->children[j]; if (n1->type == AST_RANGE && n2->type == AST_RANGE && n1->range_valid && n2->range_valid) { if (n1->range_left != n2->range_left) goto wires_are_incompatible; @@ -1159,13 +1157,10 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (node->is_signed) first_node->is_signed = true; for (auto &it : node->attributes) { - if (first_node->attributes.count(it.first) > 0) - delete first_node->attributes[it.first]; first_node->set_attribute(it.first, it.second->clone()); } children.erase(children.begin()+(i--)); did_something = true; - delete node; continue; wires_are_incompatible: if (stage > 1) @@ -1183,22 +1178,22 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } if (node->type == AST_ENUM) { current_scope[node->str] = node; - for (auto enode : node->children) { + for (auto& enode : node->children) { log_assert(enode->type==AST_ENUM_ITEM); if (current_scope.count(enode->str) == 0) - current_scope[enode->str] = enode; + current_scope[enode->str] = enode.get(); else input_error("enum item %s already exists\n", enode->str.c_str()); } } } for (size_t i = 0; i < children.size(); i++) { - AstNode *node = children[i]; + auto& node = children[i]; if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_MEMORY || node->type == AST_TYPEDEF) while (node->simplify(true, 1, -1, false)) did_something = true; if (node->type == AST_ENUM) { - for (auto enode : node->children){ + for (auto& enode : node->children){ log_assert(enode->type==AST_ENUM_ITEM); while (node->simplify(true, 1, -1, false)) did_something = true; @@ -1206,27 +1201,27 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } } - for (AstNode *child : children) + for (auto& child : children) if (child->type == AST_ALWAYS && child->attributes.count(ID::always_comb)) - check_auto_nosync(child); + check_auto_nosync(child.get()); } // create name resolution entries for all objects with names if (type == AST_PACKAGE) { //add names to package scope for (size_t i = 0; i < children.size(); i++) { - AstNode *node = children[i]; + auto& node = children[i]; // these nodes appear at the top level in a package and can define names if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_TYPEDEF || node->type == AST_FUNCTION || node->type == AST_TASK) { - current_scope[node->str] = node; + current_scope[node->str] = node.get(); } if (node->type == AST_ENUM) { - current_scope[node->str] = node; - for (auto enode : node->children) { + current_scope[node->str] = node.get(); + for (auto& enode : node->children) { log_assert(enode->type==AST_ENUM_ITEM); if (current_scope.count(enode->str) == 0) - current_scope[enode->str] = enode; + current_scope[enode->str] = enode.get(); else input_error("enum item %s already exists in package\n", enode->str.c_str()); } @@ -1250,7 +1245,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin current_always_clocked = false; if (type == AST_ALWAYS) - for (auto child : children) { + for (auto& child : children) { if (child->type == AST_POSEDGE || child->type == AST_NEGEDGE) current_always_clocked = true; if (child->type == AST_EDGE && GetSize(child->children) == 1 && @@ -1262,7 +1257,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (type == AST_CELL) { bool lookup_suggested = false; - for (AstNode *child : children) { + for (auto& child : children) { // simplify any parameters to constants if (child->type == AST_PARASET) while (child->simplify(true, 1, -1, false)) { } @@ -1272,7 +1267,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (child->type == AST_ARGUMENT) { if (child->children.size() != 1) continue; - const AstNode *value = child->children[0]; + const auto& value = child->children[0]; if (value->type == AST_IDENTIFIER) { const AstNode *elem = value->id2ast; if (elem == nullptr) { @@ -1289,7 +1284,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // to be indirected to produce an unsigned connection lookup_suggested = true; } - else if (contains_unbased_unsized(value)) + else if (contains_unbased_unsized(value.get())) // unbased unsized literals extend to width of the context lookup_suggested = true; } @@ -1300,7 +1295,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin module = lookup_cell_module(); if (module) { size_t port_counter = 0; - for (AstNode *child : children) { + for (auto& child : children) { if (child->type != AST_ARGUMENT) continue; @@ -1324,17 +1319,21 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin log_assert(child->children.size() <= 1); if (child->children.empty()) continue; - AstNode *arg = child->children[0]; - // plain identifiers never need indirection; this also prevents - // adding infinite levels of indirection - if (arg->type == AST_IDENTIFIER && arg->children.empty()) - continue; + { + auto arg_check = child->children[0].get(); - // only add indirection for standard inputs or outputs - if (ref->port_input == ref->port_output) - continue; + // plain identifiers never need indirection; this also prevents + // adding infinite levels of indirection + if (arg_check->type == AST_IDENTIFIER && arg_check->children.empty()) + continue; + // only add indirection for standard inputs or outputs + if (ref->port_input == ref->port_output) + continue; + } + + auto arg = std::move(child->children[0]); did_something = true; // create the indirection wire @@ -1343,20 +1342,21 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin std::string tmp_str = sstr.str(); add_wire_for_ref(ref, tmp_str); - AstNode *asgn = new AstNode(AST_ASSIGN); - current_ast_mod->children.push_back(asgn); + auto asgn_owned = std::make_unique(AST_ASSIGN); + auto* asgn = asgn_owned.get(); + current_ast_mod->children.push_back(std::move(asgn_owned)); - AstNode *ident = new AstNode(AST_IDENTIFIER); + auto ident = std::make_unique(AST_IDENTIFIER); ident->str = tmp_str; child->children[0] = ident->clone(); if (ref->port_input && !ref->port_output) { - asgn->children.push_back(ident); - asgn->children.push_back(arg); + asgn->children.push_back(std::move(ident)); + asgn->children.push_back(std::move(arg)); } else { log_assert(!ref->port_input && ref->port_output); - asgn->children.push_back(arg); - asgn->children.push_back(ident); + asgn->children.push_back(std::move(arg)); + asgn->children.push_back(std::move(ident)); } asgn->fixup_hierarchy_flags(); } @@ -1416,7 +1416,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin case AST_STRUCT: case AST_UNION: if (!basic_prep) { - for (auto *node : children) { + for (auto& node : children) { // resolve any ranges while (!node->basic_prep && node->simplify(true, stage, -1, false)) { did_something = true; @@ -1430,7 +1430,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // instance so add a wire for the packed structure auto wnode = make_packed_struct(this, str, attributes); log_assert(current_ast_mod); - current_ast_mod->children.push_back(wnode); + current_ast_mod->children.push_back(std::move(wnode)); } basic_prep = true; is_custom_type = false; @@ -1456,7 +1456,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin case AST_ENUM: //log("\nENUM %s: %d child %d\n", str.c_str(), basic_prep, children[0]->basic_prep); if (!basic_prep) { - for (auto item_node : children) { + for (auto& item_node : children) { while (!item_node->basic_prep && item_node->simplify(false, stage, -1, false)) did_something = true; } @@ -1473,8 +1473,8 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin auto item_node = current_scope[children[0]->str]; if (item_node->type == AST_STRUCT || item_node->type == AST_UNION) { set_attribute(ID::wiretype, item_node->clone()); - size_packed_struct(attributes[ID::wiretype], 0); - add_members_to_scope(attributes[ID::wiretype], str); + size_packed_struct(attributes[ID::wiretype].get(), 0); + add_members_to_scope(attributes[ID::wiretype].get(), str); } } while (!children[0]->basic_prep && children[0]->simplify(false, stage, -1, false) == true) @@ -1502,11 +1502,10 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin break; case AST_CAST_SIZE: { - int width = 1; - AstNode *node; - AstNode *child = children[0]; - - if (child->type == AST_WIRE) { + if (children[0]->type == AST_WIRE) { + int width = 1; + std::unique_ptr node; + AstNode* child = children[0].release(); if (child->children.size() == 0) { // Base type (e.g., int) width = child->range_left - child->range_right +1; @@ -1522,7 +1521,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (resolved_type_node->type != AST_TYPEDEF) input_error("`%s' does not name a type\n", type_name.c_str()); log_assert(resolved_type_node->children.size() == 1); - AstNode *template_node = resolved_type_node->children[0]; + AstNode *template_node = resolved_type_node->children[0].get(); // Ensure typedef itself is fully simplified while (template_node->simplify(const_fold, stage, width_hint, sign_hint)) {}; @@ -1531,7 +1530,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin { case AST_WIRE: { if (template_node->children.size() > 0 && template_node->children[0]->type == AST_RANGE) - width = range_width(this, template_node->children[0]); + width = range_width(this, template_node->children[0].get()); child->delete_children(); node = mkconst_int(width, true); break; @@ -1550,9 +1549,8 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } } - delete child; children.erase(children.begin()); - children.insert(children.begin(), node); + children.insert(children.begin(), std::move(node)); } detect_width_simple = true; @@ -1609,7 +1607,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin case AST_GT: width_hint = -1; sign_hint = true; - for (auto child : children) { + for (auto& child : children) { while (!child->basic_prep && child->simplify(false, stage, -1, false) == true) did_something = true; child->detectSignWidthWorker(width_hint, sign_hint); @@ -1647,7 +1645,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (type == AST_REPLICATE) while (children[0]->simplify(true, stage, -1, false) == true) did_something = true; - for (auto child : children) + for (auto& child : children) while (!child->basic_prep && child->simplify(false, stage, -1, false) == true) did_something = true; detectSignWidth(width_hint, sign_hint); @@ -1664,11 +1662,11 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin bool backup_unevaluated_tern_branch = unevaluated_tern_branch; AstNode *chosen = get_tern_choice().first; - unevaluated_tern_branch = backup_unevaluated_tern_branch || chosen == children[2]; + unevaluated_tern_branch = backup_unevaluated_tern_branch || chosen == children[2].get(); while (!children[1]->basic_prep && children[1]->simplify(false, stage, -1, false)) did_something = true; - unevaluated_tern_branch = backup_unevaluated_tern_branch || chosen == children[1]; + unevaluated_tern_branch = backup_unevaluated_tern_branch || chosen == children[1].get(); while (!children[2]->basic_prep && children[2]->simplify(false, stage, -1, false)) did_something = true; @@ -1705,12 +1703,12 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (children[0]->type == AST_CONSTANT && children[0]->bits_only_01()) { children[0]->is_signed = sign_hint; RTLIL::Const case_expr = children[0]->bitsAsConst(width_hint, sign_hint); - std::vector new_children; - new_children.push_back(children[0]); + std::vector> new_children; + new_children.push_back(std::move(children[0])); for (int i = 1; i < GetSize(children); i++) { - AstNode *child = children[i]; + auto& child = children[i]; log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ); - for (auto v : child->children) { + for (auto& v : child->children) { if (v->type == AST_DEFAULT) goto keep_const_cond; if (v->type == AST_BLOCK) @@ -1721,8 +1719,8 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin RTLIL::Const match = const_eq(case_expr, case_item_expr, sign_hint, sign_hint, 1); log_assert(match.size() == 1); if (match.front() == RTLIL::State::S1) { - while (i+1 < GetSize(children)) - delete children[++i]; + // This is the only reachable case. Skip to the end + i = GetSize(children); goto keep_const_cond; } continue; @@ -1731,9 +1729,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } if (0) keep_const_cond: - new_children.push_back(child); - else - delete child; + new_children.push_back(std::move(child)); } new_children.swap(children); } @@ -1769,7 +1765,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin flag_autowire = true; if (type == AST_TERNARY && i > 0 && !unevaluated_tern_branch) { AstNode *chosen = get_tern_choice().first; - unevaluated_tern_branch = chosen && chosen != children[i]; + unevaluated_tern_branch = chosen && chosen != children[i].get(); } while (did_something_here && i < children.size()) { bool const_fold_here = const_fold; @@ -1781,10 +1777,10 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin const_fold_here = true; if (type == AST_BLOCK) { current_block = this; - current_block_child = children[i]; + current_block_child = children[i].get(); } if ((type == AST_ALWAYS || type == AST_INITIAL) && children[i]->type == AST_BLOCK) - current_top_block = children[i]; + current_top_block = children[i].get(); if (i == 0 && child_0_is_self_determined) width_hint_here = -1, sign_hint_here = false; if (i == 1 && child_1_is_self_determined) @@ -1798,7 +1794,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin did_something = true; } if (stage == 2 && children[i]->type == AST_INITIAL && current_ast_mod != this) { - current_ast_mod->children.push_back(children[i]); + current_ast_mod->children.push_back(std::move(children[i])); children.erase(children.begin() + (i--)); did_something = true; } @@ -1838,7 +1834,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin current_always_clocked = backup_current_always_clocked; for (auto it = backup_scope.begin(); it != backup_scope.end(); it++) { - if (it->second == NULL) + if (it->second == nullptr) current_scope.erase(it->first); else current_scope[it->first] = it->second; @@ -1878,18 +1874,18 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin input_error("Defparam argument `%s . %s` does not match a cell!\n", RTLIL::unescape_id(modname).c_str(), RTLIL::unescape_id(paramname).c_str()); - AstNode *paraset = new AstNode(AST_PARASET, children[1]->clone(), GetSize(children) > 2 ? children[2]->clone() : NULL); + auto paraset = std::make_unique(AST_PARASET, children[1]->clone(), GetSize(children) > 2 ? children[2]->clone() : nullptr); paraset->str = paramname; AstNode *cell = current_scope.at(modname); - cell->children.insert(cell->children.begin() + 1, paraset); + cell->children.insert(cell->children.begin() + 1, std::move(paraset)); delete_children(); } // resolve typedefs if (type == AST_TYPEDEF) { log_assert(children.size() == 1); - auto type_node = children[0]; + auto& type_node = children[0]; log_assert(type_node->type == AST_WIRE || type_node->type == AST_MEMORY || type_node->type == AST_STRUCT || type_node->type == AST_UNION); while (type_node->simplify(const_fold, stage, width_hint, sign_hint)) { did_something = true; @@ -1910,7 +1906,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (resolved_type_node->type != AST_TYPEDEF) input_error("`%s' does not name a type\n", type_name.c_str()); log_assert(resolved_type_node->children.size() == 1); - AstNode *template_node = resolved_type_node->children[0]; + auto& template_node = resolved_type_node->children[0]; // Resolve the typedef from the bottom up, recursing within the current // block of code. Defer further simplification until the complete type is @@ -1919,9 +1915,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (!str.empty() && str[0] == '\\' && (template_node->type == AST_STRUCT || template_node->type == AST_UNION)) { // replace instance with wire representing the packed structure - newNode = make_packed_struct(template_node, str, attributes); - if (newNode->attributes.count(ID::wiretype)) - delete newNode->attributes[ID::wiretype]; + newNode = make_packed_struct(template_node.get(), str, attributes); newNode->set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str)); // add original input/output attribute to resolved wire newNode->is_input = this->is_input; @@ -1933,8 +1927,6 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // Prepare replacement node. newNode = template_node->clone(); newNode->str = str; - if (newNode->attributes.count(ID::wiretype)) - delete newNode->attributes[ID::wiretype]; newNode->set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str)); newNode->is_input = is_input; newNode->is_output = is_output; @@ -1944,7 +1936,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin newNode->set_attribute(pair.first, pair.second->clone()); // if an enum then add attributes to support simulator tracing - newNode->annotateTypedEnums(template_node); + newNode->annotateTypedEnums(template_node.get()); bool add_packed_dimensions = (type == AST_WIRE && GetSize(children) > 1) || (type == AST_MEMORY && GetSize(children) > 2); @@ -1954,20 +1946,20 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // Add packed dimensions. if (add_packed_dimensions) { - AstNode *packed = children[1]; + auto& packed = children[1]; if (newNode->children.empty()) newNode->children.insert(newNode->children.begin(), packed->clone()); else - prepend_ranges(newNode->children[0], packed); + prepend_ranges(newNode->children[0], packed.get()); } // Add unpacked dimensions. if (type == AST_MEMORY) { - AstNode *unpacked = children.back(); + auto& unpacked = children.back(); if (GetSize(newNode->children) < 2) newNode->children.push_back(unpacked->clone()); else - prepend_ranges(newNode->children[1], unpacked); + prepend_ranges(newNode->children[1], unpacked.get()); newNode->type = type; } @@ -1988,11 +1980,11 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // Pretend it's just a wire in order to resolve the type in the code block above. AstNodeType param_type = type; type = AST_WIRE; - AstNode *expr = children[0]; + std::unique_ptr expr = std::move(children.front()); children.erase(children.begin()); while (is_custom_type && simplify(const_fold, stage, width_hint, sign_hint)) {}; type = param_type; - children.insert(children.begin(), expr); + children.insert(children.begin(), std::move(expr)); if (children[1]->type == AST_MEMORY) input_error("unpacked array type `%s' cannot be used for a parameter\n", children[1]->str.c_str()); @@ -2005,7 +1997,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // resolve constant prefixes if (type == AST_PREFIX) { if (children[0]->type != AST_CONSTANT) { - // dumpAst(NULL, "> "); + // dumpAst(nullptr, "> "); input_error("Index in generate block prefix syntax is not constant!\n"); } if (children[1]->type == AST_PREFIX) @@ -2070,13 +2062,13 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin range_right = children[0]->range_right; bool force_upto = false, force_downto = false; if (attributes.count(ID::force_upto)) { - AstNode *val = attributes[ID::force_upto]; + AstNode *val = attributes[ID::force_upto].get(); if (val->type != AST_CONSTANT) input_error("Attribute `force_upto' with non-constant value!\n"); force_upto = val->asAttrConst().as_bool(); } if (attributes.count(ID::force_downto)) { - AstNode *val = attributes[ID::force_downto]; + AstNode *val = attributes[ID::force_downto].get(); if (val->type != AST_CONSTANT) input_error("Attribute `force_downto' with non-constant value!\n"); force_downto = val->asAttrConst().as_bool(); @@ -2097,10 +2089,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin range_swapped = false; range_left = 0; range_right = 0; - if (attributes.count(ID::single_bit_vector)) { - delete attributes[ID::single_bit_vector]; - attributes.erase(ID::single_bit_vector); - } + attributes.erase(ID::single_bit_vector); } } @@ -2111,19 +2100,18 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin for (int i = std::min(GetSize(children), 2) - 1; i >= 0; i--) { if (children[i]->type == AST_MULTIRANGE) { int width = 1; - for (auto range : children[i]->children) { - width *= add_dimension(this, range); + for (auto& range : children[i]->children) { + width *= add_dimension(this, range.get()); if (i) unpacked_dimensions++; } - delete children[i]; int left = width - 1, right = 0; if (i) std::swap(left, right); - children[i] = new AstNode(AST_RANGE, mkconst_int(left, true), mkconst_int(right, true)); + children[i] = std::make_unique(AST_RANGE, mkconst_int(left, true), mkconst_int(right, true)); fixup_hierarchy_flags(); did_something = true; } else if (children[i]->type == AST_RANGE) { - add_dimension(this, children[i]); + add_dimension(this, children[i].get()); if (i) unpacked_dimensions++; } } @@ -2135,15 +2123,15 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // Resolve multidimensional array access. if (type == AST_IDENTIFIER && !basic_prep && id2ast && (id2ast->type == AST_WIRE || id2ast->type == AST_MEMORY) && - children.size() > 0 && (children[0]->type == AST_RANGE || children[0]->type == AST_MULTIRANGE)) + children.size() > 0 && (children[0]->type == AST_RANGE || children[0]->type == AST_MULTIRANGE)) { int dims_sel = children[0]->type == AST_MULTIRANGE ? children[0]->children.size() : 1; // Save original number of dimensions for $size() etc. integer = dims_sel; // Split access into unpacked and packed parts. - AstNode *unpacked_range = nullptr; - AstNode *packed_range = nullptr; + std::unique_ptr unpacked_range = nullptr; + std::unique_ptr packed_range = nullptr; if (id2ast->unpacked_dimensions) { if (id2ast->unpacked_dimensions > 1) { @@ -2151,8 +2139,8 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin unpacked_range = make_index_range(id2ast, true); } else { // Index into one-dimensional unpacked part; unlink simple range node. - AstNode *&range = children[0]->type == AST_MULTIRANGE ? children[0]->children[0] : children[0]; - unpacked_range = range; + auto& range = children[0]->type == AST_MULTIRANGE ? children[0]->children[0] : children[0]; + unpacked_range = std::move(range); range = nullptr; } } @@ -2163,21 +2151,19 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin packed_range = make_index_range(id2ast, false); } else { // Index into one-dimensional packed part; unlink simple range node. - AstNode *&range = children[0]->type == AST_MULTIRANGE ? children[0]->children[dims_sel - 1] : children[0]; - packed_range = range; + auto& range = children[0]->type == AST_MULTIRANGE ? children[0]->children[dims_sel - 1] : children[0]; + packed_range = std::move(range); range = nullptr; } } - for (auto &it : children) - delete it; children.clear(); if (unpacked_range) - children.push_back(unpacked_range); + children.push_back(std::move(unpacked_range)); if (packed_range) - children.push_back(packed_range); + children.push_back(std::move(packed_range)); fixup_hierarchy_flags(); basic_prep = true; @@ -2194,7 +2180,6 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin RTLIL::Const constvalue = children[0]->realAsConst(width); log_file_warning(filename, location.first_line, "converting real value %e to binary %s.\n", children[0]->realvalue, log_signal(constvalue)); - delete children[0]; children[0] = mkconst_bits(constvalue.to_bits(), sign_hint); fixup_hierarchy_flags(); did_something = true; @@ -2203,9 +2188,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (width != int(children[0]->bits.size())) { RTLIL::SigSpec sig(children[0]->bits); sig.extend_u0(width, children[0]->is_signed); - AstNode *old_child_0 = children[0]; children[0] = mkconst_bits(sig.as_const().to_bits(), is_signed); - delete old_child_0; fixup_hierarchy_flags(); } children[0]->is_signed = is_signed; @@ -2217,8 +2200,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } else if (children.size() > 1 && children[1]->type == AST_REALVALUE && children[0]->type == AST_CONSTANT) { double as_realvalue = children[0]->asReal(sign_hint); - delete children[0]; - children[0] = new AstNode(AST_REALVALUE); + children[0] = std::make_unique(AST_REALVALUE); children[0]->realvalue = as_realvalue; fixup_hierarchy_flags(); did_something = true; @@ -2247,7 +2229,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (found_sname) { // structure member, rewrite this node to reference the packed struct wire auto range = make_index_range(item_node); - newNode = new AstNode(AST_IDENTIFIER, range); + newNode = std::make_unique(AST_IDENTIFIER, std::move(range)); newNode->str = sname; // save type and original number of dimensions for $size() etc. newNode->set_attribute(ID::wiretype, item_node->clone()); @@ -2259,7 +2241,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } newNode->basic_prep = true; if (item_node->is_signed) - newNode = new AstNode(AST_TO_SIGNED, newNode); + newNode = std::make_unique(AST_TO_SIGNED, std::move(newNode)); goto apply_newNode; } } @@ -2270,7 +2252,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (current_scope.count(str) == 0) { AstNode *current_scope_ast = (current_ast_mod == nullptr) ? current_ast : current_ast_mod; str = try_pop_module_prefix(); - for (auto node : current_scope_ast->children) { + for (auto& node : current_scope_ast->children) { //log("looking at mod scope child %s\n", type2str(node->type).c_str()); switch (node->type) { case AST_PARAMETER: @@ -2285,16 +2267,16 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin //log("found child %s, %s\n", type2str(node->type).c_str(), node->str.c_str()); if (str == node->str) { //log("add %s, type %s to scope\n", str.c_str(), type2str(node->type).c_str()); - current_scope[node->str] = node; + current_scope[node->str] = node.get(); } break; case AST_ENUM: - current_scope[node->str] = node; - for (auto enum_node : node->children) { + current_scope[node->str] = node.get(); + for (auto& enum_node : node->children) { log_assert(enum_node->type==AST_ENUM_ITEM); if (str == enum_node->str) { //log("\nadding enum item %s to scope\n", str.c_str()); - current_scope[str] = enum_node; + current_scope[str] = enum_node.get(); } } break; @@ -2307,10 +2289,10 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (current_ast_mod == nullptr) { input_error("Identifier `%s' is implicitly declared outside of a module.\n", str.c_str()); } else if (flag_autowire || str == "\\$global_clock") { - AstNode *auto_wire = new AstNode(AST_AUTOWIRE); + auto auto_wire = std::make_unique(AST_AUTOWIRE); auto_wire->str = str; - current_ast_mod->children.push_back(auto_wire); - current_scope[str] = auto_wire; + current_scope[str] = auto_wire.get(); + current_ast_mod->children.push_back(std::move(auto_wire)); did_something = true; } else { input_error("Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str()); @@ -2325,7 +2307,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // split memory access with bit select to individual statements if (type == AST_IDENTIFIER && children.size() == 2 && children[0]->type == AST_RANGE && children[1]->type == AST_RANGE && !in_lvalue && stage == 2) { - if (id2ast == NULL || id2ast->type != AST_MEMORY || children[0]->children.size() != 1) + if (id2ast == nullptr || id2ast->type != AST_MEMORY || children[0]->children.size() != 1) input_error("Invalid bit-select on memory access!\n"); int mem_width, mem_size, addr_bits; @@ -2341,38 +2323,38 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin sstr << "$mem2bits$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); std::string wire_id = sstr.str(); - AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(data_range_left, true), mkconst_int(data_range_right, true))); + auto wire_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(data_range_left, true), mkconst_int(data_range_right, true))); + auto* wire = wire_owned.get(); + current_ast_mod->children.push_back(std::move(wire_owned)); wire->str = wire_id; if (current_block) wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); - current_ast_mod->children.push_back(wire); while (wire->simplify(true, 1, -1, false)) { } - AstNode *data = clone(); - delete data->children[1]; + auto data = clone(); data->children.pop_back(); - AstNode *assign = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), data); + auto assign = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), std::move(data)); assign->children[0]->str = wire_id; assign->children[0]->was_checked = true; if (current_block) { size_t assign_idx = 0; - while (assign_idx < current_block->children.size() && current_block->children[assign_idx] != current_block_child) + while (assign_idx < current_block->children.size() && current_block->children[assign_idx].get() != current_block_child) assign_idx++; log_assert(assign_idx < current_block->children.size()); - current_block->children.insert(current_block->children.begin()+assign_idx, assign); + current_block->children.insert(current_block->children.begin()+assign_idx, std::move(assign)); wire->is_reg = true; } else { - AstNode *proc = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK)); - proc->children[0]->children.push_back(assign); - current_ast_mod->children.push_back(proc); + auto proc = std::make_unique(AST_ALWAYS, std::make_unique(AST_BLOCK)); + proc->children[0]->children.push_back(std::move(assign)); + current_ast_mod->children.push_back(std::move(proc)); } - newNode = new AstNode(AST_IDENTIFIER, children[1]->clone()); + newNode = std::make_unique(AST_IDENTIFIER, children[1]->clone()); newNode->str = wire_id; newNode->integer = integer; // save original number of dimensions for $size() etc. newNode->id2ast = wire; @@ -2384,8 +2366,8 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (type == AST_REPEAT) { - AstNode *count = children[0]; - AstNode *body = children[1]; + auto count = std::move(children[0]); + auto body = std::move(children[1]); // eval count expression while (count->simplify(true, stage, 32, true)) { } @@ -2399,22 +2381,20 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin for (int i = 0; i < count->bitsAsConst().as_int(); i++) children.insert(children.begin(), body->clone()); - delete count; - delete body; did_something = true; } // unroll for loops and generate-for blocks if ((type == AST_GENFOR || type == AST_FOR) && children.size() != 0) { - AstNode *init_ast = children[0]; - AstNode *while_ast = children[1]; - AstNode *next_ast = children[2]; - AstNode *body_ast = children[3]; + auto& init_ast = children[0]; + auto& while_ast = children[1]; + auto& next_ast = children[2]; + auto* body_ast = children[3].get(); while (body_ast->type == AST_GENBLOCK && body_ast->str.empty() && body_ast->children.size() == 1 && body_ast->children.at(0)->type == AST_GENBLOCK) - body_ast = body_ast->children.at(0); + body_ast = body_ast->children.at(0).get(); const char* loop_type_str = "procedural"; const char* var_type_str = "register"; @@ -2430,16 +2410,16 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (next_ast->type != AST_ASSIGN_EQ) input_error("Unsupported 3rd expression of %s for-loop!\n", loop_type_str); - if (init_ast->children[0]->id2ast == NULL || init_ast->children[0]->id2ast->type != var_type) + if (init_ast->children[0]->id2ast == nullptr || init_ast->children[0]->id2ast->type != var_type) input_error("Left hand side of 1st expression of %s for-loop is not a %s!\n", loop_type_str, var_type_str); - if (next_ast->children[0]->id2ast == NULL || next_ast->children[0]->id2ast->type != var_type) + if (next_ast->children[0]->id2ast == nullptr || next_ast->children[0]->id2ast->type != var_type) input_error("Left hand side of 3rd expression of %s for-loop is not a %s!\n", loop_type_str, var_type_str); if (init_ast->children[0]->id2ast != next_ast->children[0]->id2ast) input_error("Incompatible left-hand sides in 1st and 3rd expression of %s for-loop!\n", loop_type_str); // eval 1st expression - AstNode *varbuf = init_ast->children[1]->clone(); + auto varbuf = init_ast->children[1]->clone(); { int expr_width_hint = -1; bool expr_sign_hint = true; @@ -2464,23 +2444,23 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } } - varbuf = new AstNode(AST_LOCALPARAM, varbuf); + varbuf = std::make_unique(AST_LOCALPARAM, std::move(varbuf)); varbuf->str = init_ast->children[0]->str; AstNode *backup_scope_varbuf = current_scope[varbuf->str]; - current_scope[varbuf->str] = varbuf; + current_scope[varbuf->str] = varbuf.get(); size_t current_block_idx = 0; if (type == AST_FOR) { while (current_block_idx < current_block->children.size() && - current_block->children[current_block_idx] != current_block_child) + current_block->children[current_block_idx].get() != current_block_child) current_block_idx++; } while (1) { // eval 2nd expression - AstNode *buf = while_ast->clone(); + auto buf = while_ast->clone(); { int expr_width_hint = -1; bool expr_sign_hint = true; @@ -2492,10 +2472,8 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin input_error("2nd expression of %s for-loop is not constant!\n", loop_type_str); if (buf->integer == 0) { - delete buf; break; } - delete buf; // expand body int index = varbuf->children[0]->integer; @@ -2508,27 +2486,26 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin std::string prefix = sstr.str(); // create a scoped localparam for the current value of the loop variable - AstNode *local_index = varbuf->clone(); + auto local_index = varbuf->clone(); size_t pos = local_index->str.rfind('.'); if (pos != std::string::npos) // remove outer prefix local_index->str = "\\" + local_index->str.substr(pos + 1); local_index->str = prefix_id(prefix, local_index->str); - current_scope[local_index->str] = local_index; - current_ast_mod->children.push_back(local_index); + current_scope[local_index->str] = local_index.get(); + current_ast_mod->children.push_back(std::move(local_index)); buf->expand_genblock(prefix); if (type == AST_GENFOR) { for (size_t i = 0; i < buf->children.size(); i++) { buf->children[i]->simplify(const_fold, stage, -1, false); - current_ast_mod->children.push_back(buf->children[i]); + current_ast_mod->children.push_back(std::move(buf->children[i])); } } else { for (size_t i = 0; i < buf->children.size(); i++) - current_block->children.insert(current_block->children.begin() + current_block_idx++, buf->children[i]); + current_block->children.insert(current_block->children.begin() + current_block_idx++, std::move(buf->children[i])); } buf->children.clear(); - delete buf; // eval 3rd expression buf = next_ast->children[1]->clone(); @@ -2543,19 +2520,16 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (buf->type != AST_CONSTANT) input_error("Right hand side of 3rd expression of %s for-loop is not constant (%s)!\n", loop_type_str, type2str(buf->type).c_str()); - delete varbuf->children[0]; - varbuf->children[0] = buf; + varbuf->children[0] = std::move(buf); } if (type == AST_FOR) { - AstNode *buf = next_ast->clone(); - delete buf->children[1]; + auto buf = next_ast->clone(); buf->children[1] = varbuf->children[0]->clone(); - current_block->children.insert(current_block->children.begin() + current_block_idx++, buf); + current_block->children.insert(current_block->children.begin() + current_block_idx++, std::move(buf)); } current_scope[varbuf->str] = backup_scope_varbuf; - delete varbuf; delete_children(); did_something = true; } @@ -2566,7 +2540,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin for (size_t i = 0; i < children.size(); i++) if (children[i]->type == AST_WIRE || children[i]->type == AST_MEMORY || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM || children[i]->type == AST_TYPEDEF) { - log_assert(!VERILOG_FRONTEND::sv_mode); + log_assert(!sv_mode); children[i]->input_error("Local declaration in unnamed block is only supported in SystemVerilog mode!\n"); } } @@ -2581,19 +2555,19 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin && is_autonamed_block(str)) // track local variables in this block so we can consider adding // nosync once the block has been fully elaborated - for (AstNode *child : children) + for (auto& child : children) if (child->type == AST_WIRE && !child->attributes.count(ID::nosync)) - mark_auto_nosync(this, child); + mark_auto_nosync(this, child.get()); - std::vector new_children; + std::vector> new_children; for (size_t i = 0; i < children.size(); i++) if (children[i]->type == AST_WIRE || children[i]->type == AST_MEMORY || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM || children[i]->type == AST_TYPEDEF) { children[i]->simplify(false, stage, -1, false); - current_ast_mod->children.push_back(children[i]); - current_scope[children[i]->str] = children[i]; + current_scope[children[i]->str] = children[i].get(); + current_ast_mod->children.push_back(std::move(children[i])); } else - new_children.push_back(children[i]); + new_children.push_back(std::move(children[i])); children.swap(new_children); did_something = true; @@ -2609,7 +2583,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin for (size_t i = 0; i < children.size(); i++) { children[i]->simplify(const_fold, stage, -1, false); - current_ast_mod->children.push_back(children[i]); + current_ast_mod->children.push_back(std::move(children[i])); } children.clear(); @@ -2619,7 +2593,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // simplify generate-if blocks if (type == AST_GENIF && children.size() != 0) { - AstNode *buf = children[0]->clone(); + auto buf = children[0]->clone(); while (buf->simplify(true, stage, width_hint, sign_hint)) { } if (buf->type != AST_CONSTANT) { // for (auto f : log_files) @@ -2627,17 +2601,15 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin input_error("Condition for generate if is not constant!\n"); } if (buf->asBool() != 0) { - delete buf; buf = children[1]->clone(); } else { - delete buf; - buf = children.size() > 2 ? children[2]->clone() : NULL; + buf = children.size() > 2 ? children[2]->clone() : nullptr; } if (buf) { if (buf->type != AST_GENBLOCK) - buf = new AstNode(AST_GENBLOCK, buf); + buf = std::make_unique(AST_GENBLOCK, std::move(buf)); if (!buf->str.empty()) { buf->expand_genblock(buf->str + "."); @@ -2645,11 +2617,10 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin for (size_t i = 0; i < buf->children.size(); i++) { buf->children[i]->simplify(const_fold, stage, -1, false); - current_ast_mod->children.push_back(buf->children[i]); + current_ast_mod->children.push_back(std::move(buf->children[i])); } buf->children.clear(); - delete buf; } delete_children(); @@ -2659,7 +2630,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // simplify generate-case blocks if (type == AST_GENCASE && children.size() != 0) { - AstNode *buf = children[0]->clone(); + auto buf = children[0]->clone(); while (buf->simplify(true, stage, width_hint, sign_hint)) { } if (buf->type != AST_CONSTANT) { // for (auto f : log_files) @@ -2669,24 +2640,23 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin bool ref_signed = buf->is_signed; RTLIL::Const ref_value = buf->bitsAsConst(); - delete buf; - AstNode *selected_case = NULL; + AstNode *selected_case = nullptr; for (size_t i = 1; i < children.size(); i++) { log_assert(children.at(i)->type == AST_COND || children.at(i)->type == AST_CONDX || children.at(i)->type == AST_CONDZ); - AstNode *this_genblock = NULL; - for (auto child : children.at(i)->children) { - log_assert(this_genblock == NULL); + AstNode *this_genblock = nullptr; + for (auto& child : children.at(i)->children) { + log_assert(this_genblock == nullptr); if (child->type == AST_GENBLOCK) - this_genblock = child; + this_genblock = child.get(); } - for (auto child : children.at(i)->children) + for (auto& child : children.at(i)->children) { if (child->type == AST_DEFAULT) { - if (selected_case == NULL) + if (selected_case == nullptr) selected_case = this_genblock; continue; } @@ -2703,7 +2673,6 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } bool is_selected = RTLIL::const_eq(ref_value, buf->bitsAsConst(), ref_signed && buf->is_signed, ref_signed && buf->is_signed, 1).as_bool(); - delete buf; if (is_selected) { selected_case = this_genblock; @@ -2713,7 +2682,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } } - if (selected_case != NULL) + if (selected_case != nullptr) { log_assert(selected_case->type == AST_GENBLOCK); buf = selected_case->clone(); @@ -2724,11 +2693,10 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin for (size_t i = 0; i < buf->children.size(); i++) { buf->children[i]->simplify(const_fold, stage, -1, false); - current_ast_mod->children.push_back(buf->children[i]); + current_ast_mod->children.push_back(std::move(buf->children[i])); } buf->children.clear(); - delete buf; } delete_children(); @@ -2741,13 +2709,14 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (!children.at(0)->range_valid) input_error("Non-constant array range on cell array.\n"); - newNode = new AstNode(AST_GENBLOCK); + newNode = std::make_unique(AST_GENBLOCK); int num = max(children.at(0)->range_left, children.at(0)->range_right) - min(children.at(0)->range_left, children.at(0)->range_right) + 1; for (int i = 0; i < num; i++) { int idx = children.at(0)->range_left > children.at(0)->range_right ? children.at(0)->range_right + i : children.at(0)->range_right - i; - AstNode *new_cell = children.at(1)->clone(); - newNode->children.push_back(new_cell); + auto new_cell_owned = children.at(1)->clone(); + auto* new_cell = new_cell_owned.get(); + newNode->children.push_back(std::move(new_cell_owned)); new_cell->str += stringf("[%d]", idx); if (new_cell->type == AST_PRIMITIVE) { input_error("Cell arrays of primitives are currently not supported.\n"); @@ -2766,13 +2735,12 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (children.size() < 2) input_error("Insufficient number of arguments for primitive `%s'!\n", str.c_str()); - std::vector children_list; - for (auto child : children) { + std::vector> children_list; + for (auto& child : children) { log_assert(child->type == AST_ARGUMENT); log_assert(child->children.size() == 1); - children_list.push_back(child->children[0]); + children_list.push_back(std::move(child->children[0])); child->children.clear(); - delete child; } children.clear(); @@ -2783,39 +2751,38 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin std::vector z_const(1, RTLIL::State::Sz); - AstNode *mux_input = children_list.at(1); + auto& mux_input = children_list.at(1); if (str == "notif0" || str == "notif1") { - mux_input = new AstNode(AST_BIT_NOT, mux_input); + mux_input = std::make_unique(AST_BIT_NOT, std::move(mux_input)); } - AstNode *node = new AstNode(AST_TERNARY, children_list.at(2)); + auto node = std::make_unique(AST_TERNARY, std::move(children_list.at(2))); if (str == "bufif0") { node->children.push_back(AstNode::mkconst_bits(z_const, false)); - node->children.push_back(mux_input); + node->children.push_back(std::move(mux_input)); } else { - node->children.push_back(mux_input); + node->children.push_back(std::move(mux_input)); node->children.push_back(AstNode::mkconst_bits(z_const, false)); } str.clear(); type = AST_ASSIGN; - children.push_back(children_list.at(0)); + children.push_back(std::move(children_list.at(0))); children.back()->was_checked = true; - children.push_back(node); + children.push_back(std::move(node)); fixup_hierarchy_flags(); did_something = true; } else if (str == "buf" || str == "not") { - AstNode *input = children_list.back(); + auto& input = children_list.back(); if (str == "not") - input = new AstNode(AST_BIT_NOT, input); + input = std::make_unique(AST_BIT_NOT, std::move(input)); - newNode = new AstNode(AST_GENBLOCK); + newNode = std::make_unique(AST_GENBLOCK); for (auto it = children_list.begin(); it != std::prev(children_list.end()); it++) { - newNode->children.push_back(new AstNode(AST_ASSIGN, *it, input->clone())); + newNode->children.push_back(std::make_unique(AST_ASSIGN, std::move(*it), input->clone())); newNode->children.back()->was_checked = true; } - delete input; did_something = true; } @@ -2838,20 +2805,20 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin op_type = AST_BIT_XOR, invert_results = true; log_assert(op_type != AST_NONE); - AstNode *node = children_list[1]; + auto& node = children_list[1]; if (op_type != AST_POS) for (size_t i = 2; i < children_list.size(); i++) { - node = new AstNode(op_type, node, children_list[i]); + node = std::make_unique(op_type, std::move(node), std::move(children_list[i])); node->location = location; } if (invert_results) - node = new AstNode(AST_BIT_NOT, node); + node = std::make_unique(AST_BIT_NOT, std::move(node)); str.clear(); type = AST_ASSIGN; - children.push_back(children_list[0]); + children.push_back(std::move(children_list[0])); children.back()->was_checked = true; - children.push_back(node); + children.push_back(std::move(node)); fixup_hierarchy_flags(); did_something = true; } @@ -2866,7 +2833,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin goto skip_dynamic_range_lvalue_expansion; if (children[0]->children[0]->range_valid || did_something) goto skip_dynamic_range_lvalue_expansion; - if (children[0]->id2ast == NULL || children[0]->id2ast->type != AST_WIRE) + if (children[0]->id2ast == nullptr || children[0]->id2ast->type != AST_WIRE) goto skip_dynamic_range_lvalue_expansion; if (!children[0]->id2ast->range_valid) goto skip_dynamic_range_lvalue_expansion; @@ -2878,10 +2845,10 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin int wire_offset = children[0]->id2ast->range_right; int result_width = 1; - AstNode *shift_expr = NULL; - AstNode *range = children[0]->children[0]; + std::unique_ptr shift_expr = nullptr; + auto& range = children[0]->children[0]; - if (!try_determine_range_width(range, result_width)) + if (!try_determine_range_width(range.get(), result_width)) input_error("Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); if (range->children.size() >= 2) @@ -2925,14 +2892,14 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin AstNode *lsb_expr = shift_expr->type == AST_ADD && shift_expr->children[0]->type == AST_SELFSZ && shift_expr->children[1]->type == AST_CONSTANT && shift_expr->children[1]->integer == 0 ? - shift_expr->children[0]->children[0] : - shift_expr; + shift_expr->children[0]->children[0].get() : + shift_expr.get(); // Extract stride from indexing of two-dimensional packed arrays and // variable slices on the form dst[i*stride +: width] = src. if (lsb_expr->type == AST_MUL && - (lsb_expr->children[0]->type == AST_CONSTANT || - lsb_expr->children[1]->type == AST_CONSTANT)) + (lsb_expr->children[0]->type == AST_CONSTANT || + lsb_expr->children[1]->type == AST_CONSTANT)) { int stride_ix = lsb_expr->children[1]->type == AST_CONSTANT; stride = (int)lsb_expr->children[stride_ix]->integer; @@ -2980,11 +2947,14 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin int rvalue_width; bool rvalue_sign; children[1]->detectSignWidth(rvalue_width, rvalue_sign); - AstNode *rvalue = mktemp_logic("$bitselwrite$rvalue$", current_ast_mod, true, rvalue_width - 1, 0, rvalue_sign); - AstNode *caseNode = new AstNode(AST_CASE, shift_expr); - newNode = new AstNode(AST_BLOCK, - new AstNode(AST_ASSIGN_EQ, rvalue, children[1]->clone()), - caseNode); + auto rvalue = mktemp_logic("$bitselwrite$rvalue$", current_ast_mod, true, rvalue_width - 1, 0, rvalue_sign); + auto* rvalue_leaky = rvalue.get(); + log("make 1\n"); + auto case_node_owned = std::make_unique(AST_CASE, std::move(shift_expr)); + auto* case_node = case_node_owned.get(); + newNode = std::make_unique(AST_BLOCK, + std::make_unique(AST_ASSIGN_EQ, std::move(rvalue), children[1]->clone()), + std::move(case_node_owned)); did_something = true; for (int i = 1 - result_width; i < wire_width; i++) { @@ -2997,26 +2967,26 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (start_bit%bitno_div != 0 || (stride == 0 && start_bit != 0)) continue; - AstNode *cond = new AstNode(AST_COND, mkconst_int(start_bit, case_sign_hint, max_width)); - AstNode *lvalue = children[0]->clone(); + auto cond = std::make_unique(AST_COND, mkconst_int(start_bit, case_sign_hint, max_width)); + auto lvalue = children[0]->clone(); lvalue->delete_children(); if (member_node) lvalue->set_attribute(ID::wiretype, member_node->clone()); - lvalue->children.push_back(new AstNode(AST_RANGE, + lvalue->children.push_back(std::make_unique(AST_RANGE, mkconst_int(end_bit, true), mkconst_int(start_bit, true))); - cond->children.push_back(new AstNode(AST_BLOCK, new AstNode(type, lvalue, rvalue->clone()))); - caseNode->children.push_back(cond); + cond->children.push_back(std::make_unique(AST_BLOCK, std::make_unique(std::move(type), std::move(lvalue), rvalue_leaky->clone()))); + case_node->children.push_back(std::move(cond)); } } else { // mask and shift operations // dst = (dst & ~(width'1 << lsb)) | unsigned'(width'(src)) << lsb) - AstNode *lvalue = children[0]->clone(); + auto lvalue = children[0]->clone(); lvalue->delete_children(); if (member_node) lvalue->set_attribute(ID::wiretype, member_node->clone()); - AstNode *old_data = lvalue->clone(); + auto old_data = lvalue->clone(); if (type == AST_ASSIGN_LE) old_data->lookahead = true; @@ -3025,51 +2995,52 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin shift_expr->detectSignWidth(shift_width_hint, shift_sign_hint); // All operations are carried out in a new block. - newNode = new AstNode(AST_BLOCK); + newNode = std::make_unique(AST_BLOCK); // Temporary register holding the result of the bit- or part-select position expression. - AstNode *pos = mktemp_logic("$bitselwrite$pos$", current_ast_mod, true, shift_width_hint - 1, 0, shift_sign_hint); - newNode->children.push_back(new AstNode(AST_ASSIGN_EQ, pos, shift_expr)); - + auto pos = mktemp_logic("$bitselwrite$pos$", current_ast_mod, true, shift_width_hint - 1, 0, shift_sign_hint); // Calculate lsb from position. - AstNode *shift_val = pos->clone(); + auto shift_val = pos->clone(); + + newNode->children.push_back(std::make_unique(AST_ASSIGN_EQ, std::move(pos), std::move(shift_expr))); // If the expression is signed, we must add an extra bit for possible negation of the most negative number. // If the expression is unsigned, we must add an extra bit for sign. - shift_val = new AstNode(AST_CAST_SIZE, mkconst_int(shift_width_hint + 1, true), shift_val); + shift_val = std::make_unique(AST_CAST_SIZE, mkconst_int(shift_width_hint + 1, true), std::move(shift_val)); if (!shift_sign_hint) - shift_val = new AstNode(AST_TO_SIGNED, shift_val); + shift_val = std::make_unique(AST_TO_SIGNED, std::move(shift_val)); // offset the shift amount by the lower bound of the dimension if (wire_offset != 0) - shift_val = new AstNode(AST_SUB, shift_val, mkconst_int(wire_offset, true)); + shift_val = std::make_unique(AST_SUB, std::move(shift_val), mkconst_int(wire_offset, true)); // reflect the shift amount if the dimension is swapped if (children[0]->id2ast->range_swapped) - shift_val = new AstNode(AST_SUB, mkconst_int(wire_width - result_width, true), shift_val); + shift_val = std::make_unique(AST_SUB, mkconst_int(wire_width - result_width, true), std::move(shift_val)); // AST_SHIFT uses negative amounts for shifting left - shift_val = new AstNode(AST_NEG, shift_val); + shift_val = std::make_unique(AST_NEG, std::move(shift_val)); + auto also_shift_val = shift_val->clone(); // dst = (dst & ~(width'1 << lsb)) | unsigned'(width'(src)) << lsb) did_something = true; - AstNode *bitmask = mkconst_bits(std::vector(result_width, State::S1), false); + auto bitmask = mkconst_bits(std::vector(result_width, State::S1), false); newNode->children.push_back( - new AstNode(type, - lvalue, - new AstNode(AST_BIT_OR, - new AstNode(AST_BIT_AND, - old_data, - new AstNode(AST_BIT_NOT, - new AstNode(AST_SHIFT, - bitmask, - shift_val->clone()))), - new AstNode(AST_SHIFT, - new AstNode(AST_TO_UNSIGNED, - new AstNode(AST_CAST_SIZE, - mkconst_int(result_width, true), - children[1]->clone())), - shift_val)))); + std::make_unique(std::move(type), + std::move(lvalue), + std::make_unique(AST_BIT_OR, + std::make_unique(AST_BIT_AND, + std::move(old_data), + std::make_unique(AST_BIT_NOT, + std::make_unique(AST_SHIFT, + std::move(bitmask), + std::move(shift_val)))), + std::make_unique(AST_SHIFT, + std::make_unique(AST_TO_UNSIGNED, + std::make_unique(AST_CAST_SIZE, + mkconst_int(result_width, true), + children[1]->clone())), + std::move(also_shift_val))))); newNode->fixup_hierarchy_flags(true); } @@ -3079,11 +3050,11 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin skip_dynamic_range_lvalue_expansion:; // found right-hand side identifier for memory -> replace with memory read port - if (stage > 1 && type == AST_IDENTIFIER && id2ast != NULL && id2ast->type == AST_MEMORY && !in_lvalue && + if (stage > 1 && type == AST_IDENTIFIER && id2ast != nullptr && id2ast->type == AST_MEMORY && !in_lvalue && children.size() == 1 && children[0]->type == AST_RANGE && children[0]->children.size() == 1) { if (integer < (unsigned)id2ast->unpacked_dimensions) input_error("Insufficient number of array indices for %s.\n", log_id(str)); - newNode = new AstNode(AST_MEMRD, children[0]->children[0]->clone()); + newNode = std::make_unique(AST_MEMRD, children[0]->children[0]->clone()); newNode->str = str; newNode->id2ast = id2ast; goto apply_newNode; @@ -3094,39 +3065,41 @@ skip_dynamic_range_lvalue_expansion:; { bool found_nontrivial_member = false; - for (auto child : children[0]->children) { - if (child->type == AST_IDENTIFIER && child->id2ast != NULL && child->id2ast->type == AST_MEMORY) + for (auto& child : children[0]->children) { + if (child->type == AST_IDENTIFIER && child->id2ast != nullptr && child->id2ast->type == AST_MEMORY) found_nontrivial_member = true; } if (found_nontrivial_member) { - newNode = new AstNode(AST_BLOCK); + newNode = std::make_unique(AST_BLOCK); - AstNode *wire_tmp = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(width_hint-1, true), mkconst_int(0, true))); + auto wire_tmp_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(width_hint-1, true), mkconst_int(0, true))); + auto wire_tmp = wire_tmp_owned.get(); wire_tmp->str = stringf("$splitcmplxassign$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); - current_ast_mod->children.push_back(wire_tmp); current_scope[wire_tmp->str] = wire_tmp; + current_ast_mod->children.push_back(std::move(wire_tmp_owned)); wire_tmp->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); while (wire_tmp->simplify(true, 1, -1, false)) { } wire_tmp->is_logic = true; - AstNode *wire_tmp_id = new AstNode(AST_IDENTIFIER); + auto wire_tmp_id_owned = std::make_unique(AST_IDENTIFIER); + auto* wire_tmp_id = wire_tmp_id_owned.get(); wire_tmp_id->str = wire_tmp->str; - newNode->children.push_back(new AstNode(AST_ASSIGN_EQ, wire_tmp_id, children[1]->clone())); + newNode->children.push_back(std::make_unique(AST_ASSIGN_EQ, std::move(wire_tmp_id_owned), children[1]->clone())); newNode->children.back()->was_checked = true; int cursor = 0; - for (auto child : children[0]->children) + for (auto& child : children[0]->children) { int child_width_hint = -1; bool child_sign_hint = true; child->detectSignWidth(child_width_hint, child_sign_hint); - AstNode *rhs = wire_tmp_id->clone(); - rhs->children.push_back(new AstNode(AST_RANGE, AstNode::mkconst_int(cursor+child_width_hint-1, true), AstNode::mkconst_int(cursor, true))); - newNode->children.push_back(new AstNode(type, child->clone(), rhs)); + auto rhs = wire_tmp_id->clone(); + rhs->children.push_back(std::make_unique(AST_RANGE, AstNode::mkconst_int(cursor+child_width_hint-1, true), AstNode::mkconst_int(cursor, true))); + newNode->children.push_back(std::make_unique(type, child->clone(), std::move(rhs))); cursor += child_width_hint; } @@ -3152,8 +3125,8 @@ skip_dynamic_range_lvalue_expansion:; bool mem_signed = children[0]->id2ast->is_signed; children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits); - newNode = new AstNode(AST_BLOCK); - AstNode *defNode = new AstNode(AST_BLOCK); + newNode = std::make_unique(AST_BLOCK); + auto defNode = std::make_unique(AST_BLOCK); int data_range_left = children[0]->id2ast->children[0]->range_left; int data_range_right = children[0]->id2ast->children[0]->range_right; @@ -3172,74 +3145,75 @@ skip_dynamic_range_lvalue_expansion:; for (int i = 0; i < mem_width; i++) set_bits_en.push_back(RTLIL::State::S1); - AstNode *node_addr = nullptr; + std::unique_ptr node_addr = nullptr; if (children[0]->children[0]->children[0]->isConst()) { node_addr = children[0]->children[0]->children[0]->clone(); } else { - AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); + auto wire_addr_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); + auto* wire_addr = wire_addr_owned.get(); wire_addr->str = id_addr; wire_addr->was_checked = true; - current_ast_mod->children.push_back(wire_addr); + current_ast_mod->children.push_back(std::move(wire_addr_owned)); current_scope[wire_addr->str] = wire_addr; while (wire_addr->simplify(true, 1, -1, false)) { } - AstNode *assign_addr = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_addr, false)); + auto assign_addr = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), mkconst_bits(x_bits_addr, false)); assign_addr->children[0]->str = id_addr; assign_addr->children[0]->was_checked = true; - defNode->children.push_back(assign_addr); + defNode->children.push_back(std::move(assign_addr)); - assign_addr = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone()); + assign_addr = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone()); assign_addr->children[0]->str = id_addr; assign_addr->children[0]->was_checked = true; - newNode->children.push_back(assign_addr); + newNode->children.push_back(std::move(assign_addr)); - node_addr = new AstNode(AST_IDENTIFIER); + node_addr = std::make_unique(AST_IDENTIFIER); node_addr->str = id_addr; } - AstNode *node_data = nullptr; + std::unique_ptr node_data = nullptr; if (children[0]->children.size() == 1 && children[1]->isConst()) { node_data = children[1]->clone(); } else { - AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); + auto wire_data_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); + auto* wire_data = wire_data_owned.get(); wire_data->str = id_data; wire_data->was_checked = true; wire_data->is_signed = mem_signed; - current_ast_mod->children.push_back(wire_data); current_scope[wire_data->str] = wire_data; + current_ast_mod->children.push_back(std::move(wire_data_owned)); while (wire_data->simplify(true, 1, -1, false)) { } - AstNode *assign_data = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_data, false)); + auto assign_data = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), mkconst_bits(x_bits_data, false)); assign_data->children[0]->str = id_data; assign_data->children[0]->was_checked = true; - defNode->children.push_back(assign_data); + defNode->children.push_back(std::move(assign_data)); - node_data = new AstNode(AST_IDENTIFIER); + node_data = std::make_unique(AST_IDENTIFIER); node_data->str = id_data; } - AstNode *wire_en = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); + auto wire_en_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); + auto* wire_en = wire_en_owned.get(); wire_en->str = id_en; wire_en->was_checked = true; - current_ast_mod->children.push_back(wire_en); current_scope[wire_en->str] = wire_en; + current_ast_mod->children.push_back(std::move(wire_en_owned)); while (wire_en->simplify(true, 1, -1, false)) { } - AstNode *assign_en_first = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, mem_width)); + auto assign_en_first = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), mkconst_int(0, false, mem_width)); assign_en_first->children[0]->str = id_en; assign_en_first->children[0]->was_checked = true; - defNode->children.push_back(assign_en_first); + defNode->children.push_back(std::move(assign_en_first)); - AstNode *node_en = new AstNode(AST_IDENTIFIER); + auto node_en = std::make_unique(AST_IDENTIFIER); node_en->str = id_en; if (!defNode->children.empty()) - current_top_block->children.insert(current_top_block->children.begin(), defNode); - else - delete defNode; + current_top_block->children.insert(current_top_block->children.begin(), std::move(defNode)); - AstNode *assign_data = nullptr; - AstNode *assign_en = nullptr; + std::unique_ptr assign_data = nullptr; + std::unique_ptr assign_en = nullptr; if (children[0]->children.size() == 2) { if (children[0]->children[1]->range_valid) @@ -3250,24 +3224,24 @@ skip_dynamic_range_lvalue_expansion:; std::vector padding_x(offset, RTLIL::State::Sx); - assign_data = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), - new AstNode(AST_CONCAT, mkconst_bits(padding_x, false), children[1]->clone())); + assign_data = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), + std::make_unique(AST_CONCAT, mkconst_bits(padding_x, false), children[1]->clone())); assign_data->children[0]->str = id_data; assign_data->children[0]->was_checked = true; for (int i = 0; i < mem_width; i++) set_bits_en[i] = offset <= i && i < offset+width ? RTLIL::State::S1 : RTLIL::State::S0; - assign_en = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); + assign_en = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); assign_en->children[0]->str = id_en; assign_en->children[0]->was_checked = true; } else { - AstNode *the_range = children[0]->children[1]; - AstNode *offset_ast; + std::unique_ptr& the_range = children[0]->children[1]; + std::unique_ptr offset_ast; int width; - if (!try_determine_range_width(the_range, width)) + if (!try_determine_range_width(the_range.get(), width)) input_error("Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); if (the_range->children.size() >= 2) @@ -3276,44 +3250,43 @@ skip_dynamic_range_lvalue_expansion:; offset_ast = the_range->children[0]->clone(); if (mem_data_range_offset) - offset_ast = new AstNode(AST_SUB, offset_ast, mkconst_int(mem_data_range_offset, true)); + offset_ast = std::make_unique(AST_SUB, std::move(offset_ast), mkconst_int(mem_data_range_offset, true)); - assign_data = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), - new AstNode(AST_SHIFT_LEFT, children[1]->clone(), offset_ast->clone())); + assign_data = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), + std::make_unique(AST_SHIFT_LEFT, children[1]->clone(), offset_ast->clone())); assign_data->children[0]->str = id_data; assign_data->children[0]->was_checked = true; for (int i = 0; i < mem_width; i++) set_bits_en[i] = i < width ? RTLIL::State::S1 : RTLIL::State::S0; - assign_en = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), - new AstNode(AST_SHIFT_LEFT, mkconst_bits(set_bits_en, false), offset_ast->clone())); + assign_en = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), + std::make_unique(AST_SHIFT_LEFT, mkconst_bits(set_bits_en, false), offset_ast->clone())); assign_en->children[0]->str = id_en; assign_en->children[0]->was_checked = true; - delete offset_ast; } } else { if (!(children[0]->children.size() == 1 && children[1]->isConst())) { - assign_data = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), children[1]->clone()); + assign_data = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), children[1]->clone()); assign_data->children[0]->str = id_data; assign_data->children[0]->was_checked = true; } - assign_en = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); + assign_en = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); assign_en->children[0]->str = id_en; assign_en->children[0]->was_checked = true; } if (assign_data) - newNode->children.push_back(assign_data); + newNode->children.push_back(std::move(assign_data)); if (assign_en) - newNode->children.push_back(assign_en); + newNode->children.push_back(std::move(assign_en)); - AstNode *wrnode; + std::unique_ptr wrnode; if (current_always->type == AST_INITIAL) - wrnode = new AstNode(AST_MEMINIT, node_addr, node_data, node_en, mkconst_int(1, false)); + wrnode = std::make_unique(AST_MEMINIT, std::move(node_addr), std::move(node_data), std::move(node_en), mkconst_int(1, false)); else - wrnode = new AstNode(AST_MEMWR, node_addr, node_data, node_en); + wrnode = std::make_unique(AST_MEMWR, std::move(node_addr), std::move(node_data), std::move(node_en)); wrnode->str = children[0]->str; wrnode->id2ast = children[0]->id2ast; wrnode->location = location; @@ -3327,14 +3300,13 @@ skip_dynamic_range_lvalue_expansion:; } wrnode->children.push_back(mkconst_bits(priority_mask, false)); current_memwr_visible[wrnode->str].insert(portid); - current_always->children.push_back(wrnode); + current_always->children.push_back(std::move(wrnode)); } else { - current_ast_mod->children.push_back(wrnode); + current_ast_mod->children.push_back(std::move(wrnode)); } if (newNode->children.empty()) { - delete newNode; - newNode = new AstNode(); + newNode = std::make_unique(); } goto apply_newNode; } @@ -3348,21 +3320,22 @@ skip_dynamic_range_lvalue_expansion:; { int myidx = autoidx++; - AstNode *wire = new AstNode(AST_WIRE); + auto wire_owned = std::make_unique(AST_WIRE); + auto* wire = wire_owned.get(); + current_ast_mod->children.push_back(std::move(wire_owned)); wire->str = stringf("$initstate$%d_wire", myidx); - current_ast_mod->children.push_back(wire); while (wire->simplify(true, 1, -1, false)) { } - AstNode *cell = new AstNode(AST_CELL, new AstNode(AST_CELLTYPE), new AstNode(AST_ARGUMENT, new AstNode(AST_IDENTIFIER))); + auto cell = std::make_unique(AST_CELL, std::make_unique(AST_CELLTYPE), std::make_unique(AST_ARGUMENT, std::make_unique(AST_IDENTIFIER))); cell->str = stringf("$initstate$%d", myidx); cell->children[0]->str = "$initstate"; cell->children[1]->str = "\\Y"; cell->children[1]->children[0]->str = wire->str; cell->children[1]->children[0]->id2ast = wire; - current_ast_mod->children.push_back(cell); + current_ast_mod->children.push_back(std::move(cell)); while (cell->simplify(true, 1, -1, false)) { } - newNode = new AstNode(AST_IDENTIFIER); + newNode = std::make_unique(AST_IDENTIFIER); newNode->str = wire->str; newNode->id2ast = wire; goto apply_newNode; @@ -3385,20 +3358,19 @@ skip_dynamic_range_lvalue_expansion:; if (GetSize(children) == 2) { - AstNode *buf = children[1]->clone(); + auto buf = children[1]->clone(); while (buf->simplify(true, stage, -1, false)) { } if (buf->type != AST_CONSTANT) input_error("Failed to evaluate system function `%s' with non-constant value.\n", str.c_str()); num_steps = buf->asInt(true); - delete buf; } AstNode *block = nullptr; - for (auto child : current_always->children) + for (auto& child : current_always->children) if (child->type == AST_BLOCK) - block = child; + block = child.get(); log_assert(block != nullptr); @@ -3408,41 +3380,42 @@ skip_dynamic_range_lvalue_expansion:; } int myidx = autoidx++; - AstNode *outreg = nullptr; + AstNode* outreg = nullptr; for (int i = 0; i < num_steps; i++) { - AstNode *reg = new AstNode(AST_WIRE, new AstNode(AST_RANGE, + auto reg_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(width_hint-1, true), mkconst_int(0, true))); + auto* reg = reg_owned.get(); + current_ast_mod->children.push_back(std::move(reg_owned)); reg->str = stringf("$past$%s:%d$%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, myidx, i); reg->is_reg = true; reg->is_signed = sign_hint; - current_ast_mod->children.push_back(reg); while (reg->simplify(true, 1, -1, false)) { } - AstNode *regid = new AstNode(AST_IDENTIFIER); + auto regid = std::make_unique(AST_IDENTIFIER); regid->str = reg->str; regid->id2ast = reg; regid->was_checked = true; - AstNode *rhs = nullptr; + std::unique_ptr rhs = nullptr; if (outreg == nullptr) { rhs = children.at(0)->clone(); } else { - rhs = new AstNode(AST_IDENTIFIER); + rhs = std::make_unique(AST_IDENTIFIER); rhs->str = outreg->str; rhs->id2ast = outreg; } - block->children.push_back(new AstNode(AST_ASSIGN_LE, regid, rhs)); + block->children.push_back(std::make_unique(AST_ASSIGN_LE, std::move(regid), std::move(rhs))); outreg = reg; } - newNode = new AstNode(AST_IDENTIFIER); + newNode = std::make_unique(AST_IDENTIFIER); newNode->str = outreg->str; newNode->id2ast = outreg; goto apply_newNode; @@ -3458,25 +3431,25 @@ skip_dynamic_range_lvalue_expansion:; input_error("System function %s is only allowed in clocked blocks.\n", RTLIL::unescape_id(str).c_str()); - AstNode *present = children.at(0)->clone(); - AstNode *past = clone(); + auto present = children.at(0)->clone(); + auto past = clone(); past->str = "\\$past"; if (str == "\\$stable") - newNode = new AstNode(AST_EQ, past, present); + newNode = std::make_unique(AST_EQ, std::move(past), std::move(present)); else if (str == "\\$changed") - newNode = new AstNode(AST_NE, past, present); + newNode = std::make_unique(AST_NE, std::move(past), std::move(present)); else if (str == "\\$rose") - newNode = new AstNode(AST_LOGIC_AND, - new AstNode(AST_LOGIC_NOT, new AstNode(AST_BIT_AND, past, mkconst_int(1,false))), - new AstNode(AST_BIT_AND, present, mkconst_int(1,false))); + newNode = std::make_unique(AST_LOGIC_AND, + std::make_unique(AST_LOGIC_NOT, std::make_unique(AST_BIT_AND, std::move(past), mkconst_int(1,false))), + std::make_unique(AST_BIT_AND, std::move(present), mkconst_int(1,false))); else if (str == "\\$fell") - newNode = new AstNode(AST_LOGIC_AND, - new AstNode(AST_BIT_AND, past, mkconst_int(1,false)), - new AstNode(AST_LOGIC_NOT, new AstNode(AST_BIT_AND, present, mkconst_int(1,false)))); + newNode = std::make_unique(AST_LOGIC_AND, + std::make_unique(AST_BIT_AND, std::move(past), mkconst_int(1,false)), + std::make_unique(AST_LOGIC_NOT, std::make_unique(AST_BIT_AND, std::move(present), mkconst_int(1,false)))); else log_abort(); @@ -3496,7 +3469,7 @@ skip_dynamic_range_lvalue_expansion:; input_error("System function %s got %d arguments, expected 1.\n", RTLIL::unescape_id(str).c_str(), int(children.size())); - AstNode *buf = children[0]->clone(); + auto buf = children[0]->clone(); while (buf->simplify(true, stage, width_hint, sign_hint)) { } if (buf->type != AST_CONSTANT) input_error("Failed to evaluate system function `%s' with non-constant value.\n", str.c_str()); @@ -3504,7 +3477,6 @@ skip_dynamic_range_lvalue_expansion:; RTLIL::Const arg_value = buf->bitsAsConst(); if (arg_value.as_bool()) arg_value = const_sub(arg_value, 1, false, false, GetSize(arg_value)); - delete buf; uint32_t result = 0; for (auto i = 0; i < arg_value.size(); i++) @@ -3516,7 +3488,7 @@ skip_dynamic_range_lvalue_expansion:; } if (str == "\\$dimensions" || str == "\\$unpacked_dimensions" || - str == "\\$increment" || str == "\\$size" || str == "\\$bits" || str == "\\$high" || str == "\\$low" || str == "\\$left" || str == "\\$right") + str == "\\$increment" || str == "\\$size" || str == "\\$bits" || str == "\\$high" || str == "\\$low" || str == "\\$left" || str == "\\$right") { int dim = 1; if (str == "\\$dimensions" || str == "\\$unpacked_dimensions" || str == "\\$bits") { @@ -3528,24 +3500,23 @@ skip_dynamic_range_lvalue_expansion:; input_error("System function %s got %d arguments, expected 1 or 2.\n", RTLIL::unescape_id(str).c_str(), int(children.size())); if (children.size() == 2) { - AstNode *buf = children[1]->clone(); + auto buf = children[1]->clone(); // Evaluate constant expression while (buf->simplify(true, stage, width_hint, sign_hint)) { } dim = buf->asInt(false); - delete buf; } } - AstNode *buf = children[0]->clone(); + auto buf = children[0]->clone(); int mem_depth = 1; int result, high = 0, low = 0, left = 0, right = 0, width = 1; // defaults for a simple wire int expr_dimensions = 0, expr_unpacked_dimensions = 0; - AstNode *id_ast = NULL; + AstNode *id_ast = nullptr; buf->detectSignWidth(width_hint, sign_hint); if (buf->type == AST_IDENTIFIER) { id_ast = buf->id2ast; - if (id_ast == NULL && current_scope.count(buf->str)) + if (id_ast == nullptr && current_scope.count(buf->str)) id_ast = current_scope.at(buf->str); if (!id_ast) input_error("Failed to resolve identifier %s for width detection!\n", buf->str.c_str()); @@ -3584,7 +3555,6 @@ skip_dynamic_range_lvalue_expansion:; left = high = width - 1; expr_dimensions = 1; } - delete buf; if (str == "\\$dimensions") result = expr_dimensions; else if (str == "\\$unpacked_dimensions") @@ -3652,8 +3622,8 @@ skip_dynamic_range_lvalue_expansion:; if (str == "\\$rtoi") { newNode = AstNode::mkconst_int(x, true); } else { - newNode = new AstNode(AST_REALVALUE); - if (str == "\\$ln") newNode->realvalue = ::log(x); + newNode = std::make_unique(AST_REALVALUE); + if (str == "\\$ln") newNode->realvalue = ::log(x); else if (str == "\\$log10") newNode->realvalue = ::log10(x); else if (str == "\\$exp") newNode->realvalue = ::exp(x); else if (str == "\\$sqrt") newNode->realvalue = ::sqrt(x); @@ -3695,7 +3665,7 @@ skip_dynamic_range_lvalue_expansion:; // Determine which bits to count for (size_t i = 1; i < children.size(); i++) { - AstNode *node = children[i]; + auto& node = children[i]; while (node->simplify(true, stage, -1, false)) { } if (node->type != AST_CONSTANT) input_error("Failed to evaluate system function `%s' with non-constant control bit argument.\n", str.c_str()); @@ -3707,39 +3677,37 @@ skip_dynamic_range_lvalue_expansion:; // Detect width of exp (first argument of $countbits) int exp_width = -1; bool exp_sign = false; - AstNode *exp = children[0]; - exp->detectSignWidth(exp_width, exp_sign, NULL); + auto& exp = children[0]; + exp->detectSignWidth(exp_width, exp_sign, nullptr); newNode = mkconst_int(0, false); for (int i = 0; i < exp_width; i++) { // Generate nodes for: exp << i >> ($size(exp) - 1) - // ^^ ^^ - AstNode *lsh_node = new AstNode(AST_SHIFT_LEFT, exp->clone(), mkconst_int(i, false)); - AstNode *rsh_node = new AstNode(AST_SHIFT_RIGHT, lsh_node, mkconst_int(exp_width - 1, false)); + // ^^ ^^ + auto lsh_node = std::make_unique(AST_SHIFT_LEFT, exp->clone(), mkconst_int(i, false)); + auto rsh_node = std::make_unique(AST_SHIFT_RIGHT, std::move(lsh_node), mkconst_int(exp_width - 1, false)); - AstNode *or_node = nullptr; + std::unique_ptr or_node = nullptr; for (RTLIL::State control_bit : control_bits) { // Generate node for: (exp << i >> ($size(exp) - 1)) === control_bit - // ^^^ - AstNode *eq_node = new AstNode(AST_EQX, rsh_node->clone(), mkconst_bits({control_bit}, false)); + // ^^^ + auto eq_node = std::make_unique(AST_EQX, rsh_node->clone(), mkconst_bits({control_bit}, false)); // Or the result for each checked bit value if (or_node) - or_node = new AstNode(AST_LOGIC_OR, or_node, eq_node); + or_node = std::make_unique(AST_LOGIC_OR, std::move(or_node), std::move(eq_node)); else - or_node = eq_node; + or_node = std::move(eq_node); } // We should have at least one element in control_bits, // because we checked for the number of arguments above log_assert(or_node != nullptr); - delete rsh_node; - // Generate node for adding with result of previous bit - newNode = new AstNode(AST_ADD, newNode, or_node); + newNode = std::make_unique(AST_ADD, std::move(newNode), std::move(or_node)); } goto apply_newNode; @@ -3750,22 +3718,22 @@ skip_dynamic_range_lvalue_expansion:; input_error("System function %s got %d arguments, expected 1.\n", RTLIL::unescape_id(str).c_str(), int(children.size())); - AstNode *countbits = clone(); + auto countbits = clone(); countbits->str = "\\$countbits"; if (str == "\\$countones") { countbits->children.push_back(mkconst_bits({RTLIL::State::S1}, false)); - newNode = countbits; + newNode = std::move(countbits); } else if (str == "\\$isunknown") { countbits->children.push_back(mkconst_bits({RTLIL::Sx}, false)); countbits->children.push_back(mkconst_bits({RTLIL::Sz}, false)); - newNode = new AstNode(AST_GT, countbits, mkconst_int(0, false)); + newNode = std::make_unique(AST_GT, std::move(countbits), mkconst_int(0, false)); } else if (str == "\\$onehot") { countbits->children.push_back(mkconst_bits({RTLIL::State::S1}, false)); - newNode = new AstNode(AST_EQ, countbits, mkconst_int(1, false)); + newNode = std::make_unique(AST_EQ, std::move(countbits), mkconst_int(1, false)); } else if (str == "\\$onehot0") { countbits->children.push_back(mkconst_bits({RTLIL::State::S1}, false)); - newNode = new AstNode(AST_LE, countbits, mkconst_int(1, false)); + newNode = std::make_unique(AST_LE, std::move(countbits), mkconst_int(1, false)); } else { log_abort(); } @@ -3779,7 +3747,7 @@ skip_dynamic_range_lvalue_expansion:; std::string rtype, fname; std::vector argtypes; - std::vector args; + std::vector> args; rtype = RTLIL::unescape_id(dpi_decl->children.at(0)->str); fname = RTLIL::unescape_id(dpi_decl->children.at(1)->str); @@ -3799,9 +3767,6 @@ skip_dynamic_range_lvalue_expansion:; newNode = dpi_call(rtype, fname, argtypes, args); - for (auto arg : args) - delete arg; - goto apply_newNode; } @@ -3827,12 +3792,12 @@ skip_dynamic_range_lvalue_expansion:; input_error("System function %s got %d arguments, expected 2-4.\n", RTLIL::unescape_id(str).c_str(), int(children.size())); - AstNode *node_filename = children[0]->clone(); + auto node_filename = children[0]->clone(); while (node_filename->simplify(true, stage, width_hint, sign_hint)) { } if (node_filename->type != AST_CONSTANT) input_error("Failed to evaluate system function `%s' with non-constant 1st argument.\n", str.c_str()); - AstNode *node_memory = children[1]->clone(); + auto node_memory = children[1]->clone(); while (node_memory->simplify(true, stage, width_hint, sign_hint)) { } if (node_memory->type != AST_IDENTIFIER || node_memory->id2ast == nullptr || node_memory->id2ast->type != AST_MEMORY) input_error("Failed to evaluate system function `%s' with non-memory 2nd argument.\n", str.c_str()); @@ -3840,7 +3805,7 @@ skip_dynamic_range_lvalue_expansion:; int start_addr = -1, finish_addr = -1; if (GetSize(children) > 2) { - AstNode *node_addr = children[2]->clone(); + auto node_addr = children[2]->clone(); while (node_addr->simplify(true, stage, width_hint, sign_hint)) { } if (node_addr->type != AST_CONSTANT) input_error("Failed to evaluate system function `%s' with non-constant 3rd argument.\n", str.c_str()); @@ -3848,7 +3813,7 @@ skip_dynamic_range_lvalue_expansion:; } if (GetSize(children) > 3) { - AstNode *node_addr = children[3]->clone(); + auto node_addr = children[3]->clone(); while (node_addr->simplify(true, stage, width_hint, sign_hint)) { } if (node_addr->type != AST_CONSTANT) input_error("Failed to evaluate system function `%s' with non-constant 4th argument.\n", str.c_str()); @@ -3859,22 +3824,20 @@ skip_dynamic_range_lvalue_expansion:; if (current_always->type == AST_INITIAL) { pool queue; log_assert(current_always->children[0]->type == AST_BLOCK); - queue.insert(current_always->children[0]); + queue.insert(current_always->children[0].get()); while (!unconditional_init && !queue.empty()) { pool next_queue; - for (auto n : queue) - for (auto c : n->children) { - if (c == this) + for (auto& n : queue) + for (auto& c : n->children) { + if (c.get() == this) unconditional_init = true; - next_queue.insert(c); + next_queue.insert(c.get()); } next_queue.swap(queue); } } newNode = readmem(str == "\\$readmemh", node_filename->bitsAsConst().decode_string(), node_memory->id2ast, start_addr, finish_addr, unconditional_init); - delete node_filename; - delete node_memory; goto apply_newNode; } @@ -3889,10 +3852,11 @@ skip_dynamic_range_lvalue_expansion:; sstr << str << "$func$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++) << '.'; std::string prefix = sstr.str(); - AstNode *decl = current_scope[str]; + auto* decl = current_scope[str]; if (unevaluated_tern_branch && decl->is_recursive_function()) goto replace_fcall_later; - decl = decl->clone(); + auto decl_clone = decl->clone(); + decl = decl_clone.get(); // sketchy? decl->replace_result_wire_name_in_function(str, "$result"); // enables recursion decl->expand_genblock(prefix); @@ -3900,20 +3864,19 @@ skip_dynamic_range_lvalue_expansion:; { bool require_const_eval = decl->has_const_only_constructs(); bool all_args_const = true; - for (auto child : children) { + for (auto& child : children) { while (child->simplify(true, 1, -1, false)) { } if (child->type != AST_CONSTANT && child->type != AST_REALVALUE) all_args_const = false; } if (all_args_const) { - AstNode *func_workspace = decl->clone(); + auto func_workspace = decl->clone(); func_workspace->set_in_param_flag(true); func_workspace->str = prefix_id(prefix, "$result"); + // func_workspace->dumpAst(stdout, "func_workspace "); newNode = func_workspace->eval_const_function(this, in_param || require_const_eval); - delete func_workspace; if (newNode) { - delete decl; goto apply_newNode; } } @@ -3926,36 +3889,37 @@ skip_dynamic_range_lvalue_expansion:; size_t arg_count = 0; dict wire_cache; - vector new_stmts; - vector output_assignments; + vector> new_stmts; + vector> output_assignments; - if (current_block == NULL) + if (current_block == nullptr) { log_assert(type == AST_FCALL); - AstNode *wire = NULL; + std::unique_ptr wire = nullptr; std::string res_name = prefix_id(prefix, "$result"); - for (auto child : decl->children) + for (auto& child : decl->children) if (child->type == AST_WIRE && child->str == res_name) wire = child->clone(); - log_assert(wire != NULL); + log_assert(wire != nullptr); wire->port_id = 0; wire->is_input = false; wire->is_output = false; - current_scope[wire->str] = wire; - current_ast_mod->children.push_back(wire); - while (wire->simplify(true, 1, -1, false)) { } + auto* wire_leaky = wire.get(); + current_scope[wire->str] = wire_leaky; + current_ast_mod->children.push_back(std::move(wire)); + while (wire_leaky->simplify(true, 1, -1, false)) { } - AstNode *lvalue = new AstNode(AST_IDENTIFIER); - lvalue->str = wire->str; + auto lvalue = std::make_unique(AST_IDENTIFIER); + lvalue->str = wire_leaky->str; - AstNode *always = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK, - new AstNode(AST_ASSIGN_EQ, lvalue, clone()))); + auto always = std::make_unique(AST_ALWAYS, std::make_unique(AST_BLOCK, + std::make_unique(AST_ASSIGN_EQ, std::move(lvalue), clone()))); always->children[0]->children[0]->was_checked = true; - current_ast_mod->children.push_back(always); + current_ast_mod->children.push_back(std::move(always)); goto replace_fcall_with_id; } @@ -3972,57 +3936,57 @@ skip_dynamic_range_lvalue_expansion:; } else celltype = RTLIL::escape_id(celltype); - AstNode *cell = new AstNode(AST_CELL, new AstNode(AST_CELLTYPE)); + auto cell = std::make_unique(AST_CELL, std::make_unique(AST_CELLTYPE)); cell->str = prefix.substr(0, GetSize(prefix)-1); cell->children[0]->str = celltype; - for (auto attr : decl->attributes) + for (auto& attr : decl->attributes) if (attr.first.str().rfind("\\via_celltype_defparam_", 0) == 0) { - AstNode *cell_arg = new AstNode(AST_PARASET, attr.second->clone()); + auto cell_arg = std::make_unique(AST_PARASET, attr.second->clone()); cell_arg->str = RTLIL::escape_id(attr.first.substr(strlen("\\via_celltype_defparam_"))); - cell->children.push_back(cell_arg); + cell->children.push_back(std::move(cell_arg)); } - for (auto child : decl->children) + for (auto& child : decl->children) if (child->type == AST_WIRE && (child->is_input || child->is_output || (type == AST_FCALL && child->str == str))) { - AstNode *wire = child->clone(); + auto wire = child->clone(); wire->port_id = 0; wire->is_input = false; wire->is_output = false; - current_ast_mod->children.push_back(wire); + current_ast_mod->children.push_back(std::move(wire)); while (wire->simplify(true, 1, -1, false)) { } - AstNode *wire_id = new AstNode(AST_IDENTIFIER); + auto wire_id = std::make_unique(AST_IDENTIFIER); wire_id->str = wire->str; if ((child->is_input || child->is_output) && arg_count < children.size()) { - AstNode *arg = children[arg_count++]->clone(); - AstNode *assign = child->is_input ? - new AstNode(AST_ASSIGN_EQ, wire_id->clone(), arg) : - new AstNode(AST_ASSIGN_EQ, arg, wire_id->clone()); + auto arg = children[arg_count++]->clone(); + auto assign = child->is_input ? + std::make_unique(AST_ASSIGN_EQ, wire_id->clone(), std::move(arg)) : + std::make_unique(AST_ASSIGN_EQ, std::move(arg), wire_id->clone()); assign->children[0]->was_checked = true; for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) { - if (*it != current_block_child) + if (it->get() != current_block_child) continue; - current_block->children.insert(it, assign); + current_block->children.insert(it, std::move(assign)); break; } } - AstNode *cell_arg = new AstNode(AST_ARGUMENT, wire_id); + auto cell_arg = std::make_unique(AST_ARGUMENT, std::move(wire_id)); cell_arg->str = child->str == str ? outport : child->str; - cell->children.push_back(cell_arg); + cell->children.push_back(std::move(cell_arg)); } - current_ast_mod->children.push_back(cell); + current_ast_mod->children.push_back(std::move(cell)); goto replace_fcall_with_id; } - for (auto child : decl->children) + for (auto& child : decl->children) if (child->type == AST_WIRE || child->type == AST_MEMORY || child->type == AST_PARAMETER || child->type == AST_LOCALPARAM || child->type == AST_ENUM_ITEM) { AstNode *wire = nullptr; @@ -4032,7 +3996,7 @@ skip_dynamic_range_lvalue_expansion:; wire = wire_cache.at(child->str); bool contains_value = wire->type == AST_LOCALPARAM; if (wire->children.size() == contains_value) { - for (auto c : child->children) + for (auto& c : child->children) wire->children.push_back(c->clone()); } else if (!child->children.empty()) { while (child->simplify(true, stage, -1, false)) { } @@ -4048,38 +4012,36 @@ skip_dynamic_range_lvalue_expansion:; } else { - wire = child->clone(); + current_ast_mod->children.push_back(child->clone()); + wire = current_ast_mod->children.back().get(); wire->port_id = 0; wire->is_input = false; wire->is_output = false; wire->is_reg = true; wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); if (child->type == AST_ENUM_ITEM) - wire->set_attribute(ID::enum_base_type, child->attributes[ID::enum_base_type]); + wire->set_attribute(ID::enum_base_type, std::move(child->attributes[ID::enum_base_type])); wire_cache[child->str] = wire; current_scope[wire->str] = wire; - current_ast_mod->children.push_back(wire); } while (wire->simplify(true, 1, -1, false)) { } if ((child->is_input || child->is_output) && arg_count < children.size()) { - AstNode *arg = children[arg_count++]->clone(); + auto arg = children[arg_count++]->clone(); // convert purely constant arguments into localparams - if (child->is_input && child->type == AST_WIRE && arg->type == AST_CONSTANT && node_contains_assignment_to(decl, child)) { + if (child->is_input && child->type == AST_WIRE && arg->type == AST_CONSTANT && node_contains_assignment_to(decl, child.get())) { wire->type = AST_LOCALPARAM; - if (wire->attributes.count(ID::nosync)) - delete wire->attributes.at(ID::nosync); wire->attributes.erase(ID::nosync); wire->children.insert(wire->children.begin(), arg->clone()); // args without a range implicitly have width 1 if (wire->children.back()->type != AST_RANGE) { // check if this wire is redeclared with an explicit size bool uses_explicit_size = false; - for (const AstNode *other_child : decl->children) + for (auto& other_child : decl->children) if (other_child->type == AST_WIRE && child->str == other_child->str && !other_child->children.empty() && other_child->children.back()->type == AST_RANGE) { @@ -4087,56 +4049,53 @@ skip_dynamic_range_lvalue_expansion:; break; } if (!uses_explicit_size) { - AstNode* range = new AstNode(); + auto range = std::make_unique(); range->type = AST_RANGE; - wire->children.push_back(range); range->children.push_back(mkconst_int(0, true)); range->children.push_back(mkconst_int(0, true)); + wire->children.push_back(std::move(range)); } } wire->fixup_hierarchy_flags(); // updates the sizing while (wire->simplify(true, 1, -1, false)) { } - delete arg; continue; } - AstNode *wire_id = new AstNode(AST_IDENTIFIER); + auto wire_id = std::make_unique(AST_IDENTIFIER); wire_id->str = wire->str; - if (child->is_input) { - AstNode *assign = new AstNode(AST_ASSIGN_EQ, wire_id->clone(), arg->clone()); + auto assign = std::make_unique(AST_ASSIGN_EQ, wire_id->clone(), arg->clone()); assign->children[0]->was_checked = true; - new_stmts.push_back(assign); + new_stmts.push_back(std::move(assign)); } if (child->is_output) { - AstNode *assign = new AstNode(AST_ASSIGN_EQ, arg->clone(), wire_id->clone()); + auto assign = std::make_unique(AST_ASSIGN_EQ, arg->clone(), wire_id->clone()); assign->children[0]->was_checked = true; - output_assignments.push_back(assign); + output_assignments.push_back(std::move(assign)); } - - delete arg; - delete wire_id; } } - for (auto child : decl->children) + for (auto& child : decl->children) if (child->type != AST_WIRE && child->type != AST_MEMORY && child->type != AST_PARAMETER && child->type != AST_LOCALPARAM) new_stmts.push_back(child->clone()); - new_stmts.insert(new_stmts.end(), output_assignments.begin(), output_assignments.end()); + new_stmts.reserve(new_stmts.size() + output_assignments.size()); + std::move(output_assignments.begin(), output_assignments.end(), std::back_inserter(new_stmts)); for (auto it = current_block->children.begin(); ; it++) { log_assert(it != current_block->children.end()); - if (*it == current_block_child) { - current_block->children.insert(it, new_stmts.begin(), new_stmts.end()); + if (it->get() == current_block_child) { + current_block->children.insert(it, + std::make_move_iterator(new_stmts.begin()), + std::make_move_iterator(new_stmts.end())); break; } } replace_fcall_with_id: - delete decl; if (type == AST_FCALL) { delete_children(); type = AST_IDENTIFIER; @@ -4252,14 +4211,14 @@ replace_fcall_later:; if (0) { case AST_SHIFT_RIGHT: const_func = RTLIL::const_shr; } if (0) { case AST_SHIFT_SLEFT: const_func = RTLIL::const_sshl; } if (0) { case AST_SHIFT_SRIGHT: const_func = RTLIL::const_sshr; } - if (0) { case AST_POW: const_func = RTLIL::const_pow; } + if (0) { case AST_POW: const_func = RTLIL::const_pow; } if (children[0]->type == AST_CONSTANT && children[1]->type == AST_CONSTANT) { RTLIL::Const y = const_func(children[0]->bitsAsConst(width_hint, sign_hint), RTLIL::Const(children[1]->bits), sign_hint, type == AST_POW ? children[1]->is_signed : false, width_hint); newNode = mkconst_bits(y.to_bits(), sign_hint); } else if (type == AST_POW && children[0]->isConst() && children[1]->isConst()) { - newNode = new AstNode(AST_REALVALUE); + newNode = std::make_unique(AST_REALVALUE); newNode->realvalue = pow(children[0]->asReal(sign_hint), children[1]->asReal(sign_hint)); } break; @@ -4304,7 +4263,7 @@ replace_fcall_later:; newNode = mkconst_bits(y.to_bits(), sign_hint); } else if (children[0]->isConst() && children[1]->isConst()) { - newNode = new AstNode(AST_REALVALUE); + newNode = std::make_unique(AST_REALVALUE); switch (type) { case AST_ADD: newNode->realvalue = children[0]->asReal(sign_hint) + children[1]->asReal(sign_hint); break; case AST_SUB: newNode->realvalue = children[0]->asReal(sign_hint) - children[1]->asReal(sign_hint); break; @@ -4323,7 +4282,7 @@ replace_fcall_later:; newNode = mkconst_bits(y.to_bits(), sign_hint); } else if (children[0]->isConst()) { - newNode = new AstNode(AST_REALVALUE); + newNode = std::make_unique(AST_REALVALUE); if (type == AST_NEG) newNode->realvalue = -children[0]->asReal(sign_hint); else @@ -4337,13 +4296,13 @@ replace_fcall_later:; AstNode *choice = pair.first; AstNode *not_choice = pair.second; - if (choice != NULL) { + if (choice != nullptr) { if (choice->type == AST_CONSTANT) { int other_width_hint = width_hint; bool other_sign_hint = sign_hint, other_real = false; not_choice->detectSignWidth(other_width_hint, other_sign_hint, &other_real); if (other_real) { - newNode = new AstNode(AST_REALVALUE); + newNode = std::make_unique(AST_REALVALUE); choice->detectSignWidth(width_hint, sign_hint); newNode->realvalue = choice->asReal(sign_hint); } else { @@ -4366,7 +4325,7 @@ replace_fcall_later:; a.bits()[i] = RTLIL::State::Sx; newNode = mkconst_bits(a.to_bits(), sign_hint); } else if (children[1]->isConst() && children[2]->isConst()) { - newNode = new AstNode(AST_REALVALUE); + newNode = std::make_unique(AST_REALVALUE); if (children[1]->asReal(sign_hint) == children[2]->asReal(sign_hint)) newNode->realvalue = children[1]->asReal(sign_hint); else @@ -4418,12 +4377,12 @@ apply_newNode: // fprintf(stderr, "----\n"); // dumpAst(stderr, "- "); // newNode->dumpAst(stderr, "+ "); - log_assert(newNode != NULL); + log_assert(newNode != nullptr); + // newNode->null_check(); newNode->filename = filename; newNode->location = location; - newNode->cloneInto(this); + newNode->cloneInto(*this); fixup_hierarchy_flags(); - delete newNode; did_something = true; } @@ -4436,21 +4395,21 @@ apply_newNode: void AstNode::replace_result_wire_name_in_function(const std::string &from, const std::string &to) { - for (AstNode *child : children) + for (auto& child : children) child->replace_result_wire_name_in_function(from, to); if (str == from && type != AST_FCALL && type != AST_TCALL) str = to; } // replace a readmem[bh] TCALL ast node with a block of memory assignments -AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init) +std::unique_ptr AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init) { int mem_width, mem_size, addr_bits; memory->meminfo(mem_width, mem_size, addr_bits); - AstNode *block = new AstNode(AST_BLOCK); + auto block = std::make_unique(AST_BLOCK); - AstNode *meminit = nullptr; + AstNode* meminit = nullptr; int next_meminit_cursor=0; vector meminit_bits; vector en_bits; @@ -4524,7 +4483,8 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m continue; } - AstNode *value = VERILOG_FRONTEND::const2ast(stringf("%d'%c", mem_width, is_readmemh ? 'h' : 'b') + token); + VERILOG_FRONTEND::ConstParser p{mem_filename, std::nullopt}; + auto value = p.const2ast(stringf("%d'%c", mem_width, is_readmemh ? 'h' : 'b') + token); if (unconditional_init) { @@ -4535,7 +4495,8 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m meminit->children[3] = AstNode::mkconst_int(meminit_size, false); } - meminit = new AstNode(AST_MEMINIT); + auto meminit_owned = std::make_unique(AST_MEMINIT); + meminit = meminit_owned.get(); meminit->children.push_back(AstNode::mkconst_int(cursor, false)); meminit->children.push_back(nullptr); meminit->children.push_back(AstNode::mkconst_bits(en_bits, false)); @@ -4545,18 +4506,17 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m meminit_bits.clear(); meminit_size = 0; - current_ast_mod->children.push_back(meminit); + current_ast_mod->children.push_back(std::move(meminit_owned)); next_meminit_cursor = cursor; } meminit_size++; next_meminit_cursor++; meminit_bits.insert(meminit_bits.end(), value->bits.begin(), value->bits.end()); - delete value; } else { - block->children.push_back(new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER, new AstNode(AST_RANGE, AstNode::mkconst_int(cursor, false))), value)); + block->children.push_back(std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER, std::make_unique(AST_RANGE, AstNode::mkconst_int(cursor, false))), std::move(value))); block->children.back()->children[0]->str = memory->str; block->children.back()->children[0]->id2ast = memory; block->children.back()->children[0]->was_checked = true; @@ -4633,7 +4593,7 @@ void AstNode::expand_genblock(const std::string &prefix) }; for (size_t i = 0; i < children.size(); i++) { - AstNode *child = children[i]; + auto* child = children[i].get(); switch (child->type) { case AST_WIRE: @@ -4659,9 +4619,9 @@ void AstNode::expand_genblock(const std::string &prefix) case AST_ENUM: current_scope[child->str] = child; - for (auto enode : child->children){ + for (auto& enode : child->children){ log_assert(enode->type == AST_ENUM_ITEM); - prefix_node(enode); + prefix_node(enode.get()); } break; @@ -4671,7 +4631,7 @@ void AstNode::expand_genblock(const std::string &prefix) } for (size_t i = 0; i < children.size(); i++) { - AstNode *child = children[i]; + auto& child = children[i]; // AST_PREFIX member names should not be prefixed; we recurse into them // as normal to ensure indices and ranges are properly resolved, and // then restore the previous string @@ -4703,7 +4663,7 @@ void AstNode::label_genblks(std::set& existing, int &counter) // seeing a proper generate control flow construct increments the // counter once ++counter; - for (AstNode *child : children) + for (auto& child : children) child->label_genblks(existing, counter); break; @@ -4720,7 +4680,7 @@ void AstNode::label_genblks(std::set& existing, int &counter) // within a genblk, the counter starts fresh std::set existing_local = existing; int counter_local = 0; - for (AstNode *child : children) + for (auto& child : children) child->label_genblks(existing_local, counter_local); break; } @@ -4729,7 +4689,7 @@ void AstNode::label_genblks(std::set& existing, int &counter) // track names which could conflict with implicit genblk names if (str.rfind("\\genblk", 0) == 0) existing.insert(str); - for (AstNode *child : children) + for (auto& child : children) child->label_genblks(existing, counter); break; } @@ -4740,7 +4700,7 @@ static void mark_memories_assign_lhs_complex(dict> & dict &mem2reg_candidates, AstNode *that) { for (auto &child : that->children) - mark_memories_assign_lhs_complex(mem2reg_places, mem2reg_candidates, child); + mark_memories_assign_lhs_complex(mem2reg_places, mem2reg_candidates, child.get()); if (that->type == AST_IDENTIFIER && that->id2ast && that->id2ast->type == AST_MEMORY) { AstNode *mem = that->id2ast; @@ -4764,7 +4724,7 @@ void AstNode::mem2reg_as_needed_pass1(dict> &mem2reg { // mark all memories that are used in a complex expression on the left side of an assignment for (auto &lhs_child : children[0]->children) - mark_memories_assign_lhs_complex(mem2reg_places, mem2reg_candidates, lhs_child); + mark_memories_assign_lhs_complex(mem2reg_places, mem2reg_candidates, lhs_child.get()); if (children[0]->type == AST_IDENTIFIER && children[0]->id2ast && children[0]->id2ast->type == AST_MEMORY) { @@ -4830,11 +4790,11 @@ void AstNode::mem2reg_as_needed_pass1(dict> &mem2reg if ((type == AST_MODULE || type == AST_INTERFACE) && get_bool_attribute(ID::mem2reg)) children_flags |= AstNode::MEM2REG_FL_ALL; - dict *proc_flags_p = NULL; + dict *proc_flags_p = nullptr; if (type == AST_ALWAYS) { int count_edge_events = 0; - for (auto child : children) + for (auto& child : children) if (child->type == AST_POSEDGE || child->type == AST_NEGEDGE) count_edge_events++; if (count_edge_events != 1) @@ -4850,12 +4810,12 @@ void AstNode::mem2reg_as_needed_pass1(dict> &mem2reg flags |= children_flags; log_assert((flags & ~0x000000ff) == 0); - for (auto child : children) + for (auto& child : children) { if (lhs_children_counter > 0) { lhs_children_counter--; if (child->children.size() && child->children[0]->type == AST_RANGE && child->children[0]->children.size()) { - for (auto c : child->children[0]->children) { + for (auto& c : child->children[0]->children) { if (proc_flags_p) c->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, *proc_flags_p, flags); else @@ -4891,7 +4851,7 @@ bool AstNode::mem2reg_check(pool &mem2reg_set) return true; } -void AstNode::mem2reg_remove(pool &mem2reg_set, vector &delnodes) +void AstNode::mem2reg_remove(pool &mem2reg_set) { log_assert(mem2reg_set.count(this) == 0); @@ -4899,17 +4859,16 @@ void AstNode::mem2reg_remove(pool &mem2reg_set, vector &deln id2ast = nullptr; for (size_t i = 0; i < children.size(); i++) { - if (mem2reg_set.count(children[i]) > 0) { - delnodes.push_back(children[i]); + if (mem2reg_set.count(children[i].get()) > 0) { children.erase(children.begin() + (i--)); } else { - children[i]->mem2reg_remove(mem2reg_set, delnodes); + children[i]->mem2reg_remove(mem2reg_set); } } } // actually replace memories with registers -bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, AstNode *block, AstNode *&async_block) +bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, AstNode *block, AstNode* async_block) { bool did_something = false; @@ -4936,9 +4895,10 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, if (length != 0) { - AstNode *block = new AstNode(AST_INITIAL, new AstNode(AST_BLOCK)); - mod->children.push_back(block); - block = block->children[0]; + auto block_owned = std::make_unique(AST_INITIAL, std::make_unique(AST_BLOCK)); + auto block = block_owned.get(); + mod->children.push_back(std::move(block_owned)); + block = block->children[0].get(); int wordsz = GetSize(data) / length; @@ -4952,11 +4912,11 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, while (epos < wordsz && en[epos] == State::S1) epos++; int clen = epos - pos; - AstNode *range = new AstNode(AST_RANGE, AstNode::mkconst_int(cursor+i, false)); + auto range = std::make_unique(AST_RANGE, AstNode::mkconst_int(cursor+i, false)); if (pos != 0 || epos != wordsz) { int left; int right; - AstNode *mrange = id2ast->children[0]; + auto& mrange = id2ast->children[0]; if (mrange->range_left < mrange->range_right) { right = mrange->range_right - pos; left = mrange->range_right - epos + 1; @@ -4964,42 +4924,39 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, right = mrange->range_right + pos; left = mrange->range_right + epos - 1; } - range = new AstNode(AST_MULTIRANGE, range, new AstNode(AST_RANGE, AstNode::mkconst_int(left, true), AstNode::mkconst_int(right, true))); + range = std::make_unique(AST_MULTIRANGE, std::move(range), std::make_unique(AST_RANGE, AstNode::mkconst_int(left, true), AstNode::mkconst_int(right, true))); } - AstNode *target = new AstNode(AST_IDENTIFIER, range); + auto target = std::make_unique(AST_IDENTIFIER, std::move(range)); target->str = str; target->id2ast = id2ast; target->was_checked = true; - block->children.push_back(new AstNode(AST_ASSIGN_EQ, target, mkconst_bits(data.extract(i*wordsz + pos, clen).to_bits(), false))); + block->children.push_back(std::make_unique(AST_ASSIGN_EQ, std::move(target), mkconst_bits(data.extract(i*wordsz + pos, clen).to_bits(), false))); pos = epos; } } } } - AstNode *newNode = new AstNode(AST_NONE); - newNode->cloneInto(this); - delete newNode; - + auto newNode = std::make_unique(AST_NONE); + newNode->cloneInto(*this); did_something = true; } - if (type == AST_ASSIGN && block == NULL && children[0]->mem2reg_check(mem2reg_set)) + if (type == AST_ASSIGN && block == nullptr && children[0]->mem2reg_check(mem2reg_set)) { - if (async_block == NULL) { - async_block = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK)); - mod->children.push_back(async_block); + if (async_block == nullptr) { + auto async_block_owned = std::make_unique(AST_ALWAYS, std::make_unique(AST_BLOCK)); + async_block = async_block_owned.get(); + mod->children.push_back(std::move(async_block_owned)); } - AstNode *newNode = clone(); + auto newNode = clone(); newNode->type = AST_ASSIGN_EQ; newNode->children[0]->was_checked = true; - async_block->children[0]->children.push_back(newNode); - - newNode = new AstNode(AST_NONE); - newNode->cloneInto(this); - delete newNode; + async_block->children[0]->children.push_back(std::move(newNode)); + newNode = std::make_unique(AST_NONE); + newNode->cloneInto(*this); did_something = true; } @@ -5014,57 +4971,57 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, bool mem_signed = children[0]->id2ast->is_signed; children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits); - AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); + auto wire_addr = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); wire_addr->str = id_addr; wire_addr->is_reg = true; wire_addr->was_checked = true; wire_addr->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); - mod->children.push_back(wire_addr); while (wire_addr->simplify(true, 1, -1, false)) { } + mod->children.push_back(std::move(wire_addr)); - AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); + auto wire_data = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); wire_data->str = id_data; wire_data->is_reg = true; wire_data->was_checked = true; wire_data->is_signed = mem_signed; wire_data->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); - mod->children.push_back(wire_data); while (wire_data->simplify(true, 1, -1, false)) { } + mod->children.push_back(std::move(wire_data)); - log_assert(block != NULL); + log_assert(block != nullptr); size_t assign_idx = 0; - while (assign_idx < block->children.size() && block->children[assign_idx] != this) + while (assign_idx < block->children.size() && block->children[assign_idx].get() != this) assign_idx++; log_assert(assign_idx < block->children.size()); - AstNode *assign_addr = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone()); + auto assign_addr = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone()); assign_addr->children[0]->str = id_addr; assign_addr->children[0]->was_checked = true; - block->children.insert(block->children.begin()+assign_idx+1, assign_addr); + block->children.insert(block->children.begin()+assign_idx+1, std::move(assign_addr)); - AstNode *case_node = new AstNode(AST_CASE, new AstNode(AST_IDENTIFIER)); + auto case_node = std::make_unique(AST_CASE, std::make_unique(AST_IDENTIFIER)); case_node->children[0]->str = id_addr; for (int i = 0; i < mem_size; i++) { if (children[0]->children[0]->children[0]->type == AST_CONSTANT && int(children[0]->children[0]->children[0]->integer) != i) continue; - AstNode *cond_node = new AstNode(AST_COND, AstNode::mkconst_int(i, false, addr_bits), new AstNode(AST_BLOCK)); - AstNode *assign_reg = new AstNode(type, new AstNode(AST_IDENTIFIER), new AstNode(AST_IDENTIFIER)); + auto cond_node = std::make_unique(AST_COND, AstNode::mkconst_int(i, false, addr_bits), std::make_unique(AST_BLOCK)); + auto assign_reg = std::make_unique(type, std::make_unique(AST_IDENTIFIER), std::make_unique(AST_IDENTIFIER)); if (children[0]->children.size() == 2) assign_reg->children[0]->children.push_back(children[0]->children[1]->clone()); assign_reg->children[0]->str = stringf("%s[%d]", children[0]->str.c_str(), i); assign_reg->children[1]->str = id_data; - cond_node->children[1]->children.push_back(assign_reg); - case_node->children.push_back(cond_node); + cond_node->children[1]->children.push_back(std::move(assign_reg)); + case_node->children.push_back(std::move(cond_node)); } // fixup on the full hierarchy below case_node case_node->fixup_hierarchy_flags(true); - block->children.insert(block->children.begin()+assign_idx+2, case_node); + block->children.insert(block->children.begin()+assign_idx+2, std::move(case_node)); children[0]->delete_children(); children[0]->range_valid = false; - children[0]->id2ast = NULL; + children[0]->id2ast = nullptr; children[0]->str = id_data; type = AST_ASSIGN_EQ; children[0]->was_checked = true; @@ -5075,7 +5032,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, if (mem2reg_check(mem2reg_set)) { - AstNode *bit_part_sel = NULL; + std::unique_ptr bit_part_sel = nullptr; if (children.size() == 2) bit_part_sel = children[1]->clone(); @@ -5092,7 +5049,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, str = stringf("%s[%d]", str.c_str(), id); delete_children(); range_valid = false; - id2ast = NULL; + id2ast = nullptr; } else { @@ -5105,7 +5062,6 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, else width = bit_part_sel->children[0]->integer - bit_part_sel->children[1]->integer; - delete bit_part_sel; bit_part_sel = nullptr; } else @@ -5120,9 +5076,8 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, std::vector x_bits; for (int i = 0; i < width; i++) x_bits.push_back(RTLIL::State::Sx); - AstNode *constant = AstNode::mkconst_bits(x_bits, false); - constant->cloneInto(this); - delete constant; + std::unique_ptr constant = AstNode::mkconst_bits(x_bits, false); + constant->cloneInto(*this); } } else @@ -5135,54 +5090,54 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, bool mem_signed = id2ast->is_signed; id2ast->meminfo(mem_width, mem_size, addr_bits); - AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); + auto wire_addr = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); wire_addr->str = id_addr; wire_addr->is_reg = true; wire_addr->was_checked = true; if (block) wire_addr->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); - mod->children.push_back(wire_addr); while (wire_addr->simplify(true, 1, -1, false)) { } + mod->children.push_back(std::move(wire_addr)); - AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); + auto wire_data = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); wire_data->str = id_data; wire_data->is_reg = true; wire_data->was_checked = true; wire_data->is_signed = mem_signed; if (block) wire_data->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); - mod->children.push_back(wire_data); while (wire_data->simplify(true, 1, -1, false)) { } + mod->children.push_back(std::move(wire_data)); - AstNode *assign_addr = new AstNode(block ? AST_ASSIGN_EQ : AST_ASSIGN, new AstNode(AST_IDENTIFIER), children[0]->children[0]->clone()); + auto assign_addr = std::make_unique(block ? AST_ASSIGN_EQ : AST_ASSIGN, std::make_unique(AST_IDENTIFIER), children[0]->children[0]->clone()); assign_addr->children[0]->str = id_addr; assign_addr->children[0]->was_checked = true; - AstNode *case_node = new AstNode(AST_CASE, new AstNode(AST_IDENTIFIER)); + auto case_node = std::make_unique(AST_CASE, std::make_unique(AST_IDENTIFIER)); case_node->children[0]->str = id_addr; for (int i = 0; i < mem_size; i++) { if (children[0]->children[0]->type == AST_CONSTANT && int(children[0]->children[0]->integer) != i) continue; - AstNode *cond_node = new AstNode(AST_COND, AstNode::mkconst_int(i, false, addr_bits), new AstNode(AST_BLOCK)); - AstNode *assign_reg = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), new AstNode(AST_IDENTIFIER)); + auto cond_node = std::make_unique(AST_COND, AstNode::mkconst_int(i, false, addr_bits), std::make_unique(AST_BLOCK)); + auto assign_reg = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), std::make_unique(AST_IDENTIFIER)); assign_reg->children[0]->str = id_data; assign_reg->children[0]->was_checked = true; assign_reg->children[1]->str = stringf("%s[%d]", str.c_str(), i); - cond_node->children[1]->children.push_back(assign_reg); - case_node->children.push_back(cond_node); + cond_node->children[1]->children.push_back(std::move(assign_reg)); + case_node->children.push_back(std::move(cond_node)); } std::vector x_bits; for (int i = 0; i < mem_width; i++) x_bits.push_back(RTLIL::State::Sx); - AstNode *cond_node = new AstNode(AST_COND, new AstNode(AST_DEFAULT), new AstNode(AST_BLOCK)); - AstNode *assign_reg = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), AstNode::mkconst_bits(x_bits, false)); + auto cond_node = std::make_unique(AST_COND, std::make_unique(AST_DEFAULT), std::make_unique(AST_BLOCK)); + auto assign_reg = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), AstNode::mkconst_bits(x_bits, false)); assign_reg->children[0]->str = id_data; assign_reg->children[0]->was_checked = true; - cond_node->children[1]->children.push_back(assign_reg); - case_node->children.push_back(cond_node); + cond_node->children[1]->children.push_back(std::move(assign_reg)); + case_node->children.push_back(std::move(cond_node)); // fixup on the full hierarchy below case_node case_node->fixup_hierarchy_flags(true); @@ -5193,34 +5148,37 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, while (assign_idx < block->children.size() && !block->children[assign_idx]->contains(this)) assign_idx++; log_assert(assign_idx < block->children.size()); - block->children.insert(block->children.begin()+assign_idx, case_node); - block->children.insert(block->children.begin()+assign_idx, assign_addr); + block->children.insert(block->children.begin()+assign_idx, std::move(case_node)); + block->children.insert(block->children.begin()+assign_idx, std::move(assign_addr)); } else { - AstNode *proc = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK, case_node)); - mod->children.push_back(proc); - mod->children.push_back(assign_addr); + auto proc = std::make_unique(AST_ALWAYS, std::make_unique(AST_BLOCK, std::move(case_node))); + mod->children.push_back(std::move(proc)); + mod->children.push_back(std::move(assign_addr)); mod->fixup_hierarchy_flags(); } delete_children(); range_valid = false; - id2ast = NULL; + id2ast = nullptr; str = id_data; } if (bit_part_sel) { - children.push_back(bit_part_sel); + children.push_back(std::move(bit_part_sel)); fixup_hierarchy_flags(); } did_something = true; } - log_assert(id2ast == NULL || mem2reg_set.count(id2ast) == 0); + log_assert(id2ast == nullptr || mem2reg_set.count(id2ast) == 0); + + std::vector children_list; + for (auto& child : children) + children_list.push_back(child.get()); - auto children_list = children; for (size_t i = 0; i < children_list.size(); i++) if (children_list[i]->mem2reg_as_needed_pass2(mem2reg_set, mod, block, async_block)) did_something = true; @@ -5305,7 +5263,7 @@ bool AstNode::has_const_only_constructs() { if (type == AST_WHILE || type == AST_REPEAT) return true; - for (auto child : children) + for (auto& child : children) if (child->has_const_only_constructs()) return true; return false; @@ -5315,7 +5273,7 @@ bool AstNode::is_simple_const_expr() { if (type == AST_IDENTIFIER) return false; - for (auto child : children) + for (auto& child : children) if (!child->is_simple_const_expr()) return false; return true; @@ -5350,9 +5308,8 @@ bool AstNode::replace_variables(std::map &varia offset = -offset; std::vector &var_bits = variables.at(str).val.bits(); std::vector new_bits(var_bits.begin() + offset, var_bits.begin() + offset + width); - AstNode *newNode = mkconst_bits(new_bits, variables.at(str).is_signed); - newNode->cloneInto(this); - delete newNode; + auto newNode = mkconst_bits(new_bits, variables.at(str).is_signed); + newNode->cloneInto(*this); return true; } @@ -5363,32 +5320,34 @@ bool AstNode::replace_variables(std::map &varia } // attempt to statically evaluate a functions with all-const arguments -AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) +std::unique_ptr AstNode::eval_const_function(AstNode *fcall, bool must_succeed) { std::map backup_scope = current_scope; std::map variables; - std::vector to_delete; - AstNode *block = new AstNode(AST_BLOCK); - AstNode *result = nullptr; + auto block = std::make_unique(AST_BLOCK); + std::unique_ptr result = nullptr; size_t argidx = 0; - for (auto child : children) + for (auto& child : children) { block->children.push_back(child->clone()); } block->set_in_param_flag(true); + std::vector> temporary_nodes; while (!block->children.empty()) { - AstNode *stmt = block->children.front(); + // log("%zu left in block %p\n", block->children.size(), block.get()); + std::unique_ptr& stmt = block->children.front(); #if 0 log("-----------------------------------\n"); for (auto &it : variables) log("%20s %40s\n", it.first.c_str(), log_signal(it.second.val)); - stmt->dumpAst(NULL, "stmt> "); + stmt->dumpAst(nullptr, "stmt> "); #endif - + // log("A\n"); + // log("%s\n", type2str(stmt->type).c_str()); if (stmt->type == AST_WIRE) { while (stmt->simplify(true, 1, -1, false)) { } @@ -5413,7 +5372,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) stmt->children.back()->type == AST_RANGE; // identify the argument corresponding to this wire, if applicable if (stmt->is_input && argidx < fcall->children.size()) { - variable.arg = fcall->children.at(argidx++); + variable.arg = fcall->children.at(argidx++).get(); } // load the constant arg's value into this variable if (variable.arg) { @@ -5424,10 +5383,10 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) variable.val = variable.arg->realAsConst(width); } } - current_scope[stmt->str] = stmt; + current_scope[stmt->str] = stmt.get(); + temporary_nodes.push_back(std::move(stmt)); block->children.erase(block->children.begin()); - to_delete.push_back(stmt); continue; } @@ -5437,10 +5396,10 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) { while (stmt->simplify(true, 1, -1, false)) { } - current_scope[stmt->str] = stmt; + current_scope[stmt->str] = stmt.get(); + temporary_nodes.push_back(std::move(stmt)); block->children.erase(block->children.begin()); - to_delete.push_back(stmt); continue; } @@ -5481,7 +5440,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) if (stmt->children.at(0)->children.empty()) { variables[stmt->children.at(0)->str].val = stmt->children.at(1)->bitsAsConst(variables[stmt->children.at(0)->str].val.size()); } else { - AstNode *range = stmt->children.at(0)->children.at(0); + AstNode *range = stmt->children.at(0)->children.at(0).get(); if (!range->range_valid) { if (!must_succeed) goto finished; @@ -5499,24 +5458,28 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) } } - delete block->children.front(); block->children.erase(block->children.begin()); continue; } if (stmt->type == AST_FOR) { - block->children.insert(block->children.begin(), stmt->children.at(0)); - stmt->children.at(3)->children.push_back(stmt->children.at(2)); + stmt->type = AST_WHILE; + log_assert(stmt->children.size() > 2); + auto yoink0 = std::move(stmt->children.at(0)); + log_assert(stmt->children.size() > 2); + auto yoink2 = std::move(stmt->children.at(2)); + stmt->children.at(3)->children.push_back(std::move(yoink2)); stmt->children.erase(stmt->children.begin() + 2); stmt->children.erase(stmt->children.begin()); - stmt->type = AST_WHILE; + block->children.insert(block->children.begin(), std::move(yoink0)); + log_assert(stmt->children.size() == 2); continue; } if (stmt->type == AST_WHILE) { - AstNode *cond = stmt->children.at(0)->clone(); + auto cond = stmt->children.at(0)->clone(); if (!cond->replace_variables(variables, fcall, must_succeed)) goto finished; cond->set_in_param_flag(true); @@ -5532,17 +5495,14 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) if (cond->asBool()) { block->children.insert(block->children.begin(), stmt->children.at(1)->clone()); } else { - delete block->children.front(); block->children.erase(block->children.begin()); } - - delete cond; continue; } if (stmt->type == AST_REPEAT) { - AstNode *num = stmt->children.at(0)->clone(); + auto num = stmt->children.at(0)->clone(); if (!num->replace_variables(variables, fcall, must_succeed)) goto finished; num->set_in_param_flag(true); @@ -5555,41 +5515,41 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) fcall->loc_string().c_str()); } + temporary_nodes.push_back(std::move(stmt)); block->children.erase(block->children.begin()); for (int i = 0; i < num->bitsAsConst().as_int(); i++) - block->children.insert(block->children.begin(), stmt->children.at(1)->clone()); + block->children.insert(block->children.begin(), temporary_nodes.back()->children.at(1)->clone()); - delete stmt; - delete num; continue; } if (stmt->type == AST_CASE) { - AstNode *expr = stmt->children.at(0)->clone(); + auto expr = stmt->children.at(0)->clone(); if (!expr->replace_variables(variables, fcall, must_succeed)) goto finished; expr->set_in_param_flag(true); while (expr->simplify(true, 1, -1, false)) { } - AstNode *sel_case = NULL; + AstNode *sel_case = nullptr; + std::unique_ptr sel_case_copy = nullptr; for (size_t i = 1; i < stmt->children.size(); i++) { bool found_match = false; log_assert(stmt->children.at(i)->type == AST_COND || stmt->children.at(i)->type == AST_CONDX || stmt->children.at(i)->type == AST_CONDZ); if (stmt->children.at(i)->children.front()->type == AST_DEFAULT) { - sel_case = stmt->children.at(i)->children.back(); + sel_case = stmt->children.at(i)->children.back().get(); continue; } for (size_t j = 0; j+1 < stmt->children.at(i)->children.size() && !found_match; j++) { - AstNode *cond = stmt->children.at(i)->children.at(j)->clone(); + auto cond = stmt->children.at(i)->children.at(j)->clone(); if (!cond->replace_variables(variables, fcall, must_succeed)) goto finished; - cond = new AstNode(AST_EQ, expr->clone(), cond); + cond = std::make_unique(AST_EQ, expr->clone(), std::move(cond)); cond->set_in_param_flag(true); while (cond->simplify(true, 1, -1, false)) { } @@ -5601,20 +5561,19 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) } found_match = cond->asBool(); - delete cond; } if (found_match) { - sel_case = stmt->children.at(i)->children.back(); + sel_case = stmt->children.at(i)->children.back().get(); break; } } + if (sel_case) + sel_case_copy = sel_case->clone(); block->children.erase(block->children.begin()); - if (sel_case) - block->children.insert(block->children.begin(), sel_case->clone()); - delete stmt; - delete expr; + if (sel_case_copy) + block->children.insert(block->children.begin(), std::move(sel_case_copy)); continue; } @@ -5622,15 +5581,19 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) { if (!stmt->str.empty()) stmt->expand_genblock(stmt->str + "."); - + auto* stmt_leaky = stmt.get(); + temporary_nodes.push_back(std::move(stmt)); block->children.erase(block->children.begin()); - block->children.insert(block->children.begin(), stmt->children.begin(), stmt->children.end()); - stmt->children.clear(); + block->children.reserve(block->children.size() + stmt_leaky->children.size()); + block->children.insert(block->children.begin(), + std::make_move_iterator(stmt_leaky->children.begin()), + std::make_move_iterator(stmt_leaky->children.end())); + stmt_leaky->children.clear(); block->fixup_hierarchy_flags(); - delete stmt; continue; } + // log("C\n"); if (!must_succeed) goto finished; stmt->input_error("Unsupported language construct in constant function\n%s: ... called from here.\n", @@ -5641,14 +5604,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) result = AstNode::mkconst_bits(variables.at(str).val.to_bits(), variables.at(str).is_signed); finished: - delete block; current_scope = backup_scope; - - for (auto it : to_delete) { - delete it; - } - to_delete.clear(); - return result; } @@ -5659,14 +5615,13 @@ void AstNode::allocateDefaultEnumValues() if (children.front()->attributes.count(ID::enum_base_type)) return; // already elaborated int last_enum_int = -1; - for (auto node : children) { + for (auto& node : children) { log_assert(node->type==AST_ENUM_ITEM); node->set_attribute(ID::enum_base_type, mkconst_str(str)); for (size_t i = 0; i < node->children.size(); i++) { switch (node->children[i]->type) { case AST_NONE: // replace with auto-incremented constant - delete node->children[i]; node->children[i] = AstNode::mkconst_int(++last_enum_int, true); break; case AST_CONSTANT: @@ -5695,8 +5650,8 @@ bool AstNode::is_recursive_function() const if (it != current_scope.end() && visit(it->second)) return true; } - for (const AstNode *child : node->children) { - if (visit(child)) + for (auto& child : node->children) { + if (visit(child.get())) return true; } return false; @@ -5726,9 +5681,9 @@ std::pair AstNode::get_tern_choice() AstNode *choice = nullptr, *not_choice = nullptr; if (found_sure_true) - choice = children[1], not_choice = children[2]; + choice = children[1].get(), not_choice = children[2].get(); else if (!found_maybe_true) - choice = children[2], not_choice = children[1]; + choice = children[2].get(), not_choice = children[1].get(); return {choice, not_choice}; } diff --git a/frontends/verilog/.gitignore b/frontends/verilog/.gitignore index aadbcdcdd..a6d4c8b86 100644 --- a/frontends/verilog/.gitignore +++ b/frontends/verilog/.gitignore @@ -2,3 +2,6 @@ verilog_lexer.cc verilog_parser.output verilog_parser.tab.cc verilog_parser.tab.hh +position.hh +location.hh +stack.hh diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc index 2c923f0b7..2d26f1930 100644 --- a/frontends/verilog/Makefile.inc +++ b/frontends/verilog/Makefile.inc @@ -9,6 +9,7 @@ frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y $(P) $(BISON) -Wall -Werror -o $@ -d -r all -b frontends/verilog/verilog_parser $< frontends/verilog/verilog_parser.tab.hh: frontends/verilog/verilog_parser.tab.cc +frontends/verilog/verilog_frontend.h: frontends/verilog/verilog_parser.tab.hh frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l frontends/verilog/verilog_parser.tab.cc $(Q) mkdir -p $(dir $@) diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc index a4dfbc7ec..9c4a2e76c 100644 --- a/frontends/verilog/const2ast.cc +++ b/frontends/verilog/const2ast.cc @@ -42,14 +42,35 @@ YOSYS_NAMESPACE_BEGIN using namespace AST; +using namespace VERILOG_FRONTEND; + +std::string ConstParser::fmt_maybe_loc(std::string msg) { + std::string s; + s += filename.value_or("INTERNAL"); + + if (loc) + s += stringf("%d", loc->first_line); + s += ": "; + + s += msg; + return s; +} + +void ConstParser::log_maybe_loc_error(std::string msg) { + log_error("%s", fmt_maybe_loc(msg).c_str()); +} + +void ConstParser::log_maybe_loc_warn(std::string msg) { + log_warning("%s", fmt_maybe_loc(msg).c_str()); +} // divide an arbitrary length decimal number by two and return the rest -static int my_decimal_div_by_two(std::vector &digits) +int ConstParser::my_decimal_div_by_two(std::vector &digits) { int carry = 0; for (size_t i = 0; i < digits.size(); i++) { if (digits[i] >= 10) - log_file_error(current_filename, get_line_num(), "Invalid use of [a-fxz?] in decimal constant.\n"); + log_maybe_loc_error("Invalid use of [a-fxz?] in decimal constant.\n"); digits[i] += carry * 10; carry = digits[i] % 2; digits[i] /= 2; @@ -60,7 +81,7 @@ static int my_decimal_div_by_two(std::vector &digits) } // find the number of significant bits in a binary number (not including the sign bit) -static int my_ilog2(int x) +int ConstParser::my_ilog2(int x) { int ret = 0; while (x != 0 && x != -1) { @@ -71,7 +92,7 @@ static int my_ilog2(int x) } // parse a binary, decimal, hexadecimal or octal number with support for special bits ('x', 'z' and '?') -static void my_strtobin(std::vector &data, const char *str, int len_in_bits, int base, char case_type, bool is_unsized) +void ConstParser::my_strtobin(std::vector &data, const char *str, int len_in_bits, int base, char case_type, bool is_unsized) { // all digits in string (MSB at index 0) std::vector digits; @@ -102,8 +123,8 @@ static void my_strtobin(std::vector &data, const char *str, int le int bits_per_digit = my_ilog2(base-1); for (auto it = digits.rbegin(), e = digits.rend(); it != e; it++) { if (*it > (base-1) && *it < 0xf0) - log_file_error(current_filename, get_line_num(), "Digit larger than %d used in in base-%d constant.\n", - base-1, base); + log_maybe_loc_error(stringf("Digit larger than %d used in in base-%d constant.\n", + base-1, base)); for (int i = 0; i < bits_per_digit; i++) { int bitmask = 1 << i; if (*it == 0xf0) @@ -126,7 +147,7 @@ static void my_strtobin(std::vector &data, const char *str, int le } if (is_unsized && (len > len_in_bits)) - log_file_error(current_filename, get_line_num(), "Unsized constant must have width of 1 bit, but have %d bits!\n", len); + log_maybe_loc_error(stringf("Unsized constant must have width of 1 bit, but have %d bits!\n", len)); for (len = len - 1; len >= 0; len--) if (data[len] == State::S1) @@ -140,21 +161,19 @@ static void my_strtobin(std::vector &data, const char *str, int le } if (len_in_bits == 0) - log_file_error(current_filename, get_line_num(), "Illegal integer constant size of zero (IEEE 1800-2012, 5.7).\n"); + log_maybe_loc_error("Illegal integer constant size of zero (IEEE 1800-2012, 5.7).\n"); if (len > len_in_bits) - log_warning("Literal has a width of %d bit, but value requires %d bit. (%s:%d)\n", - len_in_bits, len, current_filename.c_str(), get_line_num()); + log_maybe_loc_warn(stringf("Literal has a width of %d bit, but value requires %d bit.\n", + len_in_bits, len)); } - // convert the Verilog code for a constant to an AST node -AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn_z) +std::unique_ptr ConstParser::const2ast(std::string code, char case_type, bool warn_z) { if (warn_z) { - AstNode *ret = const2ast(code, case_type); + auto ret = const2ast(code, case_type); if (ret != nullptr && std::find(ret->bits.begin(), ret->bits.end(), RTLIL::State::Sz) != ret->bits.end()) - log_warning("Yosys has only limited support for tri-state logic at the moment. (%s:%d)\n", - current_filename.c_str(), get_line_num()); + log_maybe_loc_warn("Yosys has only limited support for tri-state logic at the moment.\n"); return ret; } @@ -172,7 +191,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn ch = ch >> 1; } } - AstNode *ast = AstNode::mkconst_bits(data, false); + auto ast = AstNode::mkconst_bits(data, false); ast->str = code; return ast; } @@ -245,4 +264,5 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn return NULL; } + YOSYS_NAMESPACE_END diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc index e33b0a2c3..d07e39189 100644 --- a/frontends/verilog/preproc.cc +++ b/frontends/verilog/preproc.cc @@ -34,6 +34,7 @@ #include "preproc.h" #include "verilog_frontend.h" +#include "verilog_parser.tab.hh" #include "kernel/log.h" #include #include @@ -749,7 +750,9 @@ frontend_verilog_preproc(std::istream &f, std::string filename, const define_map_t &pre_defines, define_map_t &global_defines_cache, - const std::list &include_dirs) + const std::list &include_dirs, + ParseState &parse_state, + ParseMode &parse_mode) { define_map_t defines; defines.merge(pre_defines); @@ -961,11 +964,11 @@ frontend_verilog_preproc(std::istream &f, } if (tok == "`resetall") { - default_nettype_wire = true; + parse_state.default_nettype_wire = true; continue; } - if (tok == "`undefineall" && sv_mode) { + if (tok == "`undefineall" && parse_mode.sv) { defines.clear(); global_defines_cache.clear(); continue; diff --git a/frontends/verilog/preproc.h b/frontends/verilog/preproc.h index 330855a92..51562787a 100644 --- a/frontends/verilog/preproc.h +++ b/frontends/verilog/preproc.h @@ -35,6 +35,11 @@ YOSYS_NAMESPACE_BEGIN struct define_body_t; struct arg_map_t; +namespace VERILOG_FRONTEND { + struct ParseState; + struct ParseMode; +}; + struct define_map_t { define_map_t(); @@ -71,7 +76,9 @@ frontend_verilog_preproc(std::istream &f, std::string filename, const define_map_t &pre_defines, define_map_t &global_defines_cache, - const std::list &include_dirs); + const std::list &include_dirs, + VERILOG_FRONTEND::ParseState &parse_state, + VERILOG_FRONTEND::ParseMode &parse_mode); YOSYS_NAMESPACE_END diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index 1f272ca4f..f2a341f54 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -31,6 +31,7 @@ #endif #include "verilog_frontend.h" +#include "verilog_lexer.h" #include "preproc.h" #include "kernel/yosys.h" #include "libs/sha1/sha1.h" @@ -48,11 +49,11 @@ static void error_on_dpi_function(AST::AstNode *node) { if (node->type == AST::AST_DPI_FUNCTION) log_file_error(node->filename, node->location.first_line, "Found DPI function %s.\n", node->str.c_str()); - for (auto child : node->children) - error_on_dpi_function(child); + for (auto& child : node->children) + error_on_dpi_function(child.get()); } -static void add_package_types(dict &user_types, std::vector &package_list) +static void add_package_types(dict &user_types, std::vector> &package_list) { // prime the parser's user type lookup table with the package qualified names // of typedefed names in the packages seen so far. @@ -61,14 +62,22 @@ static void add_package_types(dict &user_types, std for (const auto &node: pkg->children) { if (node->type == AST::AST_TYPEDEF) { std::string s = pkg->str + "::" + node->str.substr(1); - user_types[s] = node; + user_types[s] = node.get(); } } } } struct VerilogFrontend : public Frontend { - VerilogFrontend() : Frontend("verilog", "read modules from Verilog file") { } + ParseMode parse_mode; + ParseState parse_state; + VerilogLexer lexer; + frontend_verilog_yy::parser parser; + VerilogFrontend() : Frontend("verilog", "read modules from Verilog file"), + parse_mode(), + parse_state(), + lexer(&parse_state, &parse_mode), + parser(&lexer, &parse_state, &parse_mode) { } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| @@ -266,22 +275,24 @@ struct VerilogFrontend : public Frontend { bool flag_noblackbox = false; bool flag_nowb = false; bool flag_nosynthesis = false; + bool flag_yydebug = false; define_map_t defines_map; std::list include_dirs; std::list attributes; - frontend_verilog_yydebug = false; - sv_mode = false; - formal_mode = false; - noassert_mode = false; - noassume_mode = false; - norestrict_mode = false; - assume_asserts_mode = false; - assert_assumes_mode = false; - lib_mode = false; - specify_mode = false; - default_nettype_wire = true; + lexer.set_debug(false); + parser.set_debug_level(0); + parse_mode.sv = false; + parse_mode.formal = false; + parse_mode.noassert = false; + parse_mode.noassume = false; + parse_mode.norestrict = false; + parse_mode.assume_asserts = false; + parse_mode.assert_assumes = false; + parse_mode.lib = false; + parse_mode.specify = false; + parse_state.default_nettype_wire = true; args.insert(args.begin()+1, verilog_defaults.begin(), verilog_defaults.end()); @@ -289,11 +300,11 @@ struct VerilogFrontend : public Frontend { for (argidx = 1; argidx < args.size(); argidx++) { std::string arg = args[argidx]; if (arg == "-sv") { - sv_mode = true; + parse_mode.sv = true; continue; } if (arg == "-formal") { - formal_mode = true; + parse_mode.formal = true; continue; } if (arg == "-nosynthesis") { @@ -301,23 +312,23 @@ struct VerilogFrontend : public Frontend { continue; } if (arg == "-noassert") { - noassert_mode = true; + parse_mode.noassert = true; continue; } if (arg == "-noassume") { - noassume_mode = true; + parse_mode.noassume = true; continue; } if (arg == "-norestrict") { - norestrict_mode = true; + parse_mode.norestrict = true; continue; } if (arg == "-assume-asserts") { - assume_asserts_mode = true; + parse_mode.assume_asserts = true; continue; } if (arg == "-assert-assumes") { - assert_assumes_mode = true; + parse_mode.assert_assumes = true; continue; } if (arg == "-nodisplay") { @@ -329,7 +340,8 @@ struct VerilogFrontend : public Frontend { flag_dump_ast2 = true; flag_dump_vlog1 = true; flag_dump_vlog2 = true; - frontend_verilog_yydebug = true; + lexer.set_debug(true); + parser.set_debug_level(1); continue; } if (arg == "-dump_ast1") { @@ -357,7 +369,7 @@ struct VerilogFrontend : public Frontend { continue; } if (arg == "-yydebug") { - frontend_verilog_yydebug = true; + flag_yydebug = true; continue; } if (arg == "-nolatches") { @@ -393,7 +405,7 @@ struct VerilogFrontend : public Frontend { continue; } if (arg == "-lib") { - lib_mode = true; + parse_mode.lib = true; defines_map.add("BLACKBOX", ""); continue; } @@ -402,7 +414,7 @@ struct VerilogFrontend : public Frontend { continue; } if (arg == "-specify") { - specify_mode = true; + parse_mode.specify = true; continue; } if (arg == "-noopt") { @@ -432,7 +444,7 @@ struct VerilogFrontend : public Frontend { continue; } if (arg == "-noautowire") { - default_nettype_wire = false; + parse_state.default_nettype_wire = false; continue; } if (arg == "-setattr" && argidx+1 < args.size()) { @@ -469,54 +481,59 @@ struct VerilogFrontend : public Frontend { break; } - if (formal_mode || !flag_nosynthesis) - defines_map.add(formal_mode ? "FORMAL" : "SYNTHESIS", "1"); + if (parse_mode.formal || !flag_nosynthesis) + defines_map.add(parse_mode.formal ? "FORMAL" : "SYNTHESIS", "1"); extra_args(f, filename, args, argidx); log_header(design, "Executing Verilog-2005 frontend: %s\n", filename.c_str()); log("Parsing %s%s input from `%s' to AST representation.\n", - formal_mode ? "formal " : "", sv_mode ? "SystemVerilog" : "Verilog", filename.c_str()); + parse_mode.formal ? "formal " : "", parse_mode.sv ? "SystemVerilog" : "Verilog", filename.c_str()); AST::current_filename = filename; - AST::set_line_num = &frontend_verilog_yyset_lineno; - AST::get_line_num = &frontend_verilog_yyget_lineno; + AST::sv_mode = parse_mode.sv; - current_ast = new AST::AstNode(AST::AST_DESIGN); + parse_state.current_ast = new AST::AstNode(AST::AST_DESIGN); - lexin = f; + parse_state.lexin = f; std::string code_after_preproc; if (!flag_nopp) { - code_after_preproc = frontend_verilog_preproc(*f, filename, defines_map, *design->verilog_defines, include_dirs); + code_after_preproc = frontend_verilog_preproc(*f, filename, defines_map, *design->verilog_defines, include_dirs, parse_state, parse_mode); if (flag_ppdump) log("-- Verilog code after preprocessor --\n%s-- END OF DUMP --\n", code_after_preproc.c_str()); - lexin = new std::istringstream(code_after_preproc); + parse_state.lexin = new std::istringstream(code_after_preproc); } // make package typedefs available to parser - add_package_types(pkg_user_types, design->verilog_packages); + add_package_types(parse_state.pkg_user_types, design->verilog_packages); UserTypeMap global_types_map; - for (auto def : design->verilog_globals) { + for (auto& def : design->verilog_globals) { if (def->type == AST::AST_TYPEDEF) { - global_types_map[def->str] = def; + global_types_map[def->str] = def.get(); } } - log_assert(user_type_stack.empty()); + log_assert(parse_state.user_type_stack.empty()); // use previous global typedefs as bottom level of user type stack - user_type_stack.push_back(std::move(global_types_map)); + parse_state.user_type_stack.push_back(std::move(global_types_map)); // add a new empty type map to allow overriding existing global definitions - user_type_stack.push_back(UserTypeMap()); + parse_state.user_type_stack.push_back(UserTypeMap()); - frontend_verilog_yyset_lineno(1); - frontend_verilog_yyrestart(NULL); - frontend_verilog_yyparse(); - frontend_verilog_yylex_destroy(); + parser.~parser(); + lexer.~VerilogLexer(); + new (&lexer) VerilogLexer(&parse_state, &parse_mode); + new (&parser) frontend_verilog_yy::parser(&lexer, &parse_state, &parse_mode); + if (flag_yydebug) { + lexer.set_debug(true); + parser.set_debug_level(1); + } + parser.parse(); + // frontend_verilog_yyset_lineno(1); - for (auto &child : current_ast->children) { + for (auto &child : parse_state.current_ast->children) { if (child->type == AST::AST_MODULE) for (auto &attr : attributes) if (child->attributes.count(attr) == 0) @@ -524,21 +541,21 @@ struct VerilogFrontend : public Frontend { } if (flag_nodpi) - error_on_dpi_function(current_ast); + error_on_dpi_function(parse_state.current_ast); - AST::process(design, current_ast, flag_nodisplay, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, - flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_noblackbox, lib_mode, flag_nowb, flag_noopt, flag_icells, flag_pwires, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire); + AST::process(design, parse_state.current_ast, flag_nodisplay, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, + flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_noblackbox, parse_mode.lib, flag_nowb, flag_noopt, flag_icells, flag_pwires, flag_nooverwrite, flag_overwrite, flag_defer, parse_state.default_nettype_wire); if (!flag_nopp) - delete lexin; + delete parse_state.lexin; // only the previous and new global type maps remain - log_assert(user_type_stack.size() == 2); - user_type_stack.clear(); + log_assert(parse_state.user_type_stack.size() == 2); + parse_state.user_type_stack.clear(); - delete current_ast; - current_ast = NULL; + delete parse_state.current_ast; + parse_state.current_ast = NULL; log("Successfully finished Verilog frontend.\n"); } @@ -759,19 +776,33 @@ struct VerilogFileList : public Pass { #endif -YOSYS_NAMESPACE_END - -// the yyerror function used by bison to report parser errors -void frontend_verilog_yyerror(char const *fmt, ...) +[[noreturn]] +void VERILOG_FRONTEND::verr_at(std::string filename, int begin_line, char const *fmt, va_list ap) { - va_list ap; - char buffer[1024]; - char *p = buffer; - va_start(ap, fmt); - p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap); - va_end(ap); - p += snprintf(p, buffer + sizeof(buffer) - p, "\n"); - YOSYS_NAMESPACE_PREFIX log_file_error(YOSYS_NAMESPACE_PREFIX AST::current_filename, frontend_verilog_yyget_lineno(), - "%s", buffer); - exit(1); + char buffer[1024]; + char *p = buffer; + p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap); + p += snprintf(p, buffer + sizeof(buffer) - p, "\n"); + YOSYS_NAMESPACE_PREFIX log_file_error(filename, begin_line, "%s", buffer); + exit(1); } + +[[noreturn]] +void VERILOG_FRONTEND::err_at_loc(parser::location_type loc, char const *fmt, ...) +{ + va_list args; + va_start(args, fmt); + verr_at(AST::current_filename, loc.begin.line, fmt, args); + va_end(args); +} + +[[noreturn]] +void VERILOG_FRONTEND::err_at_ast(AstSrcLocType loc, char const *fmt, ...) +{ + va_list args; + va_start(args, fmt); + verr_at(AST::current_filename, loc.first_line, fmt, args); + va_end(args); +} + +YOSYS_NAMESPACE_END diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h index 8454e7999..6426f57d8 100644 --- a/frontends/verilog/verilog_frontend.h +++ b/frontends/verilog/verilog_frontend.h @@ -31,6 +31,13 @@ #include "kernel/yosys.h" #include "frontends/ast/ast.h" +#include "frontends/verilog/location.hh" + +#if ! defined(yyFlexLexerOnce) +#define yyFlexLexer frontend_verilog_yyFlexLexer +#include +#endif + #include #include #include @@ -39,62 +46,33 @@ YOSYS_NAMESPACE_BEGIN namespace VERILOG_FRONTEND { - // this variable is set to a new AST_DESIGN node and then filled with the AST by the bison parser - extern struct AST::AstNode *current_ast; + /* Ephemeral context class */ + struct ConstParser { + std::optional filename; + std::optional loc; + private: + std::string fmt_maybe_loc(std::string msg); + void log_maybe_loc_error(std::string msg); + void log_maybe_loc_warn(std::string msg); + // divide an arbitrary length decimal number by two and return the rest + int my_decimal_div_by_two(std::vector &digits); + // find the number of significant bits in a binary number (not including the sign bit) + int my_ilog2(int x); + // parse a binary, decimal, hexadecimal or octal number with support for special bits ('x', 'z' and '?') + void my_strtobin(std::vector &data, const char *str, int len_in_bits, int base, char case_type, bool is_unsized); + public: + // convert the Verilog code for a constant to an AST node + std::unique_ptr const2ast(std::string code, char case_type = 0, bool warn_z = false); - // this function converts a Verilog constant to an AST_CONSTANT node - AST::AstNode *const2ast(std::string code, char case_type = 0, bool warn_z = false); - - // names of locally typedef'ed types in a stack - typedef std::map UserTypeMap; - extern std::vector user_type_stack; - - // names of package typedef'ed types - extern dict pkg_user_types; - - // state of `default_nettype - extern bool default_nettype_wire; - - // running in SystemVerilog mode - extern bool sv_mode; - - // running in -formal mode - extern bool formal_mode; - - // running in -noassert mode - extern bool noassert_mode; - - // running in -noassume mode - extern bool noassume_mode; - - // running in -norestrict mode - extern bool norestrict_mode; - - // running in -assume-asserts mode - extern bool assume_asserts_mode; - - // running in -assert-assumes mode - extern bool assert_assumes_mode; - - // running in -lib mode - extern bool lib_mode; - - // running in -specify mode - extern bool specify_mode; - - // lexer input stream - extern std::istream *lexin; -} + }; + [[noreturn]] + extern void verr_at(std::string filename, int begin_line, char const *fmt, va_list ap); + [[noreturn]] + extern void err_at_loc(frontend_verilog_yy::location loc, char const *fmt, ...); + [[noreturn]] + extern void err_at_ast(AST::AstSrcLocType loc, char const *fmt, ...); +}; YOSYS_NAMESPACE_END -// the usual bison/flex stuff -extern int frontend_verilog_yydebug; -void frontend_verilog_yyerror(char const *fmt, ...); -void frontend_verilog_yyrestart(FILE *f); -int frontend_verilog_yyparse(void); -int frontend_verilog_yylex_destroy(void); -int frontend_verilog_yyget_lineno(void); -void frontend_verilog_yyset_lineno (int); - #endif diff --git a/frontends/verilog/verilog_lexer.h b/frontends/verilog/verilog_lexer.h new file mode 100644 index 000000000..7d73ae193 --- /dev/null +++ b/frontends/verilog/verilog_lexer.h @@ -0,0 +1,48 @@ +#ifndef VERILOG_LEXER_H +#define VERILOG_LEXER_H + +#include "kernel/yosys.h" +#include "frontends/ast/ast.h" +#include "frontends/verilog/verilog_parser.tab.hh" + +YOSYS_NAMESPACE_BEGIN + +namespace VERILOG_FRONTEND { + // lexer input stream + using parser = frontend_verilog_yy::parser; + class VerilogLexer : public frontend_verilog_yyFlexLexer { + ParseState* extra; + ParseMode* mode; + public: + VerilogLexer(ParseState* e, ParseMode* m) : frontend_verilog_yyFlexLexer(e->lexin), extra(e), mode(m) {} + ~VerilogLexer() override {} + // autogenerated body due to YY_DECL + parser::symbol_type nextToken(); + // get rid of override virtual function warning + using FlexLexer::yylex; + parser::symbol_type terminate() { + return parser::make_FRONTEND_VERILOG_YYEOF(out_loc); + } + parser::location_type out_loc; + [[noreturn]] + void err(char const *fmt, ...) + { + va_list args; + va_start(args, fmt); + verr_at(AST::current_filename, yylineno, fmt, args); + } + private: + std::vector fn_stack; + std::vector ln_stack; + parser::location_type real_loc; + parser::location_type old_loc; + int LexerInput(char* buf, int max_size) override { + return readsome(*extra->lexin, buf, max_size); + } + }; + +}; + +YOSYS_NAMESPACE_END + +#endif diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 8148748d8..49be54183 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -32,6 +32,13 @@ * */ +%option c++ +%option yyclass="VerilogLexer" +%option noyywrap +%option nounput +%option yylineno +%option prefix="frontend_verilog_yy" + %{ #ifdef __clang__ @@ -41,85 +48,112 @@ #pragma clang diagnostic ignored "-Wmisleading-indentation" #endif -#include "kernel/log.h" -#include "frontends/verilog/verilog_frontend.h" +#include "frontends/verilog/verilog_lexer.h" #include "frontends/ast/ast.h" -#include "verilog_parser.tab.hh" +#include "kernel/log.h" +#include USING_YOSYS_NAMESPACE using namespace AST; using namespace VERILOG_FRONTEND; - -#define YYSTYPE FRONTEND_VERILOG_YYSTYPE -#define YYLTYPE FRONTEND_VERILOG_YYLTYPE +using parser = frontend_verilog_yy::parser; +//#define YYSTYPE FRONTEND_VERILOG_YYSTYPE +//#define YYLTYPE FRONTEND_VERILOG_YYLTYPE YOSYS_NAMESPACE_BEGIN -namespace VERILOG_FRONTEND { - std::vector fn_stack; - std::vector ln_stack; - YYLTYPE real_location; - YYLTYPE old_location; -} +#undef YY_DECL +#define YY_DECL parser::symbol_type VerilogLexer::nextToken() + +#undef yyterminate +#define yyterminate() terminate() + YOSYS_NAMESPACE_END #define SV_KEYWORD(_tok) \ - if (sv_mode) return _tok; \ + if (mode->sv) return _tok; \ log("Lexer warning: The SystemVerilog keyword `%s' (at %s:%d) is not "\ - "recognized unless read_verilog is called with -sv!\n", yytext, \ - AST::current_filename.c_str(), frontend_verilog_yyget_lineno()); \ - yylval->string = new std::string(std::string("\\") + yytext); \ - return TOK_ID; + "recognized unless read_verilog is called with -sv!\n", YYText(), \ + AST::current_filename.c_str(), yylineno); \ + string_t val = new std::string(std::string("\\") + YYText()); \ + return parser::make_TOK_ID(val, out_loc); #define NON_KEYWORD() \ - yylval->string = new std::string(std::string("\\") + yytext); \ - return TOK_ID; + string_t val = new std::string(std::string("\\") + YYText()); \ + return parser::make_TOK_ID(val, out_loc); -#define YY_INPUT(buf,result,max_size) \ - result = readsome(*VERILOG_FRONTEND::lexin, buf, max_size) +// #define YY_INPUT(buf,result,max_size) \ +// result = readsome(*extra->lexin, buf, max_size) #define YY_USER_ACTION \ - old_location = real_location; \ - real_location.first_line = real_location.last_line; \ - real_location.first_column = real_location.last_column; \ - for(int i = 0; yytext[i] != '\0'; ++i){ \ - if(yytext[i] == '\n') { \ - real_location.last_line++; \ - real_location.last_column = 1; \ - } \ - else { \ - real_location.last_column++; \ - } \ - } \ - (*yylloc) = real_location; + real_loc.begin = real_loc.end; \ + for(int i = 0; YYText()[i] != '\0'; ++i){ \ + if(YYText()[i] == '\n') { \ + real_loc.end.line++; \ + real_loc.end.column = 1; \ + } \ + else { \ + real_loc.end.column++; \ + } \ + } \ + out_loc = real_loc; #define YY_BREAK \ - (*yylloc) = old_location; \ break; #undef YY_BUF_SIZE #define YY_BUF_SIZE 65536 -extern int frontend_verilog_yylex(YYSTYPE *yylval_param, YYLTYPE *yyloc_param); - -static bool isUserType(std::string &s) +static bool isUserType(ParseState* extra, std::string &s) { // check current scope then outer scopes for a name - for (auto it = user_type_stack.rbegin(); it != user_type_stack.rend(); ++it) { + for (auto it = extra->user_type_stack.rbegin(); it != extra->user_type_stack.rend(); ++it) { if (it->count(s) > 0) { - return true; + return true; } } return false; } -%} +parser::symbol_type char_tok(char c, parser::location_type loc) { + switch (c) { + case '!': return parser::make_TOK_EXCL(loc); + case '#': return parser::make_TOK_HASH(loc); + case '%': return parser::make_TOK_PERC(loc); + case '&': return parser::make_TOK_AMP(loc); + case '(': return parser::make_TOK_LPAREN(loc); + case ')': return parser::make_TOK_RPAREN(loc); + case '*': return parser::make_TOK_ASTER(loc); + case '+': return parser::make_TOK_PLUS(loc); + case ',': return parser::make_TOK_COMMA(loc); + case '-': return parser::make_TOK_MINUS(loc); + case '.': return parser::make_TOK_DOT(loc); + case '/': return parser::make_TOK_SLASH(loc); + case ':': return parser::make_TOK_COL(loc); + case ';': return parser::make_TOK_SEMICOL(loc); + case '<': return parser::make_TOK_LT(loc); + case '=': return parser::make_TOK_EQ(loc); + case '>': return parser::make_TOK_GT(loc); + case '?': return parser::make_TOK_QUE(loc); + case '@': return parser::make_TOK_AT(loc); + case '[': return parser::make_TOK_LBRA(loc); + case ']': return parser::make_TOK_RBRA(loc); + case '^': return parser::make_TOK_CARET(loc); + case '_': return parser::make_TOK_UNDER(loc); + case '{': return parser::make_TOK_LCURL(loc); + case '|': return parser::make_TOK_PIPE(loc); + case '}': return parser::make_TOK_RCURL(loc); + case '~': return parser::make_TOK_TILDE(loc); + case 'n': return parser::make_TOK_n(loc); + case 'p': return parser::make_TOK_p(loc); + case 'x': return parser::make_TOK_x(loc); + case 'z': return parser::make_TOK_z(loc); + case 0: return parser::make_FRONTEND_VERILOG_YYEOF(loc); + default: + return parser::make_ch_t(c, loc); + } +} -%option yylineno -%option noyywrap -%option nounput -%option bison-locations -%option bison-bridge -%option prefix="frontend_verilog_yy" +%} %x COMMENT %x STRING @@ -134,47 +168,48 @@ FIXED_POINT_NUMBER_NO_DEC [0-9][0-9_]*[eE][-+]?[0-9_]+ TIME_SCALE_SUFFIX [munpf]?s %% + // Initialise comment_caller to something to avoid a "maybe undefined" // warning from GCC. int comment_caller = INITIAL; "`file_push "[^\n]* { fn_stack.push_back(current_filename); - ln_stack.push_back(frontend_verilog_yyget_lineno()); - current_filename = yytext+11; + ln_stack.push_back(yylineno); + current_filename = YYText()+11; if (!current_filename.empty() && current_filename.front() == '"') current_filename = current_filename.substr(1); if (!current_filename.empty() && current_filename.back() == '"') current_filename = current_filename.substr(0, current_filename.size()-1); - frontend_verilog_yyset_lineno(0); - yylloc->first_line = yylloc->last_line = 0; - real_location.first_line = real_location.last_line = 0; + yylineno = (0); + out_loc.begin.line = out_loc.end.line = 0; + real_loc.begin.line = real_loc.end.line = 0; } "`file_pop"[^\n]*\n { current_filename = fn_stack.back(); fn_stack.pop_back(); - frontend_verilog_yyset_lineno(ln_stack.back()); - yylloc->first_line = yylloc->last_line = ln_stack.back(); - real_location.first_line = real_location.last_line = ln_stack.back(); + yylineno = (ln_stack.back()); + out_loc.begin.line = out_loc.end.line = ln_stack.back(); + real_loc.begin.line = real_loc.end.line = ln_stack.back(); ln_stack.pop_back(); } "`line"[ \t]+[^ \t\r\n]+[ \t]+\"[^ \r\n]+\"[^\r\n]*\n { - char *p = yytext + 5; + const char *p = YYText() + 5; while (*p == ' ' || *p == '\t') p++; - frontend_verilog_yyset_lineno(atoi(p)); - yylloc->first_line = yylloc->last_line = atoi(p); - real_location.first_line = real_location.last_line = atoi(p); + yylineno = (atoi(p)); + out_loc.begin.line = out_loc.end.line = atoi(p); + real_loc.begin.line = real_loc.end.line = atoi(p); while (*p && *p != ' ' && *p != '\t') p++; while (*p == ' ' || *p == '\t') p++; - char *q = *p ? p + 1 : p; + const char *q = *p ? p + 1 : p; while (*q && *q != '"') q++; current_filename = std::string(p).substr(1, q-p-1); } "`file_notfound "[^\n]* { - log_error("Can't open include file `%s'!\n", yytext + 15); + log_error("Can't open include file `%s'!\n", YYText() + 15); } "`timescale"[ \t]+[^ \t\r\n/]+[ \t]*"/"[ \t]*[^ \t\r\n]* /* ignore timescale directive */ @@ -183,164 +218,164 @@ TIME_SCALE_SUFFIX [munpf]?s "`endcelldefine"[^\n]* /* ignore `endcelldefine */ "`default_nettype"[ \t]+[^ \t\r\n/]+ { - char *p = yytext; + const char *p = YYText(); while (*p != 0 && *p != ' ' && *p != '\t') p++; while (*p == ' ' || *p == '\t') p++; if (!strcmp(p, "none")) - VERILOG_FRONTEND::default_nettype_wire = false; + extra->default_nettype_wire = false; else if (!strcmp(p, "wire")) - VERILOG_FRONTEND::default_nettype_wire = true; + extra->default_nettype_wire = true; else - frontend_verilog_yyerror("Unsupported default nettype: %s", p); + err("Unsupported default nettype: %s", p); } "`protect"[^\n]* /* ignore `protect*/ "`endprotect"[^\n]* /* ignore `endprotect*/ "`"[a-zA-Z_$][a-zA-Z0-9_$]* { - frontend_verilog_yyerror("Unimplemented compiler directive or undefined macro %s.", yytext); + err("Unimplemented compiler directive or undefined macro %s.", YYText()); } -"module" { return TOK_MODULE; } -"endmodule" { return TOK_ENDMODULE; } -"function" { return TOK_FUNCTION; } -"endfunction" { return TOK_ENDFUNCTION; } -"task" { return TOK_TASK; } -"endtask" { return TOK_ENDTASK; } -"specify" { return specify_mode ? TOK_SPECIFY : TOK_IGNORED_SPECIFY; } -"endspecify" { return TOK_ENDSPECIFY; } -"specparam" { return TOK_SPECPARAM; } -"package" { SV_KEYWORD(TOK_PACKAGE); } -"endpackage" { SV_KEYWORD(TOK_ENDPACKAGE); } -"interface" { SV_KEYWORD(TOK_INTERFACE); } -"endinterface" { SV_KEYWORD(TOK_ENDINTERFACE); } -"modport" { SV_KEYWORD(TOK_MODPORT); } -"parameter" { return TOK_PARAMETER; } -"localparam" { return TOK_LOCALPARAM; } -"defparam" { return TOK_DEFPARAM; } -"assign" { return TOK_ASSIGN; } -"always" { return TOK_ALWAYS; } -"initial" { return TOK_INITIAL; } -"begin" { return TOK_BEGIN; } -"end" { return TOK_END; } -"if" { return TOK_IF; } -"else" { return TOK_ELSE; } -"for" { return TOK_FOR; } -"posedge" { return TOK_POSEDGE; } -"negedge" { return TOK_NEGEDGE; } -"or" { return TOK_OR; } -"case" { return TOK_CASE; } -"casex" { return TOK_CASEX; } -"casez" { return TOK_CASEZ; } -"endcase" { return TOK_ENDCASE; } -"default" { return TOK_DEFAULT; } -"generate" { return TOK_GENERATE; } -"endgenerate" { return TOK_ENDGENERATE; } -"while" { return TOK_WHILE; } -"repeat" { return TOK_REPEAT; } -"automatic" { return TOK_AUTOMATIC; } +"module" { return parser::make_TOK_MODULE(out_loc); } +"endmodule" { return parser::make_TOK_ENDMODULE(out_loc); } +"function" { return parser::make_TOK_FUNCTION(out_loc); } +"endfunction" { return parser::make_TOK_ENDFUNCTION(out_loc); } +"task" { return parser::make_TOK_TASK(out_loc); } +"endtask" { return parser::make_TOK_ENDTASK(out_loc); } +"specify" { return mode->specify ? parser::make_TOK_SPECIFY(out_loc) : parser::make_TOK_IGNORED_SPECIFY(out_loc); } +"endspecify" { return parser::make_TOK_ENDSPECIFY(out_loc); } +"specparam" { return parser::make_TOK_SPECPARAM(out_loc); } +"package" { SV_KEYWORD(parser::make_TOK_PACKAGE(out_loc)); } +"endpackage" { SV_KEYWORD(parser::make_TOK_ENDPACKAGE(out_loc)); } +"interface" { SV_KEYWORD(parser::make_TOK_INTERFACE(out_loc)); } +"endinterface" { SV_KEYWORD(parser::make_TOK_ENDINTERFACE(out_loc)); } +"modport" { SV_KEYWORD(parser::make_TOK_MODPORT(out_loc)); } +"parameter" { return parser::make_TOK_PARAMETER(out_loc); } +"localparam" { return parser::make_TOK_LOCALPARAM(out_loc); } +"defparam" { return parser::make_TOK_DEFPARAM(out_loc); } +"assign" { return parser::make_TOK_ASSIGN(out_loc); } +"always" { return parser::make_TOK_ALWAYS(out_loc); } +"initial" { return parser::make_TOK_INITIAL(out_loc); } +"begin" { return parser::make_TOK_BEGIN(out_loc); } +"end" { return parser::make_TOK_END(out_loc); } +"if" { return parser::make_TOK_IF(out_loc); } +"else" { return parser::make_TOK_ELSE(out_loc); } +"for" { return parser::make_TOK_FOR(out_loc); } +"posedge" { return parser::make_TOK_POSEDGE(out_loc); } +"negedge" { return parser::make_TOK_NEGEDGE(out_loc); } +"or" { return parser::make_TOK_OR(out_loc); } +"case" { return parser::make_TOK_CASE(out_loc); } +"casex" { return parser::make_TOK_CASEX(out_loc); } +"casez" { return parser::make_TOK_CASEZ(out_loc); } +"endcase" { return parser::make_TOK_ENDCASE(out_loc); } +"default" { return parser::make_TOK_DEFAULT(out_loc); } +"generate" { return parser::make_TOK_GENERATE(out_loc); } +"endgenerate" { return parser::make_TOK_ENDGENERATE(out_loc); } +"while" { return parser::make_TOK_WHILE(out_loc); } +"repeat" { return parser::make_TOK_REPEAT(out_loc); } +"automatic" { return parser::make_TOK_AUTOMATIC(out_loc); } -"unique" { SV_KEYWORD(TOK_UNIQUE); } -"unique0" { SV_KEYWORD(TOK_UNIQUE0); } -"priority" { SV_KEYWORD(TOK_PRIORITY); } +"unique" { SV_KEYWORD(parser::make_TOK_UNIQUE(out_loc)); } +"unique0" { SV_KEYWORD(parser::make_TOK_UNIQUE0(out_loc)); } +"priority" { SV_KEYWORD(parser::make_TOK_PRIORITY(out_loc)); } -"always_comb" { SV_KEYWORD(TOK_ALWAYS_COMB); } -"always_ff" { SV_KEYWORD(TOK_ALWAYS_FF); } -"always_latch" { SV_KEYWORD(TOK_ALWAYS_LATCH); } +"always_comb" { SV_KEYWORD(parser::make_TOK_ALWAYS_COMB(out_loc)); } +"always_ff" { SV_KEYWORD(parser::make_TOK_ALWAYS_FF(out_loc)); } +"always_latch" { SV_KEYWORD(parser::make_TOK_ALWAYS_LATCH(out_loc)); } /* use special token for labels on assert, assume, cover, and restrict because it's insanley complex to fix parsing of cells otherwise. (the current cell parser forces a reduce very early to update some global state.. its a mess) */ [a-zA-Z_$][a-zA-Z0-9_$]*/[ \t\r\n]*:[ \t\r\n]*(assert|assume|cover|restrict)[^a-zA-Z0-9_$\.] { - if (!strcmp(yytext, "default")) - return TOK_DEFAULT; - yylval->string = new std::string(std::string("\\") + yytext); - return TOK_SVA_LABEL; + if (!strcmp(YYText(), "default")) + return parser::make_TOK_DEFAULT(out_loc); + string_t val = new std::string(std::string("\\") + YYText()); + return parser::make_TOK_SVA_LABEL(val, out_loc); } -"assert" { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); } -"assume" { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); } -"cover" { if (formal_mode) return TOK_COVER; SV_KEYWORD(TOK_COVER); } -"restrict" { if (formal_mode) return TOK_RESTRICT; SV_KEYWORD(TOK_RESTRICT); } -"property" { if (formal_mode) return TOK_PROPERTY; SV_KEYWORD(TOK_PROPERTY); } -"rand" { if (formal_mode) return TOK_RAND; SV_KEYWORD(TOK_RAND); } -"const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); } -"checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); } -"endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); } -"bind" { if (formal_mode) return TOK_BIND; SV_KEYWORD(TOK_BIND); } -"final" { SV_KEYWORD(TOK_FINAL); } -"logic" { SV_KEYWORD(TOK_LOGIC); } -"var" { SV_KEYWORD(TOK_VAR); } -"bit" { SV_KEYWORD(TOK_LOGIC); } -"int" { SV_KEYWORD(TOK_INT); } -"byte" { SV_KEYWORD(TOK_BYTE); } -"shortint" { SV_KEYWORD(TOK_SHORTINT); } -"longint" { SV_KEYWORD(TOK_LONGINT); } -"void" { SV_KEYWORD(TOK_VOID); } +"assert" { if (mode->formal) return parser::make_TOK_ASSERT(out_loc); SV_KEYWORD(parser::make_TOK_ASSERT(out_loc)); } +"assume" { if (mode->formal) return parser::make_TOK_ASSUME(out_loc); SV_KEYWORD(parser::make_TOK_ASSUME(out_loc)); } +"cover" { if (mode->formal) return parser::make_TOK_COVER(out_loc); SV_KEYWORD(parser::make_TOK_COVER(out_loc)); } +"restrict" { if (mode->formal) return parser::make_TOK_RESTRICT(out_loc); SV_KEYWORD(parser::make_TOK_RESTRICT(out_loc)); } +"property" { if (mode->formal) return parser::make_TOK_PROPERTY(out_loc); SV_KEYWORD(parser::make_TOK_PROPERTY(out_loc)); } +"rand" { if (mode->formal) return parser::make_TOK_RAND(out_loc); SV_KEYWORD(parser::make_TOK_RAND(out_loc)); } +"const" { if (mode->formal) return parser::make_TOK_CONST(out_loc); SV_KEYWORD(parser::make_TOK_CONST(out_loc)); } +"checker" { if (mode->formal) return parser::make_TOK_CHECKER(out_loc); SV_KEYWORD(parser::make_TOK_CHECKER(out_loc)); } +"endchecker" { if (mode->formal) return parser::make_TOK_ENDCHECKER(out_loc); SV_KEYWORD(parser::make_TOK_ENDCHECKER(out_loc)); } +"bind" { if (mode->formal) return parser::make_TOK_BIND(out_loc); SV_KEYWORD(parser::make_TOK_BIND(out_loc)); } +"final" { SV_KEYWORD(parser::make_TOK_FINAL(out_loc)); } +"logic" { SV_KEYWORD(parser::make_TOK_LOGIC(out_loc)); } +"var" { SV_KEYWORD(parser::make_TOK_VAR(out_loc)); } +"bit" { SV_KEYWORD(parser::make_TOK_LOGIC(out_loc)); } +"int" { SV_KEYWORD(parser::make_TOK_INT(out_loc)); } +"byte" { SV_KEYWORD(parser::make_TOK_BYTE(out_loc)); } +"shortint" { SV_KEYWORD(parser::make_TOK_SHORTINT(out_loc)); } +"longint" { SV_KEYWORD(parser::make_TOK_LONGINT(out_loc)); } +"void" { SV_KEYWORD(parser::make_TOK_VOID(out_loc)); } -"eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); } -"s_eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); } +"eventually" { if (mode->formal) return parser::make_TOK_EVENTUALLY(out_loc); SV_KEYWORD(parser::make_TOK_EVENTUALLY(out_loc)); } +"s_eventually" { if (mode->formal) return parser::make_TOK_EVENTUALLY(out_loc); SV_KEYWORD(parser::make_TOK_EVENTUALLY(out_loc)); } -"input" { return TOK_INPUT; } -"output" { return TOK_OUTPUT; } -"inout" { return TOK_INOUT; } -"wire" { return TOK_WIRE; } -"tri" { return TOK_WIRE; } -"wor" { return TOK_WOR; } -"trior" { return TOK_WOR; } -"wand" { return TOK_WAND; } -"triand" { return TOK_WAND; } -"reg" { return TOK_REG; } -"integer" { return TOK_INTEGER; } -"signed" { return TOK_SIGNED; } -"unsigned" { SV_KEYWORD(TOK_UNSIGNED); } -"genvar" { return TOK_GENVAR; } -"real" { return TOK_REAL; } +"input" { return parser::make_TOK_INPUT(out_loc); } +"output" { return parser::make_TOK_OUTPUT(out_loc); } +"inout" { return parser::make_TOK_INOUT(out_loc); } +"wire" { return parser::make_TOK_WIRE(out_loc); } +"tri" { return parser::make_TOK_WIRE(out_loc); } +"wor" { return parser::make_TOK_WOR(out_loc); } +"trior" { return parser::make_TOK_WOR(out_loc); } +"wand" { return parser::make_TOK_WAND(out_loc); } +"triand" { return parser::make_TOK_WAND(out_loc); } +"reg" { return parser::make_TOK_REG(out_loc); } +"integer" { return parser::make_TOK_INTEGER(out_loc); } +"signed" { return parser::make_TOK_SIGNED(out_loc); } +"unsigned" { SV_KEYWORD(parser::make_TOK_UNSIGNED(out_loc)); } +"genvar" { return parser::make_TOK_GENVAR(out_loc); } +"real" { return parser::make_TOK_REAL(out_loc); } -"enum" { SV_KEYWORD(TOK_ENUM); } -"typedef" { SV_KEYWORD(TOK_TYPEDEF); } -"struct" { SV_KEYWORD(TOK_STRUCT); } -"union" { SV_KEYWORD(TOK_UNION); } -"packed" { SV_KEYWORD(TOK_PACKED); } +"enum" { SV_KEYWORD(parser::make_TOK_ENUM(out_loc)); } +"typedef" { SV_KEYWORD(parser::make_TOK_TYPEDEF(out_loc)); } +"struct" { SV_KEYWORD(parser::make_TOK_STRUCT(out_loc)); } +"union" { SV_KEYWORD(parser::make_TOK_UNION(out_loc)); } +"packed" { SV_KEYWORD(parser::make_TOK_PACKED(out_loc)); } {UNSIGNED_NUMBER} { - yylval->string = new std::string(yytext); - return TOK_CONSTVAL; + string_t val = new std::string(YYText()); + return parser::make_TOK_CONSTVAL(val, out_loc); } \'[01zxZX] { - yylval->string = new std::string(yytext); - return TOK_UNBASED_UNSIZED_CONSTVAL; + string_t val = new std::string(YYText()); + return parser::make_TOK_UNBASED_UNSIZED_CONSTVAL(val, out_loc); } \'[sS]?[bodhBODH] { BEGIN(BASED_CONST); - yylval->string = new std::string(yytext); - return TOK_BASE; + string_t val = new std::string(YYText()); + return parser::make_TOK_BASE(val, out_loc); } [0-9a-fA-FzxZX?][0-9a-fA-FzxZX?_]* { BEGIN(0); - yylval->string = new std::string(yytext); - return TOK_BASED_CONSTVAL; + string_t val = new std::string(YYText()); + return parser::make_TOK_BASED_CONSTVAL(val, out_loc); } {FIXED_POINT_NUMBER_DEC} { - yylval->string = new std::string(yytext); - return TOK_REALVAL; + string_t val = new std::string(YYText()); + return parser::make_TOK_REALVAL(val, out_loc); } {FIXED_POINT_NUMBER_NO_DEC} { - yylval->string = new std::string(yytext); - return TOK_REALVAL; + string_t val = new std::string(YYText()); + return parser::make_TOK_REALVAL(val, out_loc); } \" { BEGIN(STRING); } -([^\"]|\\.)+ { yymore(); real_location = old_location; } +([^\"]|\\.)+ { yymore(); } \" { BEGIN(0); - char *yystr = strdup(yytext); - yystr[strlen(yytext) - 1] = 0; + char *yystr = strdup(YYText()); + yystr[strlen(YYText()) - 1] = 0; int i = 0, j = 0; while (yystr[i]) { if (yystr[i] == '\\' && yystr[i + 1]) { @@ -372,71 +407,71 @@ TIME_SCALE_SUFFIX [munpf]?s yystr[j++] = yystr[i++]; } yystr[j] = 0; - yylval->string = new std::string(yystr, j); + string_t val = new std::string(yystr, j); free(yystr); - return TOK_STRING; + return parser::make_TOK_STRING(val, out_loc); } and|nand|or|nor|xor|xnor|not|buf|bufif0|bufif1|notif0|notif1 { - yylval->string = new std::string(yytext); - return TOK_PRIMITIVE; + auto val = new std::string(YYText()); + return parser::make_TOK_PRIMITIVE(val, out_loc); } -supply0 { return TOK_SUPPLY0; } -supply1 { return TOK_SUPPLY1; } +supply0 { return parser::make_TOK_SUPPLY0(out_loc); } +supply1 { return parser::make_TOK_SUPPLY1(out_loc); } "$"(display[bho]?|write[bho]?|strobe|monitor|time|realtime|stop|finish|dumpfile|dumpvars|dumpon|dumpoff|dumpall) { - yylval->string = new std::string(yytext); - return TOK_ID; + auto val = new std::string(YYText()); + return parser::make_TOK_ID(val, out_loc); } "$"(setup|hold|setuphold|removal|recovery|recrem|skew|timeskew|fullskew|nochange) { - if (!specify_mode) REJECT; - yylval->string = new std::string(yytext); - return TOK_ID; + if (!mode->specify) REJECT; + auto val = new std::string(YYText()); + return parser::make_TOK_ID(val, out_loc); } "$"(info|warning|error|fatal) { - yylval->string = new std::string(yytext); - return TOK_MSG_TASKS; + auto val = new std::string(YYText()); + return parser::make_TOK_MSG_TASKS(val, out_loc); } -"$signed" { return TOK_TO_SIGNED; } -"$unsigned" { return TOK_TO_UNSIGNED; } +"$signed" { return parser::make_TOK_TO_SIGNED(out_loc); } +"$unsigned" { return parser::make_TOK_TO_UNSIGNED(out_loc); } [a-zA-Z_][a-zA-Z0-9_]*::[a-zA-Z_$][a-zA-Z0-9_$]* { // package qualifier - auto s = std::string("\\") + yytext; - if (pkg_user_types.count(s) > 0) { + auto s = std::string("\\") + YYText(); + if (extra->pkg_user_types.count(s) > 0) { // package qualified typedefed name - yylval->string = new std::string(s); - return TOK_PKG_USER_TYPE; + auto val = new std::string(s); + return parser::make_TOK_PKG_USER_TYPE(val, out_loc); } else { // backup before :: just return first part - size_t len = strchr(yytext, ':') - yytext; + size_t len = strchr(YYText(), ':') - YYText(); yyless(len); - yylval->string = new std::string(std::string("\\") + yytext); - return TOK_ID; + auto val = new std::string(std::string("\\") + YYText()); + return parser::make_TOK_ID(val, out_loc); } } [a-zA-Z_$][a-zA-Z0-9_$]* { - auto s = std::string("\\") + yytext; - if (isUserType(s)) { + auto s = std::string("\\") + YYText(); + if (isUserType(extra, s)) { // previously typedefed name - yylval->string = new std::string(s); - return TOK_USER_TYPE; + auto val = new std::string(s); + return parser::make_TOK_USER_TYPE(val, out_loc); } else { - yylval->string = new std::string(std::string("\\") + yytext); - return TOK_ID; + auto val = new std::string(std::string("\\") + YYText()); + return parser::make_TOK_ID(val, out_loc); } } [a-zA-Z_$][a-zA-Z0-9_$\.]* { - yylval->string = new std::string(std::string("\\") + yytext); - return TOK_ID; + auto val = new std::string(std::string("\\") + YYText()); + return parser::make_TOK_ID(val, out_loc); } "/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" { @@ -472,7 +507,7 @@ supply1 { return TOK_SUPPLY1; } ); printed_warning = true; } - return TOK_SYNOPSYS_FULL_CASE; + return parser::make_TOK_SYNOPSYS_FULL_CASE(out_loc); } parallel_case { static bool printed_warning = false; @@ -486,119 +521,115 @@ supply1 { return TOK_SUPPLY1; } ); printed_warning = true; } - return TOK_SYNOPSYS_PARALLEL_CASE; + return parser::make_TOK_SYNOPSYS_PARALLEL_CASE(out_loc); } . /* ignore everything else */ "*/" { BEGIN(0); } import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ { BEGIN(IMPORT_DPI); - return TOK_DPI_FUNCTION; + return parser::make_TOK_DPI_FUNCTION(out_loc); } [a-zA-Z_$][a-zA-Z0-9_$]* { - yylval->string = new std::string(std::string("\\") + yytext); - return TOK_ID; + auto val = new std::string(std::string("\\") + YYText()); + return parser::make_TOK_ID(val, out_loc); } [ \t\r\n] /* ignore whitespaces */ ";" { BEGIN(0); - return *yytext; + return char_tok(*YYText(), out_loc); } . { - return *yytext; + return char_tok(*YYText(), out_loc); } "\\"[^ \t\r\n]+ { - yylval->string = new std::string(yytext); - return TOK_ID; + auto val = new std::string(YYText()); + return parser::make_TOK_ID(val, out_loc); } -"(*" { return ATTR_BEGIN; } -"*)" { return ATTR_END; } +"(*" { return parser::make_ATTR_BEGIN(out_loc); } +"*)" { return parser::make_ATTR_END(out_loc); } -"{*" { return DEFATTR_BEGIN; } -"*}" { return DEFATTR_END; } +"{*" { return parser::make_DEFATTR_BEGIN(out_loc); } +"*}" { return parser::make_DEFATTR_END(out_loc); } -"**" { return OP_POW; } -"||" { return OP_LOR; } -"&&" { return OP_LAND; } -"==" { return OP_EQ; } -"!=" { return OP_NE; } -"<=" { return OP_LE; } -">=" { return OP_GE; } +"**" { return parser::make_OP_POW(out_loc); } +"||" { return parser::make_OP_LOR(out_loc); } +"&&" { return parser::make_OP_LAND(out_loc); } +"==" { return parser::make_OP_EQ(out_loc); } +"!=" { return parser::make_OP_NE(out_loc); } +"<=" { return parser::make_OP_LE(out_loc); } +">=" { return parser::make_OP_GE(out_loc); } -"===" { return OP_EQX; } -"!==" { return OP_NEX; } +"===" { return parser::make_OP_EQX(out_loc); } +"!==" { return parser::make_OP_NEX(out_loc); } -"~&" { return OP_NAND; } -"~|" { return OP_NOR; } -"~^" { return OP_XNOR; } -"^~" { return OP_XNOR; } +"~&" { return parser::make_OP_NAND(out_loc); } +"~|" { return parser::make_OP_NOR(out_loc); } +"~^" { return parser::make_OP_XNOR(out_loc); } +"^~" { return parser::make_OP_XNOR(out_loc); } -"<<" { return OP_SHL; } -">>" { return OP_SHR; } -"<<<" { return OP_SSHL; } -">>>" { return OP_SSHR; } +"<<" { return parser::make_OP_SHL(out_loc); } +">>" { return parser::make_OP_SHR(out_loc); } +"<<<" { return parser::make_OP_SSHL(out_loc); } +">>>" { return parser::make_OP_SSHR(out_loc); } -"'" { return OP_CAST; } +"'" { return parser::make_OP_CAST(out_loc); } -"::" { return TOK_PACKAGESEP; } -"++" { return TOK_INCREMENT; } -"--" { return TOK_DECREMENT; } +"::" { return parser::make_TOK_PACKAGESEP(out_loc); } +"++" { return parser::make_TOK_INCREMENT(out_loc); } +"--" { return parser::make_TOK_DECREMENT(out_loc); } -"+:" { return TOK_POS_INDEXED; } -"-:" { return TOK_NEG_INDEXED; } +"+:" { return parser::make_TOK_POS_INDEXED(out_loc); } +"-:" { return parser::make_TOK_NEG_INDEXED(out_loc); } -".*" { return TOK_WILDCARD_CONNECT; } +".*" { return parser::make_TOK_WILDCARD_CONNECT(out_loc); } -"|=" { SV_KEYWORD(TOK_BIT_OR_ASSIGN); } -"&=" { SV_KEYWORD(TOK_BIT_AND_ASSIGN); } -"+=" { SV_KEYWORD(TOK_ADD_ASSIGN); } -"-=" { SV_KEYWORD(TOK_SUB_ASSIGN); } -"^=" { SV_KEYWORD(TOK_BIT_XOR_ASSIGN); } -"/=" { SV_KEYWORD(TOK_DIV_ASSIGN); } -"%=" { SV_KEYWORD(TOK_MOD_ASSIGN); } -"*=" { SV_KEYWORD(TOK_MUL_ASSIGN); } -"<<=" { SV_KEYWORD(TOK_SHL_ASSIGN); } -">>=" { SV_KEYWORD(TOK_SHR_ASSIGN); } -"<<<=" { SV_KEYWORD(TOK_SSHL_ASSIGN); } -">>>=" { SV_KEYWORD(TOK_SSHR_ASSIGN); } +"|=" { SV_KEYWORD(parser::make_TOK_BIT_OR_ASSIGN(out_loc)); } +"&=" { SV_KEYWORD(parser::make_TOK_BIT_AND_ASSIGN(out_loc)); } +"+=" { SV_KEYWORD(parser::make_TOK_ADD_ASSIGN(out_loc)); } +"-=" { SV_KEYWORD(parser::make_TOK_SUB_ASSIGN(out_loc)); } +"^=" { SV_KEYWORD(parser::make_TOK_BIT_XOR_ASSIGN(out_loc)); } +"/=" { SV_KEYWORD(parser::make_TOK_DIV_ASSIGN(out_loc)); } +"%=" { SV_KEYWORD(parser::make_TOK_MOD_ASSIGN(out_loc)); } +"*=" { SV_KEYWORD(parser::make_TOK_MUL_ASSIGN(out_loc)); } +"<<=" { SV_KEYWORD(parser::make_TOK_SHL_ASSIGN(out_loc)); } +">>=" { SV_KEYWORD(parser::make_TOK_SHR_ASSIGN(out_loc)); } +"<<<=" { SV_KEYWORD(parser::make_TOK_SSHL_ASSIGN(out_loc)); } +">>>=" { SV_KEYWORD(parser::make_TOK_SSHR_ASSIGN(out_loc)); } [-+]?[=*]> { - if (!specify_mode) REJECT; - yylval->string = new std::string(yytext); - return TOK_SPECIFY_OPER; + if (!mode->specify) REJECT; + auto val = new std::string(YYText()); + return parser::make_TOK_SPECIFY_OPER(val, out_loc); } "&&&" { - if (!specify_mode) return TOK_IGNORED_SPECIFY_AND; - return TOK_SPECIFY_AND; + if (!mode->specify) return parser::make_TOK_IGNORED_SPECIFY_AND(out_loc); + return parser::make_TOK_SPECIFY_AND(out_loc); } -{UNSIGNED_NUMBER}{TIME_SCALE_SUFFIX} { return TOK_TIME_SCALE; } -{FIXED_POINT_NUMBER_DEC}{TIME_SCALE_SUFFIX} { return TOK_TIME_SCALE; } -{FIXED_POINT_NUMBER_NO_DEC}{TIME_SCALE_SUFFIX} { return TOK_TIME_SCALE; } +{UNSIGNED_NUMBER}{TIME_SCALE_SUFFIX} { return parser::make_TOK_TIME_SCALE(out_loc); } +{FIXED_POINT_NUMBER_DEC}{TIME_SCALE_SUFFIX} { return parser::make_TOK_TIME_SCALE(out_loc); } +{FIXED_POINT_NUMBER_NO_DEC}{TIME_SCALE_SUFFIX} { return parser::make_TOK_TIME_SCALE(out_loc); } "/*" { comment_caller=YY_START; BEGIN(COMMENT); } . /* ignore comment body */ \n /* ignore comment body */ "*/" { BEGIN(comment_caller); } + [ \t\r\n] /* ignore whitespaces */ \\[\r\n] /* ignore continuation sequence */ "//"[^\r\n]* /* ignore one-line comments */ -. { return *yytext; } -<*>. { BEGIN(0); return *yytext; } +. { return char_tok(*YYText(), out_loc); } +<*>. { BEGIN(0); return char_tok(*YYText(), out_loc); } %% -// this is a hack to avoid the 'yyinput defined but not used' error msgs -void *frontend_verilog_avoid_input_warnings() { - return (void*)&yyinput; -} - diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 7e53005f3..0ac1d938f 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -34,366 +34,479 @@ */ %require "3.0" +%language "c++" +%define api.value.type variant +%define api.prefix {frontend_verilog_yy} +%define api.token.constructor -%{ -#include -#include -#include -#include "frontends/verilog/verilog_frontend.h" -#include "frontends/verilog/verilog_parser.tab.hh" -#include "kernel/log.h" +%param { YOSYS_NAMESPACE_PREFIX VERILOG_FRONTEND::VerilogLexer* lexer } +%parse-param { YOSYS_NAMESPACE_PREFIX VERILOG_FRONTEND::ParseState* extra } +%parse-param { YOSYS_NAMESPACE_PREFIX VERILOG_FRONTEND::ParseMode* mode } -#define YYLEX_PARAM &yylval, &yylloc - -USING_YOSYS_NAMESPACE -using namespace AST; -using namespace VERILOG_FRONTEND; - -YOSYS_NAMESPACE_BEGIN -namespace VERILOG_FRONTEND { - int port_counter; - dict port_stubs; - dict *attr_list, default_attr_list; - std::stack *> attr_list_stack; - dict *albuf; - std::vector user_type_stack; - dict pkg_user_types; - std::vector ast_stack; - struct AstNode *astbuf1, *astbuf2, *astbuf3; - struct AstNode *current_function_or_task; - struct AstNode *current_ast, *current_ast_mod; - int current_function_or_task_port_id; - std::vector case_type_stack; - bool do_not_require_port_stubs; - bool default_nettype_wire; - bool sv_mode, formal_mode, lib_mode, specify_mode; - bool noassert_mode, noassume_mode, norestrict_mode; - bool assume_asserts_mode, assert_assumes_mode; - bool current_wire_rand, current_wire_const; - bool current_modport_input, current_modport_output; - std::istream *lexin; +%code requires { + #include "kernel/yosys_common.h" + // #include "frontends/verilog/verilog_lexer.h" + // start requires + YOSYS_NAMESPACE_BEGIN + namespace VERILOG_FRONTEND { + struct ParseState; + struct ParseMode; + class VerilogLexer; + }; + YOSYS_NAMESPACE_END + // end requires } -YOSYS_NAMESPACE_END -#define SET_AST_NODE_LOC(WHICH, BEGIN, END) \ - do { (WHICH)->location.first_line = (BEGIN).first_line; \ - (WHICH)->location.first_column = (BEGIN).first_column; \ - (WHICH)->location.last_line = (END).last_line; \ - (WHICH)->location.last_column = (END).last_column; } while(0) +%code provides { + // start provides + USING_YOSYS_NAMESPACE; + using namespace AST; + using namespace VERILOG_FRONTEND; + using parser = frontend_verilog_yy::parser; + YOSYS_NAMESPACE_BEGIN + namespace VERILOG_FRONTEND { + typedef std::map UserTypeMap; + struct ParseState { + // TODO initialization? + int port_counter; + dict port_stubs; + dict> *attr_list, default_attr_list; + std::stack> *> attr_list_stack; + dict> *albuf; + std::vector user_type_stack; + dict pkg_user_types; + std::vector ast_stack; + std::unique_ptr astbuf1, astbuf2, astbuf3; + AstNode* cell_hack; + AstNode* member_hack; + struct AstNode *current_function_or_task; + struct AstNode *current_ast, *current_ast_mod; + int current_function_or_task_port_id; + std::vector case_type_stack; + bool do_not_require_port_stubs; + bool current_wire_rand, current_wire_const; + bool current_modport_input, current_modport_output; + bool default_nettype_wire = true; + std::istream* lexin; -#define SET_RULE_LOC(LHS, BEGIN, END) \ - do { (LHS).first_line = (BEGIN).first_line; \ - (LHS).first_column = (BEGIN).first_column; \ - (LHS).last_line = (END).last_line; \ - (LHS).last_column = (END).last_column; } while(0) + AstNode* saveChild(std::unique_ptr child); + AstNode* pushChild(std::unique_ptr child); + void addWiretypeNode(std::string *name, AstNode* node); + void addTypedefNode(std::string *name, std::unique_ptr node); + void enterTypeScope(); + void exitTypeScope(); + bool isInLocalScope(const std::string *name); + void rewriteGenForDeclInit(AstNode *loop); + void ensureAsgnExprAllowed(const parser::location_type loc, bool sv_mode); + const AstNode *addIncOrDecStmt(dict> *stmt_attr, + std::unique_ptr lhs, + dict> *op_attr, AST::AstNodeType op, + parser::location_type begin, parser::location_type end); + std::unique_ptr addIncOrDecExpr(std::unique_ptr lhs, dict> *attr, AST::AstNodeType op, parser::location_type begin, parser::location_type end, bool undo, bool sv_mode); + // add a binary operator assignment statement, e.g., a += b + std::unique_ptr addAsgnBinopStmt(dict> *attr, std::unique_ptr eq_lhs, AST::AstNodeType op, std::unique_ptr rhs, parser::location_type begin, parser::location_type end); + }; + struct ParseMode { + bool noassert = false; + bool noassume = false; + bool norestrict = false; + bool sv = false; + bool formal = false; + bool lib = false; + bool specify = false; + bool assume_asserts = false; + bool assert_assumes = false; + }; + }; + YOSYS_NAMESPACE_END + // end provides +} -int frontend_verilog_yylex(YYSTYPE *yylval_param, YYLTYPE *yyloc_param); +%code { + // start unqual + #include + #include + #include + #include + #include "kernel/log.h" + #include "frontends/verilog/verilog_lexer.h" -static void append_attr(AstNode *ast, dict *al) -{ - for (auto &it : *al) { - if (ast->attributes.count(it.first) > 0) - delete ast->attributes[it.first]; - ast->attributes[it.first] = it.second; + USING_YOSYS_NAMESPACE + using namespace AST; + using namespace VERILOG_FRONTEND; + + // Silly little C adapter between C++ bison and C++ flex + auto frontend_verilog_yylex(YOSYS_NAMESPACE_PREFIX VERILOG_FRONTEND::VerilogLexer* lexer) { + return lexer->nextToken(); } - delete al; -} -static void append_attr_clone(AstNode *ast, dict *al) -{ - for (auto &it : *al) { - if (ast->attributes.count(it.first) > 0) - delete ast->attributes[it.first]; - ast->attributes[it.first] = it.second->clone(); - } -} + #define SET_LOC(WHICH, BEGIN, END) \ + do { WHICH.first_line = (BEGIN).begin.line; \ + WHICH.first_column = (BEGIN).begin.column; \ + WHICH.last_line = (END).end.line; \ + WHICH.last_column = (END).end.column; } while(0) -static void free_attr(dict *al) -{ - for (auto &it : *al) - delete it.second; - delete al; -} + #define SET_AST_NODE_LOC(WHICH, BEGIN, END) SET_LOC((WHICH)->location, BEGIN, END) -struct specify_target { - char polarity_op; - AstNode *dst, *dat; -}; + #define SET_RULE_LOC(LHS, BEGIN, END) \ + do { (LHS).begin = BEGIN.begin; \ + (LHS).end = (END).end; } while(0) -struct specify_triple { - AstNode *t_min, *t_avg, *t_max; -}; - -struct specify_rise_fall { - specify_triple rise; - specify_triple fall; -}; - -static void addWiretypeNode(std::string *name, AstNode *node) -{ - log_assert(node); - node->is_custom_type = true; - node->children.push_back(new AstNode(AST_WIRETYPE)); - node->children.back()->str = *name; - delete name; -} - -static void addTypedefNode(std::string *name, AstNode *node) -{ - log_assert(node); - auto *tnode = new AstNode(AST_TYPEDEF, node); - tnode->str = *name; - auto &user_types = user_type_stack.back(); - user_types[*name] = tnode; - if (current_ast_mod && current_ast_mod->type == AST_PACKAGE) { - // typedef inside a package so we need the qualified name - auto qname = current_ast_mod->str + "::" + (*name).substr(1); - pkg_user_types[qname] = tnode; - } - delete name; - ast_stack.back()->children.push_back(tnode); -} - -static void enterTypeScope() -{ - user_type_stack.push_back(UserTypeMap()); -} - -static void exitTypeScope() -{ - user_type_stack.pop_back(); -} - -static bool isInLocalScope(const std::string *name) -{ - // tests if a name was declared in the current block scope - auto &user_types = user_type_stack.back(); - return (user_types.count(*name) > 0); -} - -static AstNode *makeRange(int msb = 31, int lsb = 0, bool isSigned = true) -{ - auto range = new AstNode(AST_RANGE); - range->children.push_back(AstNode::mkconst_int(msb, true)); - range->children.push_back(AstNode::mkconst_int(lsb, true)); - range->is_signed = isSigned; - return range; -} - -static void addRange(AstNode *parent, int msb = 31, int lsb = 0, bool isSigned = true) -{ - auto range = makeRange(msb, lsb, isSigned); - parent->children.push_back(range); -} - -static AstNode *checkRange(AstNode *type_node, AstNode *range_node) -{ - if (type_node->range_left >= 0 && type_node->range_right >= 0) { - // type already restricts the range - if (range_node) { - frontend_verilog_yyerror("integer/genvar types cannot have packed dimensions."); + YOSYS_NAMESPACE_BEGIN + namespace VERILOG_FRONTEND { + static ConstParser make_ConstParser_here(parser::location_type flex_loc) { + AstSrcLocType loc; + SET_LOC(loc, flex_loc, flex_loc); + std::optional filename = flex_loc.begin.filename ? std::make_optional(*(flex_loc.begin.filename)) : std::nullopt; + ConstParser p{filename, loc}; + return p; } - else { - range_node = makeRange(type_node->range_left, type_node->range_right, false); + static void append_attr(AstNode *ast, dict> *al) + { + for (auto &it : *al) { + ast->attributes[it.first] = std::move(it.second); + } + delete al; } - } - if (range_node) { - bool valid = true; - if (range_node->type == AST_RANGE) { - valid = range_node->children.size() == 2; - } else { // AST_MULTIRANGE - for (auto child : range_node->children) { - valid = valid && child->children.size() == 2; + static void append_attr_clone(AstNode *ast, dict> *al) + { + for (auto &it : *al) { + ast->attributes[it.first] = it.second->clone(); } } - if (!valid) - frontend_verilog_yyerror("wire/reg/logic packed dimension must be of the form [:]"); - } - return range_node; -} + static void free_attr(dict> *al) + { + delete al; + } -static void rewriteRange(AstNode *rangeNode) -{ - if (rangeNode->type == AST_RANGE && rangeNode->children.size() == 1) { - // SV array size [n], rewrite as [0:n-1] - rangeNode->children.push_back(new AstNode(AST_SUB, rangeNode->children[0], AstNode::mkconst_int(1, true))); - rangeNode->children[0] = AstNode::mkconst_int(0, false); - } -} + static std::unique_ptr makeRange(int msb = 31, int lsb = 0, bool isSigned = true) + { + auto range = std::make_unique(AST_RANGE); + range->children.push_back(AstNode::mkconst_int(msb, true)); + range->children.push_back(AstNode::mkconst_int(lsb, true)); + range->is_signed = isSigned; + return range; + } -static void rewriteAsMemoryNode(AstNode *node, AstNode *rangeNode) -{ - node->type = AST_MEMORY; - if (rangeNode->type == AST_MULTIRANGE) { - for (auto *itr : rangeNode->children) - rewriteRange(itr); - } else - rewriteRange(rangeNode); - node->children.push_back(rangeNode); -} + static void addRange(AstNode *parent, int msb = 31, int lsb = 0, bool isSigned = true) + { + auto range = makeRange(msb, lsb, isSigned); + parent->children.push_back(std::move(range)); + } -static void checkLabelsMatch(const char *element, const std::string *before, const std::string *after) -{ - if (!before && after) - frontend_verilog_yyerror("%s missing where end label (%s) was given.", - element, after->c_str() + 1); - if (before && after && *before != *after) - frontend_verilog_yyerror("%s (%s) and end label (%s) don't match.", - element, before->c_str() + 1, after->c_str() + 1); -} + static std::unique_ptr checkRange(AstNode *type_node, std::unique_ptr range_node) + { + if (type_node->range_left >= 0 && type_node->range_right >= 0) { + // type already restricts the range + if (range_node) { + err_at_ast(type_node->location, "integer/genvar types cannot have packed dimensions."); + } + else { + range_node = makeRange(type_node->range_left, type_node->range_right, false); + } + } -// This transforms a loop like -// for (genvar i = 0; i < 10; i++) begin : blk -// to -// genvar _i; -// for (_i = 0; _i < 10; _i++) begin : blk -// localparam i = _i; -// where `_i` is actually some auto-generated name. -static void rewriteGenForDeclInit(AstNode *loop) -{ - // check if this generate for loop contains an inline declaration - log_assert(loop->type == AST_GENFOR); - AstNode *decl = loop->children[0]; - if (decl->type == AST_ASSIGN_EQ) - return; - log_assert(decl->type == AST_GENVAR); - log_assert(loop->children.size() == 5); + if (range_node) { + bool valid = true; + if (range_node->type == AST_RANGE) { + valid = range_node->children.size() == 2; + } else { // AST_MULTIRANGE + for (auto& child : range_node->children) { + valid = valid && child->children.size() == 2; + } + } + if (!valid) + err_at_ast(type_node->location, "wire/reg/logic packed dimension must be of the form [:]"); + } - // identify each component of the loop - AstNode *init = loop->children[1]; - AstNode *cond = loop->children[2]; - AstNode *incr = loop->children[3]; - AstNode *body = loop->children[4]; - log_assert(init->type == AST_ASSIGN_EQ); - log_assert(incr->type == AST_ASSIGN_EQ); - log_assert(body->type == AST_GENBLOCK); + return range_node; + } - // create a unique name for the genvar - std::string old_str = decl->str; - std::string new_str = stringf("$genfordecl$%d$%s", autoidx++, old_str.c_str()); + static void rewriteRange(AstNode *rangeNode) + { + if (rangeNode->type == AST_RANGE && rangeNode->children.size() == 1) { + // SV array size [n], rewrite as [0:n-1] + rangeNode->children.push_back(std::make_unique(AST_SUB, std::move(rangeNode->children[0]), AstNode::mkconst_int(1, true))); + rangeNode->children[0] = AstNode::mkconst_int(0, false); + } + } - // rename and move the genvar declaration to the containing description - decl->str = new_str; - loop->children.erase(loop->children.begin()); - log_assert(current_ast_mod != nullptr); - current_ast_mod->children.push_back(decl); + static void rewriteAsMemoryNode(AstNode *node, std::unique_ptr rangeNode) + { + node->type = AST_MEMORY; + if (rangeNode->type == AST_MULTIRANGE) { + for (auto& child : rangeNode->children) + rewriteRange(child.get()); + } else + rewriteRange(rangeNode.get()); + node->children.push_back(std::move(rangeNode)); + } - // create a new localparam with old name so that the items in the loop - // can simply use the old name and shadow it as necessary - AstNode *indirect = new AstNode(AST_LOCALPARAM); - indirect->str = old_str; - AstNode *ident = new AstNode(AST_IDENTIFIER); - ident->str = new_str; - indirect->children.push_back(ident); + static void checkLabelsMatch(const frontend_verilog_yy::parser::location_type& loc, const char *element, const std::string *before, const std::string *after) + { + if (!before && after) + err_at_loc(loc, "%s missing where end label (%s) was given.", + element, after->c_str() + 1); + if (before && after && *before != *after) + err_at_loc(loc, "%s (%s) and end label (%s) don't match.", + element, before->c_str() + 1, after->c_str() + 1); + } - body->children.insert(body->children.begin(), indirect); + AstNode* ParseState::saveChild(std::unique_ptr child) { + auto* child_leaky = child.get(); + ast_stack.back()->children.push_back(std::move(child)); + return child_leaky; + } + AstNode* ParseState::pushChild(std::unique_ptr child) { + auto* child_leaky = saveChild(std::move(child)); + ast_stack.push_back(child_leaky); + return child_leaky; + } - // only perform the renaming for the initialization, guard, and - // incrementation to enable proper shadowing of the synthetic localparam - std::function substitute = [&](AstNode *node) { - if (node->type == AST_IDENTIFIER && node->str == old_str) - node->str = new_str; - for (AstNode *child : node->children) - substitute(child); + void ParseState::addWiretypeNode(std::string *name, AstNode* node) + { + log_assert(node); + node->is_custom_type = true; + node->children.push_back(std::make_unique(AST_WIRETYPE)); + node->children.back()->str = *name; + delete name; + } + + void ParseState::addTypedefNode(std::string *name, std::unique_ptr node) + { + log_assert((bool)node); + AstNode* tnode = saveChild(std::make_unique(AST_TYPEDEF, std::move(node))); + log_assert((bool)name); + tnode->str = *name; + auto &user_types = user_type_stack.back(); + user_types[*name] = tnode; + if (current_ast_mod && current_ast_mod->type == AST_PACKAGE) { + // typedef inside a package so we need the qualified name + auto qname = current_ast_mod->str + "::" + (*name).substr(1); + pkg_user_types[qname] = tnode; + } + delete name; + } + + void ParseState::enterTypeScope() + { + user_type_stack.push_back(UserTypeMap()); + } + + void ParseState::exitTypeScope() + { + user_type_stack.pop_back(); + } + + bool ParseState::isInLocalScope(const std::string *name) + { + // tests if a name was declared in the current block scope + auto &user_types = user_type_stack.back(); + return (user_types.count(*name) > 0); + } + + // This transforms a loop like + // for (genvar i = 0; i < 10; i++) begin : blk + // to + // genvar _i; + // for (_i = 0; _i < 10; _i++) begin : blk + // localparam i = _i; + // where `_i` is actually some auto-generated name. + void ParseState::rewriteGenForDeclInit(AstNode *loop) + { + // check if this generate for loop contains an inline declaration + log_assert(loop->type == AST_GENFOR); + auto& decl = loop->children[0]; + if (decl->type == AST_ASSIGN_EQ) + return; + + log_assert(decl->type == AST_GENVAR); + log_assert(loop->children.size() == 5); + + // identify each component of the loop + AstNode *init = loop->children[1].get(); + AstNode *cond = loop->children[2].get(); + AstNode *incr = loop->children[3].get(); + AstNode *body = loop->children[4].get(); + log_assert(init->type == AST_ASSIGN_EQ); + log_assert(incr->type == AST_ASSIGN_EQ); + log_assert(body->type == AST_GENBLOCK); + + // create a unique name for the genvar + std::string old_str = decl->str; + std::string new_str = stringf("$genfordecl$%d$%s", autoidx++, old_str.c_str()); + + // rename and move the genvar declaration to the containing description + decl->str = new_str; + log_assert(current_ast_mod != nullptr); + current_ast_mod->children.push_back(std::move(decl)); + + // create a new localparam with old name so that the items in the loop + // can simply use the old name and shadow it as necessary + auto indirect = std::make_unique(AST_LOCALPARAM); + indirect->str = old_str; + auto ident = std::make_unique(AST_IDENTIFIER); + ident->str = new_str; + indirect->children.push_back(std::move(ident)); + + body->children.insert(body->children.begin(), std::move(indirect)); + + // only perform the renaming for the initialization, guard, and + // incrementation to enable proper shadowing of the synthetic localparam + std::function substitute = [&](AstNode *node) { + if (node->type == AST_IDENTIFIER && node->str == old_str) + node->str = new_str; + for (auto& child : node->children) + substitute(child.get()); + }; + substitute(init); + substitute(cond); + substitute(incr); + loop->children.erase(loop->children.begin()); + } + + void ParseState::ensureAsgnExprAllowed(const parser::location_type loc, bool sv_mode) + { + if (!sv_mode) + err_at_loc(loc, "Assignments within expressions are only supported in SystemVerilog mode."); + if (ast_stack.back()->type != AST_BLOCK) + err_at_loc(loc, "Assignments within expressions are only permitted within procedures."); + } + + // add a pre/post-increment/decrement statement + const AstNode *ParseState::addIncOrDecStmt(dict> *stmt_attr, + std::unique_ptr lhs, + dict> *op_attr, AST::AstNodeType op, + frontend_verilog_yy::location begin, frontend_verilog_yy::location end) + { + auto one = AstNode::mkconst_int(1, true); + auto rhs = std::make_unique(op, lhs->clone(), std::move(one)); + if (op_attr != nullptr) + append_attr(rhs.get(), op_attr); + auto stmt_owned = std::make_unique(AST_ASSIGN_EQ, std::move(lhs), std::move(rhs)); + auto* stmt = stmt_owned.get(); + ast_stack.back()->children.push_back(std::move(stmt_owned)); + SET_AST_NODE_LOC(stmt, begin, end); + if (stmt_attr != nullptr) + append_attr(stmt, stmt_attr); + return stmt; + } + + // create a pre/post-increment/decrement expression, and add the corresponding statement + std::unique_ptr ParseState::addIncOrDecExpr(std::unique_ptr lhs, dict> *attr, AST::AstNodeType op, frontend_verilog_yy::location begin, frontend_verilog_yy::location end, bool undo, bool sv_mode) + { + ensureAsgnExprAllowed(begin, sv_mode); + const AstNode *stmt = addIncOrDecStmt(nullptr, std::move(lhs), attr, op, begin, end); + log_assert(stmt->type == AST_ASSIGN_EQ); + auto expr = stmt->children[0]->clone(); + if (undo) { + auto one = AstNode::mkconst_int(1, false, 1); + auto minus_one = std::make_unique(AST_NEG, std::move(one)); + expr = std::make_unique(op, std::move(expr), std::move(minus_one)); + } + SET_AST_NODE_LOC(expr.get(), begin, end); + return expr; + } + + // add a binary operator assignment statement, e.g., a += b + std::unique_ptr ParseState::addAsgnBinopStmt(dict> *attr, std::unique_ptr eq_lhs, AST::AstNodeType op, std::unique_ptr rhs, frontend_verilog_yy::location begin, frontend_verilog_yy::location end) + { + SET_AST_NODE_LOC(rhs.get(), end, end); + if (op == AST_SHIFT_LEFT || op == AST_SHIFT_RIGHT || + op == AST_SHIFT_SLEFT || op == AST_SHIFT_SRIGHT) { + rhs = std::make_unique(AST_TO_UNSIGNED, std::move(rhs)); + SET_AST_NODE_LOC(rhs.get(), end, end); + } + auto binop_lhs = eq_lhs->clone(); + auto eq_rhs_owned = std::make_unique(op, std::move(binop_lhs), std::move(rhs)); + auto* eq_rhs = eq_rhs_owned.get(); + auto ret_lhs = eq_lhs->clone(); + auto stmt_owned = std::make_unique(AST_ASSIGN_EQ, std::move(eq_lhs), std::move(eq_rhs_owned)); + auto* stmt = stmt_owned.get(); + SET_AST_NODE_LOC(eq_rhs, begin, end); + SET_AST_NODE_LOC(stmt, begin, end); + ast_stack.back()->children.push_back(std::move(stmt_owned)); + if (attr != nullptr) + append_attr(stmt, attr); + return ret_lhs; + } }; - substitute(init); - substitute(cond); - substitute(incr); -} + YOSYS_NAMESPACE_END -static void ensureAsgnExprAllowed() -{ - if (!sv_mode) - frontend_verilog_yyerror("Assignments within expressions are only supported in SystemVerilog mode."); - if (ast_stack.back()->type != AST_BLOCK) - frontend_verilog_yyerror("Assignments within expressions are only permitted within procedures."); -} - -// add a pre/post-increment/decrement statement -static const AstNode *addIncOrDecStmt(dict *stmt_attr, AstNode *lhs, - dict *op_attr, AST::AstNodeType op, - YYLTYPE begin, YYLTYPE end) -{ - AstNode *one = AstNode::mkconst_int(1, true); - AstNode *rhs = new AstNode(op, lhs->clone(), one); - if (op_attr != nullptr) - append_attr(rhs, op_attr); - AstNode *stmt = new AstNode(AST_ASSIGN_EQ, lhs, rhs); - SET_AST_NODE_LOC(stmt, begin, end); - if (stmt_attr != nullptr) - append_attr(stmt, stmt_attr); - ast_stack.back()->children.push_back(stmt); - return stmt; -} - -// create a pre/post-increment/decrement expression, and add the corresponding statement -static AstNode *addIncOrDecExpr(AstNode *lhs, dict *attr, AST::AstNodeType op, YYLTYPE begin, YYLTYPE end, bool undo) -{ - ensureAsgnExprAllowed(); - const AstNode *stmt = addIncOrDecStmt(nullptr, lhs, attr, op, begin, end); - log_assert(stmt->type == AST_ASSIGN_EQ); - AstNode *expr = stmt->children[0]->clone(); - if (undo) { - AstNode *one = AstNode::mkconst_int(1, false, 1); - AstNode *minus_one = new AstNode(AST_NEG, one); - expr = new AstNode(op, expr, minus_one); + void frontend_verilog_yy::parser::error(const frontend_verilog_yy::parser::location_type& loc, const std::string& msg) + { + err_at_loc(loc, "%s", msg.c_str()); } - SET_AST_NODE_LOC(expr, begin, end); - return expr; + // end unqual } -// add a binary operator assignment statement, e.g., a += b -static const AstNode *addAsgnBinopStmt(dict *attr, AstNode *lhs, AST::AstNodeType op, AstNode *rhs, YYLTYPE begin, YYLTYPE end) -{ - SET_AST_NODE_LOC(rhs, end, end); - if (op == AST_SHIFT_LEFT || op == AST_SHIFT_RIGHT || - op == AST_SHIFT_SLEFT || op == AST_SHIFT_SRIGHT) { - rhs = new AstNode(AST_TO_UNSIGNED, rhs); - SET_AST_NODE_LOC(rhs, end, end); - } - rhs = new AstNode(op, lhs->clone(), rhs); - AstNode *stmt = new AstNode(AST_ASSIGN_EQ, lhs, rhs); - SET_AST_NODE_LOC(rhs, begin, end); - SET_AST_NODE_LOC(stmt, begin, end); - ast_stack.back()->children.push_back(stmt); - if (attr != nullptr) - append_attr(stmt, attr); - return lhs; -} - -%} - -%define api.prefix {frontend_verilog_yy} -%define api.pure - -/* The union is defined in the header, so we need to provide all the - * includes it requires - */ %code requires { -#include -#include -#include "frontends/verilog/verilog_frontend.h" + // start requires + #include + #include + #include + #include "frontends/verilog/verilog_frontend.h" + + struct specify_target { + char polarity_op; + std::unique_ptr dst, dat; + specify_target& operator=(specify_target&& other) noexcept { + if (this != &other) { + dst = std::move(other.dst); + dat = std::move(other.dat); + polarity_op = other.polarity_op; + } + return *this; + } + }; + + struct specify_triple { + std::unique_ptr t_min, t_avg, t_max; + specify_triple& operator=(specify_triple&& other) noexcept { + if (this != &other) { + t_min = std::move(other.t_min); + t_avg = std::move(other.t_avg); + t_max = std::move(other.t_max); + } + return *this; + } + }; + + struct specify_rise_fall { + specify_triple rise; + specify_triple fall; + }; + + using string_t = std::string *; + using ast_t = std::unique_ptr; + using al_t = YOSYS_NAMESPACE_PREFIX dict>*; + using specify_target_ptr_t = std::unique_ptr; + using specify_triple_ptr_t = std::unique_ptr; + using specify_rise_fall_ptr_t = std::unique_ptr; + using boolean_t = bool; + using ch_t = char; + using integer_t = int; + using ast_node_type_t = YOSYS_NAMESPACE_PREFIX AST::AstNodeType; + // end requires } -%union { - std::string *string; - struct YOSYS_NAMESPACE_PREFIX AST::AstNode *ast; - YOSYS_NAMESPACE_PREFIX dict *al; - struct specify_target *specify_target_ptr; - struct specify_triple *specify_triple_ptr; - struct specify_rise_fall *specify_rise_fall_ptr; - bool boolean; - char ch; - int integer; - YOSYS_NAMESPACE_PREFIX AST::AstNodeType ast_node_type; -} +%token string_t "string" +%token ast_t +%token al_t +%token specify_target_ptr_t "specify target" +%token specify_triple_ptr_t "specify triple" +%token specify_rise_fall_ptr_t "specify rise and fall" +%token boolean_t "boolean" +%token ch_t "invalid token" +%token integer_t "integer" +%token ast_node_type_t -%token TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE -%token TOK_SVA_LABEL TOK_SPECIFY_OPER TOK_MSG_TASKS -%token TOK_BASE TOK_BASED_CONSTVAL TOK_UNBASED_UNSIZED_CONSTVAL -%token TOK_USER_TYPE TOK_PKG_USER_TYPE +%token TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE +%token TOK_SVA_LABEL TOK_SPECIFY_OPER TOK_MSG_TASKS +%token TOK_BASE TOK_BASED_CONSTVAL TOK_UNBASED_UNSIZED_CONSTVAL +%token TOK_USER_TYPE TOK_PKG_USER_TYPE %token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER TOK_FINAL %token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END %token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM @@ -419,41 +532,73 @@ static const AstNode *addAsgnBinopStmt(dict *attr, AstNode * %token TOK_SHL_ASSIGN TOK_SHR_ASSIGN TOK_SSHL_ASSIGN TOK_SSHR_ASSIGN %token TOK_BIND TOK_TIME_SCALE -%type range range_or_multirange non_opt_range non_opt_multirange -%type wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list non_io_wire_type io_wire_type -%type opt_label opt_sva_label tok_prim_wrapper hierarchical_id hierarchical_type_id integral_number -%type type_name -%type opt_enum_init enum_type struct_type enum_struct_type func_return_type typedef_base_type -%type opt_property always_comb_or_latch always_or_always_ff -%type opt_signedness_default_signed opt_signedness_default_unsigned -%type integer_atom_type integer_vector_type -%type attr if_attr case_attr -%type struct_union -%type asgn_binop inc_or_dec_op -%type genvar_identifier +%token TOK_EXCL "'!'" +%token TOK_HASH "'#'" +%token TOK_PERC "'%'" +%token TOK_AMP "'&'" +%token TOK_LPAREN "'('" +%token TOK_RPAREN "')'" +%token TOK_ASTER "'*'" +%token TOK_PLUS "'+'" +%token TOK_COMMA "','" +%token TOK_MINUS "'-'" +%token TOK_DOT "'.'" +%token TOK_SLASH "'/'" +%token TOK_COL "':'" +%token TOK_SEMICOL "';'" +%token TOK_LT "'<'" +%token TOK_EQ "'='" +%token TOK_GT "'>'" +%token TOK_QUE "'?'" +%token TOK_AT "'@'" +%token TOK_LBRA "'['" +%token TOK_RBRA "']'" +%token TOK_CARET "'^'" +%token TOK_UNDER "'_'" +%token TOK_LCURL "'{'" +%token TOK_PIPE "'|'" +%token TOK_RCURL "'}'" +%token TOK_TILDE "'~'" +%token TOK_n "'n'" +%token TOK_p "'p'" +%token TOK_x "'x'" +%token TOK_z "'z'" -%type specify_target -%type specify_triple specify_opt_triple -%type specify_rise_fall -%type specify_if specify_condition -%type specify_edge +%type range range_or_multirange non_opt_range non_opt_multirange +%type wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list non_io_wire_type io_wire_type +%type opt_label opt_sva_label tok_prim_wrapper hierarchical_id hierarchical_type_id integral_number +%type type_name +%type opt_enum_init enum_type struct_type enum_struct_type func_return_type typedef_base_type +%type opt_property always_comb_or_latch always_or_always_ff +%type opt_signedness_default_signed opt_signedness_default_unsigned +%type integer_atom_type integer_vector_type +%type attr if_attr case_attr +%type struct_union +%type asgn_binop inc_or_dec_op +%type genvar_identifier + +%type specify_target +%type specify_triple specify_opt_triple +%type specify_rise_fall +%type specify_if specify_condition +%type specify_edge // operator precedence from low to high %left OP_LOR %left OP_LAND -%left '|' OP_NOR -%left '^' OP_XNOR -%left '&' OP_NAND +%left TOK_PIPE OP_NOR +%left TOK_CARET OP_XNOR +%left TOK_AMP OP_NAND %left OP_EQ OP_NE OP_EQX OP_NEX -%left '<' OP_LE OP_GE '>' +%left TOK_LT OP_LE OP_GE TOK_GT %left OP_SHL OP_SHR OP_SSHL OP_SSHR -%left '+' '-' -%left '*' '/' '%' +%left TOK_PLUS TOK_MINUS +%left TOK_ASTER TOK_SLASH TOK_PERC %left OP_POW %precedence OP_CAST %precedence UNARY_OPS -%define parse.error verbose +%define parse.error detailed %define parse.lac full %precedence FAKE_THEN @@ -465,15 +610,13 @@ static const AstNode *addAsgnBinopStmt(dict *attr, AstNode * %% input: { - (void)frontend_verilog_yynerrs; - ast_stack.clear(); - ast_stack.push_back(current_ast); + (void)yynerrs_; + extra->ast_stack.clear(); + extra->ast_stack.push_back(extra->current_ast); } design { - ast_stack.pop_back(); - log_assert(GetSize(ast_stack) == 0); - for (auto &it : default_attr_list) - delete it.second; - default_attr_list.clear(); + extra->ast_stack.pop_back(); + log_assert(GetSize(extra->ast_stack) == 0); + extra->default_attr_list.clear(); }; design: @@ -490,18 +633,18 @@ design: attr: { - if (attr_list != nullptr) - attr_list_stack.push(attr_list); - attr_list = new dict; - for (auto &it : default_attr_list) - (*attr_list)[it.first] = it.second->clone(); + if (extra->attr_list != nullptr) + extra->attr_list_stack.push(extra->attr_list); + extra->attr_list = new dict>; + for (auto &it : extra->default_attr_list) + (*extra->attr_list)[it.first] = it.second->clone(); } attr_opt { - $$ = attr_list; - if (!attr_list_stack.empty()) { - attr_list = attr_list_stack.top(); - attr_list_stack.pop(); + $$ = extra->attr_list; + if (!extra->attr_list_stack.empty()) { + extra->attr_list = extra->attr_list_stack.top(); + extra->attr_list_stack.pop(); } else - attr_list = nullptr; + extra->attr_list = nullptr; }; attr_opt: @@ -512,20 +655,18 @@ attr_opt: defattr: DEFATTR_BEGIN { - if (attr_list != nullptr) - attr_list_stack.push(attr_list); - attr_list = new dict; - for (auto &it : default_attr_list) - delete it.second; - default_attr_list.clear(); + if (extra->attr_list != nullptr) + extra->attr_list_stack.push(extra->attr_list); + extra->attr_list = new dict>; + extra->default_attr_list.clear(); } opt_attr_list { - attr_list->swap(default_attr_list); - delete attr_list; - if (!attr_list_stack.empty()) { - attr_list = attr_list_stack.top(); - attr_list_stack.pop(); + extra->attr_list->swap(extra->default_attr_list); + delete extra->attr_list; + if (!extra->attr_list_stack.empty()) { + extra->attr_list = extra->attr_list_stack.top(); + extra->attr_list_stack.pop(); } else - attr_list = nullptr; + extra->attr_list = nullptr; } DEFATTR_END; opt_attr_list: @@ -533,20 +674,14 @@ opt_attr_list: attr_list: attr_assign | - attr_list ',' attr_assign; + attr_list TOK_COMMA attr_assign; attr_assign: hierarchical_id { - if (attr_list->count(*$1) != 0) - delete (*attr_list)[*$1]; - (*attr_list)[*$1] = AstNode::mkconst_int(1, false); - delete $1; + (*extra->attr_list)[*$1] = AstNode::mkconst_int(1, false); } | - hierarchical_id '=' expr { - if (attr_list->count(*$1) != 0) - delete (*attr_list)[*$1]; - (*attr_list)[*$1] = $3; - delete $1; + hierarchical_id TOK_EQ expr { + (*extra->attr_list)[*$1] = std::move($3); }; hierarchical_id: @@ -558,170 +693,151 @@ hierarchical_id: *$1 += "::" + $3->substr(1); else *$1 += "::" + *$3; - delete $3; $$ = $1; } | - hierarchical_id '.' TOK_ID { + hierarchical_id TOK_DOT TOK_ID { if ($3->compare(0, 1, "\\") == 0) *$1 += "." + $3->substr(1); else *$1 += "." + *$3; - delete $3; $$ = $1; }; hierarchical_type_id: TOK_USER_TYPE | TOK_PKG_USER_TYPE // package qualified type name - | '(' TOK_USER_TYPE ')' { $$ = $2; } // non-standard grammar + | TOK_LPAREN TOK_USER_TYPE TOK_RPAREN { $$ = $2; } // non-standard grammar ; module: attr TOK_MODULE { - enterTypeScope(); + extra->enterTypeScope(); } TOK_ID { - do_not_require_port_stubs = false; - AstNode *mod = new AstNode(AST_MODULE); - ast_stack.back()->children.push_back(mod); - ast_stack.push_back(mod); - current_ast_mod = mod; - port_stubs.clear(); - port_counter = 0; + extra->do_not_require_port_stubs = false; + AstNode* mod = extra->pushChild(std::make_unique(AST_MODULE)); + extra->current_ast_mod = mod; + extra->port_stubs.clear(); + extra->port_counter = 0; mod->str = *$4; append_attr(mod, $1); - } module_para_opt module_args_opt ';' module_body TOK_ENDMODULE opt_label { - if (port_stubs.size() != 0) - frontend_verilog_yyerror("Missing details for module port `%s'.", - port_stubs.begin()->first.c_str()); - SET_AST_NODE_LOC(ast_stack.back(), @2, @$); - ast_stack.pop_back(); - log_assert(ast_stack.size() == 1); - checkLabelsMatch("Module name", $4, $11); - current_ast_mod = NULL; - delete $4; - delete $11; - exitTypeScope(); + } module_para_opt module_args_opt TOK_SEMICOL module_body TOK_ENDMODULE opt_label { + if (extra->port_stubs.size() != 0) + lexer->err("Missing details for module port `%s'.", + extra->port_stubs.begin()->first.c_str()); + SET_AST_NODE_LOC(extra->ast_stack.back(), @2, @$); + extra->ast_stack.pop_back(); + log_assert(extra->ast_stack.size() == 1); + checkLabelsMatch(@11, "Module name", $4, $11); + extra->current_ast_mod = nullptr; + extra->exitTypeScope(); }; module_para_opt: - '#' '(' { astbuf1 = nullptr; } module_para_list { if (astbuf1) delete astbuf1; } ')' | %empty; + TOK_HASH TOK_LPAREN module_para_list TOK_RPAREN | %empty; module_para_list: - single_module_para | module_para_list ',' single_module_para; + single_module_para | module_para_list TOK_COMMA single_module_para; single_module_para: %empty | attr TOK_PARAMETER { - if (astbuf1) delete astbuf1; - astbuf1 = new AstNode(AST_PARAMETER); - astbuf1->children.push_back(AstNode::mkconst_int(0, true)); - append_attr(astbuf1, $1); + extra->astbuf1 = std::make_unique(AST_PARAMETER); + extra->astbuf1->children.push_back(AstNode::mkconst_int(0, true)); + append_attr(extra->astbuf1.get(), $1); } param_type single_param_decl | attr TOK_LOCALPARAM { - if (astbuf1) delete astbuf1; - astbuf1 = new AstNode(AST_LOCALPARAM); - astbuf1->children.push_back(AstNode::mkconst_int(0, true)); - append_attr(astbuf1, $1); + extra->astbuf1 = std::make_unique(AST_LOCALPARAM); + extra->astbuf1->children.push_back(AstNode::mkconst_int(0, true)); + append_attr(extra->astbuf1.get(), $1); } param_type single_param_decl | single_param_decl; module_args_opt: - '(' ')' | %empty | '(' module_args optional_comma ')'; + TOK_LPAREN TOK_RPAREN | %empty | TOK_LPAREN module_args optional_comma TOK_RPAREN; module_args: - module_arg | module_args ',' module_arg; + module_arg | module_args TOK_COMMA module_arg; optional_comma: - ',' | %empty; + TOK_COMMA | %empty; module_arg_opt_assignment: - '=' expr { - if (ast_stack.back()->children.size() > 0 && ast_stack.back()->children.back()->type == AST_WIRE) { - if (ast_stack.back()->children.back()->is_input) { - AstNode *n = ast_stack.back()->children.back(); - if (n->attributes.count(ID::defaultvalue)) - delete n->attributes.at(ID::defaultvalue); - n->attributes[ID::defaultvalue] = $2; + TOK_EQ expr { + if (extra->ast_stack.back()->children.size() > 0 && extra->ast_stack.back()->children.back()->type == AST_WIRE) { + if (extra->ast_stack.back()->children.back()->is_input) { + auto& n = extra->ast_stack.back()->children.back(); + n->attributes[ID::defaultvalue] = std::move($2); } else { - AstNode *wire = new AstNode(AST_IDENTIFIER); - wire->str = ast_stack.back()->children.back()->str; - if (ast_stack.back()->children.back()->is_reg || ast_stack.back()->children.back()->is_logic) - ast_stack.back()->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, wire, $2)))); + auto wire = std::make_unique(AST_IDENTIFIER); + wire->str = extra->ast_stack.back()->children.back()->str; + if (extra->ast_stack.back()->children.back()->is_reg || extra->ast_stack.back()->children.back()->is_logic) + extra->ast_stack.back()->children.push_back(std::make_unique(AST_INITIAL, std::make_unique(AST_BLOCK, std::make_unique(AST_ASSIGN_LE, std::move(wire), std::move($2))))); else - ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, $2)); + extra->ast_stack.back()->children.push_back(std::make_unique(AST_ASSIGN, std::move(wire), std::move($2))); } } else - frontend_verilog_yyerror("SystemVerilog interface in module port list cannot have a default value."); + lexer->err("SystemVerilog interface in module port list cannot have a default value."); } | %empty; module_arg: TOK_ID { - if (ast_stack.back()->children.size() > 0 && ast_stack.back()->children.back()->type == AST_WIRE) { - AstNode *node = ast_stack.back()->children.back()->clone(); + if (extra->ast_stack.back()->children.size() > 0 && extra->ast_stack.back()->children.back()->type == AST_WIRE) { + auto node = extra->ast_stack.back()->children.back()->clone(); node->str = *$1; - node->port_id = ++port_counter; - ast_stack.back()->children.push_back(node); - SET_AST_NODE_LOC(node, @1, @1); + node->port_id = ++extra->port_counter; + SET_AST_NODE_LOC(node.get(), @1, @1); + extra->ast_stack.back()->children.push_back(std::move(node)); } else { - if (port_stubs.count(*$1) != 0) - frontend_verilog_yyerror("Duplicate module port `%s'.", $1->c_str()); - port_stubs[*$1] = ++port_counter; + if (extra->port_stubs.count(*$1) != 0) + lexer->err("Duplicate module port `%s'.", $1->c_str()); + extra->port_stubs[*$1] = ++extra->port_counter; } - delete $1; } module_arg_opt_assignment | TOK_ID { - astbuf1 = new AstNode(AST_INTERFACEPORT); - astbuf1->children.push_back(new AstNode(AST_INTERFACEPORTTYPE)); - astbuf1->children[0]->str = *$1; - delete $1; + extra->astbuf1 = std::make_unique(AST_INTERFACEPORT); + extra->astbuf1->children.push_back(std::make_unique(AST_INTERFACEPORTTYPE)); + extra->astbuf1->children[0]->str = *$1; } TOK_ID { /* SV interfaces */ - if (!sv_mode) - frontend_verilog_yyerror("Interface found in port list (%s). This is not supported unless read_verilog is called with -sv!", $3->c_str()); - astbuf2 = astbuf1->clone(); // really only needed if multiple instances of same type. - astbuf2->str = *$3; - delete $3; - astbuf2->port_id = ++port_counter; - ast_stack.back()->children.push_back(astbuf2); - delete astbuf1; // really only needed if multiple instances of same type. + if (!mode->sv) + lexer->err("Interface found in port list (%s). This is not supported unless read_verilog is called with -sv!", $3->c_str()); + extra->astbuf2 = extra->astbuf1->clone(); // really only needed if multiple instances of same type. + extra->astbuf2->str = *$3; + extra->astbuf2->port_id = ++extra->port_counter; + extra->ast_stack.back()->children.push_back(std::move(extra->astbuf2)); } module_arg_opt_assignment | attr wire_type range_or_multirange TOK_ID { - AstNode *node = $2; + auto node = std::move($2); node->str = *$4; - SET_AST_NODE_LOC(node, @4, @4); - node->port_id = ++port_counter; - AstNode *range = checkRange(node, $3); - if (range != NULL) - node->children.push_back(range); + SET_AST_NODE_LOC(node.get(), @4, @4); + node->port_id = ++extra->port_counter; + auto range = checkRange(node.get(), std::move($3)); + if (range != nullptr) + node->children.push_back(std::move(range)); if (!node->is_input && !node->is_output) - frontend_verilog_yyerror("Module port `%s' is neither input nor output.", $4->c_str()); - if (node->is_reg && node->is_input && !node->is_output && !sv_mode) - frontend_verilog_yyerror("Input port `%s' is declared as register.", $4->c_str()); - ast_stack.back()->children.push_back(node); - append_attr(node, $1); - delete $4; + lexer->err("Module port `%s' is neither input nor output.", $4->c_str()); + if (node->is_reg && node->is_input && !node->is_output && !mode->sv) + lexer->err("Input port `%s' is declared as register.", $4->c_str()); + append_attr(node.get(), $1); + extra->ast_stack.back()->children.push_back(std::move(node)); } module_arg_opt_assignment | - '.' '.' '.' { - do_not_require_port_stubs = true; + TOK_DOT TOK_DOT TOK_DOT { + extra->do_not_require_port_stubs = true; }; package: attr TOK_PACKAGE { - enterTypeScope(); + extra->enterTypeScope(); } TOK_ID { - AstNode *mod = new AstNode(AST_PACKAGE); - ast_stack.back()->children.push_back(mod); - ast_stack.push_back(mod); - current_ast_mod = mod; + AstNode* mod = extra->pushChild(std::make_unique(AST_PACKAGE)); + extra->current_ast_mod = mod; mod->str = *$4; append_attr(mod, $1); - } ';' package_body TOK_ENDPACKAGE opt_label { - ast_stack.pop_back(); - checkLabelsMatch("Package name", $4, $9); - current_ast_mod = NULL; - delete $4; - delete $9; - exitTypeScope(); + } TOK_SEMICOL package_body TOK_ENDPACKAGE opt_label { + extra->ast_stack.pop_back(); + checkLabelsMatch(@9, "Package name", $4, $9); + extra->current_ast_mod = nullptr; + extra->exitTypeScope(); }; package_body: @@ -732,25 +848,22 @@ package_body_stmt: interface: TOK_INTERFACE { - enterTypeScope(); + extra->enterTypeScope(); } TOK_ID { - do_not_require_port_stubs = false; - AstNode *intf = new AstNode(AST_INTERFACE); - ast_stack.back()->children.push_back(intf); - ast_stack.push_back(intf); - current_ast_mod = intf; - port_stubs.clear(); - port_counter = 0; + extra->do_not_require_port_stubs = false; + AstNode* intf = extra->pushChild(std::make_unique(AST_INTERFACE)); + extra->current_ast_mod = intf; + extra->port_stubs.clear(); + extra->port_counter = 0; intf->str = *$3; - delete $3; - } module_para_opt module_args_opt ';' interface_body TOK_ENDINTERFACE { - if (port_stubs.size() != 0) - frontend_verilog_yyerror("Missing details for module port `%s'.", - port_stubs.begin()->first.c_str()); - ast_stack.pop_back(); - log_assert(ast_stack.size() == 1); - current_ast_mod = NULL; - exitTypeScope(); + } module_para_opt module_args_opt TOK_SEMICOL interface_body TOK_ENDINTERFACE { + if (extra->port_stubs.size() != 0) + lexer->err("Missing details for module port `%s'.", + extra->port_stubs.begin()->first.c_str()); + extra->ast_stack.pop_back(); + log_assert(extra->ast_stack.size() == 1); + extra->current_ast_mod = nullptr; + extra->exitTypeScope(); }; interface_body: @@ -762,27 +875,24 @@ interface_body_stmt: bind_directive: TOK_BIND { - AstNode *bnode = new AstNode(AST_BIND); - ast_stack.back()->children.push_back(bnode); - ast_stack.push_back(bnode); + (void)extra->pushChild(std::make_unique(AST_BIND)); } bind_target { // bind_target should have added at least one child - log_assert(ast_stack.back()->children.size() >= 1); + log_assert(extra->ast_stack.back()->children.size() >= 1); } TOK_ID { - // The single_cell parser in cell_list_no_array uses astbuf1 as + // The single_cell parser in cell_list_no_array uses extra->astbuf1 as // a sort of template for constructing cells. - astbuf1 = new AstNode(AST_CELL); - astbuf1->children.push_back(new AstNode(AST_CELLTYPE)); - astbuf1->children[0]->str = *$5; - delete $5; + extra->astbuf1 = std::make_unique(AST_CELL); + extra->astbuf1->children.push_back(std::make_unique(AST_CELLTYPE)); + extra->astbuf1->children[0]->str = *$5; } - cell_parameter_list_opt cell_list_no_array ';' { + cell_parameter_list_opt cell_list_no_array TOK_SEMICOL { // cell_list should have added at least one more child - log_assert(ast_stack.back()->children.size() >= 2); - delete astbuf1; - ast_stack.pop_back(); + log_assert(extra->ast_stack.back()->children.size() >= 2); + (void)extra->astbuf1.reset(); + extra->ast_stack.pop_back(); }; // bind_target matches the target of the bind (everything before @@ -791,7 +901,7 @@ bind_directive: // We can't use the BNF from the spec directly because it's ambiguous: // something like "bind foo bar_i (.*)" can either be interpreted with "foo" as // a module or interface identifier (matching bind_target_scope in the spec) or -// by considering foo as a degenerate hierarchical identifier with no '.' +// by considering foo as a degenerate hierarchical identifier with no TOK_DOT // characters, followed by no bit select (which matches bind_target_instance in // the spec). // @@ -803,82 +913,81 @@ bind_target: // An optional list of target instances for a bind statement, introduced by a // colon. opt_bind_target_instance_list: - ':' bind_target_instance_list | + TOK_COL bind_target_instance_list | %empty; bind_target_instance_list: bind_target_instance | - bind_target_instance_list ',' bind_target_instance; + bind_target_instance_list TOK_COMMA bind_target_instance; -// A single target instance for a bind statement. The top of ast_stack will be +// A single target instance for a bind statement. The top of extra->ast_stack will be // the bind node where we should add it. bind_target_instance: hierarchical_id { - auto *node = new AstNode(AST_IDENTIFIER); + auto node = std::make_unique(AST_IDENTIFIER); node->str = *$1; - delete $1; - ast_stack.back()->children.push_back(node); + extra->ast_stack.back()->children.push_back(std::move(node)); }; mintypmax_expr: - expr { delete $1; } | - expr ':' expr ':' expr { delete $1; delete $3; delete $5; }; + expr { } | + expr TOK_COL expr TOK_COL expr { }; non_opt_delay: - '#' TOK_ID { delete $2; } | - '#' TOK_CONSTVAL { delete $2; } | - '#' TOK_REALVAL { delete $2; } | + TOK_HASH TOK_ID { } | + TOK_HASH TOK_CONSTVAL { } | + TOK_HASH TOK_REALVAL { } | // our `expr` doesn't have time_scale, so we need the parenthesized variant - '#' TOK_TIME_SCALE | - '#' '(' TOK_TIME_SCALE ')' | - '#' '(' mintypmax_expr ')' | - '#' '(' mintypmax_expr ',' mintypmax_expr ')' | - '#' '(' mintypmax_expr ',' mintypmax_expr ',' mintypmax_expr ')'; + TOK_HASH TOK_TIME_SCALE | + TOK_HASH TOK_LPAREN TOK_TIME_SCALE TOK_RPAREN | + TOK_HASH TOK_LPAREN mintypmax_expr TOK_RPAREN | + TOK_HASH TOK_LPAREN mintypmax_expr TOK_COMMA mintypmax_expr TOK_RPAREN | + TOK_HASH TOK_LPAREN mintypmax_expr TOK_COMMA mintypmax_expr TOK_COMMA mintypmax_expr TOK_RPAREN; delay: non_opt_delay | %empty; io_wire_type: - { astbuf3 = new AstNode(AST_WIRE); current_wire_rand = false; current_wire_const = false; } + { extra->astbuf3 = std::make_unique(AST_WIRE); extra->current_wire_rand = false; extra->current_wire_const = false; } wire_type_token_io wire_type_const_rand opt_wire_type_token wire_type_signedness - { $$ = astbuf3; SET_RULE_LOC(@$, @2, @$); }; + { $$ = std::move(extra->astbuf3); SET_RULE_LOC(@$, @2, @$); }; non_io_wire_type: - { astbuf3 = new AstNode(AST_WIRE); current_wire_rand = false; current_wire_const = false; } + { extra->astbuf3 = std::make_unique(AST_WIRE); extra->current_wire_rand = false; extra->current_wire_const = false; } wire_type_const_rand wire_type_token wire_type_signedness - { $$ = astbuf3; SET_RULE_LOC(@$, @2, @$); }; + { $$ = std::move(extra->astbuf3); SET_RULE_LOC(@$, @2, @$); }; wire_type: - io_wire_type | - non_io_wire_type; + io_wire_type { $$ = std::move($1); } | + non_io_wire_type { $$ = std::move($1); }; wire_type_token_io: TOK_INPUT { - astbuf3->is_input = true; + extra->astbuf3->is_input = true; } | TOK_OUTPUT { - astbuf3->is_output = true; + extra->astbuf3->is_output = true; } | TOK_INOUT { - astbuf3->is_input = true; - astbuf3->is_output = true; + extra->astbuf3->is_input = true; + extra->astbuf3->is_output = true; }; wire_type_signedness: - TOK_SIGNED { astbuf3->is_signed = true; } | - TOK_UNSIGNED { astbuf3->is_signed = false; } | + TOK_SIGNED { extra->astbuf3->is_signed = true; } | + TOK_UNSIGNED { extra->astbuf3->is_signed = false; } | %empty; wire_type_const_rand: TOK_RAND TOK_CONST { - current_wire_rand = true; - current_wire_const = true; + extra->current_wire_rand = true; + extra->current_wire_const = true; } | TOK_CONST { - current_wire_const = true; + extra->current_wire_const = true; } | TOK_RAND { - current_wire_rand = true; + extra->current_wire_rand = true; } | %empty; @@ -893,35 +1002,35 @@ wire_type_token: } | // regs TOK_REG { - astbuf3->is_reg = true; + extra->astbuf3->is_reg = true; } | TOK_VAR TOK_REG { - astbuf3->is_reg = true; + extra->astbuf3->is_reg = true; } | // logics TOK_VAR { - astbuf3->is_logic = true; + extra->astbuf3->is_logic = true; } | TOK_VAR logic_type { - astbuf3->is_logic = true; + extra->astbuf3->is_logic = true; } | logic_type { - astbuf3->is_logic = true; + extra->astbuf3->is_logic = true; } | TOK_GENVAR { - astbuf3->type = AST_GENVAR; - astbuf3->is_reg = true; - astbuf3->is_signed = true; - astbuf3->range_left = 31; - astbuf3->range_right = 0; + extra->astbuf3->type = AST_GENVAR; + extra->astbuf3->is_reg = true; + extra->astbuf3->is_signed = true; + extra->astbuf3->range_left = 31; + extra->astbuf3->range_right = 0; }; net_type: TOK_WOR { - astbuf3->is_wor = true; + extra->astbuf3->is_wor = true; } | TOK_WAND { - astbuf3->is_wand = true; + extra->astbuf3->is_wand = true; } | TOK_WIRE; @@ -929,12 +1038,12 @@ logic_type: TOK_LOGIC { } | integer_atom_type { - astbuf3->range_left = $1 - 1; - astbuf3->range_right = 0; - astbuf3->is_signed = true; + extra->astbuf3->range_left = $1 - 1; + extra->astbuf3->range_right = 0; + extra->astbuf3->is_signed = true; } | hierarchical_type_id { - addWiretypeNode($1, astbuf3); + extra->addWiretypeNode($1, extra->astbuf3.get()); }; integer_atom_type: @@ -945,59 +1054,59 @@ integer_atom_type: TOK_BYTE { $$ = 8; } ; integer_vector_type: - TOK_LOGIC { $$ = TOK_LOGIC; } | - TOK_REG { $$ = TOK_REG; } ; + TOK_LOGIC { $$ = token::TOK_LOGIC; } | + TOK_REG { $$ = token::TOK_REG; } ; non_opt_range: - '[' expr ':' expr ']' { - $$ = new AstNode(AST_RANGE); - $$->children.push_back($2); - $$->children.push_back($4); + TOK_LBRA expr TOK_COL expr TOK_RBRA { + $$ = std::make_unique(AST_RANGE); + $$->children.push_back(std::move($2)); + $$->children.push_back(std::move($4)); } | - '[' expr TOK_POS_INDEXED expr ']' { - $$ = new AstNode(AST_RANGE); - AstNode *expr = new AstNode(AST_SELFSZ, $2); - $$->children.push_back(new AstNode(AST_SUB, new AstNode(AST_ADD, expr->clone(), $4), AstNode::mkconst_int(1, true))); - $$->children.push_back(new AstNode(AST_ADD, expr, AstNode::mkconst_int(0, true))); + TOK_LBRA expr TOK_POS_INDEXED expr TOK_RBRA { + $$ = std::make_unique(AST_RANGE); + auto expr = std::make_unique(AST_SELFSZ, std::move($2)); + $$->children.push_back(std::make_unique(AST_SUB, std::make_unique(AST_ADD, expr->clone(), std::move($4)), AstNode::mkconst_int(1, true))); + $$->children.push_back(std::make_unique(AST_ADD, std::move(expr), AstNode::mkconst_int(0, true))); } | - '[' expr TOK_NEG_INDEXED expr ']' { - $$ = new AstNode(AST_RANGE); - AstNode *expr = new AstNode(AST_SELFSZ, $2); - $$->children.push_back(new AstNode(AST_ADD, expr, AstNode::mkconst_int(0, true))); - $$->children.push_back(new AstNode(AST_SUB, new AstNode(AST_ADD, expr->clone(), AstNode::mkconst_int(1, true)), $4)); + TOK_LBRA expr TOK_NEG_INDEXED expr TOK_RBRA { + $$ = std::make_unique(AST_RANGE); + auto expr = std::make_unique(AST_SELFSZ, std::move($2)); + $$->children.push_back(std::make_unique(AST_ADD, expr->clone(), AstNode::mkconst_int(0, true))); + $$->children.push_back(std::make_unique(AST_SUB, std::make_unique(AST_ADD, std::move(expr), AstNode::mkconst_int(1, true)), std::move($4))); } | - '[' expr ']' { - $$ = new AstNode(AST_RANGE); - $$->children.push_back($2); + TOK_LBRA expr TOK_RBRA { + $$ = std::make_unique(AST_RANGE); + $$->children.push_back(std::move($2)); }; non_opt_multirange: non_opt_range non_opt_range { - $$ = new AstNode(AST_MULTIRANGE, $1, $2); + $$ = std::make_unique(AST_MULTIRANGE, std::move($1), std::move($2)); } | non_opt_multirange non_opt_range { - $$ = $1; - $$->children.push_back($2); + $$ = std::move($1); + $$->children.push_back(std::move($2)); }; range: non_opt_range { - $$ = $1; + $$ = std::move($1); } | %empty { - $$ = NULL; + $$ = nullptr; }; range_or_multirange: - range { $$ = $1; } | - non_opt_multirange { $$ = $1; }; + range { $$ = std::move($1); } | + non_opt_multirange { $$ = std::move($1); }; module_body: module_body module_body_stmt | /* the following line makes the generate..endgenrate keywords optional */ module_body gen_stmt | module_body gen_block | - module_body ';' | + module_body TOK_SEMICOL | %empty; module_body_stmt: @@ -1006,61 +1115,43 @@ module_body_stmt: always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block; checker_decl: - TOK_CHECKER TOK_ID ';' { - AstNode *node = new AstNode(AST_GENBLOCK); + TOK_CHECKER TOK_ID TOK_SEMICOL { + AstNode* node = extra->pushChild(std::make_unique(AST_GENBLOCK)); node->str = *$2; - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); } module_body TOK_ENDCHECKER { - delete $2; - ast_stack.pop_back(); + extra->ast_stack.pop_back(); }; task_func_decl: attr TOK_DPI_FUNCTION TOK_ID TOK_ID { - current_function_or_task = new AstNode(AST_DPI_FUNCTION, AstNode::mkconst_str(*$3), AstNode::mkconst_str(*$4)); - current_function_or_task->str = *$4; - append_attr(current_function_or_task, $1); - ast_stack.back()->children.push_back(current_function_or_task); - delete $3; - delete $4; - } opt_dpi_function_args ';' { - current_function_or_task = NULL; + extra->current_function_or_task = extra->saveChild(std::make_unique(AST_DPI_FUNCTION, AstNode::mkconst_str(*$3), AstNode::mkconst_str(*$4))); + extra->current_function_or_task->str = *$4; + append_attr(extra->current_function_or_task, $1); + } opt_dpi_function_args TOK_SEMICOL { + extra->current_function_or_task = nullptr; } | - attr TOK_DPI_FUNCTION TOK_ID '=' TOK_ID TOK_ID { - current_function_or_task = new AstNode(AST_DPI_FUNCTION, AstNode::mkconst_str(*$5), AstNode::mkconst_str(*$3)); - current_function_or_task->str = *$6; - append_attr(current_function_or_task, $1); - ast_stack.back()->children.push_back(current_function_or_task); - delete $3; - delete $5; - delete $6; - } opt_dpi_function_args ';' { - current_function_or_task = NULL; + attr TOK_DPI_FUNCTION TOK_ID TOK_EQ TOK_ID TOK_ID { + extra->current_function_or_task = extra->saveChild(std::make_unique(AST_DPI_FUNCTION, AstNode::mkconst_str(*$5), AstNode::mkconst_str(*$3))); + extra->current_function_or_task->str = *$6; + append_attr(extra->current_function_or_task, $1); + } opt_dpi_function_args TOK_SEMICOL { + extra->current_function_or_task = nullptr; } | - attr TOK_DPI_FUNCTION TOK_ID ':' TOK_ID '=' TOK_ID TOK_ID { - current_function_or_task = new AstNode(AST_DPI_FUNCTION, AstNode::mkconst_str(*$7), AstNode::mkconst_str(*$3 + ":" + RTLIL::unescape_id(*$5))); - current_function_or_task->str = *$8; - append_attr(current_function_or_task, $1); - ast_stack.back()->children.push_back(current_function_or_task); - delete $3; - delete $5; - delete $7; - delete $8; - } opt_dpi_function_args ';' { - current_function_or_task = NULL; + attr TOK_DPI_FUNCTION TOK_ID TOK_COL TOK_ID TOK_EQ TOK_ID TOK_ID { + extra->current_function_or_task = extra->saveChild(std::make_unique(AST_DPI_FUNCTION, AstNode::mkconst_str(*$7), AstNode::mkconst_str(*$3 + ":" + RTLIL::unescape_id(*$5)))); + extra->current_function_or_task->str = *$8; + append_attr(extra->current_function_or_task, $1); + } opt_dpi_function_args TOK_SEMICOL { + extra->current_function_or_task = nullptr; } | attr TOK_TASK opt_automatic TOK_ID { - current_function_or_task = new AstNode(AST_TASK); - current_function_or_task->str = *$4; - append_attr(current_function_or_task, $1); - ast_stack.back()->children.push_back(current_function_or_task); - ast_stack.push_back(current_function_or_task); - current_function_or_task_port_id = 1; - delete $4; - } task_func_args_opt ';' task_func_body TOK_ENDTASK { - current_function_or_task = NULL; - ast_stack.pop_back(); + extra->current_function_or_task = extra->pushChild(std::make_unique(AST_TASK)); + extra->current_function_or_task->str = *$4; + append_attr(extra->current_function_or_task, $1); + extra->current_function_or_task_port_id = 1; + } task_func_args_opt TOK_SEMICOL task_func_body TOK_ENDTASK { + extra->current_function_or_task = nullptr; + extra->ast_stack.pop_back(); } | attr TOK_FUNCTION opt_automatic TOK_VOID TOK_ID { // The difference between void functions and tasks is that @@ -1068,52 +1159,45 @@ task_func_decl: // inlined, but ignores signals read only in tasks. This only matters // for event based simulation, and for synthesis we can treat a void // function like a task. - current_function_or_task = new AstNode(AST_TASK); - current_function_or_task->str = *$5; - append_attr(current_function_or_task, $1); - ast_stack.back()->children.push_back(current_function_or_task); - ast_stack.push_back(current_function_or_task); - current_function_or_task_port_id = 1; - delete $5; - } task_func_args_opt ';' task_func_body TOK_ENDFUNCTION { - current_function_or_task = NULL; - ast_stack.pop_back(); + extra->current_function_or_task = extra->pushChild(std::make_unique(AST_TASK)); + extra->current_function_or_task->str = *$5; + append_attr(extra->current_function_or_task, $1); + extra->current_function_or_task_port_id = 1; + } task_func_args_opt TOK_SEMICOL task_func_body TOK_ENDFUNCTION { + extra->current_function_or_task = nullptr; + extra->ast_stack.pop_back(); } | attr TOK_FUNCTION opt_automatic func_return_type TOK_ID { - current_function_or_task = new AstNode(AST_FUNCTION); - current_function_or_task->str = *$5; - append_attr(current_function_or_task, $1); - ast_stack.back()->children.push_back(current_function_or_task); - ast_stack.push_back(current_function_or_task); - AstNode *outreg = new AstNode(AST_WIRE); + extra->current_function_or_task = extra->pushChild(std::make_unique(AST_FUNCTION)); + extra->current_function_or_task->str = *$5; + append_attr(extra->current_function_or_task, $1); + auto outreg = std::make_unique(AST_WIRE); outreg->str = *$5; outreg->is_signed = false; outreg->is_reg = true; - if ($4 != NULL) { - outreg->children.push_back($4); + if ($4 != nullptr) { outreg->is_signed = $4->is_signed; $4->is_signed = false; outreg->is_custom_type = $4->type == AST_WIRETYPE; + outreg->children.push_back(std::move($4)); } - current_function_or_task->children.push_back(outreg); - current_function_or_task_port_id = 1; - delete $5; - } task_func_args_opt ';' task_func_body TOK_ENDFUNCTION { - current_function_or_task = NULL; - ast_stack.pop_back(); + extra->current_function_or_task->children.push_back(std::move(outreg)); + extra->current_function_or_task_port_id = 1; + } task_func_args_opt TOK_SEMICOL task_func_body TOK_ENDFUNCTION { + extra->current_function_or_task = nullptr; + extra->ast_stack.pop_back(); }; func_return_type: hierarchical_type_id { - $$ = new AstNode(AST_WIRETYPE); + $$ = std::make_unique(AST_WIRETYPE); $$->str = *$1; - delete $1; } | opt_type_vec opt_signedness_default_unsigned { $$ = makeRange(0, 0, $2); } | opt_type_vec opt_signedness_default_unsigned non_opt_range { - $$ = $3; + $$ = std::move($3); $$->is_signed = $2; } | integer_atom_type opt_signedness_default_signed { @@ -1139,22 +1223,19 @@ opt_signedness_default_unsigned: dpi_function_arg: TOK_ID TOK_ID { - current_function_or_task->children.push_back(AstNode::mkconst_str(*$1)); - delete $1; - delete $2; + extra->current_function_or_task->children.push_back(AstNode::mkconst_str(*$1)); } | TOK_ID { - current_function_or_task->children.push_back(AstNode::mkconst_str(*$1)); - delete $1; + extra->current_function_or_task->children.push_back(AstNode::mkconst_str(*$1)); }; opt_dpi_function_args: - '(' dpi_function_args ')' | + TOK_LPAREN dpi_function_args TOK_RPAREN | %empty; dpi_function_args: - dpi_function_args ',' dpi_function_arg | - dpi_function_args ',' | + dpi_function_args TOK_COMMA dpi_function_arg | + dpi_function_args TOK_COMMA | dpi_function_arg | %empty; @@ -1163,52 +1244,52 @@ opt_automatic: %empty; task_func_args_opt: - '(' ')' | %empty | '(' { - albuf = nullptr; - astbuf1 = nullptr; - astbuf2 = nullptr; + TOK_LPAREN TOK_RPAREN | %empty | TOK_LPAREN { + extra->albuf = nullptr; + extra->astbuf1 = nullptr; + extra->astbuf2 = nullptr; } task_func_args optional_comma { - delete astbuf1; - if (astbuf2 != NULL) - delete astbuf2; - free_attr(albuf); - } ')'; + (void)extra->astbuf1.reset(); + if (extra->astbuf2 != nullptr) + (void)extra->astbuf2.reset(); + free_attr(extra->albuf); + } TOK_RPAREN; task_func_args: - task_func_port | task_func_args ',' task_func_port; + task_func_port | task_func_args TOK_COMMA task_func_port; task_func_port: attr wire_type range_or_multirange { bool prev_was_input = true; bool prev_was_output = false; - if (albuf) { - prev_was_input = astbuf1->is_input; - prev_was_output = astbuf1->is_output; - delete astbuf1; - if (astbuf2 != NULL) - delete astbuf2; - free_attr(albuf); + if (extra->albuf) { + prev_was_input = extra->astbuf1->is_input; + prev_was_output = extra->astbuf1->is_output; + (void)extra->astbuf1.reset(); + if (extra->astbuf2 != nullptr) + (void)extra->astbuf2.reset(); + free_attr(extra->albuf); } - albuf = $1; - astbuf1 = $2; - astbuf2 = checkRange(astbuf1, $3); - if (!astbuf1->is_input && !astbuf1->is_output) { - if (!sv_mode) - frontend_verilog_yyerror("task/function argument direction missing"); - astbuf1->is_input = prev_was_input; - astbuf1->is_output = prev_was_output; + extra->albuf = $1; + extra->astbuf1 = std::move($2); + extra->astbuf2 = checkRange(extra->astbuf1.get(), std::move($3)); + if (!extra->astbuf1->is_input && !extra->astbuf1->is_output) { + if (!mode->sv) + lexer->err("task/function argument direction missing"); + extra->astbuf1->is_input = prev_was_input; + extra->astbuf1->is_output = prev_was_output; } } wire_name | { - if (!astbuf1) { - if (!sv_mode) - frontend_verilog_yyerror("task/function argument direction missing"); - albuf = new dict; - astbuf1 = new AstNode(AST_WIRE); - current_wire_rand = false; - current_wire_const = false; - astbuf1->is_input = true; - astbuf2 = NULL; + if (!extra->astbuf1) { + if (!mode->sv) + lexer->err("task/function argument direction missing"); + extra->albuf = new dict>; + extra->astbuf1 = std::make_unique(AST_WIRE); + extra->current_wire_rand = false; + extra->current_wire_const = false; + extra->astbuf1->is_input = true; + extra->astbuf2 = nullptr; } } wire_name; @@ -1226,23 +1307,24 @@ specify_item_list: %empty; specify_item: - specify_if '(' specify_edge expr TOK_SPECIFY_OPER specify_target ')' '=' specify_rise_fall ';' { - AstNode *en_expr = $1; + specify_if TOK_LPAREN specify_edge expr TOK_SPECIFY_OPER specify_target TOK_RPAREN TOK_EQ specify_rise_fall TOK_SEMICOL { + auto en_expr = std::move($1); char specify_edge = $3; - AstNode *src_expr = $4; + auto src_expr = std::move($4); string *oper = $5; - specify_target *target = $6; - specify_rise_fall *timing = $9; + specify_target_ptr_t target = std::move($6); + specify_rise_fall_ptr_t timing = std::move($9); if (specify_edge != 0 && target->dat == nullptr) - frontend_verilog_yyerror("Found specify edge but no data spec.\n"); + lexer->err("Found specify edge but no data spec.\n"); - AstNode *cell = new AstNode(AST_CELL); - ast_stack.back()->children.push_back(cell); + auto cell_owned = std::make_unique(AST_CELL); + auto cell = cell_owned.get(); + extra->ast_stack.back()->children.push_back(std::move(cell_owned)); cell->str = stringf("$specify$%d", autoidx++); - cell->children.push_back(new AstNode(AST_CELLTYPE)); + cell->children.push_back(std::make_unique(AST_CELLTYPE)); cell->children.back()->str = target->dat ? "$specify3" : "$specify2"; - SET_AST_NODE_LOC(cell, en_expr ? @1 : @2, @10); + SET_AST_NODE_LOC(cell, en_expr.get() ? @1 : @2, @10); char oper_polarity = 0; char oper_type = oper->at(0); @@ -1252,148 +1334,143 @@ specify_item: oper_type = oper->at(1); } - cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_type == '*', false, 1))); + cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_int(oper_type == '*', false, 1))); cell->children.back()->str = "\\FULL"; - cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_polarity != 0, false, 1))); + cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_int(oper_polarity != 0, false, 1))); cell->children.back()->str = "\\SRC_DST_PEN"; - cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_polarity == '+', false, 1))); + cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_int(oper_polarity == '+', false, 1))); cell->children.back()->str = "\\SRC_DST_POL"; - cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_min)); + cell->children.push_back(std::make_unique(AST_PARASET, std::move(timing->rise.t_min))); cell->children.back()->str = "\\T_RISE_MIN"; - cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_avg)); + cell->children.push_back(std::make_unique(AST_PARASET, std::move(timing->rise.t_avg))); cell->children.back()->str = "\\T_RISE_TYP"; - cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_max)); + cell->children.push_back(std::make_unique(AST_PARASET, std::move(timing->rise.t_max))); cell->children.back()->str = "\\T_RISE_MAX"; - cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_min)); + cell->children.push_back(std::make_unique(AST_PARASET, std::move(timing->fall.t_min))); cell->children.back()->str = "\\T_FALL_MIN"; - cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_avg)); + cell->children.push_back(std::make_unique(AST_PARASET, std::move(timing->fall.t_avg))); cell->children.back()->str = "\\T_FALL_TYP"; - cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_max)); + cell->children.push_back(std::make_unique(AST_PARASET, std::move(timing->fall.t_max))); cell->children.back()->str = "\\T_FALL_MAX"; - cell->children.push_back(new AstNode(AST_ARGUMENT, en_expr ? en_expr : AstNode::mkconst_int(1, false, 1))); + cell->children.push_back(std::make_unique(AST_ARGUMENT, en_expr ? std::move(en_expr) : AstNode::mkconst_int(1, false, 1))); cell->children.back()->str = "\\EN"; - cell->children.push_back(new AstNode(AST_ARGUMENT, src_expr)); + cell->children.push_back(std::make_unique(AST_ARGUMENT, std::move(src_expr))); cell->children.back()->str = "\\SRC"; - cell->children.push_back(new AstNode(AST_ARGUMENT, target->dst)); + cell->children.push_back(std::make_unique(AST_ARGUMENT, std::move(target->dst))); cell->children.back()->str = "\\DST"; if (target->dat) { - cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(specify_edge != 0, false, 1))); + cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_int(specify_edge != 0, false, 1))); cell->children.back()->str = "\\EDGE_EN"; - cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(specify_edge == 'p', false, 1))); + cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_int(specify_edge == 'p', false, 1))); cell->children.back()->str = "\\EDGE_POL"; - cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(target->polarity_op != 0, false, 1))); + cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_int(target->polarity_op != 0, false, 1))); cell->children.back()->str = "\\DAT_DST_PEN"; - cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(target->polarity_op == '+', false, 1))); + cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_int(target->polarity_op == '+', false, 1))); cell->children.back()->str = "\\DAT_DST_POL"; - cell->children.push_back(new AstNode(AST_ARGUMENT, target->dat)); + cell->children.push_back(std::make_unique(AST_ARGUMENT, std::move(target->dat))); cell->children.back()->str = "\\DAT"; } delete oper; - delete target; - delete timing; } | - TOK_ID '(' specify_edge expr specify_condition ',' specify_edge expr specify_condition ',' specify_triple specify_opt_triple ')' ';' { + TOK_ID TOK_LPAREN specify_edge expr specify_condition TOK_COMMA specify_edge expr specify_condition TOK_COMMA specify_triple specify_opt_triple TOK_RPAREN TOK_SEMICOL { if (*$1 != "$setup" && *$1 != "$hold" && *$1 != "$setuphold" && *$1 != "$removal" && *$1 != "$recovery" && *$1 != "$recrem" && *$1 != "$skew" && *$1 != "$timeskew" && *$1 != "$fullskew" && *$1 != "$nochange") - frontend_verilog_yyerror("Unsupported specify rule type: %s\n", $1->c_str()); + lexer->err("Unsupported specify rule type: %s\n", $1->c_str()); - AstNode *src_pen = AstNode::mkconst_int($3 != 0, false, 1); - AstNode *src_pol = AstNode::mkconst_int($3 == 'p', false, 1); - AstNode *src_expr = $4, *src_en = $5 ? $5 : AstNode::mkconst_int(1, false, 1); + auto src_pen = AstNode::mkconst_int($3 != 0, false, 1); + auto src_pol = AstNode::mkconst_int($3 == 'p', false, 1); + auto src_expr = std::move($4), src_en = $5 ? std::move($5) : AstNode::mkconst_int(1, false, 1); - AstNode *dst_pen = AstNode::mkconst_int($7 != 0, false, 1); - AstNode *dst_pol = AstNode::mkconst_int($7 == 'p', false, 1); - AstNode *dst_expr = $8, *dst_en = $9 ? $9 : AstNode::mkconst_int(1, false, 1); + auto dst_pen = AstNode::mkconst_int($7 != 0, false, 1); + auto dst_pol = AstNode::mkconst_int($7 == 'p', false, 1); + auto dst_expr = std::move($8), dst_en = $9 ? std::move($9) : AstNode::mkconst_int(1, false, 1); - specify_triple *limit = $11; - specify_triple *limit2 = $12; + specify_triple_ptr_t limit = std::move($11); + specify_triple_ptr_t limit2 = std::move($12); - AstNode *cell = new AstNode(AST_CELL); - ast_stack.back()->children.push_back(cell); + auto cell_owned = std::make_unique(AST_CELL); + auto cell = cell_owned.get(); + extra->ast_stack.back()->children.push_back(std::move(cell_owned)); cell->str = stringf("$specify$%d", autoidx++); - cell->children.push_back(new AstNode(AST_CELLTYPE)); + cell->children.push_back(std::make_unique(AST_CELLTYPE)); cell->children.back()->str = "$specrule"; SET_AST_NODE_LOC(cell, @1, @14); - cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_str(*$1))); + cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_str(*$1))); cell->children.back()->str = "\\TYPE"; - cell->children.push_back(new AstNode(AST_PARASET, limit->t_min)); + cell->children.push_back(std::make_unique(AST_PARASET, std::move(limit->t_min))); cell->children.back()->str = "\\T_LIMIT_MIN"; - cell->children.push_back(new AstNode(AST_PARASET, limit->t_avg)); + cell->children.push_back(std::make_unique(AST_PARASET, std::move(limit->t_avg))); cell->children.back()->str = "\\T_LIMIT_TYP"; - cell->children.push_back(new AstNode(AST_PARASET, limit->t_max)); + cell->children.push_back(std::make_unique(AST_PARASET, std::move(limit->t_max))); cell->children.back()->str = "\\T_LIMIT_MAX"; - cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2->t_min : AstNode::mkconst_int(0, true))); + cell->children.push_back(std::make_unique(AST_PARASET, limit2 ? std::move(limit2->t_min) : AstNode::mkconst_int(0, true))); cell->children.back()->str = "\\T_LIMIT2_MIN"; - cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2->t_avg : AstNode::mkconst_int(0, true))); + cell->children.push_back(std::make_unique(AST_PARASET, limit2 ? std::move(limit2->t_avg) : AstNode::mkconst_int(0, true))); cell->children.back()->str = "\\T_LIMIT2_TYP"; - cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2->t_max : AstNode::mkconst_int(0, true))); + cell->children.push_back(std::make_unique(AST_PARASET, limit2 ? std::move(limit2->t_max) : AstNode::mkconst_int(0, true))); cell->children.back()->str = "\\T_LIMIT2_MAX"; - cell->children.push_back(new AstNode(AST_PARASET, src_pen)); + cell->children.push_back(std::make_unique(AST_PARASET, std::move(src_pen))); cell->children.back()->str = "\\SRC_PEN"; - cell->children.push_back(new AstNode(AST_PARASET, src_pol)); + cell->children.push_back(std::make_unique(AST_PARASET, std::move(src_pol))); cell->children.back()->str = "\\SRC_POL"; - cell->children.push_back(new AstNode(AST_PARASET, dst_pen)); + cell->children.push_back(std::make_unique(AST_PARASET, std::move(dst_pen))); cell->children.back()->str = "\\DST_PEN"; - cell->children.push_back(new AstNode(AST_PARASET, dst_pol)); + cell->children.push_back(std::make_unique(AST_PARASET, std::move(dst_pol))); cell->children.back()->str = "\\DST_POL"; - cell->children.push_back(new AstNode(AST_ARGUMENT, src_en)); + cell->children.push_back(std::make_unique(AST_ARGUMENT, std::move(src_en))); cell->children.back()->str = "\\SRC_EN"; - cell->children.push_back(new AstNode(AST_ARGUMENT, src_expr)); + cell->children.push_back(std::make_unique(AST_ARGUMENT, std::move(src_expr))); cell->children.back()->str = "\\SRC"; - cell->children.push_back(new AstNode(AST_ARGUMENT, dst_en)); + cell->children.push_back(std::make_unique(AST_ARGUMENT, std::move(dst_en))); cell->children.back()->str = "\\DST_EN"; - cell->children.push_back(new AstNode(AST_ARGUMENT, dst_expr)); + cell->children.push_back(std::make_unique(AST_ARGUMENT, std::move(dst_expr))); cell->children.back()->str = "\\DST"; - - delete $1; - delete limit; - delete limit2; }; specify_opt_triple: - ',' specify_triple { - $$ = $2; + TOK_COMMA specify_triple { + $$ = std::move($2); } | %empty { $$ = nullptr; }; specify_if: - TOK_IF '(' expr ')' { - $$ = $3; + TOK_IF TOK_LPAREN expr TOK_RPAREN { + $$ = std::move($3); } | %empty { $$ = nullptr; @@ -1401,7 +1478,7 @@ specify_if: specify_condition: TOK_SPECIFY_AND expr { - $$ = $2; + $$ = std::move($2); } | %empty { $$ = nullptr; @@ -1409,28 +1486,28 @@ specify_condition: specify_target: expr { - $$ = new specify_target; + $$ = std::make_unique(); $$->polarity_op = 0; - $$->dst = $1; + $$->dst = std::move($1); $$->dat = nullptr; } | - '(' expr ':' expr ')'{ - $$ = new specify_target; + TOK_LPAREN expr TOK_COL expr TOK_RPAREN{ + $$ = std::make_unique(); $$->polarity_op = 0; - $$->dst = $2; - $$->dat = $4; + $$->dst = std::move($2); + $$->dat = std::move($4); } | - '(' expr TOK_NEG_INDEXED expr ')'{ - $$ = new specify_target; + TOK_LPAREN expr TOK_NEG_INDEXED expr TOK_RPAREN{ + $$ = std::make_unique(); $$->polarity_op = '-'; - $$->dst = $2; - $$->dat = $4; + $$->dst = std::move($2); + $$->dat = std::move($4); } | - '(' expr TOK_POS_INDEXED expr ')'{ - $$ = new specify_target; + TOK_LPAREN expr TOK_POS_INDEXED expr TOK_RPAREN{ + $$ = std::make_unique(); $$->polarity_op = '+'; - $$->dst = $2; - $$->dat = $4; + $$->dst = std::move($2); + $$->dat = std::move($4); }; specify_edge: @@ -1440,72 +1517,48 @@ specify_edge: specify_rise_fall: specify_triple { - $$ = new specify_rise_fall; - $$->rise = *$1; + $$ = std::make_unique(); $$->fall.t_min = $1->t_min->clone(); $$->fall.t_avg = $1->t_avg->clone(); $$->fall.t_max = $1->t_max->clone(); - delete $1; + $$->rise = std::move(*$1); } | - '(' specify_triple ',' specify_triple ')' { - $$ = new specify_rise_fall; - $$->rise = *$2; - $$->fall = *$4; - delete $2; - delete $4; + TOK_LPAREN specify_triple TOK_COMMA specify_triple TOK_RPAREN { + $$ = std::make_unique(); + $$->rise = std::move(*$2); + $$->fall = std::move(*$4); } | - '(' specify_triple ',' specify_triple ',' specify_triple ')' { - $$ = new specify_rise_fall; - $$->rise = *$2; - $$->fall = *$4; - delete $2; - delete $4; - delete $6; - log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); + TOK_LPAREN specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_RPAREN { + $$ = std::make_unique(); + $$->rise = std::move(*$2); + $$->fall = std::move(*$4); + log_file_warning(current_filename, @$.begin.line, "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); } | - '(' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ')' { - $$ = new specify_rise_fall; - $$->rise = *$2; - $$->fall = *$4; - delete $2; - delete $4; - delete $6; - delete $8; - delete $10; - delete $12; - log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); + TOK_LPAREN specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_RPAREN { + $$ = std::make_unique(); + $$->rise = std::move(*$2); + $$->fall = std::move(*$4); + log_file_warning(current_filename, @$.begin.line, "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); } | - '(' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ')' { - $$ = new specify_rise_fall; - $$->rise = *$2; - $$->fall = *$4; - delete $2; - delete $4; - delete $6; - delete $8; - delete $10; - delete $12; - delete $14; - delete $16; - delete $18; - delete $20; - delete $22; - delete $24; - log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); + TOK_LPAREN specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_RPAREN { + $$ = std::make_unique(); + $$->rise = std::move(*$2); + $$->fall = std::move(*$4); + log_file_warning(current_filename, @$.begin.line, "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); } specify_triple: expr { - $$ = new specify_triple; - $$->t_min = $1; + $$ = std::make_unique(); $$->t_avg = $1->clone(); $$->t_max = $1->clone(); + $$->t_min = std::move($1); } | - expr ':' expr ':' expr { - $$ = new specify_triple; - $$->t_min = $1; - $$->t_avg = $3; - $$->t_max = $5; + expr TOK_COL expr TOK_COL expr { + $$ = std::make_unique(); + $$->t_min = std::move($1); + $$->t_avg = std::move($3); + $$->t_max = std::move($5); }; /******************** ignored specify parser **************************/ @@ -1527,58 +1580,58 @@ ignored_specify_item: ; specparam_declaration: - TOK_SPECPARAM list_of_specparam_assignments ';' | - TOK_SPECPARAM specparam_range list_of_specparam_assignments ';' ; + TOK_SPECPARAM list_of_specparam_assignments TOK_SEMICOL | + TOK_SPECPARAM specparam_range list_of_specparam_assignments TOK_SEMICOL ; // IEEE 1364-2005 calls this sinmply 'range' but the current 'range' rule allows empty match // and the 'non_opt_range' rule allows index ranges not allowed by 1364-2005 // exxxxtending this for SV specparam would change this anyhow specparam_range: - '[' ignspec_constant_expression ':' ignspec_constant_expression ']' ; + TOK_LBRA ignspec_constant_expression TOK_COL ignspec_constant_expression TOK_RBRA ; list_of_specparam_assignments: - specparam_assignment | list_of_specparam_assignments ',' specparam_assignment; + specparam_assignment | list_of_specparam_assignments TOK_COMMA specparam_assignment; specparam_assignment: - ignspec_id '=' ignspec_expr ; + ignspec_id TOK_EQ ignspec_expr ; ignspec_opt_cond: - TOK_IF '(' ignspec_expr ')' | %empty; + TOK_IF TOK_LPAREN ignspec_expr TOK_RPAREN | %empty; path_declaration : - simple_path_declaration ';' + simple_path_declaration TOK_SEMICOL // | edge_sensitive_path_declaration // | state_dependent_path_declaration ; simple_path_declaration : - ignspec_opt_cond parallel_path_description '=' path_delay_value | - ignspec_opt_cond full_path_description '=' path_delay_value + ignspec_opt_cond parallel_path_description TOK_EQ path_delay_value | + ignspec_opt_cond full_path_description TOK_EQ path_delay_value ; path_delay_value : - '(' ignspec_expr list_of_path_delay_extra_expressions ')' + TOK_LPAREN ignspec_expr list_of_path_delay_extra_expressions TOK_RPAREN | ignspec_expr | ignspec_expr list_of_path_delay_extra_expressions ; list_of_path_delay_extra_expressions : - ',' ignspec_expr - | ',' ignspec_expr list_of_path_delay_extra_expressions + TOK_COMMA ignspec_expr + | TOK_COMMA ignspec_expr list_of_path_delay_extra_expressions ; specify_edge_identifier : TOK_POSEDGE | TOK_NEGEDGE ; parallel_path_description : - '(' specify_input_terminal_descriptor opt_polarity_operator '=' '>' specify_output_terminal_descriptor ')' | - '(' specify_edge_identifier specify_input_terminal_descriptor '=' '>' '(' specify_output_terminal_descriptor opt_polarity_operator ':' ignspec_expr ')' ')' | - '(' specify_edge_identifier specify_input_terminal_descriptor '=' '>' '(' specify_output_terminal_descriptor TOK_POS_INDEXED ignspec_expr ')' ')' ; + TOK_LPAREN specify_input_terminal_descriptor opt_polarity_operator TOK_EQ TOK_GT specify_output_terminal_descriptor TOK_RPAREN | + TOK_LPAREN specify_edge_identifier specify_input_terminal_descriptor TOK_EQ TOK_GT TOK_LPAREN specify_output_terminal_descriptor opt_polarity_operator TOK_COL ignspec_expr TOK_RPAREN TOK_RPAREN | + TOK_LPAREN specify_edge_identifier specify_input_terminal_descriptor TOK_EQ TOK_GT TOK_LPAREN specify_output_terminal_descriptor TOK_POS_INDEXED ignspec_expr TOK_RPAREN TOK_RPAREN ; full_path_description : - '(' list_of_path_inputs '*' '>' list_of_path_outputs ')' | - '(' specify_edge_identifier list_of_path_inputs '*' '>' '(' list_of_path_outputs opt_polarity_operator ':' ignspec_expr ')' ')' | - '(' specify_edge_identifier list_of_path_inputs '*' '>' '(' list_of_path_outputs TOK_POS_INDEXED ignspec_expr ')' ')' ; + TOK_LPAREN list_of_path_inputs TOK_ASTER TOK_GT list_of_path_outputs TOK_RPAREN | + TOK_LPAREN specify_edge_identifier list_of_path_inputs TOK_ASTER TOK_GT TOK_LPAREN list_of_path_outputs opt_polarity_operator TOK_COL ignspec_expr TOK_RPAREN TOK_RPAREN | + TOK_LPAREN specify_edge_identifier list_of_path_inputs TOK_ASTER TOK_GT TOK_LPAREN list_of_path_outputs TOK_POS_INDEXED ignspec_expr TOK_RPAREN TOK_RPAREN ; // This was broken into 2 rules to solve shift/reduce conflicts list_of_path_inputs : @@ -1586,15 +1639,15 @@ list_of_path_inputs : specify_input_terminal_descriptor more_path_inputs opt_polarity_operator ; more_path_inputs : - ',' specify_input_terminal_descriptor | - more_path_inputs ',' specify_input_terminal_descriptor ; + TOK_COMMA specify_input_terminal_descriptor | + more_path_inputs TOK_COMMA specify_input_terminal_descriptor ; list_of_path_outputs : specify_output_terminal_descriptor | - list_of_path_outputs ',' specify_output_terminal_descriptor ; + list_of_path_outputs TOK_COMMA specify_output_terminal_descriptor ; opt_polarity_operator : - '+' | '-' | %empty; + TOK_PLUS | TOK_MINUS | %empty; // Good enough for the time being specify_input_terminal_descriptor : @@ -1605,7 +1658,7 @@ specify_output_terminal_descriptor : ignspec_id ; system_timing_declaration : - ignspec_id '(' system_timing_args ')' ';' ; + ignspec_id TOK_LPAREN system_timing_args TOK_RPAREN TOK_SEMICOL ; system_timing_arg : TOK_POSEDGE ignspec_id | @@ -1615,140 +1668,135 @@ system_timing_arg : system_timing_args : system_timing_arg | system_timing_args TOK_IGNORED_SPECIFY_AND system_timing_arg | - system_timing_args ',' system_timing_arg ; + system_timing_args TOK_COMMA system_timing_arg ; // for the time being this is OK, but we may write our own expr here. // as I'm not sure it is legal to use a full expr here (probably not) // On the other hand, other rules requiring constant expressions also use 'expr' // (such as param assignment), so we may leave this as-is, perhaps adding runtime checks for constant-ness ignspec_constant_expression: - expr { delete $1; }; + expr { }; ignspec_expr: - expr { delete $1; } | - expr ':' expr ':' expr { - delete $1; - delete $3; - delete $5; + expr { } | + expr TOK_COL expr TOK_COL expr { }; ignspec_id: - TOK_ID { delete $1; } - range_or_multirange { delete $3; }; + TOK_ID { } + range_or_multirange { }; /**********************************************************************/ param_signed: TOK_SIGNED { - astbuf1->is_signed = true; + extra->astbuf1->is_signed = true; } | TOK_UNSIGNED { - astbuf1->is_signed = false; + extra->astbuf1->is_signed = false; } | %empty; param_integer: type_atom { - astbuf1->is_reg = false; + extra->astbuf1->is_reg = false; }; param_real: TOK_REAL { - astbuf1->children.push_back(new AstNode(AST_REALVALUE)); + extra->astbuf1->children.push_back(std::make_unique(AST_REALVALUE)); }; param_range: range { - if ($1 != NULL) { - astbuf1->children.push_back($1); + if ($1 != nullptr) { + extra->astbuf1->children.push_back(std::move($1)); } }; param_integer_type: param_integer param_signed; param_range_type: type_vec param_signed { - addRange(astbuf1, 0, 0); + addRange(extra->astbuf1.get(), 0, 0); } | type_vec param_signed non_opt_range { - astbuf1->children.push_back($3); + extra->astbuf1->children.push_back(std::move($3)); }; param_implicit_type: param_signed param_range; param_type: param_integer_type | param_real | param_range_type | param_implicit_type | hierarchical_type_id { - addWiretypeNode($1, astbuf1); + extra->addWiretypeNode($1, extra->astbuf1.get()); }; param_decl: attr TOK_PARAMETER { - astbuf1 = new AstNode(AST_PARAMETER); - astbuf1->children.push_back(AstNode::mkconst_int(0, true)); - append_attr(astbuf1, $1); - } param_type param_decl_list ';' { - delete astbuf1; + extra->astbuf1 = std::make_unique(AST_PARAMETER); + extra->astbuf1->children.push_back(AstNode::mkconst_int(0, true)); + append_attr(extra->astbuf1.get(), $1); + } param_type param_decl_list TOK_SEMICOL { + (void)extra->astbuf1.reset(); }; localparam_decl: attr TOK_LOCALPARAM { - astbuf1 = new AstNode(AST_LOCALPARAM); - astbuf1->children.push_back(AstNode::mkconst_int(0, true)); - append_attr(astbuf1, $1); - } param_type param_decl_list ';' { - delete astbuf1; + extra->astbuf1 = std::make_unique(AST_LOCALPARAM); + extra->astbuf1->children.push_back(AstNode::mkconst_int(0, true)); + append_attr(extra->astbuf1.get(), $1); + } param_type param_decl_list TOK_SEMICOL { + (void)extra->astbuf1.reset(); }; param_decl_list: - single_param_decl | param_decl_list ',' single_param_decl; + single_param_decl | param_decl_list TOK_COMMA single_param_decl; single_param_decl: - single_param_decl_ident '=' expr { - AstNode *decl = ast_stack.back()->children.back(); + single_param_decl_ident TOK_EQ expr { + AstNode *decl = extra->ast_stack.back()->children.back().get(); log_assert(decl->type == AST_PARAMETER || decl->type == AST_LOCALPARAM); - delete decl->children[0]; - decl->children[0] = $3; + decl->children[0] = std::move($3); } | single_param_decl_ident { - AstNode *decl = ast_stack.back()->children.back(); + AstNode *decl = extra->ast_stack.back()->children.back().get(); if (decl->type != AST_PARAMETER) { log_assert(decl->type == AST_LOCALPARAM); - frontend_verilog_yyerror("localparam initialization is missing!"); + lexer->err("localparam initialization is missing!"); } - if (!sv_mode) - frontend_verilog_yyerror("Parameter defaults can only be omitted in SystemVerilog mode!"); - delete decl->children[0]; + if (!mode->sv) + lexer->err("Parameter defaults can only be omitted in SystemVerilog mode!"); decl->children.erase(decl->children.begin()); }; single_param_decl_ident: TOK_ID { - AstNode *node; - if (astbuf1 == nullptr) { - if (!sv_mode) - frontend_verilog_yyerror("In pure Verilog (not SystemVerilog), parameter/localparam with an initializer must use the parameter/localparam keyword"); - node = new AstNode(AST_PARAMETER); - node->children.push_back(AstNode::mkconst_int(0, true)); + std::unique_ptr node_owned; + if (extra->astbuf1 == nullptr) { + if (!mode->sv) + lexer->err("In pure Verilog (not SystemVerilog), parameter/localparam with an initializer must use the parameter/localparam keyword"); + node_owned = std::make_unique(AST_PARAMETER); + node_owned->children.push_back(AstNode::mkconst_int(0, true)); } else { - node = astbuf1->clone(); + node_owned = extra->astbuf1->clone(); } - node->str = *$1; - ast_stack.back()->children.push_back(node); - delete $1; + node_owned->str = *$1; + auto node = node_owned.get(); + extra->ast_stack.back()->children.push_back(std::move(node_owned)); SET_AST_NODE_LOC(node, @1, @1); }; defparam_decl: - TOK_DEFPARAM defparam_decl_list ';'; + TOK_DEFPARAM defparam_decl_list TOK_SEMICOL; defparam_decl_list: - single_defparam_decl | defparam_decl_list ',' single_defparam_decl; + single_defparam_decl | defparam_decl_list TOK_COMMA single_defparam_decl; single_defparam_decl: - range rvalue '=' expr { - AstNode *node = new AstNode(AST_DEFPARAM); - node->children.push_back($2); - node->children.push_back($4); - if ($1 != NULL) - node->children.push_back($1); - ast_stack.back()->children.push_back(node); + range rvalue TOK_EQ expr { + auto node = std::make_unique(AST_DEFPARAM); + node->children.push_back(std::move($2)); + node->children.push_back(std::move($4)); + if ($1 != nullptr) + node->children.push_back(std::move($1)); + extra->ast_stack.back()->children.push_back(std::move(node)); }; ///////// @@ -1758,90 +1806,89 @@ single_defparam_decl: enum_type: TOK_ENUM { static int enum_count; // create parent node for the enum - astbuf2 = new AstNode(AST_ENUM); - ast_stack.back()->children.push_back(astbuf2); - astbuf2->str = std::string("$enum"); - astbuf2->str += std::to_string(enum_count++); + extra->astbuf2 = std::make_unique(AST_ENUM); + extra->astbuf2->str = std::string("$enum"); + extra->astbuf2->str += std::to_string(enum_count++); + log_assert(!extra->cell_hack); + extra->cell_hack = extra->astbuf2.get(); + extra->ast_stack.back()->children.push_back(std::move(extra->astbuf2)); // create the template for the names - astbuf1 = new AstNode(AST_ENUM_ITEM); - astbuf1->children.push_back(AstNode::mkconst_int(0, true)); - } enum_base_type '{' enum_name_list optional_comma '}' { + extra->astbuf1 = std::make_unique(AST_ENUM_ITEM); + extra->astbuf1->children.push_back(AstNode::mkconst_int(0, true)); + } enum_base_type TOK_LCURL enum_name_list optional_comma TOK_RCURL { // create template for the enum vars - auto tnode = astbuf1->clone(); - delete astbuf1; - astbuf1 = tnode; + log_assert(extra->cell_hack); + auto tnode_owned = extra->astbuf1->clone(); + auto* tnode = tnode_owned.get(); + extra->astbuf1 = std::move(tnode_owned); tnode->type = AST_WIRE; - tnode->attributes[ID::enum_type] = AstNode::mkconst_str(astbuf2->str); + tnode->attributes[ID::enum_type] = AstNode::mkconst_str(extra->cell_hack->str); + extra->cell_hack = nullptr; // drop constant but keep any range - delete tnode->children[0]; tnode->children.erase(tnode->children.begin()); - $$ = astbuf1; + $$ = extra->astbuf1->clone(); }; enum_base_type: type_atom type_signing - | type_vec type_signing range { if ($3) astbuf1->children.push_back($3); } - | %empty { astbuf1->is_reg = true; addRange(astbuf1); } + | type_vec type_signing range { if ($3) extra->astbuf1->children.push_back(std::move($3)); } + | %empty { extra->astbuf1->is_reg = true; addRange(extra->astbuf1.get()); } ; type_atom: integer_atom_type { - astbuf1->is_reg = true; - astbuf1->is_signed = true; - addRange(astbuf1, $1 - 1, 0); + extra->astbuf1->is_reg = true; + extra->astbuf1->is_signed = true; + addRange(extra->astbuf1.get(), $1 - 1, 0); }; -type_vec: TOK_REG { astbuf1->is_reg = true; } // unsigned - | TOK_LOGIC { astbuf1->is_logic = true; } // unsigned +type_vec: TOK_REG { extra->astbuf1->is_reg = true; } // unsigned + | TOK_LOGIC { extra->astbuf1->is_logic = true; } // unsigned ; type_signing: - TOK_SIGNED { astbuf1->is_signed = true; } - | TOK_UNSIGNED { astbuf1->is_signed = false; } + TOK_SIGNED { extra->astbuf1->is_signed = true; } + | TOK_UNSIGNED { extra->astbuf1->is_signed = false; } | %empty ; enum_name_list: enum_name_decl - | enum_name_list ',' enum_name_decl + | enum_name_list TOK_COMMA enum_name_decl ; enum_name_decl: TOK_ID opt_enum_init { // put in fn - log_assert(astbuf1); - log_assert(astbuf2); - auto node = astbuf1->clone(); + log_assert((bool)extra->astbuf1); + log_assert((bool)extra->cell_hack); + auto node = extra->astbuf1->clone(); node->str = *$1; - delete $1; - SET_AST_NODE_LOC(node, @1, @1); - delete node->children[0]; - node->children[0] = $2 ? $2 : new AstNode(AST_NONE); - astbuf2->children.push_back(node); + SET_AST_NODE_LOC(node.get(), @1, @1); + node->children[0] = $2 ? std::move($2) : std::make_unique(AST_NONE); + extra->cell_hack->children.push_back(std::move(node)); } ; opt_enum_init: - '=' basic_expr { $$ = $2; } // TODO: restrict this - | %empty { $$ = NULL; } + TOK_EQ basic_expr { $$ = std::move($2); } // TODO: restrict this + | %empty { $$ = nullptr; } ; enum_var_list: enum_var - | enum_var_list ',' enum_var + | enum_var_list TOK_COMMA enum_var ; enum_var: TOK_ID { - log_assert(astbuf1); - log_assert(astbuf2); - auto node = astbuf1->clone(); - ast_stack.back()->children.push_back(node); + log_assert((bool)extra->astbuf1); + auto node = extra->astbuf1->clone(); node->str = *$1; - delete $1; - SET_AST_NODE_LOC(node, @1, @1); + SET_AST_NODE_LOC(node.get(), @1, @1); node->is_enum = true; + extra->ast_stack.back()->children.push_back(std::move(node)); } ; -enum_decl: enum_type enum_var_list ';' { delete $1; } +enum_decl: enum_type enum_var_list TOK_SEMICOL { } ; ////////////////// @@ -1850,30 +1897,36 @@ enum_decl: enum_type enum_var_list ';' { delete $1; } struct_decl: attr struct_type { - append_attr($2, $1); - } struct_var_list ';' { - delete astbuf2; + append_attr(extra->astbuf2.get(), $1); + } struct_var_list TOK_SEMICOL { + (void)extra->astbuf2.reset(); } ; -struct_type: struct_union { astbuf2 = $1; astbuf2->is_custom_type = true; } struct_body { $$ = astbuf2; } +struct_type: + struct_union { + extra->astbuf2 = std::move($1); + extra->astbuf2->is_custom_type = true; + } struct_body { + $$ = extra->astbuf2->clone(); + } ; struct_union: - TOK_STRUCT { $$ = new AstNode(AST_STRUCT); } - | TOK_UNION { $$ = new AstNode(AST_UNION); } + TOK_STRUCT { $$ = std::make_unique(AST_STRUCT); } + | TOK_UNION { $$ = std::make_unique(AST_UNION); } ; -struct_body: opt_packed '{' struct_member_list '}' +struct_body: opt_packed TOK_LCURL struct_member_list TOK_RCURL ; opt_packed: TOK_PACKED opt_signed_struct | - %empty { frontend_verilog_yyerror("Only PACKED supported at this time"); }; + %empty { lexer->err("Only PACKED supported at this time"); }; opt_signed_struct: - TOK_SIGNED { astbuf2->is_signed = true; } - | TOK_UNSIGNED { astbuf2->is_signed = false; } + TOK_SIGNED { extra->astbuf2->is_signed = true; } + | TOK_UNSIGNED { extra->astbuf2->is_signed = false; } | %empty // default is unsigned ; @@ -1881,62 +1934,68 @@ struct_member_list: struct_member | struct_member_list struct_member ; -struct_member: struct_member_type member_name_list ';' { delete astbuf1; } +struct_member: struct_member_type member_name_list TOK_SEMICOL { (void)extra->astbuf1.reset(); } ; member_name_list: member_name - | member_name_list ',' member_name + | member_name_list TOK_COMMA member_name ; member_name: TOK_ID { - astbuf1->str = $1->substr(1); - delete $1; - astbuf3 = astbuf1->clone(); - SET_AST_NODE_LOC(astbuf3, @1, @1); - astbuf2->children.push_back(astbuf3); - } range { if ($3) astbuf3->children.push_back($3); } + extra->astbuf1->str = $1->substr(1); + extra->astbuf3 = extra->astbuf1->clone(); + log_assert(!extra->member_hack); + extra->member_hack = extra->astbuf3.get(); + SET_AST_NODE_LOC(extra->member_hack, @1, @1); + extra->astbuf2->children.push_back(std::move(extra->astbuf3)); + } range { + log_assert((bool)extra->member_hack); + if ($3) extra->member_hack->children.push_back(std::move($3)); + extra->member_hack = nullptr; + } ; -struct_member_type: { astbuf1 = new AstNode(AST_STRUCT_ITEM); } member_type_token +struct_member_type: { extra->astbuf1 = std::make_unique(AST_STRUCT_ITEM); } member_type_token ; member_type_token: member_type range_or_multirange { - AstNode *range = checkRange(astbuf1, $2); + auto range = checkRange(extra->astbuf1.get(), std::move($2)); if (range) - astbuf1->children.push_back(range); + extra->astbuf1->children.push_back(std::move(range)); } | { - delete astbuf1; + (void)extra->astbuf1.reset(); } struct_union { - // stash state on ast_stack - ast_stack.push_back(astbuf2); - astbuf2 = $2; + // stash state on extra->ast_stack + // sketchy! + extra->ast_stack.push_back(extra->astbuf2.release()); + extra->astbuf2 = std::move($2); } struct_body { - astbuf1 = astbuf2; + extra->astbuf1 = std::move(extra->astbuf2); // recover state - astbuf2 = ast_stack.back(); - ast_stack.pop_back(); + extra->astbuf2.reset(extra->ast_stack.back()); + extra->ast_stack.pop_back(); } ; member_type: type_atom type_signing | type_vec type_signing - | hierarchical_type_id { addWiretypeNode($1, astbuf1); } + | hierarchical_type_id { extra->addWiretypeNode($1, extra->astbuf1.get()); } ; struct_var_list: struct_var - | struct_var_list ',' struct_var + | struct_var_list TOK_COMMA struct_var ; -struct_var: TOK_ID { auto *var_node = astbuf2->clone(); - var_node->str = *$1; - delete $1; - SET_AST_NODE_LOC(var_node, @1, @1); - ast_stack.back()->children.push_back(var_node); - } - ; +struct_var: + TOK_ID { + auto var_node = extra->astbuf2->clone(); + var_node->str = *$1; + SET_AST_NODE_LOC(var_node.get(), @1, @1); + extra->ast_stack.back()->children.push_back(std::move(var_node)); + }; ///////// // wire @@ -1944,46 +2003,43 @@ struct_var: TOK_ID { auto *var_node = astbuf2->clone(); wire_decl: attr wire_type range_or_multirange { - albuf = $1; - astbuf1 = $2; - astbuf2 = checkRange(astbuf1, $3); + extra->albuf = $1; + extra->astbuf1 = std::move($2); + extra->astbuf2 = checkRange(extra->astbuf1.get(), std::move($3)); } delay wire_name_list { - delete astbuf1; - if (astbuf2 != NULL) - delete astbuf2; - free_attr(albuf); - } ';' | + (void)extra->astbuf1.reset(); + if (extra->astbuf2 != nullptr) + (void)extra->astbuf2.reset(); + free_attr(extra->albuf); + } TOK_SEMICOL | attr TOK_SUPPLY0 TOK_ID { - ast_stack.back()->children.push_back(new AstNode(AST_WIRE)); - ast_stack.back()->children.back()->str = *$3; - append_attr(ast_stack.back()->children.back(), $1); - ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, new AstNode(AST_IDENTIFIER), AstNode::mkconst_int(0, false, 1))); - ast_stack.back()->children.back()->children[0]->str = *$3; - delete $3; - } opt_supply_wires ';' | + extra->ast_stack.back()->children.push_back(std::make_unique(AST_WIRE)); + extra->ast_stack.back()->children.back()->str = *$3; + append_attr(extra->ast_stack.back()->children.back().get(), $1); + extra->ast_stack.back()->children.push_back(std::make_unique(AST_ASSIGN, std::make_unique(AST_IDENTIFIER), AstNode::mkconst_int(0, false, 1))); + extra->ast_stack.back()->children.back()->children[0]->str = *$3; + } opt_supply_wires TOK_SEMICOL | attr TOK_SUPPLY1 TOK_ID { - ast_stack.back()->children.push_back(new AstNode(AST_WIRE)); - ast_stack.back()->children.back()->str = *$3; - append_attr(ast_stack.back()->children.back(), $1); - ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, new AstNode(AST_IDENTIFIER), AstNode::mkconst_int(1, false, 1))); - ast_stack.back()->children.back()->children[0]->str = *$3; - delete $3; - } opt_supply_wires ';'; + extra->ast_stack.back()->children.push_back(std::make_unique(AST_WIRE)); + extra->ast_stack.back()->children.back()->str = *$3; + append_attr(extra->ast_stack.back()->children.back().get(), $1); + extra->ast_stack.back()->children.push_back(std::make_unique(AST_ASSIGN, std::make_unique(AST_IDENTIFIER), AstNode::mkconst_int(1, false, 1))); + extra->ast_stack.back()->children.back()->children[0]->str = *$3; + } opt_supply_wires TOK_SEMICOL; opt_supply_wires: %empty | - opt_supply_wires ',' TOK_ID { - AstNode *wire_node = ast_stack.back()->children.at(GetSize(ast_stack.back()->children)-2)->clone(); - AstNode *assign_node = ast_stack.back()->children.at(GetSize(ast_stack.back()->children)-1)->clone(); + opt_supply_wires TOK_COMMA TOK_ID { + auto wire_node = extra->ast_stack.back()->children.at(GetSize(extra->ast_stack.back()->children)-2)->clone(); + auto assign_node = extra->ast_stack.back()->children.at(GetSize(extra->ast_stack.back()->children)-1)->clone(); wire_node->str = *$3; assign_node->children[0]->str = *$3; - ast_stack.back()->children.push_back(wire_node); - ast_stack.back()->children.push_back(assign_node); - delete $3; + extra->ast_stack.back()->children.push_back(std::move(wire_node)); + extra->ast_stack.back()->children.push_back(std::move(assign_node)); }; wire_name_list: - wire_name_and_opt_assign | wire_name_list ',' wire_name_and_opt_assign; + wire_name_and_opt_assign | wire_name_list TOK_COMMA wire_name_and_opt_assign; wire_name_and_opt_assign: wire_name { @@ -1991,31 +2047,27 @@ wire_name_and_opt_assign: bool attr_anyseq = false; bool attr_allconst = false; bool attr_allseq = false; - if (ast_stack.back()->children.back()->get_bool_attribute(ID::anyconst)) { - delete ast_stack.back()->children.back()->attributes.at(ID::anyconst); - ast_stack.back()->children.back()->attributes.erase(ID::anyconst); + if (extra->ast_stack.back()->children.back()->get_bool_attribute(ID::anyconst)) { + extra->ast_stack.back()->children.back()->attributes.erase(ID::anyconst); attr_anyconst = true; } - if (ast_stack.back()->children.back()->get_bool_attribute(ID::anyseq)) { - delete ast_stack.back()->children.back()->attributes.at(ID::anyseq); - ast_stack.back()->children.back()->attributes.erase(ID::anyseq); + if (extra->ast_stack.back()->children.back()->get_bool_attribute(ID::anyseq)) { + extra->ast_stack.back()->children.back()->attributes.erase(ID::anyseq); attr_anyseq = true; } - if (ast_stack.back()->children.back()->get_bool_attribute(ID::allconst)) { - delete ast_stack.back()->children.back()->attributes.at(ID::allconst); - ast_stack.back()->children.back()->attributes.erase(ID::allconst); + if (extra->ast_stack.back()->children.back()->get_bool_attribute(ID::allconst)) { + extra->ast_stack.back()->children.back()->attributes.erase(ID::allconst); attr_allconst = true; } - if (ast_stack.back()->children.back()->get_bool_attribute(ID::allseq)) { - delete ast_stack.back()->children.back()->attributes.at(ID::allseq); - ast_stack.back()->children.back()->attributes.erase(ID::allseq); + if (extra->ast_stack.back()->children.back()->get_bool_attribute(ID::allseq)) { + extra->ast_stack.back()->children.back()->attributes.erase(ID::allseq); attr_allseq = true; } - if (current_wire_rand || attr_anyconst || attr_anyseq || attr_allconst || attr_allseq) { - AstNode *wire = new AstNode(AST_IDENTIFIER); - AstNode *fcall = new AstNode(AST_FCALL); - wire->str = ast_stack.back()->children.back()->str; - fcall->str = current_wire_const ? "\\$anyconst" : "\\$anyseq"; + if (extra->current_wire_rand || attr_anyconst || attr_anyseq || attr_allconst || attr_allseq) { + auto wire = std::make_unique(AST_IDENTIFIER); + auto fcall = std::make_unique(AST_FCALL); + wire->str = extra->ast_stack.back()->children.back()->str; + fcall->str = extra->current_wire_const ? "\\$anyconst" : "\\$anyseq"; if (attr_anyconst) fcall->str = "\\$anyconst"; if (attr_anyseq) @@ -2025,125 +2077,122 @@ wire_name_and_opt_assign: if (attr_allseq) fcall->str = "\\$allseq"; fcall->attributes[ID::reg] = AstNode::mkconst_str(RTLIL::unescape_id(wire->str)); - ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, fcall)); + extra->ast_stack.back()->children.push_back(std::make_unique(AST_ASSIGN, std::move(wire), std::move(fcall))); } } | - wire_name '=' expr { - AstNode *wire = new AstNode(AST_IDENTIFIER); - wire->str = ast_stack.back()->children.back()->str; - if (astbuf1->is_input) { - if (astbuf1->attributes.count(ID::defaultvalue)) - delete astbuf1->attributes.at(ID::defaultvalue); - astbuf1->attributes[ID::defaultvalue] = $3; + wire_name TOK_EQ expr { + auto wire = std::make_unique(AST_IDENTIFIER); + wire->str = extra->ast_stack.back()->children.back()->str; + if (extra->astbuf1->is_input) { + extra->astbuf1->attributes[ID::defaultvalue] = std::move($3); } - else if (astbuf1->is_reg || astbuf1->is_logic){ - AstNode *assign = new AstNode(AST_ASSIGN_LE, wire, $3); - AstNode *block = new AstNode(AST_BLOCK, assign); - AstNode *init = new AstNode(AST_INITIAL, block); + else if (extra->astbuf1->is_reg || extra->astbuf1->is_logic){ + auto assign = std::make_unique(AST_ASSIGN_LE, std::move(wire), std::move($3)); + SET_AST_NODE_LOC(assign.get(), @1, @3); + auto block = std::make_unique(AST_BLOCK, std::move(assign)); + SET_AST_NODE_LOC(block.get(), @1, @3); + auto init = std::make_unique(AST_INITIAL, std::move(block)); + SET_AST_NODE_LOC(init.get(), @1, @3); - SET_AST_NODE_LOC(assign, @1, @3); - SET_AST_NODE_LOC(block, @1, @3); - SET_AST_NODE_LOC(init, @1, @3); - - ast_stack.back()->children.push_back(init); + extra->ast_stack.back()->children.push_back(std::move(init)); } else { - AstNode *assign = new AstNode(AST_ASSIGN, wire, $3); - SET_AST_NODE_LOC(assign, @1, @3); - ast_stack.back()->children.push_back(assign); + auto assign = std::make_unique(AST_ASSIGN, std::move(wire), std::move($3)); + SET_AST_NODE_LOC(assign.get(), @1, @3); + extra->ast_stack.back()->children.push_back(std::move(assign)); } }; wire_name: TOK_ID range_or_multirange { - if (astbuf1 == nullptr) - frontend_verilog_yyerror("Internal error - should not happen - no AST_WIRE node."); - AstNode *node = astbuf1->clone(); + if (extra->astbuf1 == nullptr) + lexer->err("Internal error - should not happen - no AST_WIRE node."); + auto node = extra->astbuf1->clone(); node->str = *$1; - append_attr_clone(node, albuf); - if (astbuf2 != NULL) - node->children.push_back(astbuf2->clone()); - if ($2 != NULL) { + append_attr_clone(node.get(), extra->albuf); + if (extra->astbuf2 != nullptr) + node->children.push_back(extra->astbuf2->clone()); + if ($2 != nullptr) { if (node->is_input || node->is_output) - frontend_verilog_yyerror("input/output/inout ports cannot have unpacked dimensions."); - if (!astbuf2 && !node->is_custom_type) { - addRange(node, 0, 0, false); + lexer->err("input/output/inout ports cannot have unpacked dimensions."); + if (!extra->astbuf2 && !node->is_custom_type) { + addRange(node.get(), 0, 0, false); } - rewriteAsMemoryNode(node, $2); + rewriteAsMemoryNode(node.get(), std::move($2)); } - if (current_function_or_task) { + if (extra->current_function_or_task) { if (node->is_input || node->is_output) - node->port_id = current_function_or_task_port_id++; - } else if (ast_stack.back()->type == AST_GENBLOCK) { + node->port_id = extra->current_function_or_task_port_id++; + } else if (extra->ast_stack.back()->type == AST_GENBLOCK) { if (node->is_input || node->is_output) - frontend_verilog_yyerror("Cannot declare module port `%s' within a generate block.", $1->c_str()); + lexer->err("Cannot declare module port `%s' within a generate block.", $1->c_str()); } else { - if (do_not_require_port_stubs && (node->is_input || node->is_output) && port_stubs.count(*$1) == 0) { - port_stubs[*$1] = ++port_counter; + if (extra->do_not_require_port_stubs && (node->is_input || node->is_output) && extra->port_stubs.count(*$1) == 0) { + extra->port_stubs[*$1] = ++extra->port_counter; } - if (port_stubs.count(*$1) != 0) { + if (extra->port_stubs.count(*$1) != 0) { if (!node->is_input && !node->is_output) - frontend_verilog_yyerror("Module port `%s' is neither input nor output.", $1->c_str()); - if (node->is_reg && node->is_input && !node->is_output && !sv_mode) - frontend_verilog_yyerror("Input port `%s' is declared as register.", $1->c_str()); - node->port_id = port_stubs[*$1]; - port_stubs.erase(*$1); + lexer->err("Module port `%s' is neither input nor output.", $1->c_str()); + if (node->is_reg && node->is_input && !node->is_output && !mode->sv) + lexer->err("Input port `%s' is declared as register.", $1->c_str()); + node->port_id = extra->port_stubs[*$1]; + extra->port_stubs.erase(*$1); } else { if (node->is_input || node->is_output) - frontend_verilog_yyerror("Module port `%s' is not declared in module header.", $1->c_str()); + lexer->err("Module port `%s' is not declared in module header.", $1->c_str()); } } //FIXME: for some reason, TOK_ID has a location which always points to one column *after* the real last column... - SET_AST_NODE_LOC(node, @1, @1); - ast_stack.back()->children.push_back(node); + SET_AST_NODE_LOC(node.get(), @1, @1); + extra->ast_stack.back()->children.push_back(std::move(node)); - delete $1; }; assign_stmt: - TOK_ASSIGN delay assign_expr_list ';'; + TOK_ASSIGN delay assign_expr_list TOK_SEMICOL; assign_expr_list: - assign_expr | assign_expr_list ',' assign_expr; + assign_expr | assign_expr_list TOK_COMMA assign_expr; assign_expr: - lvalue '=' expr { - AstNode *node = new AstNode(AST_ASSIGN, $1, $3); + lvalue TOK_EQ expr { + AstNode* node = extra->saveChild(std::make_unique(AST_ASSIGN, std::move($1), std::move($3))); SET_AST_NODE_LOC(node, @$, @$); - ast_stack.back()->children.push_back(node); }; type_name: TOK_ID // first time seen - | TOK_USER_TYPE { if (isInLocalScope($1)) frontend_verilog_yyerror("Duplicate declaration of TYPEDEF '%s'", $1->c_str()+1); } + | TOK_USER_TYPE { if (extra->isInLocalScope($1)) lexer->err("Duplicate declaration of TYPEDEF '%s'", $1->c_str()+1); $$ = std::move($1); } ; typedef_decl: - TOK_TYPEDEF typedef_base_type range_or_multirange type_name range_or_multirange ';' { - astbuf1 = $2; - astbuf2 = checkRange(astbuf1, $3); - if (astbuf2) - astbuf1->children.push_back(astbuf2); - - if ($5 != NULL) { - if (!astbuf2 && !astbuf1->is_custom_type) { - addRange(astbuf1, 0, 0, false); - } - rewriteAsMemoryNode(astbuf1, $5); + TOK_TYPEDEF typedef_base_type range_or_multirange type_name range_or_multirange TOK_SEMICOL { + extra->astbuf1 = std::move($2); + extra->astbuf2 = checkRange(extra->astbuf1.get(), std::move($3)); + bool has_a_range = (bool)extra->astbuf2; + if (extra->astbuf2) { + extra->astbuf1->children.push_back(std::move(extra->astbuf2)); } - addTypedefNode($4, astbuf1); } - | TOK_TYPEDEF enum_struct_type type_name ';' { addTypedefNode($3, $2); } + + if ($5 != nullptr) { + if (!has_a_range && !extra->astbuf1->is_custom_type) { + addRange(extra->astbuf1.get(), 0, 0, false); + } + rewriteAsMemoryNode(extra->astbuf1.get(), std::move($5)); + } + extra->addTypedefNode($4, std::move(extra->astbuf1)); } + | TOK_TYPEDEF enum_struct_type type_name TOK_SEMICOL { extra->addTypedefNode($3, std::move($2)); } ; typedef_base_type: hierarchical_type_id { - $$ = new AstNode(AST_WIRE); + $$ = std::make_unique(AST_WIRE); $$->is_logic = true; - addWiretypeNode($1, $$); + extra->addWiretypeNode($1, $$.get()); } | integer_vector_type opt_signedness_default_unsigned { - $$ = new AstNode(AST_WIRE); - if ($1 == TOK_REG) { + $$ = std::make_unique(AST_WIRE); + if ($1 == token::TOK_REG) { $$->is_reg = true; } else { $$->is_logic = true; @@ -2151,7 +2200,7 @@ typedef_base_type: $$->is_signed = $2; } | integer_atom_type opt_signedness_default_signed { - $$ = new AstNode(AST_WIRE); + $$ = std::make_unique(AST_WIRE); $$->is_logic = true; $$->is_signed = $2; $$->range_left = $1 - 1; @@ -2159,27 +2208,25 @@ typedef_base_type: }; enum_struct_type: - enum_type - | struct_type + enum_type { $$ = std::move($1); } + | struct_type { $$ = std::move($1); } ; cell_stmt: attr TOK_ID { - astbuf1 = new AstNode(AST_CELL); - append_attr(astbuf1, $1); - astbuf1->children.push_back(new AstNode(AST_CELLTYPE)); - astbuf1->children[0]->str = *$2; - delete $2; - } cell_parameter_list_opt cell_list ';' { - delete astbuf1; + extra->astbuf1 = std::make_unique(AST_CELL); + append_attr(extra->astbuf1.get(), $1); + extra->astbuf1->children.push_back(std::make_unique(AST_CELLTYPE)); + extra->astbuf1->children[0]->str = *$2; + } cell_parameter_list_opt cell_list TOK_SEMICOL { + (void)extra->astbuf1.reset(); } | attr tok_prim_wrapper delay { - astbuf1 = new AstNode(AST_PRIMITIVE); - astbuf1->str = *$2; - append_attr(astbuf1, $1); - delete $2; - } prim_list ';' { - delete astbuf1; + extra->astbuf1 = std::make_unique(AST_PRIMITIVE); + extra->astbuf1->str = *$2; + append_attr(extra->astbuf1.get(), $1); + } prim_list TOK_SEMICOL { + (void)extra->astbuf1.reset(); }; tok_prim_wrapper: @@ -2192,91 +2239,99 @@ tok_prim_wrapper: cell_list: single_cell | - cell_list ',' single_cell; + cell_list TOK_COMMA single_cell; single_cell: single_cell_no_array | single_cell_arraylist; single_cell_no_array: TOK_ID { - astbuf2 = astbuf1->clone(); - if (astbuf2->type != AST_PRIMITIVE) - astbuf2->str = *$1; - delete $1; - ast_stack.back()->children.push_back(astbuf2); - } '(' cell_port_list ')' { - SET_AST_NODE_LOC(astbuf2, @1, @$); + extra->astbuf2 = extra->astbuf1->clone(); + if (extra->astbuf2->type != AST_PRIMITIVE) + extra->astbuf2->str = *$1; + // TODO optimize again + extra->cell_hack = extra->astbuf2.get(); + extra->ast_stack.back()->children.push_back(std::move(extra->astbuf2)); + } TOK_LPAREN cell_port_list TOK_RPAREN { + log_assert(extra->cell_hack); + SET_AST_NODE_LOC(extra->cell_hack, @1, @$); + extra->cell_hack = nullptr; } single_cell_arraylist: TOK_ID non_opt_range { - astbuf2 = astbuf1->clone(); - if (astbuf2->type != AST_PRIMITIVE) - astbuf2->str = *$1; - delete $1; - ast_stack.back()->children.push_back(new AstNode(AST_CELLARRAY, $2, astbuf2)); - } '(' cell_port_list ')'{ - SET_AST_NODE_LOC(astbuf2, @1, @$); + extra->astbuf2 = extra->astbuf1->clone(); + if (extra->astbuf2->type != AST_PRIMITIVE) + extra->astbuf2->str = *$1; + // TODO optimize again + extra->cell_hack = extra->astbuf2.get(); + extra->ast_stack.back()->children.push_back(std::make_unique(AST_CELLARRAY, std::move($2), std::move(extra->astbuf2))); + } TOK_LPAREN cell_port_list TOK_RPAREN{ + log_assert(extra->cell_hack); + SET_AST_NODE_LOC(extra->cell_hack, @1, @$); + extra->cell_hack = nullptr; }; cell_list_no_array: single_cell_no_array | - cell_list_no_array ',' single_cell_no_array; + cell_list_no_array TOK_COMMA single_cell_no_array; prim_list: single_prim | - prim_list ',' single_prim; + prim_list TOK_COMMA single_prim; single_prim: single_cell | /* no name */ { - astbuf2 = astbuf1->clone(); - ast_stack.back()->children.push_back(astbuf2); - } '(' cell_port_list ')' { - SET_AST_NODE_LOC(astbuf2, @1, @$); + extra->astbuf2 = extra->astbuf1->clone(); + log_assert(!extra->cell_hack); + extra->cell_hack = extra->astbuf2.get(); + // TODO optimize again + extra->ast_stack.back()->children.push_back(std::move(extra->astbuf2)); + } TOK_LPAREN cell_port_list TOK_RPAREN { + log_assert(extra->cell_hack); + SET_AST_NODE_LOC(extra->cell_hack, @1, @$); + extra->cell_hack = nullptr; } cell_parameter_list_opt: - '#' '(' cell_parameter_list ')' | %empty; + TOK_HASH TOK_LPAREN cell_parameter_list TOK_RPAREN | %empty; cell_parameter_list: - cell_parameter | cell_parameter_list ',' cell_parameter; + cell_parameter | cell_parameter_list TOK_COMMA cell_parameter; cell_parameter: %empty | expr { - AstNode *node = new AstNode(AST_PARASET); - astbuf1->children.push_back(node); - node->children.push_back($1); + auto node = std::make_unique(AST_PARASET); + node->children.push_back(std::move($1)); + extra->astbuf1->children.push_back(std::move(node)); } | - '.' TOK_ID '(' ')' { - // delete unused TOK_ID - delete $2; + TOK_DOT TOK_ID TOK_LPAREN TOK_RPAREN { + // just ignore empty parameters } | - '.' TOK_ID '(' expr ')' { - AstNode *node = new AstNode(AST_PARASET); + TOK_DOT TOK_ID TOK_LPAREN expr TOK_RPAREN { + auto node = std::make_unique(AST_PARASET); node->str = *$2; - astbuf1->children.push_back(node); - node->children.push_back($4); - delete $2; + node->children.push_back(std::move($4)); + extra->astbuf1->children.push_back(std::move(node)); }; cell_port_list: cell_port_list_rules { // remove empty args from end of list - while (!astbuf2->children.empty()) { - AstNode *node = astbuf2->children.back(); + while (!extra->cell_hack->children.empty()) { + auto& node = extra->cell_hack->children.back(); if (node->type != AST_ARGUMENT) break; if (!node->children.empty()) break; if (!node->str.empty()) break; - astbuf2->children.pop_back(); - delete node; + extra->cell_hack->children.pop_back(); } // check port types bool has_positional_args = false; bool has_named_args = false; - for (auto node : astbuf2->children) { + for (auto& node : extra->cell_hack->children) { if (node->type != AST_ARGUMENT) continue; if (node->str.empty()) has_positional_args = true; @@ -2285,52 +2340,49 @@ cell_port_list: } if (has_positional_args && has_named_args) - frontend_verilog_yyerror("Mix of positional and named cell ports."); + lexer->err("Mix of positional and named cell ports."); }; cell_port_list_rules: - cell_port | cell_port_list_rules ',' cell_port; + cell_port | cell_port_list_rules TOK_COMMA cell_port; cell_port: attr { - AstNode *node = new AstNode(AST_ARGUMENT); - astbuf2->children.push_back(node); + auto node = std::make_unique(AST_ARGUMENT); + extra->cell_hack->children.push_back(std::move(node)); free_attr($1); } | attr expr { - AstNode *node = new AstNode(AST_ARGUMENT); - astbuf2->children.push_back(node); - node->children.push_back($2); + auto node = std::make_unique(AST_ARGUMENT); + node->children.push_back(std::move($2)); + extra->cell_hack->children.push_back(std::move(node)); free_attr($1); } | - attr '.' TOK_ID '(' expr ')' { - AstNode *node = new AstNode(AST_ARGUMENT); + attr TOK_DOT TOK_ID TOK_LPAREN expr TOK_RPAREN { + auto node = std::make_unique(AST_ARGUMENT); node->str = *$3; - astbuf2->children.push_back(node); - node->children.push_back($5); - delete $3; + node->children.push_back(std::move($5)); + extra->cell_hack->children.push_back(std::move(node)); free_attr($1); } | - attr '.' TOK_ID '(' ')' { - AstNode *node = new AstNode(AST_ARGUMENT); + attr TOK_DOT TOK_ID TOK_LPAREN TOK_RPAREN { + auto node = std::make_unique(AST_ARGUMENT); node->str = *$3; - astbuf2->children.push_back(node); - delete $3; + extra->cell_hack->children.push_back(std::move(node)); free_attr($1); } | - attr '.' TOK_ID { - AstNode *node = new AstNode(AST_ARGUMENT); + attr TOK_DOT TOK_ID { + auto node = std::make_unique(AST_ARGUMENT); node->str = *$3; - astbuf2->children.push_back(node); - node->children.push_back(new AstNode(AST_IDENTIFIER)); + node->children.push_back(std::make_unique(AST_IDENTIFIER)); node->children.back()->str = *$3; - delete $3; + extra->cell_hack->children.push_back(std::move(node)); free_attr($1); } | attr TOK_WILDCARD_CONNECT { - if (!sv_mode) - frontend_verilog_yyerror("Wildcard port connections are only supported in SystemVerilog mode."); - astbuf2->attributes[ID::wildcard_port_conns] = AstNode::mkconst_int(1, false); + if (!mode->sv) + lexer->err("Wildcard port connections are only supported in SystemVerilog mode."); + extra->cell_hack->attributes[ID::wildcard_port_conns] = AstNode::mkconst_int(1, false); free_attr($1); }; @@ -2352,100 +2404,88 @@ always_or_always_ff: always_stmt: attr always_or_always_ff { - AstNode *node = new AstNode(AST_ALWAYS); + AstNode* node = extra->pushChild(std::make_unique(AST_ALWAYS)); append_attr(node, $1); if ($2) node->attributes[ID::always_ff] = AstNode::mkconst_int(1, false); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); } always_cond { - AstNode *block = new AstNode(AST_BLOCK); - ast_stack.back()->children.push_back(block); - ast_stack.push_back(block); + (void)extra->pushChild(std::make_unique(AST_BLOCK)); } behavioral_stmt { - SET_AST_NODE_LOC(ast_stack.back(), @6, @6); - ast_stack.pop_back(); + SET_AST_NODE_LOC(extra->ast_stack.back(), @6, @6); + extra->ast_stack.pop_back(); - SET_AST_NODE_LOC(ast_stack.back(), @2, @$); - ast_stack.pop_back(); + SET_AST_NODE_LOC(extra->ast_stack.back(), @2, @$); + extra->ast_stack.pop_back(); SET_RULE_LOC(@$, @2, @$); } | attr always_comb_or_latch { - AstNode *node = new AstNode(AST_ALWAYS); + AstNode* node = extra->pushChild(std::make_unique(AST_ALWAYS)); append_attr(node, $1); if ($2) node->attributes[ID::always_latch] = AstNode::mkconst_int(1, false); else node->attributes[ID::always_comb] = AstNode::mkconst_int(1, false); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); - AstNode *block = new AstNode(AST_BLOCK); - ast_stack.back()->children.push_back(block); - ast_stack.push_back(block); + (void)extra->pushChild(std::make_unique(AST_BLOCK)); } behavioral_stmt { - ast_stack.pop_back(); - ast_stack.pop_back(); + extra->ast_stack.pop_back(); + extra->ast_stack.pop_back(); } | attr TOK_INITIAL { - AstNode *node = new AstNode(AST_INITIAL); + AstNode* node = extra->pushChild(std::make_unique(AST_INITIAL)); append_attr(node, $1); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); - AstNode *block = new AstNode(AST_BLOCK); - ast_stack.back()->children.push_back(block); - ast_stack.push_back(block); + (void)extra->pushChild(std::make_unique(AST_BLOCK)); } behavioral_stmt { - ast_stack.pop_back(); - ast_stack.pop_back(); + extra->ast_stack.pop_back(); + extra->ast_stack.pop_back(); }; always_cond: - '@' '(' always_events ')' | - '@' '(' '*' ')' | - '@' ATTR_BEGIN ')' | - '@' '(' ATTR_END | - '@' '*' | + TOK_AT TOK_LPAREN always_events TOK_RPAREN | + TOK_AT TOK_LPAREN TOK_ASTER TOK_RPAREN | + TOK_AT ATTR_BEGIN TOK_RPAREN | + TOK_AT TOK_LPAREN ATTR_END | + TOK_AT TOK_ASTER | %empty; always_events: always_event | always_events TOK_OR always_event | - always_events ',' always_event; + always_events TOK_COMMA always_event; always_event: TOK_POSEDGE expr { - AstNode *node = new AstNode(AST_POSEDGE); - SET_AST_NODE_LOC(node, @1, @1); - ast_stack.back()->children.push_back(node); - node->children.push_back($2); + auto node = std::make_unique(AST_POSEDGE); + SET_AST_NODE_LOC(node.get(), @1, @1); + node->children.push_back(std::move($2)); + extra->ast_stack.back()->children.push_back(std::move(node)); } | TOK_NEGEDGE expr { - AstNode *node = new AstNode(AST_NEGEDGE); - SET_AST_NODE_LOC(node, @1, @1); - ast_stack.back()->children.push_back(node); - node->children.push_back($2); + auto node = std::make_unique(AST_NEGEDGE); + SET_AST_NODE_LOC(node.get(), @1, @1); + node->children.push_back(std::move($2)); + extra->ast_stack.back()->children.push_back(std::move(node)); } | expr { - AstNode *node = new AstNode(AST_EDGE); - ast_stack.back()->children.push_back(node); - node->children.push_back($1); + auto node = std::make_unique(AST_EDGE); + node->children.push_back(std::move($1)); + extra->ast_stack.back()->children.push_back(std::move(node)); }; opt_label: - ':' TOK_ID { + TOK_COL TOK_ID { $$ = $2; } | %empty { - $$ = NULL; + $$ = nullptr; }; opt_sva_label: - TOK_SVA_LABEL ':' { + TOK_SVA_LABEL TOK_COL { $$ = $1; } | %empty { - $$ = NULL; + $$ = nullptr; }; opt_property: @@ -2461,21 +2501,19 @@ opt_property: modport_stmt: TOK_MODPORT TOK_ID { - AstNode *modport = new AstNode(AST_MODPORT); - ast_stack.back()->children.push_back(modport); - ast_stack.push_back(modport); + AstNode* modport = extra->pushChild(std::make_unique(AST_MODPORT)); modport->str = *$2; - delete $2; + } modport_args_opt { - ast_stack.pop_back(); - log_assert(ast_stack.size() == 2); - } ';' + extra->ast_stack.pop_back(); + log_assert(extra->ast_stack.size() == 2); + } TOK_SEMICOL modport_args_opt: - '(' ')' | '(' modport_args optional_comma ')'; + TOK_LPAREN TOK_RPAREN | TOK_LPAREN modport_args optional_comma TOK_RPAREN; modport_args: - modport_arg | modport_args ',' modport_arg; + modport_arg | modport_args TOK_COMMA modport_arg; modport_arg: modport_type_token modport_member | @@ -2483,222 +2521,174 @@ modport_arg: modport_member: TOK_ID { - AstNode *modport_member = new AstNode(AST_MODPORTMEMBER); - ast_stack.back()->children.push_back(modport_member); + AstNode* modport_member = extra->saveChild(std::make_unique(AST_MODPORTMEMBER)); modport_member->str = *$1; - modport_member->is_input = current_modport_input; - modport_member->is_output = current_modport_output; - delete $1; + modport_member->is_input = extra->current_modport_input; + modport_member->is_output = extra->current_modport_output; + } modport_type_token: - TOK_INPUT {current_modport_input = 1; current_modport_output = 0;} | TOK_OUTPUT {current_modport_input = 0; current_modport_output = 1;} + TOK_INPUT {extra->current_modport_input = 1; extra->current_modport_output = 0;} | TOK_OUTPUT {extra->current_modport_input = 0; extra->current_modport_output = 1;} assert: - opt_sva_label TOK_ASSERT opt_property '(' expr ')' ';' { - if (noassert_mode) { - delete $5; + opt_sva_label TOK_ASSERT opt_property TOK_LPAREN expr TOK_RPAREN TOK_SEMICOL { + if (mode->noassert) { + } else { - AstNode *node = new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5); + AstNode* node = extra->saveChild(std::make_unique(mode->assume_asserts ? AST_ASSUME : AST_ASSERT, std::move($5))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @6); if ($1 != nullptr) node->str = *$1; - ast_stack.back()->children.push_back(node); } - if ($1 != nullptr) - delete $1; } | - opt_sva_label TOK_ASSUME opt_property '(' expr ')' ';' { - if (noassume_mode) { - delete $5; + opt_sva_label TOK_ASSUME opt_property TOK_LPAREN expr TOK_RPAREN TOK_SEMICOL { + if (mode->noassume) { } else { - AstNode *node = new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $5); + AstNode* node = extra->saveChild(std::make_unique(mode->assert_assumes ? AST_ASSERT : AST_ASSUME, std::move($5))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @6); if ($1 != nullptr) node->str = *$1; - ast_stack.back()->children.push_back(node); } - if ($1 != nullptr) - delete $1; } | - opt_sva_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' { - if (noassert_mode) { - delete $6; + opt_sva_label TOK_ASSERT opt_property TOK_LPAREN TOK_EVENTUALLY expr TOK_RPAREN TOK_SEMICOL { + if (mode->noassert) { } else { - AstNode *node = new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6); + AstNode* node = extra->saveChild(std::make_unique(mode->assume_asserts ? AST_FAIR : AST_LIVE, std::move($6))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @7); if ($1 != nullptr) node->str = *$1; - ast_stack.back()->children.push_back(node); } - if ($1 != nullptr) - delete $1; } | - opt_sva_label TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' { - if (noassume_mode) { - delete $6; + opt_sva_label TOK_ASSUME opt_property TOK_LPAREN TOK_EVENTUALLY expr TOK_RPAREN TOK_SEMICOL { + if (mode->noassume) { } else { - AstNode *node = new AstNode(assert_assumes_mode ? AST_LIVE : AST_FAIR, $6); + AstNode* node = extra->saveChild(std::make_unique(mode->assert_assumes ? AST_LIVE : AST_FAIR, std::move($6))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @7); if ($1 != nullptr) node->str = *$1; - ast_stack.back()->children.push_back(node); } - if ($1 != nullptr) - delete $1; } | - opt_sva_label TOK_COVER opt_property '(' expr ')' ';' { - AstNode *node = new AstNode(AST_COVER, $5); + opt_sva_label TOK_COVER opt_property TOK_LPAREN expr TOK_RPAREN TOK_SEMICOL { + AstNode* node = extra->saveChild(std::make_unique(AST_COVER, std::move($5))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @6); if ($1 != nullptr) { node->str = *$1; - delete $1; } - ast_stack.back()->children.push_back(node); } | - opt_sva_label TOK_COVER opt_property '(' ')' ';' { - AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false)); + opt_sva_label TOK_COVER opt_property TOK_LPAREN TOK_RPAREN TOK_SEMICOL { + AstNode* node = extra->saveChild(std::make_unique(AST_COVER, AstNode::mkconst_int(1, false))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @5); if ($1 != nullptr) { node->str = *$1; - delete $1; } - ast_stack.back()->children.push_back(node); } | - opt_sva_label TOK_COVER ';' { - AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false)); + opt_sva_label TOK_COVER TOK_SEMICOL { + AstNode* node = extra->saveChild(std::make_unique(AST_COVER, AstNode::mkconst_int(1, false))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @2); if ($1 != nullptr) { node->str = *$1; - delete $1; } - ast_stack.back()->children.push_back(node); } | - opt_sva_label TOK_RESTRICT opt_property '(' expr ')' ';' { - if (norestrict_mode) { - delete $5; + opt_sva_label TOK_RESTRICT opt_property TOK_LPAREN expr TOK_RPAREN TOK_SEMICOL { + if (mode->norestrict) { } else { - AstNode *node = new AstNode(AST_ASSUME, $5); + AstNode* node = extra->saveChild(std::make_unique(AST_ASSUME, std::move($5))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @6); if ($1 != nullptr) node->str = *$1; - ast_stack.back()->children.push_back(node); } if (!$3) - log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n"); - if ($1 != nullptr) - delete $1; + log_file_warning(current_filename, @$.begin.line, "SystemVerilog does not allow \"restrict\" without \"property\".\n"); } | - opt_sva_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' { - if (norestrict_mode) { - delete $6; + opt_sva_label TOK_RESTRICT opt_property TOK_LPAREN TOK_EVENTUALLY expr TOK_RPAREN TOK_SEMICOL { + if (mode->norestrict) { } else { - AstNode *node = new AstNode(AST_FAIR, $6); + AstNode* node = extra->saveChild(std::make_unique(AST_FAIR, std::move($6))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @7); if ($1 != nullptr) node->str = *$1; - ast_stack.back()->children.push_back(node); } if (!$3) - log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n"); - if ($1 != nullptr) - delete $1; + log_file_warning(current_filename, @$.begin.line, "SystemVerilog does not allow \"restrict\" without \"property\".\n"); }; assert_property: - opt_sva_label TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' { - AstNode *node = new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5); + opt_sva_label TOK_ASSERT TOK_PROPERTY TOK_LPAREN expr TOK_RPAREN TOK_SEMICOL { + AstNode* node = extra->saveChild(std::make_unique(mode->assume_asserts ? AST_ASSUME : AST_ASSERT, std::move($5))); SET_AST_NODE_LOC(node, @1, @6); - ast_stack.back()->children.push_back(node); if ($1 != nullptr) { - ast_stack.back()->children.back()->str = *$1; - delete $1; + extra->ast_stack.back()->children.back()->str = *$1; } } | - opt_sva_label TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' { - AstNode *node = new AstNode(AST_ASSUME, $5); + opt_sva_label TOK_ASSUME TOK_PROPERTY TOK_LPAREN expr TOK_RPAREN TOK_SEMICOL { + AstNode* node = extra->saveChild(std::make_unique(AST_ASSUME, std::move($5))); SET_AST_NODE_LOC(node, @1, @6); - ast_stack.back()->children.push_back(node); if ($1 != nullptr) { - ast_stack.back()->children.back()->str = *$1; - delete $1; + extra->ast_stack.back()->children.back()->str = *$1; } } | - opt_sva_label TOK_ASSERT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { - AstNode *node = new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6); + opt_sva_label TOK_ASSERT TOK_PROPERTY TOK_LPAREN TOK_EVENTUALLY expr TOK_RPAREN TOK_SEMICOL { + AstNode* node = extra->saveChild(std::make_unique(mode->assume_asserts ? AST_FAIR : AST_LIVE, std::move($6))); SET_AST_NODE_LOC(node, @1, @7); - ast_stack.back()->children.push_back(node); if ($1 != nullptr) { - ast_stack.back()->children.back()->str = *$1; - delete $1; + extra->ast_stack.back()->children.back()->str = *$1; } } | - opt_sva_label TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { - AstNode *node = new AstNode(AST_FAIR, $6); + opt_sva_label TOK_ASSUME TOK_PROPERTY TOK_LPAREN TOK_EVENTUALLY expr TOK_RPAREN TOK_SEMICOL { + AstNode* node = extra->saveChild(std::make_unique(AST_FAIR, std::move($6))); SET_AST_NODE_LOC(node, @1, @7); - ast_stack.back()->children.push_back(node); if ($1 != nullptr) { - ast_stack.back()->children.back()->str = *$1; - delete $1; + extra->ast_stack.back()->children.back()->str = *$1; } } | - opt_sva_label TOK_COVER TOK_PROPERTY '(' expr ')' ';' { - AstNode *node = new AstNode(AST_COVER, $5); + opt_sva_label TOK_COVER TOK_PROPERTY TOK_LPAREN expr TOK_RPAREN TOK_SEMICOL { + AstNode* node = extra->saveChild(std::make_unique(AST_COVER, std::move($5))); SET_AST_NODE_LOC(node, @1, @6); - ast_stack.back()->children.push_back(node); if ($1 != nullptr) { - ast_stack.back()->children.back()->str = *$1; - delete $1; + extra->ast_stack.back()->children.back()->str = *$1; } } | - opt_sva_label TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' { - if (norestrict_mode) { - delete $5; + opt_sva_label TOK_RESTRICT TOK_PROPERTY TOK_LPAREN expr TOK_RPAREN TOK_SEMICOL { + if (mode->norestrict) { } else { - AstNode *node = new AstNode(AST_ASSUME, $5); + AstNode* node = extra->saveChild(std::make_unique(AST_ASSUME, std::move($5))); SET_AST_NODE_LOC(node, @1, @6); - ast_stack.back()->children.push_back(node); if ($1 != nullptr) { - ast_stack.back()->children.back()->str = *$1; - delete $1; + extra->ast_stack.back()->children.back()->str = *$1; } } } | - opt_sva_label TOK_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { - if (norestrict_mode) { - delete $6; + opt_sva_label TOK_RESTRICT TOK_PROPERTY TOK_LPAREN TOK_EVENTUALLY expr TOK_RPAREN TOK_SEMICOL { + if (mode->norestrict) { } else { - AstNode *node = new AstNode(AST_FAIR, $6); + AstNode* node = extra->saveChild(std::make_unique(AST_FAIR, std::move($6))); SET_AST_NODE_LOC(node, @1, @7); - ast_stack.back()->children.push_back(node); if ($1 != nullptr) { - ast_stack.back()->children.back()->str = *$1; - delete $1; + extra->ast_stack.back()->children.back()->str = *$1; } } }; simple_behavioral_stmt: - attr lvalue '=' delay expr { - AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, $5); - ast_stack.back()->children.push_back(node); + attr lvalue TOK_EQ delay expr { + AstNode* node = extra->saveChild(std::make_unique(AST_ASSIGN_EQ, std::move($2), std::move($5))); SET_AST_NODE_LOC(node, @2, @5); append_attr(node, $1); } | attr lvalue attr inc_or_dec_op { - addIncOrDecStmt($1, $2, $3, $4, @1, @4); + extra->addIncOrDecStmt($1, std::move($2), $3, $4, @1, @4); } | attr inc_or_dec_op attr lvalue { - addIncOrDecStmt($1, $4, $3, $2, @1, @4); + extra->addIncOrDecStmt($1, std::move($4), $3, $2, @1, @4); } | attr lvalue OP_LE delay expr { - AstNode *node = new AstNode(AST_ASSIGN_LE, $2, $5); - ast_stack.back()->children.push_back(node); + AstNode* node = extra->saveChild(std::make_unique(AST_ASSIGN_LE, std::move($2), std::move($5))); SET_AST_NODE_LOC(node, @2, @5); append_attr(node, $1); } | attr lvalue asgn_binop delay expr { - addAsgnBinopStmt($1, $2, $3, $5, @2, @5); + (void)extra->addAsgnBinopStmt($1, std::move($2), $3, std::move($5), @2, @5); }; asgn_binop: @@ -2722,202 +2712,184 @@ inc_or_dec_op: TOK_DECREMENT { $$ = AST_SUB; } ; for_initialization: - TOK_ID '=' expr { - AstNode *ident = new AstNode(AST_IDENTIFIER); + TOK_ID TOK_EQ expr { + auto ident = std::make_unique(AST_IDENTIFIER); ident->str = *$1; - AstNode *node = new AstNode(AST_ASSIGN_EQ, ident, $3); - ast_stack.back()->children.push_back(node); - SET_AST_NODE_LOC(node, @1, @3); - delete $1; + auto node = std::make_unique(AST_ASSIGN_EQ, std::move(ident), std::move($3)); + SET_AST_NODE_LOC(node.get(), @1, @3); + extra->ast_stack.back()->children.push_back(std::move(node)); } | non_io_wire_type range TOK_ID { - frontend_verilog_yyerror("For loop variable declaration is missing initialization!"); + lexer->err("For loop variable declaration is missing initialization!"); } | - non_io_wire_type range TOK_ID '=' expr { - if (!sv_mode) - frontend_verilog_yyerror("For loop inline variable declaration is only supported in SystemVerilog mode!"); + non_io_wire_type range TOK_ID TOK_EQ expr { + if (!mode->sv) + lexer->err("For loop inline variable declaration is only supported in SystemVerilog mode!"); // loop variable declaration - AstNode *wire = $1; - AstNode *range = checkRange(wire, $2); + auto wire = std::move($1); + auto range = checkRange(wire.get(), std::move($2)); + SET_AST_NODE_LOC(wire.get(), @1, @3); + SET_AST_NODE_LOC(range.get(), @2, @2); if (range != nullptr) - wire->children.push_back(range); - SET_AST_NODE_LOC(wire, @1, @3); - SET_AST_NODE_LOC(range, @2, @2); + wire->children.push_back(std::move(range)); - AstNode *ident = new AstNode(AST_IDENTIFIER); + auto ident = std::make_unique(AST_IDENTIFIER); ident->str = *$3; wire->str = *$3; - delete $3; - AstNode *loop = ast_stack.back(); - AstNode *parent = ast_stack.at(ast_stack.size() - 2); - log_assert(parent->children.back() == loop); + AstNode *parent = extra->ast_stack.at(extra->ast_stack.size() - 2); + auto& loop = parent->children.back(); + log_assert(extra->ast_stack.back() == loop.get()); // loop variable initialization - AstNode *asgn = new AstNode(AST_ASSIGN_EQ, ident, $5); - loop->children.push_back(asgn); - SET_AST_NODE_LOC(asgn, @3, @5); - SET_AST_NODE_LOC(ident, @3, @3); + SET_AST_NODE_LOC(ident.get(), @3, @3); + auto asgn = std::make_unique(AST_ASSIGN_EQ, std::move(ident), std::move($5)); + SET_AST_NODE_LOC(asgn.get(), @3, @5); + loop->children.push_back(std::move(asgn)); // inject a wrapping block to declare the loop variable and // contain the current loop - AstNode *wrapper = new AstNode(AST_BLOCK); + auto wrapper = std::make_unique(AST_BLOCK); wrapper->str = "$fordecl_block$" + std::to_string(autoidx++); - wrapper->children.push_back(wire); - wrapper->children.push_back(loop); - parent->children.back() = wrapper; // replaces `loop` + wrapper->children.push_back(std::move(wire)); + wrapper->children.push_back(std::move(loop)); + parent->children.back() = std::move(wrapper); }; // this production creates the obligatory if-else shift/reduce conflict behavioral_stmt: defattr | assert | wire_decl | param_decl | localparam_decl | typedef_decl | non_opt_delay behavioral_stmt | - simple_behavioral_stmt ';' | - attr ';' { + simple_behavioral_stmt TOK_SEMICOL | + attr TOK_SEMICOL { free_attr($1); } | attr hierarchical_id { - AstNode *node = new AstNode(AST_TCALL); + AstNode* node = extra->pushChild(std::make_unique(AST_TCALL)); node->str = *$2; - delete $2; - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); append_attr(node, $1); - } opt_arg_list ';'{ - SET_AST_NODE_LOC(ast_stack.back(), @2, @5); - ast_stack.pop_back(); + } opt_arg_list TOK_SEMICOL{ + SET_AST_NODE_LOC(extra->ast_stack.back(), @2, @5); + extra->ast_stack.pop_back(); } | attr TOK_MSG_TASKS { - AstNode *node = new AstNode(AST_TCALL); + AstNode* node = extra->pushChild(std::make_unique(AST_TCALL)); node->str = *$2; - delete $2; - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); append_attr(node, $1); - } opt_arg_list ';'{ - SET_AST_NODE_LOC(ast_stack.back(), @2, @5); - ast_stack.pop_back(); + } opt_arg_list TOK_SEMICOL{ + SET_AST_NODE_LOC(extra->ast_stack.back(), @2, @5); + extra->ast_stack.pop_back(); } | attr TOK_BEGIN { - enterTypeScope(); + extra->enterTypeScope(); } opt_label { - AstNode *node = new AstNode(AST_BLOCK); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); + AstNode* node = extra->pushChild(std::make_unique(AST_BLOCK)); append_attr(node, $1); - if ($4 != NULL) + if ($4 != nullptr) node->str = *$4; } behavioral_stmt_list TOK_END opt_label { - exitTypeScope(); - checkLabelsMatch("Begin label", $4, $8); - AstNode *node = ast_stack.back(); + extra->exitTypeScope(); + checkLabelsMatch(@8, "Begin label", $4, $8); + AstNode *node = extra->ast_stack.back(); // In SystemVerilog, unnamed blocks with block item declarations // create an implicit hierarchy scope - if (sv_mode && node->str.empty()) - for (const AstNode* child : node->children) + if (mode->sv && node->str.empty()) + for (auto& child : node->children) if (child->type == AST_WIRE || child->type == AST_MEMORY || child->type == AST_PARAMETER || child->type == AST_LOCALPARAM || child->type == AST_TYPEDEF) { node->str = "$unnamed_block$" + std::to_string(autoidx++); break; } - SET_AST_NODE_LOC(ast_stack.back(), @2, @8); - delete $4; - delete $8; - ast_stack.pop_back(); + SET_AST_NODE_LOC(extra->ast_stack.back(), @2, @8); + extra->ast_stack.pop_back(); } | - attr TOK_FOR '(' { - AstNode *node = new AstNode(AST_FOR); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); + attr TOK_FOR TOK_LPAREN { + AstNode* node = extra->pushChild(std::make_unique(AST_FOR)); append_attr(node, $1); - } for_initialization ';' expr { - ast_stack.back()->children.push_back($7); - } ';' simple_behavioral_stmt ')' { - AstNode *block = new AstNode(AST_BLOCK); + } for_initialization TOK_SEMICOL expr { + extra->ast_stack.back()->children.push_back(std::move($7)); + } TOK_SEMICOL simple_behavioral_stmt TOK_RPAREN { + AstNode* block = extra->pushChild(std::make_unique(AST_BLOCK)); block->str = "$for_loop$" + std::to_string(autoidx++); - ast_stack.back()->children.push_back(block); - ast_stack.push_back(block); } behavioral_stmt { - SET_AST_NODE_LOC(ast_stack.back(), @13, @13); - ast_stack.pop_back(); - SET_AST_NODE_LOC(ast_stack.back(), @2, @13); - ast_stack.pop_back(); + SET_AST_NODE_LOC(extra->ast_stack.back(), @13, @13); + extra->ast_stack.pop_back(); + SET_AST_NODE_LOC(extra->ast_stack.back(), @2, @13); + extra->ast_stack.pop_back(); } | - attr TOK_WHILE '(' expr ')' { - AstNode *node = new AstNode(AST_WHILE); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); + attr TOK_WHILE TOK_LPAREN expr TOK_RPAREN { + AstNode* node = extra->pushChild(std::make_unique(AST_WHILE)); append_attr(node, $1); - AstNode *block = new AstNode(AST_BLOCK); - ast_stack.back()->children.push_back($4); - ast_stack.back()->children.push_back(block); - ast_stack.push_back(block); + auto block_owned = std::make_unique(AST_BLOCK); + auto* block = block_owned.get(); + extra->ast_stack.back()->children.push_back(std::move($4)); + extra->ast_stack.back()->children.push_back(std::move(block_owned)); + extra->ast_stack.push_back(block); } behavioral_stmt { - SET_AST_NODE_LOC(ast_stack.back(), @7, @7); - ast_stack.pop_back(); - ast_stack.pop_back(); + SET_AST_NODE_LOC(extra->ast_stack.back(), @7, @7); + extra->ast_stack.pop_back(); + extra->ast_stack.pop_back(); } | - attr TOK_REPEAT '(' expr ')' { - AstNode *node = new AstNode(AST_REPEAT); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); + attr TOK_REPEAT TOK_LPAREN expr TOK_RPAREN { + AstNode* node = extra->pushChild(std::make_unique(AST_REPEAT)); append_attr(node, $1); - AstNode *block = new AstNode(AST_BLOCK); - ast_stack.back()->children.push_back($4); - ast_stack.back()->children.push_back(block); - ast_stack.push_back(block); + auto block_owned = std::make_unique(AST_BLOCK); + auto* block = block_owned.get(); + extra->ast_stack.back()->children.push_back(std::move($4)); + extra->ast_stack.back()->children.push_back(std::move(block_owned)); + extra->ast_stack.push_back(block); } behavioral_stmt { - SET_AST_NODE_LOC(ast_stack.back(), @7, @7); - ast_stack.pop_back(); - ast_stack.pop_back(); + SET_AST_NODE_LOC(extra->ast_stack.back(), @7, @7); + extra->ast_stack.pop_back(); + extra->ast_stack.pop_back(); } | - if_attr TOK_IF '(' expr ')' { - AstNode *node = 0; - AstNode *context = ast_stack.back(); + if_attr TOK_IF TOK_LPAREN expr TOK_RPAREN { + std::unique_ptr node_owned; + AstNode* node = nullptr; + AstNode *context = extra->ast_stack.back(); if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if)) { - AstNode *outer = ast_stack[ast_stack.size() - 2]; + AstNode *outer = extra->ast_stack[extra->ast_stack.size() - 2]; log_assert (outer && outer->type == AST_CASE); if (outer->get_bool_attribute(ID::parallel_case)) { // parallel "else if": append condition to outer "if" node = outer; log_assert (node->children.size()); - delete node->children.back(); node->children.pop_back(); } else if (outer->get_bool_attribute(ID::full_case)) (*$1)[ID::full_case] = AstNode::mkconst_int(1, false); } - AstNode *expr = new AstNode(AST_REDUCE_BOOL, $4); + auto expr = std::make_unique(AST_REDUCE_BOOL, std::move($4)); if (!node) { // not parallel "else if": begin new construction - node = new AstNode(AST_CASE); + node_owned = std::make_unique(AST_CASE); + node = node_owned.get(); append_attr(node, $1); - ast_stack.back()->children.push_back(node); - node->children.push_back(node->get_bool_attribute(ID::parallel_case) ? AstNode::mkconst_int(1, false, 1) : expr); + node->children.push_back(node->get_bool_attribute(ID::parallel_case) ? AstNode::mkconst_int(1, false, 1) : expr->clone()); + extra->ast_stack.back()->children.push_back(std::move(node_owned)); } - AstNode *block = new AstNode(AST_BLOCK); - AstNode *cond = new AstNode(AST_COND, node->get_bool_attribute(ID::parallel_case) ? expr : AstNode::mkconst_int(1, false, 1), block); - SET_AST_NODE_LOC(cond, @4, @4); - node->children.push_back(cond); - ast_stack.push_back(node); - ast_stack.push_back(block); + auto block_owned = std::make_unique(AST_BLOCK); + auto* block = block_owned.get(); + auto cond_owned = std::make_unique(AST_COND, node->get_bool_attribute(ID::parallel_case) ? std::move(expr) : AstNode::mkconst_int(1, false, 1), std::move(block_owned)); + SET_AST_NODE_LOC(cond_owned.get(), @4, @4); + node->children.push_back(std::move(cond_owned)); + extra->ast_stack.push_back(node); + extra->ast_stack.push_back(block); } behavioral_stmt { - SET_AST_NODE_LOC(ast_stack.back(), @7, @7); + SET_AST_NODE_LOC(extra->ast_stack.back(), @7, @7); } optional_else { - ast_stack.pop_back(); - SET_AST_NODE_LOC(ast_stack.back(), @2, @9); - ast_stack.pop_back(); + extra->ast_stack.pop_back(); + SET_AST_NODE_LOC(extra->ast_stack.back(), @2, @9); + extra->ast_stack.pop_back(); } | - case_attr case_type '(' expr ')' { - AstNode *node = new AstNode(AST_CASE, $4); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); + case_attr case_type TOK_LPAREN expr TOK_RPAREN { + AstNode* node = extra->pushChild(std::make_unique(AST_CASE, std::move($4))); append_attr(node, $1); - SET_AST_NODE_LOC(ast_stack.back(), @4, @4); + SET_AST_NODE_LOC(extra->ast_stack.back(), @4, @4); } opt_synopsys_attr case_body TOK_ENDCASE { - SET_AST_NODE_LOC(ast_stack.back(), @2, @9); - case_type_stack.pop_back(); - ast_stack.pop_back(); + SET_AST_NODE_LOC(extra->ast_stack.back(), @2, @9); + extra->case_type_stack.pop_back(); + extra->ast_stack.pop_back(); }; if_attr: @@ -2925,23 +2897,23 @@ if_attr: $$ = $1; } | attr TOK_UNIQUE0 { - AstNode *context = ast_stack.back(); + AstNode *context = extra->ast_stack.back(); if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if)) - frontend_verilog_yyerror("unique0 keyword cannot be used for 'else if' branch."); + lexer->err("unique0 keyword cannot be used for 'else if' branch."); (*$1)[ID::parallel_case] = AstNode::mkconst_int(1, false); $$ = $1; } | attr TOK_PRIORITY { - AstNode *context = ast_stack.back(); + AstNode *context = extra->ast_stack.back(); if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if)) - frontend_verilog_yyerror("priority keyword cannot be used for 'else if' branch."); + lexer->err("priority keyword cannot be used for 'else if' branch."); (*$1)[ID::full_case] = AstNode::mkconst_int(1, false); $$ = $1; } | attr TOK_UNIQUE { - AstNode *context = ast_stack.back(); + AstNode *context = extra->ast_stack.back(); if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if)) - frontend_verilog_yyerror("unique keyword cannot be used for 'else if' branch."); + lexer->err("unique keyword cannot be used for 'else if' branch."); (*$1)[ID::full_case] = AstNode::mkconst_int(1, false); (*$1)[ID::parallel_case] = AstNode::mkconst_int(1, false); $$ = $1; @@ -2967,23 +2939,23 @@ case_attr: case_type: TOK_CASE { - case_type_stack.push_back(0); + extra->case_type_stack.push_back(0); } | TOK_CASEX { - case_type_stack.push_back('x'); + extra->case_type_stack.push_back('x'); } | TOK_CASEZ { - case_type_stack.push_back('z'); + extra->case_type_stack.push_back('z'); }; opt_synopsys_attr: opt_synopsys_attr TOK_SYNOPSYS_FULL_CASE { - if (ast_stack.back()->attributes.count(ID::full_case) == 0) - ast_stack.back()->attributes[ID::full_case] = AstNode::mkconst_int(1, false); + if (extra->ast_stack.back()->attributes.count(ID::full_case) == 0) + extra->ast_stack.back()->attributes[ID::full_case] = AstNode::mkconst_int(1, false); } | opt_synopsys_attr TOK_SYNOPSYS_PARALLEL_CASE { - if (ast_stack.back()->attributes.count(ID::parallel_case) == 0) - ast_stack.back()->attributes[ID::parallel_case] = AstNode::mkconst_int(1, false); + if (extra->ast_stack.back()->attributes.count(ID::parallel_case) == 0) + extra->ast_stack.back()->attributes[ID::parallel_case] = AstNode::mkconst_int(1, false); } | %empty; @@ -2993,16 +2965,18 @@ behavioral_stmt_list: optional_else: TOK_ELSE { - AstNode *block = new AstNode(AST_BLOCK); - block->attributes[ID::promoted_if] = AstNode::mkconst_int(1, false ); - AstNode *cond = new AstNode(AST_COND, new AstNode(AST_DEFAULT), block); + extra->ast_stack.pop_back(); + auto block_owned = std::make_unique(AST_BLOCK); + auto* block = block_owned.get(); + block->attributes[ID::promoted_if] = AstNode::mkconst_int(1, false); + AstNode* cond = extra->saveChild( + std::make_unique(AST_COND, + std::make_unique(AST_DEFAULT), + std::move(block_owned))); + extra->ast_stack.push_back(block); SET_AST_NODE_LOC(cond, @1, @1); - - ast_stack.pop_back(); - ast_stack.back()->children.push_back(cond); - ast_stack.push_back(block); } behavioral_stmt { - SET_AST_NODE_LOC(ast_stack.back(), @3, @3); + SET_AST_NODE_LOC(extra->ast_stack.back(), @3, @3); } | %empty %prec FAKE_THEN; @@ -3012,21 +2986,17 @@ case_body: case_item: { - AstNode *node = new AstNode( - case_type_stack.size() && case_type_stack.back() == 'x' ? AST_CONDX : - case_type_stack.size() && case_type_stack.back() == 'z' ? AST_CONDZ : AST_COND); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); + (void)extra->pushChild(std::make_unique( + extra->case_type_stack.size() && extra->case_type_stack.back() == 'x' ? AST_CONDX : + extra->case_type_stack.size() && extra->case_type_stack.back() == 'z' ? AST_CONDZ : AST_COND)); } case_select { - AstNode *block = new AstNode(AST_BLOCK); - ast_stack.back()->children.push_back(block); - ast_stack.push_back(block); - case_type_stack.push_back(0); + (void)extra->pushChild(std::make_unique(AST_BLOCK)); + extra->case_type_stack.push_back(0); } behavioral_stmt { - case_type_stack.pop_back(); - SET_AST_NODE_LOC(ast_stack.back(), @4, @4); - ast_stack.pop_back(); - ast_stack.pop_back(); + extra->case_type_stack.pop_back(); + SET_AST_NODE_LOC(extra->ast_stack.back(), @4, @4); + extra->ast_stack.pop_back(); + extra->ast_stack.pop_back(); }; gen_case_body: @@ -3035,87 +3005,78 @@ gen_case_body: gen_case_item: { - AstNode *node = new AstNode( - case_type_stack.size() && case_type_stack.back() == 'x' ? AST_CONDX : - case_type_stack.size() && case_type_stack.back() == 'z' ? AST_CONDZ : AST_COND); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); + (void)extra->pushChild(std::make_unique( + extra->case_type_stack.size() && extra->case_type_stack.back() == 'x' ? AST_CONDX : + extra->case_type_stack.size() && extra->case_type_stack.back() == 'z' ? AST_CONDZ : AST_COND)); } case_select { - case_type_stack.push_back(0); - SET_AST_NODE_LOC(ast_stack.back(), @2, @2); + extra->case_type_stack.push_back(0); + SET_AST_NODE_LOC(extra->ast_stack.back(), @2, @2); } gen_stmt_block { - case_type_stack.pop_back(); - ast_stack.pop_back(); + extra->case_type_stack.pop_back(); + extra->ast_stack.pop_back(); }; case_select: - case_expr_list ':' | + case_expr_list TOK_COL | TOK_DEFAULT; case_expr_list: TOK_DEFAULT { - AstNode *node = new AstNode(AST_DEFAULT); + AstNode* node = extra->saveChild(std::make_unique(AST_DEFAULT)); SET_AST_NODE_LOC(node, @1, @1); - ast_stack.back()->children.push_back(node); } | TOK_SVA_LABEL { - AstNode *node = new AstNode(AST_IDENTIFIER); + AstNode* node = extra->pushChild(std::make_unique(AST_IDENTIFIER)); SET_AST_NODE_LOC(node, @1, @1); - ast_stack.back()->children.push_back(node); - ast_stack.back()->children.back()->str = *$1; - delete $1; } | expr { - ast_stack.back()->children.push_back($1); + extra->ast_stack.back()->children.push_back(std::move($1)); } | - case_expr_list ',' expr { - ast_stack.back()->children.push_back($3); + case_expr_list TOK_COMMA expr { + extra->ast_stack.back()->children.push_back(std::move($3)); }; rvalue: - hierarchical_id '[' expr ']' '.' rvalue { - $$ = new AstNode(AST_PREFIX, $3, $6); + hierarchical_id TOK_LBRA expr TOK_RBRA TOK_DOT rvalue { + $$ = std::make_unique(AST_PREFIX, std::move($3), std::move($6)); $$->str = *$1; - SET_AST_NODE_LOC($$, @1, @6); - delete $1; + SET_AST_NODE_LOC($$.get(), @1, @6); } | hierarchical_id range { - $$ = new AstNode(AST_IDENTIFIER, $2); + $$ = std::make_unique(AST_IDENTIFIER, std::move($2)); $$->str = *$1; - SET_AST_NODE_LOC($$, @1, @1); - delete $1; + SET_AST_NODE_LOC($$.get(), @1, @1); if ($2 == nullptr && ($$->str == "\\$initstate" || $$->str == "\\$anyconst" || $$->str == "\\$anyseq" || $$->str == "\\$allconst" || $$->str == "\\$allseq")) $$->type = AST_FCALL; } | hierarchical_id non_opt_multirange { - $$ = new AstNode(AST_IDENTIFIER, $2); + $$ = std::make_unique(AST_IDENTIFIER, std::move($2)); $$->str = *$1; - SET_AST_NODE_LOC($$, @1, @1); - delete $1; + SET_AST_NODE_LOC($$.get(), @1, @1); }; lvalue: rvalue { - $$ = $1; + $$ = std::move($1); } | - '{' lvalue_concat_list '}' { - $$ = $2; + TOK_LCURL lvalue_concat_list TOK_RCURL { + $$ = std::move($2); }; lvalue_concat_list: expr { - $$ = new AstNode(AST_CONCAT); - $$->children.push_back($1); + $$ = std::make_unique(AST_CONCAT); + $$->children.push_back(std::move($1)); } | - expr ',' lvalue_concat_list { - $$ = $3; - $$->children.push_back($1); + expr TOK_COMMA lvalue_concat_list { + $$ = std::move($3); + $$->children.push_back(std::move($1)); }; opt_arg_list: - '(' arg_list optional_comma ')' | + TOK_LPAREN arg_list optional_comma TOK_RPAREN | %empty; arg_list: @@ -3124,11 +3085,11 @@ arg_list: arg_list2: single_arg | - arg_list ',' single_arg; + arg_list TOK_COMMA single_arg; single_arg: expr { - ast_stack.back()->children.push_back($1); + extra->ast_stack.back()->children.push_back(std::move($1)); }; module_gen_body: @@ -3138,111 +3099,92 @@ module_gen_body: gen_stmt_or_module_body_stmt: gen_stmt | module_body_stmt | - attr ';' { + attr TOK_SEMICOL { free_attr($1); }; genvar_identifier: TOK_ID { - $$ = new AstNode(AST_IDENTIFIER); + $$ = std::make_unique(AST_IDENTIFIER); $$->str = *$1; - delete $1; }; genvar_initialization: TOK_GENVAR genvar_identifier { - frontend_verilog_yyerror("Generate for loop variable declaration is missing initialization!"); + lexer->err("Generate for loop variable declaration is missing initialization!"); } | - TOK_GENVAR genvar_identifier '=' expr { - if (!sv_mode) - frontend_verilog_yyerror("Generate for loop inline variable declaration is only supported in SystemVerilog mode!"); - AstNode *node = new AstNode(AST_GENVAR); + TOK_GENVAR genvar_identifier TOK_EQ expr { + if (!mode->sv) + lexer->err("Generate for loop inline variable declaration is only supported in SystemVerilog mode!"); + AstNode* node = extra->saveChild(std::make_unique(AST_GENVAR)); node->is_reg = true; node->is_signed = true; node->range_left = 31; node->range_right = 0; node->str = $2->str; node->children.push_back(checkRange(node, nullptr)); - ast_stack.back()->children.push_back(node); SET_AST_NODE_LOC(node, @1, @4); - node = new AstNode(AST_ASSIGN_EQ, $2, $4); - ast_stack.back()->children.push_back(node); + node = extra->saveChild(std::make_unique(AST_ASSIGN_EQ, std::move($2), std::move($4))); SET_AST_NODE_LOC(node, @1, @4); } | - genvar_identifier '=' expr { - AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $3); - ast_stack.back()->children.push_back(node); + genvar_identifier TOK_EQ expr { + AstNode* node = extra->saveChild(std::make_unique(AST_ASSIGN_EQ, std::move($1), std::move($3))); SET_AST_NODE_LOC(node, @1, @3); }; // this production creates the obligatory if-else shift/reduce conflict gen_stmt: - TOK_FOR '(' { - AstNode *node = new AstNode(AST_GENFOR); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); - } genvar_initialization ';' expr { - ast_stack.back()->children.push_back($6); - } ';' simple_behavioral_stmt ')' gen_stmt_block { - SET_AST_NODE_LOC(ast_stack.back(), @1, @11); - rewriteGenForDeclInit(ast_stack.back()); - ast_stack.pop_back(); + TOK_FOR TOK_LPAREN { + (void)extra->pushChild(std::make_unique(AST_GENFOR)); + } genvar_initialization TOK_SEMICOL expr { + extra->ast_stack.back()->children.push_back(std::move($6)); + } TOK_SEMICOL simple_behavioral_stmt TOK_RPAREN gen_stmt_block { + SET_AST_NODE_LOC(extra->ast_stack.back(), @1, @11); + extra->rewriteGenForDeclInit(extra->ast_stack.back()); + extra->ast_stack.pop_back(); } | - TOK_IF '(' expr ')' { - AstNode *node = new AstNode(AST_GENIF); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); - ast_stack.back()->children.push_back($3); + TOK_IF TOK_LPAREN expr TOK_RPAREN { + (void)extra->pushChild(std::make_unique(AST_GENIF)); + extra->ast_stack.back()->children.push_back(std::move($3)); } gen_stmt_block opt_gen_else { - SET_AST_NODE_LOC(ast_stack.back(), @1, @7); - ast_stack.pop_back(); + SET_AST_NODE_LOC(extra->ast_stack.back(), @1, @7); + extra->ast_stack.pop_back(); } | - case_type '(' expr ')' { - AstNode *node = new AstNode(AST_GENCASE, $3); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); + case_type TOK_LPAREN expr TOK_RPAREN { + (void)extra->pushChild(std::make_unique(AST_GENCASE, std::move($3))); } gen_case_body TOK_ENDCASE { - case_type_stack.pop_back(); - SET_AST_NODE_LOC(ast_stack.back(), @1, @7); - ast_stack.pop_back(); + extra->case_type_stack.pop_back(); + SET_AST_NODE_LOC(extra->ast_stack.back(), @1, @7); + extra->ast_stack.pop_back(); } | TOK_MSG_TASKS { - AstNode *node = new AstNode(AST_TECALL); + AstNode* node = extra->pushChild(std::make_unique(AST_TECALL)); node->str = *$1; - delete $1; - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); - } opt_arg_list ';'{ - SET_AST_NODE_LOC(ast_stack.back(), @1, @3); - ast_stack.pop_back(); + } opt_arg_list TOK_SEMICOL{ + SET_AST_NODE_LOC(extra->ast_stack.back(), @1, @3); + extra->ast_stack.pop_back(); }; gen_block: TOK_BEGIN { - enterTypeScope(); + extra->enterTypeScope(); } opt_label { - AstNode *node = new AstNode(AST_GENBLOCK); + AstNode* node = extra->pushChild(std::make_unique(AST_GENBLOCK)); node->str = $3 ? *$3 : std::string(); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); } module_gen_body TOK_END opt_label { - exitTypeScope(); - checkLabelsMatch("Begin label", $3, $7); - delete $3; - delete $7; - SET_AST_NODE_LOC(ast_stack.back(), @1, @7); - ast_stack.pop_back(); + extra->exitTypeScope(); + checkLabelsMatch(@7, "Begin label", $3, $7); + SET_AST_NODE_LOC(extra->ast_stack.back(), @1, @7); + extra->ast_stack.pop_back(); }; // result is wrapped in a genblock only if necessary gen_stmt_block: { - AstNode *node = new AstNode(AST_GENBLOCK); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); + (void)extra->pushChild(std::make_unique(AST_GENBLOCK)); } gen_stmt_or_module_body_stmt { - SET_AST_NODE_LOC(ast_stack.back(), @2, @2); - ast_stack.pop_back(); + SET_AST_NODE_LOC(extra->ast_stack.back(), @2, @2); + extra->ast_stack.pop_back(); } | gen_block; opt_gen_else: @@ -3250,336 +3192,330 @@ opt_gen_else: expr: basic_expr { - $$ = $1; + $$ = std::move($1); } | - basic_expr '?' attr expr ':' expr { - $$ = new AstNode(AST_TERNARY); - $$->children.push_back($1); - $$->children.push_back($4); - $$->children.push_back($6); - SET_AST_NODE_LOC($$, @1, @$); - append_attr($$, $3); + basic_expr TOK_QUE attr expr TOK_COL expr { + $$ = std::make_unique(AST_TERNARY); + $$->children.push_back(std::move($1)); + $$->children.push_back(std::move($4)); + $$->children.push_back(std::move($6)); + SET_AST_NODE_LOC($$.get(), @1, @$); + append_attr($$.get(), $3); } | inc_or_dec_op attr rvalue { - $$ = addIncOrDecExpr($3, $2, $1, @1, @3, false); + $$ = extra->addIncOrDecExpr(std::move($3), $2, $1, @1, @3, false, mode->sv); } | // TODO: Attributes are allowed in the middle here, but they create some // non-trivial conflicts that don't seem worth solving for now. rvalue inc_or_dec_op { - $$ = addIncOrDecExpr($1, nullptr, $2, @1, @2, true); + $$ = extra->addIncOrDecExpr(std::move($1), nullptr, $2, @1, @2, true, mode->sv); }; basic_expr: rvalue { - $$ = $1; + $$ = std::move($1); } | - '(' expr ')' integral_number { + TOK_LPAREN expr TOK_RPAREN integral_number { if ($4->compare(0, 1, "'") != 0) - frontend_verilog_yyerror("Cast operation must be applied on sized constants e.g. () , while %s is not a sized constant.", $4->c_str()); - AstNode *bits = $2; - AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); - if (val == NULL) + lexer->err("Cast operation must be applied on sized constants e.g. () , while %s is not a sized constant.", $4->c_str()); + auto p = make_ConstParser_here(@4); + auto val = p.const2ast(*$4, extra->case_type_stack.size() == 0 ? 0 : extra->case_type_stack.back(), !mode->lib); + if (val == nullptr) log_error("Value conversion failed: `%s'\n", $4->c_str()); - $$ = new AstNode(AST_TO_BITS, bits, val); - delete $4; + $$ = std::make_unique(AST_TO_BITS, std::move($2), std::move(val)); } | hierarchical_id integral_number { if ($2->compare(0, 1, "'") != 0) - frontend_verilog_yyerror("Cast operation must be applied on sized constants, e.g. \'d0, while %s is not a sized constant.", $2->c_str()); - AstNode *bits = new AstNode(AST_IDENTIFIER); + lexer->err("Cast operation must be applied on sized constants, e.g. \'d0, while %s is not a sized constant.", $2->c_str()); + auto bits = std::make_unique(AST_IDENTIFIER); bits->str = *$1; - SET_AST_NODE_LOC(bits, @1, @1); - AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); - SET_AST_NODE_LOC(val, @2, @2); - if (val == NULL) + SET_AST_NODE_LOC(bits.get(), @1, @1); + auto p = make_ConstParser_here(@2); + auto val = p.const2ast(*$2, extra->case_type_stack.size() == 0 ? 0 : extra->case_type_stack.back(), !mode->lib); + SET_AST_NODE_LOC(val.get(), @2, @2); + if (val == nullptr) log_error("Value conversion failed: `%s'\n", $2->c_str()); - $$ = new AstNode(AST_TO_BITS, bits, val); - delete $1; - delete $2; + $$ = std::make_unique(AST_TO_BITS, std::move(bits), std::move(val)); } | integral_number { - $$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); - SET_AST_NODE_LOC($$, @1, @1); - if ($$ == NULL) + auto p = make_ConstParser_here(@1); + $$ = p.const2ast(*$1, extra->case_type_stack.size() == 0 ? 0 : extra->case_type_stack.back(), !mode->lib); + SET_AST_NODE_LOC($$.get(), @1, @1); + if ($$ == nullptr) log_error("Value conversion failed: `%s'\n", $1->c_str()); - delete $1; } | TOK_REALVAL { - $$ = new AstNode(AST_REALVALUE); + $$ = std::make_unique(AST_REALVALUE); char *p = (char*)malloc(GetSize(*$1) + 1), *q; for (int i = 0, j = 0; j < GetSize(*$1); j++) if ((*$1)[j] != '_') p[i++] = (*$1)[j], p[i] = 0; $$->realvalue = strtod(p, &q); - SET_AST_NODE_LOC($$, @1, @1); + SET_AST_NODE_LOC($$.get(), @1, @1); log_assert(*q == 0); - delete $1; free(p); } | TOK_STRING { $$ = AstNode::mkconst_str(*$1); - SET_AST_NODE_LOC($$, @1, @1); - delete $1; + SET_AST_NODE_LOC($$.get(), @1, @1); } | hierarchical_id attr { + // super sketchy! Orphaned pointer in non-owning extra->ast_stack AstNode *node = new AstNode(AST_FCALL); node->str = *$1; - delete $1; - ast_stack.push_back(node); + extra->ast_stack.push_back(node); SET_AST_NODE_LOC(node, @1, @1); append_attr(node, $2); - } '(' arg_list optional_comma ')' { - $$ = ast_stack.back(); - ast_stack.pop_back(); + } TOK_LPAREN arg_list optional_comma TOK_RPAREN { + $$.reset(extra->ast_stack.back()); + extra->ast_stack.pop_back(); } | - TOK_TO_SIGNED attr '(' expr ')' { - $$ = new AstNode(AST_TO_SIGNED, $4); - append_attr($$, $2); + TOK_TO_SIGNED attr TOK_LPAREN expr TOK_RPAREN { + $$ = std::make_unique(AST_TO_SIGNED, std::move($4)); + append_attr($$.get(), $2); } | - TOK_TO_UNSIGNED attr '(' expr ')' { - $$ = new AstNode(AST_TO_UNSIGNED, $4); - append_attr($$, $2); + TOK_TO_UNSIGNED attr TOK_LPAREN expr TOK_RPAREN { + $$ = std::make_unique(AST_TO_UNSIGNED, std::move($4)); + append_attr($$.get(), $2); } | - '(' expr ')' { - $$ = $2; + TOK_LPAREN expr TOK_RPAREN { + $$ = std::move($2); } | - '(' expr ':' expr ':' expr ')' { - delete $2; - $$ = $4; - delete $6; + TOK_LPAREN expr TOK_COL expr TOK_COL expr TOK_RPAREN { + $$ = std::move($4); } | - '{' concat_list '}' { - $$ = $2; + TOK_LCURL concat_list TOK_RCURL { + $$ = std::move($2); } | - '{' expr '{' concat_list '}' '}' { - $$ = new AstNode(AST_REPLICATE, $2, $4); + TOK_LCURL expr TOK_LCURL concat_list TOK_RCURL TOK_RCURL { + $$ = std::make_unique(AST_REPLICATE, std::move($2), std::move($4)); } | - '~' attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_BIT_NOT, $3); - SET_AST_NODE_LOC($$, @1, @3); - append_attr($$, $2); + TOK_TILDE attr basic_expr %prec UNARY_OPS { + $$ = std::make_unique(AST_BIT_NOT, std::move($3)); + SET_AST_NODE_LOC($$.get(), @1, @3); + append_attr($$.get(), $2); } | - basic_expr '&' attr basic_expr { - $$ = new AstNode(AST_BIT_AND, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + basic_expr TOK_AMP attr basic_expr { + $$ = std::make_unique(AST_BIT_AND, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | basic_expr OP_NAND attr basic_expr { - $$ = new AstNode(AST_BIT_NOT, new AstNode(AST_BIT_AND, $1, $4)); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + $$ = std::make_unique(AST_BIT_NOT, std::make_unique(AST_BIT_AND, std::move($1), std::move($4))); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | - basic_expr '|' attr basic_expr { - $$ = new AstNode(AST_BIT_OR, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + basic_expr TOK_PIPE attr basic_expr { + $$ = std::make_unique(AST_BIT_OR, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | basic_expr OP_NOR attr basic_expr { - $$ = new AstNode(AST_BIT_NOT, new AstNode(AST_BIT_OR, $1, $4)); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + $$ = std::make_unique(AST_BIT_NOT, std::make_unique(AST_BIT_OR, std::move($1), std::move($4))); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | - basic_expr '^' attr basic_expr { - $$ = new AstNode(AST_BIT_XOR, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + basic_expr TOK_CARET attr basic_expr { + $$ = std::make_unique(AST_BIT_XOR, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | basic_expr OP_XNOR attr basic_expr { - $$ = new AstNode(AST_BIT_XNOR, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + $$ = std::make_unique(AST_BIT_XNOR, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | - '&' attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_REDUCE_AND, $3); - SET_AST_NODE_LOC($$, @1, @3); - append_attr($$, $2); + TOK_AMP attr basic_expr %prec UNARY_OPS { + $$ = std::make_unique(AST_REDUCE_AND, std::move($3)); + SET_AST_NODE_LOC($$.get(), @1, @3); + append_attr($$.get(), $2); } | OP_NAND attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_REDUCE_AND, $3); - SET_AST_NODE_LOC($$, @1, @3); - append_attr($$, $2); - $$ = new AstNode(AST_LOGIC_NOT, $$); + $$ = std::make_unique(AST_REDUCE_AND, std::move($3)); + SET_AST_NODE_LOC($$.get(), @1, @3); + append_attr($$.get(), $2); + $$ = std::make_unique(AST_LOGIC_NOT, std::move($$)); } | - '|' attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_REDUCE_OR, $3); - SET_AST_NODE_LOC($$, @1, @3); - append_attr($$, $2); + TOK_PIPE attr basic_expr %prec UNARY_OPS { + $$ = std::make_unique(AST_REDUCE_OR, std::move($3)); + SET_AST_NODE_LOC($$.get(), @1, @3); + append_attr($$.get(), std::move($2)); } | OP_NOR attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_REDUCE_OR, $3); - SET_AST_NODE_LOC($$, @1, @3); - append_attr($$, $2); - $$ = new AstNode(AST_LOGIC_NOT, $$); - SET_AST_NODE_LOC($$, @1, @3); + $$ = std::make_unique(AST_REDUCE_OR, std::move($3)); + SET_AST_NODE_LOC($$.get(), @1, @3); + append_attr($$.get(), $2); + $$ = std::make_unique(AST_LOGIC_NOT, std::move($$)); + SET_AST_NODE_LOC($$.get(), @1, @3); } | - '^' attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_REDUCE_XOR, $3); - SET_AST_NODE_LOC($$, @1, @3); - append_attr($$, $2); + TOK_CARET attr basic_expr %prec UNARY_OPS { + $$ = std::make_unique(AST_REDUCE_XOR, std::move($3)); + SET_AST_NODE_LOC($$.get(), @1, @3); + append_attr($$.get(), $2); } | OP_XNOR attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_REDUCE_XNOR, $3); - SET_AST_NODE_LOC($$, @1, @3); - append_attr($$, $2); + $$ = std::make_unique(AST_REDUCE_XNOR, std::move($3)); + SET_AST_NODE_LOC($$.get(), @1, @3); + append_attr($$.get(), $2); } | basic_expr OP_SHL attr basic_expr { - $$ = new AstNode(AST_SHIFT_LEFT, $1, new AstNode(AST_TO_UNSIGNED, $4)); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + $$ = std::make_unique(AST_SHIFT_LEFT, std::move($1), std::make_unique(AST_TO_UNSIGNED, std::move($4))); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | basic_expr OP_SHR attr basic_expr { - $$ = new AstNode(AST_SHIFT_RIGHT, $1, new AstNode(AST_TO_UNSIGNED, $4)); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + $$ = std::make_unique(AST_SHIFT_RIGHT, std::move($1), std::make_unique(AST_TO_UNSIGNED, std::move($4))); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | basic_expr OP_SSHL attr basic_expr { - $$ = new AstNode(AST_SHIFT_SLEFT, $1, new AstNode(AST_TO_UNSIGNED, $4)); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + $$ = std::make_unique(AST_SHIFT_SLEFT, std::move($1), std::make_unique(AST_TO_UNSIGNED, std::move($4))); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | basic_expr OP_SSHR attr basic_expr { - $$ = new AstNode(AST_SHIFT_SRIGHT, $1, new AstNode(AST_TO_UNSIGNED, $4)); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + $$ = std::make_unique(AST_SHIFT_SRIGHT, std::move($1), std::make_unique(AST_TO_UNSIGNED, std::move($4))); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | - basic_expr '<' attr basic_expr { - $$ = new AstNode(AST_LT, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + basic_expr TOK_LT attr basic_expr { + $$ = std::make_unique(AST_LT, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | basic_expr OP_LE attr basic_expr { - $$ = new AstNode(AST_LE, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + $$ = std::make_unique(AST_LE, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | basic_expr OP_EQ attr basic_expr { - $$ = new AstNode(AST_EQ, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + $$ = std::make_unique(AST_EQ, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | basic_expr OP_NE attr basic_expr { - $$ = new AstNode(AST_NE, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + $$ = std::make_unique(AST_NE, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | basic_expr OP_EQX attr basic_expr { - $$ = new AstNode(AST_EQX, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + $$ = std::make_unique(AST_EQX, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | basic_expr OP_NEX attr basic_expr { - $$ = new AstNode(AST_NEX, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + $$ = std::make_unique(AST_NEX, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | basic_expr OP_GE attr basic_expr { - $$ = new AstNode(AST_GE, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + $$ = std::make_unique(AST_GE, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | - basic_expr '>' attr basic_expr { - $$ = new AstNode(AST_GT, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + basic_expr TOK_GT attr basic_expr { + $$ = std::make_unique(AST_GT, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | - basic_expr '+' attr basic_expr { - $$ = new AstNode(AST_ADD, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + basic_expr TOK_PLUS attr basic_expr { + $$ = std::make_unique(AST_ADD, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | - basic_expr '-' attr basic_expr { - $$ = new AstNode(AST_SUB, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + basic_expr TOK_MINUS attr basic_expr { + $$ = std::make_unique(AST_SUB, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | - basic_expr '*' attr basic_expr { - $$ = new AstNode(AST_MUL, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + basic_expr TOK_ASTER attr basic_expr { + $$ = std::make_unique(AST_MUL, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | - basic_expr '/' attr basic_expr { - $$ = new AstNode(AST_DIV, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + basic_expr TOK_SLASH attr basic_expr { + $$ = std::make_unique(AST_DIV, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | - basic_expr '%' attr basic_expr { - $$ = new AstNode(AST_MOD, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + basic_expr TOK_PERC attr basic_expr { + $$ = std::make_unique(AST_MOD, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | basic_expr OP_POW attr basic_expr { - $$ = new AstNode(AST_POW, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + $$ = std::make_unique(AST_POW, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | - '+' attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_POS, $3); - SET_AST_NODE_LOC($$, @1, @3); - append_attr($$, $2); + TOK_PLUS attr basic_expr %prec UNARY_OPS { + $$ = std::make_unique(AST_POS, std::move($3)); + SET_AST_NODE_LOC($$.get(), @1, @3); + append_attr($$.get(), $2); } | - '-' attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_NEG, $3); - SET_AST_NODE_LOC($$, @1, @3); - append_attr($$, $2); + TOK_MINUS attr basic_expr %prec UNARY_OPS { + $$ = std::make_unique(AST_NEG, std::move($3)); + SET_AST_NODE_LOC($$.get(), @1, @3); + append_attr($$.get(), $2); } | basic_expr OP_LAND attr basic_expr { - $$ = new AstNode(AST_LOGIC_AND, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + $$ = std::make_unique(AST_LOGIC_AND, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | basic_expr OP_LOR attr basic_expr { - $$ = new AstNode(AST_LOGIC_OR, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + $$ = std::make_unique(AST_LOGIC_OR, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | - '!' attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_LOGIC_NOT, $3); - SET_AST_NODE_LOC($$, @1, @3); - append_attr($$, $2); + TOK_EXCL attr basic_expr %prec UNARY_OPS { + $$ = std::make_unique(AST_LOGIC_NOT, std::move($3)); + SET_AST_NODE_LOC($$.get(), @1, @3); + append_attr($$.get(), $2); } | - TOK_SIGNED OP_CAST '(' expr ')' { - if (!sv_mode) - frontend_verilog_yyerror("Static cast is only supported in SystemVerilog mode."); - $$ = new AstNode(AST_TO_SIGNED, $4); - SET_AST_NODE_LOC($$, @1, @4); + TOK_SIGNED OP_CAST TOK_LPAREN expr TOK_RPAREN { + if (!mode->sv) + lexer->err("Static cast is only supported in SystemVerilog mode."); + $$ = std::make_unique(AST_TO_SIGNED, std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); } | - TOK_UNSIGNED OP_CAST '(' expr ')' { - if (!sv_mode) - frontend_verilog_yyerror("Static cast is only supported in SystemVerilog mode."); - $$ = new AstNode(AST_TO_UNSIGNED, $4); - SET_AST_NODE_LOC($$, @1, @4); + TOK_UNSIGNED OP_CAST TOK_LPAREN expr TOK_RPAREN { + if (!mode->sv) + lexer->err("Static cast is only supported in SystemVerilog mode."); + $$ = std::make_unique(AST_TO_UNSIGNED, std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); } | - basic_expr OP_CAST '(' expr ')' { - if (!sv_mode) - frontend_verilog_yyerror("Static cast is only supported in SystemVerilog mode."); - $$ = new AstNode(AST_CAST_SIZE, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); + basic_expr OP_CAST TOK_LPAREN expr TOK_RPAREN { + if (!mode->sv) + lexer->err("Static cast is only supported in SystemVerilog mode."); + $$ = std::make_unique(AST_CAST_SIZE, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); } | - typedef_base_type OP_CAST '(' expr ')' { - if (!sv_mode) - frontend_verilog_yyerror("Static cast is only supported in SystemVerilog mode."); - $$ = new AstNode(AST_CAST_SIZE, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); + typedef_base_type OP_CAST TOK_LPAREN expr TOK_RPAREN { + if (!mode->sv) + lexer->err("Static cast is only supported in SystemVerilog mode."); + $$ = std::make_unique(AST_CAST_SIZE, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); } | - '(' expr '=' expr ')' { - ensureAsgnExprAllowed(); - AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, $4); - ast_stack.back()->children.push_back(node); - SET_AST_NODE_LOC(node, @2, @4); + TOK_LPAREN expr TOK_EQ expr TOK_RPAREN { + extra->ensureAsgnExprAllowed(@3, mode->sv); $$ = $2->clone(); + auto node = std::make_unique(AST_ASSIGN_EQ, std::move($2), std::move($4)); + SET_AST_NODE_LOC(node.get(), @2, @4); + extra->ast_stack.back()->children.push_back(std::move(node)); } | - '(' expr asgn_binop expr ')' { - ensureAsgnExprAllowed(); - $$ = addAsgnBinopStmt(nullptr, $2, $3, $4, @2, @4)-> clone(); + TOK_LPAREN expr asgn_binop expr TOK_RPAREN { + extra->ensureAsgnExprAllowed(@3, mode->sv); + $$ = extra->addAsgnBinopStmt(nullptr, std::move($2), $3, std::move($4), @2, @4)-> clone(); }; concat_list: expr { - $$ = new AstNode(AST_CONCAT, $1); + $$ = std::make_unique(AST_CONCAT, std::move($1)); } | - expr ',' concat_list { - $$ = $3; - $$->children.push_back($1); + expr TOK_COMMA concat_list { + $$ = std::move($3); + $$->children.push_back(std::move($1)); }; integral_number: @@ -3587,12 +3523,9 @@ integral_number: TOK_UNBASED_UNSIZED_CONSTVAL { $$ = $1; } | TOK_BASE TOK_BASED_CONSTVAL { $1->append(*$2); - $$ = $1; - delete $2; + $$ = std::move($1); } | TOK_CONSTVAL TOK_BASE TOK_BASED_CONSTVAL { $1->append(*$2).append(*$3); - $$ = $1; - delete $2; - delete $3; + $$ = std::move($1); }; diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 8a0080dbf..d9e437ac5 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -952,10 +952,6 @@ RTLIL::Design::~Design() delete pr.second; for (auto n : bindings_) delete n; - for (auto n : verilog_packages) - delete n; - for (auto n : verilog_globals) - delete n; #ifdef WITH_PYTHON RTLIL::Design::get_all_designs()->erase(hashidx_); #endif @@ -5704,11 +5700,6 @@ static void sigspec_parse_split(std::vector &tokens, const std::str tokens.push_back(text.substr(start)); } -static int sigspec_parse_get_dummy_line_num() -{ - return 0; -} - bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str) { cover("kernel.rtlil.sigspec.parse"); @@ -5729,12 +5720,11 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri if (('0' <= netname[0] && netname[0] <= '9') || netname[0] == '\'') { cover("kernel.rtlil.sigspec.parse.const"); - AST::get_line_num = sigspec_parse_get_dummy_line_num; - AST::AstNode *ast = VERILOG_FRONTEND::const2ast(netname); - if (ast == NULL) + VERILOG_FRONTEND::ConstParser p; + auto ast = p.const2ast(netname); + if (ast == nullptr) return false; sig.append(RTLIL::Const(ast->bits)); - delete ast; continue; } diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 504fa0062..ec66746e6 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1331,7 +1331,7 @@ struct RTLIL::Design dict modules_; std::vector bindings_; - std::vector verilog_packages, verilog_globals; + std::vector> verilog_packages, verilog_globals; std::unique_ptr verilog_defines; std::vector selection_stack; diff --git a/passes/cmds/design.cc b/passes/cmds/design.cc index a2ae45ef3..59cd39c98 100644 --- a/passes/cmds/design.cc +++ b/passes/cmds/design.cc @@ -368,14 +368,8 @@ struct DesignPass : public Pass { if (reset_mode || reset_vlog_mode || !load_name.empty() || push_mode || pop_mode) { - for (auto node : design->verilog_packages) - delete node; design->verilog_packages.clear(); - - for (auto node : design->verilog_globals) - delete node; design->verilog_globals.clear(); - design->verilog_defines->clear(); } diff --git a/passes/memory/memlib.h b/passes/memory/memlib.h index c3f7728f1..43dec7386 100644 --- a/passes/memory/memlib.h +++ b/passes/memory/memlib.h @@ -100,7 +100,7 @@ enum class WrTransKind { struct WrTransDef { WrTransTargetKind target_kind; - int target_group; + int target_group = 0; WrTransKind kind; }; From 6cb789b2c2e0fe97eda518f405269dea68763dc8 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 17 Jun 2025 01:57:51 +0200 Subject: [PATCH 05/38] ast: ownership for string values --- frontends/verilog/verilog_lexer.l | 88 +++++++++++++++--------------- frontends/verilog/verilog_parser.y | 58 +++++++++----------- 2 files changed, 71 insertions(+), 75 deletions(-) diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 49be54183..d57912265 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -74,12 +74,12 @@ YOSYS_NAMESPACE_END log("Lexer warning: The SystemVerilog keyword `%s' (at %s:%d) is not "\ "recognized unless read_verilog is called with -sv!\n", YYText(), \ AST::current_filename.c_str(), yylineno); \ - string_t val = new std::string(std::string("\\") + YYText()); \ - return parser::make_TOK_ID(val, out_loc); + string_t val = std::make_unique(std::string("\\") + YYText()); \ + return parser::make_TOK_ID(std::move(val), out_loc); #define NON_KEYWORD() \ - string_t val = new std::string(std::string("\\") + YYText()); \ - return parser::make_TOK_ID(val, out_loc); + string_t val = std::make_unique(std::string("\\") + YYText()); \ + return parser::make_TOK_ID(std::move(val), out_loc); // #define YY_INPUT(buf,result,max_size) \ // result = readsome(*extra->lexin, buf, max_size) @@ -289,8 +289,8 @@ TIME_SCALE_SUFFIX [munpf]?s [a-zA-Z_$][a-zA-Z0-9_$]*/[ \t\r\n]*:[ \t\r\n]*(assert|assume|cover|restrict)[^a-zA-Z0-9_$\.] { if (!strcmp(YYText(), "default")) return parser::make_TOK_DEFAULT(out_loc); - string_t val = new std::string(std::string("\\") + YYText()); - return parser::make_TOK_SVA_LABEL(val, out_loc); + string_t val = std::make_unique(std::string("\\") + YYText()); + return parser::make_TOK_SVA_LABEL(std::move(val), out_loc); } "assert" { if (mode->formal) return parser::make_TOK_ASSERT(out_loc); SV_KEYWORD(parser::make_TOK_ASSERT(out_loc)); } @@ -339,35 +339,35 @@ TIME_SCALE_SUFFIX [munpf]?s "packed" { SV_KEYWORD(parser::make_TOK_PACKED(out_loc)); } {UNSIGNED_NUMBER} { - string_t val = new std::string(YYText()); - return parser::make_TOK_CONSTVAL(val, out_loc); + string_t val = std::make_unique(YYText()); + return parser::make_TOK_CONSTVAL(std::move(val), out_loc); } \'[01zxZX] { - string_t val = new std::string(YYText()); - return parser::make_TOK_UNBASED_UNSIZED_CONSTVAL(val, out_loc); + string_t val = std::make_unique(YYText()); + return parser::make_TOK_UNBASED_UNSIZED_CONSTVAL(std::move(val), out_loc); } \'[sS]?[bodhBODH] { BEGIN(BASED_CONST); - string_t val = new std::string(YYText()); - return parser::make_TOK_BASE(val, out_loc); + string_t val = std::make_unique(YYText()); + return parser::make_TOK_BASE(std::move(val), out_loc); } [0-9a-fA-FzxZX?][0-9a-fA-FzxZX?_]* { BEGIN(0); - string_t val = new std::string(YYText()); - return parser::make_TOK_BASED_CONSTVAL(val, out_loc); + string_t val = std::make_unique(YYText()); + return parser::make_TOK_BASED_CONSTVAL(std::move(val), out_loc); } {FIXED_POINT_NUMBER_DEC} { - string_t val = new std::string(YYText()); - return parser::make_TOK_REALVAL(val, out_loc); + string_t val = std::make_unique(YYText()); + return parser::make_TOK_REALVAL(std::move(val), out_loc); } {FIXED_POINT_NUMBER_NO_DEC} { - string_t val = new std::string(YYText()); - return parser::make_TOK_REALVAL(val, out_loc); + string_t val = std::make_unique(YYText()); + return parser::make_TOK_REALVAL(std::move(val), out_loc); } \" { BEGIN(STRING); } @@ -407,33 +407,33 @@ TIME_SCALE_SUFFIX [munpf]?s yystr[j++] = yystr[i++]; } yystr[j] = 0; - string_t val = new std::string(yystr, j); + string_t val = std::make_unique(yystr, j); free(yystr); - return parser::make_TOK_STRING(val, out_loc); + return parser::make_TOK_STRING(std::move(val), out_loc); } and|nand|or|nor|xor|xnor|not|buf|bufif0|bufif1|notif0|notif1 { - auto val = new std::string(YYText()); - return parser::make_TOK_PRIMITIVE(val, out_loc); + auto val = std::make_unique(YYText()); + return parser::make_TOK_PRIMITIVE(std::move(val), out_loc); } supply0 { return parser::make_TOK_SUPPLY0(out_loc); } supply1 { return parser::make_TOK_SUPPLY1(out_loc); } "$"(display[bho]?|write[bho]?|strobe|monitor|time|realtime|stop|finish|dumpfile|dumpvars|dumpon|dumpoff|dumpall) { - auto val = new std::string(YYText()); - return parser::make_TOK_ID(val, out_loc); + auto val = std::make_unique(YYText()); + return parser::make_TOK_ID(std::move(val), out_loc); } "$"(setup|hold|setuphold|removal|recovery|recrem|skew|timeskew|fullskew|nochange) { if (!mode->specify) REJECT; - auto val = new std::string(YYText()); - return parser::make_TOK_ID(val, out_loc); + auto val = std::make_unique(YYText()); + return parser::make_TOK_ID(std::move(val), out_loc); } "$"(info|warning|error|fatal) { - auto val = new std::string(YYText()); - return parser::make_TOK_MSG_TASKS(val, out_loc); + auto val = std::make_unique(YYText()); + return parser::make_TOK_MSG_TASKS(std::move(val), out_loc); } "$signed" { return parser::make_TOK_TO_SIGNED(out_loc); } @@ -444,15 +444,15 @@ supply1 { return parser::make_TOK_SUPPLY1(out_loc); } auto s = std::string("\\") + YYText(); if (extra->pkg_user_types.count(s) > 0) { // package qualified typedefed name - auto val = new std::string(s); - return parser::make_TOK_PKG_USER_TYPE(val, out_loc); + auto val = std::make_unique(s); + return parser::make_TOK_PKG_USER_TYPE(std::move(val), out_loc); } else { // backup before :: just return first part size_t len = strchr(YYText(), ':') - YYText(); yyless(len); - auto val = new std::string(std::string("\\") + YYText()); - return parser::make_TOK_ID(val, out_loc); + auto val = std::make_unique(std::string("\\") + YYText()); + return parser::make_TOK_ID(std::move(val), out_loc); } } @@ -460,18 +460,18 @@ supply1 { return parser::make_TOK_SUPPLY1(out_loc); } auto s = std::string("\\") + YYText(); if (isUserType(extra, s)) { // previously typedefed name - auto val = new std::string(s); - return parser::make_TOK_USER_TYPE(val, out_loc); + auto val = std::make_unique(s); + return parser::make_TOK_USER_TYPE(std::move(val), out_loc); } else { - auto val = new std::string(std::string("\\") + YYText()); - return parser::make_TOK_ID(val, out_loc); + auto val = std::make_unique(std::string("\\") + YYText()); + return parser::make_TOK_ID(std::move(val), out_loc); } } [a-zA-Z_$][a-zA-Z0-9_$\.]* { - auto val = new std::string(std::string("\\") + YYText()); - return parser::make_TOK_ID(val, out_loc); + auto val = std::make_unique(std::string("\\") + YYText()); + return parser::make_TOK_ID(std::move(val), out_loc); } "/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" { @@ -532,8 +532,8 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ { } [a-zA-Z_$][a-zA-Z0-9_$]* { - auto val = new std::string(std::string("\\") + YYText()); - return parser::make_TOK_ID(val, out_loc); + auto val = std::make_unique(std::string("\\") + YYText()); + return parser::make_TOK_ID(std::move(val), out_loc); } [ \t\r\n] /* ignore whitespaces */ @@ -548,8 +548,8 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ { } "\\"[^ \t\r\n]+ { - auto val = new std::string(YYText()); - return parser::make_TOK_ID(val, out_loc); + auto val = std::make_unique(YYText()); + return parser::make_TOK_ID(std::move(val), out_loc); } "(*" { return parser::make_ATTR_BEGIN(out_loc); } @@ -605,8 +605,8 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ { [-+]?[=*]> { if (!mode->specify) REJECT; - auto val = new std::string(YYText()); - return parser::make_TOK_SPECIFY_OPER(val, out_loc); + auto val = std::make_unique(YYText()); + return parser::make_TOK_SPECIFY_OPER(std::move(val), out_loc); } "&&&" { diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 0ac1d938f..e32446f69 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -244,7 +244,7 @@ node->children.push_back(std::move(rangeNode)); } - static void checkLabelsMatch(const frontend_verilog_yy::parser::location_type& loc, const char *element, const std::string *before, const std::string *after) + static void checkLabelsMatch(const frontend_verilog_yy::parser::location_type& loc, const char *element, const std::string* before, const std::string *after) { if (!before && after) err_at_loc(loc, "%s missing where end label (%s) was given.", @@ -271,7 +271,6 @@ node->is_custom_type = true; node->children.push_back(std::make_unique(AST_WIRETYPE)); node->children.back()->str = *name; - delete name; } void ParseState::addTypedefNode(std::string *name, std::unique_ptr node) @@ -287,7 +286,6 @@ auto qname = current_ast_mod->str + "::" + (*name).substr(1); pkg_user_types[qname] = tnode; } - delete name; } void ParseState::enterTypeScope() @@ -479,7 +477,7 @@ specify_triple fall; }; - using string_t = std::string *; + using string_t = std::unique_ptr; using ast_t = std::unique_ptr; using al_t = YOSYS_NAMESPACE_PREFIX dict>*; using specify_target_ptr_t = std::unique_ptr; @@ -686,27 +684,27 @@ attr_assign: hierarchical_id: TOK_ID { - $$ = $1; + $$ = std::move($1); } | hierarchical_id TOK_PACKAGESEP TOK_ID { if ($3->compare(0, 1, "\\") == 0) *$1 += "::" + $3->substr(1); else *$1 += "::" + *$3; - $$ = $1; + $$ = std::move($1); } | hierarchical_id TOK_DOT TOK_ID { if ($3->compare(0, 1, "\\") == 0) *$1 += "." + $3->substr(1); else *$1 += "." + *$3; - $$ = $1; + $$ = std::move($1); }; hierarchical_type_id: - TOK_USER_TYPE - | TOK_PKG_USER_TYPE // package qualified type name - | TOK_LPAREN TOK_USER_TYPE TOK_RPAREN { $$ = $2; } // non-standard grammar + TOK_USER_TYPE {$$ = std::move($1); } + | TOK_PKG_USER_TYPE {$$ = std::move($1); } // package qualified type name + | TOK_LPAREN TOK_USER_TYPE TOK_RPAREN { $$ = std::move($2); } // non-standard grammar ; module: @@ -727,7 +725,7 @@ module: SET_AST_NODE_LOC(extra->ast_stack.back(), @2, @$); extra->ast_stack.pop_back(); log_assert(extra->ast_stack.size() == 1); - checkLabelsMatch(@11, "Module name", $4, $11); + checkLabelsMatch(@11, "Module name", $4.get(), $11.get()); extra->current_ast_mod = nullptr; extra->exitTypeScope(); }; @@ -835,7 +833,7 @@ package: append_attr(mod, $1); } TOK_SEMICOL package_body TOK_ENDPACKAGE opt_label { extra->ast_stack.pop_back(); - checkLabelsMatch(@9, "Package name", $4, $9); + checkLabelsMatch(@9, "Package name", $4.get(), $9.get()); extra->current_ast_mod = nullptr; extra->exitTypeScope(); }; @@ -1043,7 +1041,7 @@ logic_type: extra->astbuf3->is_signed = true; } | hierarchical_type_id { - extra->addWiretypeNode($1, extra->astbuf3.get()); + extra->addWiretypeNode($1.get(), extra->astbuf3.get()); }; integer_atom_type: @@ -1311,7 +1309,7 @@ specify_item: auto en_expr = std::move($1); char specify_edge = $3; auto src_expr = std::move($4); - string *oper = $5; + string *oper = $5.get(); specify_target_ptr_t target = std::move($6); specify_rise_fall_ptr_t timing = std::move($9); @@ -1387,8 +1385,6 @@ specify_item: cell->children.push_back(std::make_unique(AST_ARGUMENT, std::move(target->dat))); cell->children.back()->str = "\\DAT"; } - - delete oper; } | TOK_ID TOK_LPAREN specify_edge expr specify_condition TOK_COMMA specify_edge expr specify_condition TOK_COMMA specify_triple specify_opt_triple TOK_RPAREN TOK_SEMICOL { if (*$1 != "$setup" && *$1 != "$hold" && *$1 != "$setuphold" && *$1 != "$removal" && *$1 != "$recovery" && @@ -1725,7 +1721,7 @@ param_implicit_type: param_signed param_range; param_type: param_integer_type | param_real | param_range_type | param_implicit_type | hierarchical_type_id { - extra->addWiretypeNode($1, extra->astbuf1.get()); + extra->addWiretypeNode($1.get(), extra->astbuf1.get()); }; param_decl: @@ -1982,7 +1978,7 @@ member_type_token: member_type: type_atom type_signing | type_vec type_signing - | hierarchical_type_id { extra->addWiretypeNode($1, extra->astbuf1.get()); } + | hierarchical_type_id { extra->addWiretypeNode($1.get(), extra->astbuf1.get()); } ; struct_var_list: struct_var @@ -2161,8 +2157,8 @@ assign_expr: SET_AST_NODE_LOC(node, @$, @$); }; -type_name: TOK_ID // first time seen - | TOK_USER_TYPE { if (extra->isInLocalScope($1)) lexer->err("Duplicate declaration of TYPEDEF '%s'", $1->c_str()+1); $$ = std::move($1); } +type_name: TOK_ID { $$ = std::move($1); } // first time seen + | TOK_USER_TYPE { if (extra->isInLocalScope($1.get())) lexer->err("Duplicate declaration of TYPEDEF '%s'", $1->c_str()+1); $$ = std::move($1); } ; typedef_decl: @@ -2180,15 +2176,15 @@ typedef_decl: } rewriteAsMemoryNode(extra->astbuf1.get(), std::move($5)); } - extra->addTypedefNode($4, std::move(extra->astbuf1)); } - | TOK_TYPEDEF enum_struct_type type_name TOK_SEMICOL { extra->addTypedefNode($3, std::move($2)); } + extra->addTypedefNode($4.get(), std::move(extra->astbuf1)); } + | TOK_TYPEDEF enum_struct_type type_name TOK_SEMICOL { extra->addTypedefNode($3.get(), std::move($2)); } ; typedef_base_type: hierarchical_type_id { $$ = std::make_unique(AST_WIRE); $$->is_logic = true; - extra->addWiretypeNode($1, $$.get()); + extra->addWiretypeNode($1.get(), $$.get()); } | integer_vector_type opt_signedness_default_unsigned { $$ = std::make_unique(AST_WIRE); @@ -2231,10 +2227,10 @@ cell_stmt: tok_prim_wrapper: TOK_PRIMITIVE { - $$ = $1; + $$ = std::move($1); } | TOK_OR { - $$ = new std::string("or"); + $$ = std::make_unique("or"); }; cell_list: @@ -2474,7 +2470,7 @@ always_event: opt_label: TOK_COL TOK_ID { - $$ = $2; + $$ = std::move($2); } | %empty { $$ = nullptr; @@ -2482,7 +2478,7 @@ opt_label: opt_sva_label: TOK_SVA_LABEL TOK_COL { - $$ = $1; + $$ = std::move($1); } | %empty { $$ = nullptr; @@ -2790,7 +2786,7 @@ behavioral_stmt: node->str = *$4; } behavioral_stmt_list TOK_END opt_label { extra->exitTypeScope(); - checkLabelsMatch(@8, "Begin label", $4, $8); + checkLabelsMatch(@8, "Begin label", $4.get(), $8.get()); AstNode *node = extra->ast_stack.back(); // In SystemVerilog, unnamed blocks with block item declarations // create an implicit hierarchy scope @@ -3173,7 +3169,7 @@ gen_block: node->str = $3 ? *$3 : std::string(); } module_gen_body TOK_END opt_label { extra->exitTypeScope(); - checkLabelsMatch(@7, "Begin label", $3, $7); + checkLabelsMatch(@7, "Begin label", $3.get(), $7.get()); SET_AST_NODE_LOC(extra->ast_stack.back(), @1, @7); extra->ast_stack.pop_back(); }; @@ -3519,8 +3515,8 @@ concat_list: }; integral_number: - TOK_CONSTVAL { $$ = $1; } | - TOK_UNBASED_UNSIZED_CONSTVAL { $$ = $1; } | + TOK_CONSTVAL { $$ = std::move($1); } | + TOK_UNBASED_UNSIZED_CONSTVAL { $$ = std::move($1); } | TOK_BASE TOK_BASED_CONSTVAL { $1->append(*$2); $$ = std::move($1); From 31002cf25912f2cb05e8c0dfefeacfa76c9371bc Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 17 Jun 2025 15:25:57 +0200 Subject: [PATCH 06/38] ast: fix new memory safety bugs from rebase --- frontends/ast/genrtlil.cc | 4 ++-- frontends/ast/simplify.cc | 2 +- frontends/verilog/verilog_parser.y | 9 +++++++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index fcc91adfc..e8f964ebf 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -1612,7 +1612,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) input_error("Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; - auto fake_ast = new AstNode(AST_NONE, clone(), children[0]->children.size() >= 2 ? + auto fake_ast = std::make_unique(AST_NONE, clone(), children[0]->children.size() >= 2 ? children[0]->children[1]->clone() : children[0]->children[0]->clone()); fake_ast->children[0]->delete_children(); if (member_node) @@ -1633,7 +1633,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) } if (GetSize(shift_val) >= 32) fake_ast->children[1]->is_signed = true; - RTLIL::SigSpec sig = binop2rtlil(fake_ast, ID($shiftx), width, fake_ast->children[0]->genRTLIL(), shift_val); + RTLIL::SigSpec sig = binop2rtlil(fake_ast.get(), ID($shiftx), width, fake_ast->children[0]->genRTLIL(), shift_val); return sig; } else { chunk.width = children[0]->range_left - children[0]->range_right + 1; diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index d306c6022..86c5efb6d 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1505,7 +1505,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (children[0]->type == AST_WIRE) { int width = 1; std::unique_ptr node; - AstNode* child = children[0].release(); + AstNode* child = children[0].get(); if (child->children.size() == 0) { // Base type (e.g., int) width = child->range_left - child->range_right +1; diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index e32446f69..7233d52b5 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -2844,6 +2844,7 @@ behavioral_stmt: std::unique_ptr node_owned; AstNode* node = nullptr; AstNode *context = extra->ast_stack.back(); + bool patch_block_on_stack = false; if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if)) { AstNode *outer = extra->ast_stack[extra->ast_stack.size() - 2]; log_assert (outer && outer->type == AST_CASE); @@ -2852,6 +2853,9 @@ behavioral_stmt: node = outer; log_assert (node->children.size()); node->children.pop_back(); + // `context` has been killed as a grandchild of `outer` + // we have to undangle it from the stack + patch_block_on_stack = true; } else if (outer->get_bool_attribute(ID::full_case)) (*$1)[ID::full_case] = AstNode::mkconst_int(1, false); } @@ -2863,12 +2867,17 @@ behavioral_stmt: append_attr(node, $1); node->children.push_back(node->get_bool_attribute(ID::parallel_case) ? AstNode::mkconst_int(1, false, 1) : expr->clone()); extra->ast_stack.back()->children.push_back(std::move(node_owned)); + } else { + free_attr($1); } auto block_owned = std::make_unique(AST_BLOCK); auto* block = block_owned.get(); auto cond_owned = std::make_unique(AST_COND, node->get_bool_attribute(ID::parallel_case) ? std::move(expr) : AstNode::mkconst_int(1, false, 1), std::move(block_owned)); SET_AST_NODE_LOC(cond_owned.get(), @4, @4); node->children.push_back(std::move(cond_owned)); + // Double it and give it to the next person + if (patch_block_on_stack) + extra->ast_stack.back() = block; extra->ast_stack.push_back(node); extra->ast_stack.push_back(block); } behavioral_stmt { From 88800a16ea82387a3f30e81d57b65cd8b4507b61 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 18 Jun 2025 12:39:32 +0200 Subject: [PATCH 07/38] ast, read_verilog: refactoring --- frontends/ast/genrtlil.cc | 2 -- frontends/ast/simplify.cc | 4 ---- frontends/verilog/Makefile.inc | 3 +++ frontends/verilog/verilog_frontend.cc | 9 --------- frontends/verilog/verilog_frontend.h | 5 ----- frontends/verilog/verilog_lexer.h | 3 ++- frontends/verilog/verilog_parser.y | 11 +++++++++++ 7 files changed, 16 insertions(+), 21 deletions(-) diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index e8f964ebf..994c87da6 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -1339,8 +1339,6 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) // be instantiated for this type of AST node. IdString type_name; - current_filename = filename; - switch (type) { // simply ignore this nodes. diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 86c5efb6d..f4c27caf4 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1038,8 +1038,6 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin return false; } - current_filename = filename; - // we do not look inside a task or function // (but as soon as a task or function is instantiated we process the generated AST as usual) if (type == AST_FUNCTION || type == AST_TASK) { @@ -1840,8 +1838,6 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin current_scope[it->first] = it->second; } - current_filename = filename; - if (type == AST_MODULE || type == AST_INTERFACE) current_scope.clear(); diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc index 2d26f1930..cc8baf6aa 100644 --- a/frontends/verilog/Makefile.inc +++ b/frontends/verilog/Makefile.inc @@ -3,6 +3,9 @@ GENFILES += frontends/verilog/verilog_parser.tab.cc GENFILES += frontends/verilog/verilog_parser.tab.hh GENFILES += frontends/verilog/verilog_parser.output GENFILES += frontends/verilog/verilog_lexer.cc +GENFILES += frontends/verilog/location.hh +GENFILES += frontends/verilog/position.hh +GENFILES += frontends/verilog/stack.hh frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y $(Q) mkdir -p $(dir $@) diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index f2a341f54..d4bee02da 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -787,15 +787,6 @@ void VERILOG_FRONTEND::verr_at(std::string filename, int begin_line, char const exit(1); } -[[noreturn]] -void VERILOG_FRONTEND::err_at_loc(parser::location_type loc, char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - verr_at(AST::current_filename, loc.begin.line, fmt, args); - va_end(args); -} - [[noreturn]] void VERILOG_FRONTEND::err_at_ast(AstSrcLocType loc, char const *fmt, ...) { diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h index 6426f57d8..29c16c039 100644 --- a/frontends/verilog/verilog_frontend.h +++ b/frontends/verilog/verilog_frontend.h @@ -31,7 +31,6 @@ #include "kernel/yosys.h" #include "frontends/ast/ast.h" -#include "frontends/verilog/location.hh" #if ! defined(yyFlexLexerOnce) #define yyFlexLexer frontend_verilog_yyFlexLexer @@ -66,10 +65,6 @@ namespace VERILOG_FRONTEND }; [[noreturn]] - extern void verr_at(std::string filename, int begin_line, char const *fmt, va_list ap); - [[noreturn]] - extern void err_at_loc(frontend_verilog_yy::location loc, char const *fmt, ...); - [[noreturn]] extern void err_at_ast(AST::AstSrcLocType loc, char const *fmt, ...); }; diff --git a/frontends/verilog/verilog_lexer.h b/frontends/verilog/verilog_lexer.h index 7d73ae193..2c31160dd 100644 --- a/frontends/verilog/verilog_lexer.h +++ b/frontends/verilog/verilog_lexer.h @@ -8,7 +8,8 @@ YOSYS_NAMESPACE_BEGIN namespace VERILOG_FRONTEND { - // lexer input stream + [[noreturn]] + extern void verr_at(std::string filename, int begin_line, char const *fmt, va_list ap); using parser = frontend_verilog_yy::parser; class VerilogLexer : public frontend_verilog_yyFlexLexer { ParseState* extra; diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 7233d52b5..24a21a740 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -244,6 +244,17 @@ node->children.push_back(std::move(rangeNode)); } + [[noreturn]] + extern void verr_at(std::string filename, int begin_line, char const *fmt, va_list ap); + [[noreturn]] + static void err_at_loc(frontend_verilog_yy::parser::location_type loc, char const *fmt, ...) + { + va_list args; + va_start(args, fmt); + verr_at(AST::current_filename, loc.begin.line, fmt, args); + va_end(args); + } + static void checkLabelsMatch(const frontend_verilog_yy::parser::location_type& loc, const char *element, const std::string* before, const std::string *after) { if (!before && after) From b276fb6616defe9eff26e19b719a0fdcb1e060f2 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 18 Jun 2025 18:05:48 +0200 Subject: [PATCH 08/38] neater errors, lost in the sauce of source --- .../yosys_internals/flow/verilog_frontend.rst | 11 +-- frontends/ast/ast.cc | 50 +++++------ frontends/ast/ast.h | 24 ++--- frontends/ast/dpicall.cc | 12 +-- frontends/ast/genrtlil.cc | 50 +++++------ frontends/ast/simplify.cc | 80 +++++++++-------- frontends/verilog/Makefile.inc | 2 + frontends/verilog/const2ast.cc | 11 +-- frontends/verilog/verilog_frontend.cc | 69 +++++--------- frontends/verilog/verilog_frontend.h | 6 +- frontends/verilog/verilog_lexer.h | 18 ++-- frontends/verilog/verilog_lexer.l | 18 ++-- frontends/verilog/verilog_parser.y | 90 ++++++++----------- 13 files changed, 196 insertions(+), 245 deletions(-) diff --git a/docs/source/yosys_internals/flow/verilog_frontend.rst b/docs/source/yosys_internals/flow/verilog_frontend.rst index b6a7ba8a0..d6bdf6b6d 100644 --- a/docs/source/yosys_internals/flow/verilog_frontend.rst +++ b/docs/source/yosys_internals/flow/verilog_frontend.rst @@ -48,7 +48,7 @@ The lexer does little more than identifying all keywords and literals recognised by the Yosys Verilog frontend. The lexer keeps track of the current location in the Verilog source code using -some global variables. These variables are used by the constructor of AST nodes +some VerilogLexer member variables. These variables are used by the constructor of AST nodes to annotate each node with the source code location it originated from. Finally the lexer identifies and handles special comments such as "``// synopsys @@ -189,10 +189,11 @@ the bison code for parsing multiplications: .. code:: none :number-lines: - basic_expr '*' attr basic_expr { - $$ = new AstNode(AST_MUL, $1, $4); - append_attr($$, $3); - } | + basic_expr TOK_ASTER attr basic_expr { + $$ = std::make_unique(AST_MUL, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); + } | The generated AST data structure is then passed directly to the AST frontend that performs the actual conversion to RTLIL. diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 2844f96b7..28a6fce99 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -38,8 +38,7 @@ using namespace AST_INTERNAL; // instantiate global variables (public API) namespace AST { - std::string current_filename; - bool sv_mode; + bool sv_mode_but_global_and_used_for_literally_one_condition; unsigned long long astnodes = 0; unsigned long long astnode_count() { return astnodes; } } @@ -200,7 +199,7 @@ bool AstNode::get_bool_attribute(RTLIL::IdString id) // create new node (AstNode constructor) // (the optional child arguments make it easier to create AST trees) -AstNode::AstNode(AstNodeType type, std::unique_ptr child1, std::unique_ptr child2, std::unique_ptr child3, std::unique_ptr child4) +AstNode::AstNode(AstSrcLocType loc, AstNodeType type, std::unique_ptr child1, std::unique_ptr child2, std::unique_ptr child3, std::unique_ptr child4) { static unsigned int hashidx_count = 123456789; hashidx_count = mkhash_xorshift(hashidx_count); @@ -208,7 +207,7 @@ AstNode::AstNode(AstNodeType type, std::unique_ptr child1, std::unique_ astnodes++; this->type = type; - filename = current_filename; + loc = loc; is_input = false; is_output = false; is_reg = false; @@ -252,7 +251,7 @@ AstNode::AstNode(AstNodeType type, std::unique_ptr child1, std::unique_ // create a (deep recursive) copy of a node std::unique_ptr AstNode::clone() const { - auto that = std::make_unique(this->type); + auto that = std::make_unique(this->location, this->type); cloneInto(*that.get()); return that; } @@ -287,7 +286,6 @@ void AstNode::cloneInto(AstNode &other) const other.id2ast = id2ast; other.basic_prep = basic_prep; other.lookahead = lookahead; - other.filename = filename; other.location = location; other.in_lvalue = in_lvalue; other.in_param = in_param; @@ -842,9 +840,9 @@ bool AstNode::contains(const AstNode *other) const } // create an AST node for a constant (using a 32 bit int as value) -std::unique_ptr AstNode::mkconst_int(uint32_t v, bool is_signed, int width) +std::unique_ptr AstNode::mkconst_int(AstSrcLocType loc, uint32_t v, bool is_signed, int width) { - auto node = std::make_unique(AST_CONSTANT); + auto node = std::make_unique(loc, AST_CONSTANT); node->integer = v; node->is_signed = is_signed; for (int i = 0; i < width; i++) { @@ -858,9 +856,9 @@ std::unique_ptr AstNode::mkconst_int(uint32_t v, bool is_signed, int wi } // create an AST node for a constant (using a bit vector as value) -std::unique_ptr AstNode::mkconst_bits(const std::vector &v, bool is_signed, bool is_unsized) +std::unique_ptr AstNode::mkconst_bits(AstSrcLocType loc, const std::vector &v, bool is_signed, bool is_unsized) { - auto node = std::make_unique(AST_CONSTANT); + auto node = std::make_unique(loc, AST_CONSTANT); node->is_signed = is_signed; node->bits = v; for (size_t i = 0; i < 32; i++) { @@ -876,15 +874,15 @@ std::unique_ptr AstNode::mkconst_bits(const std::vector & return node; } -std::unique_ptr AstNode::mkconst_bits(const std::vector &v, bool is_signed) +std::unique_ptr AstNode::mkconst_bits(AstSrcLocType loc, const std::vector &v, bool is_signed) { - return mkconst_bits(v, is_signed, false); + return mkconst_bits(loc, v, is_signed, false); } // create an AST node for a constant (using a string in bit vector form as value) -std::unique_ptr AstNode::mkconst_str(const std::vector &v) +std::unique_ptr AstNode::mkconst_str(AstSrcLocType loc, const std::vector &v) { - auto node = mkconst_str(RTLIL::Const(v).decode_string()); + auto node = mkconst_str(loc, RTLIL::Const(v).decode_string()); while (GetSize(node->bits) < GetSize(v)) node->bits.push_back(RTLIL::State::S0); log_assert(node->bits == v); @@ -892,14 +890,14 @@ std::unique_ptr AstNode::mkconst_str(const std::vector &v } // create an AST node for a constant (using a string as value) -std::unique_ptr AstNode::mkconst_str(const std::string &str) +std::unique_ptr AstNode::mkconst_str(AstSrcLocType loc, const std::string &str) { std::unique_ptr node; // LRM 1364-2005 5.2.3.3 The empty string literal ("") shall be considered // equivalent to the ASCII NUL ("\0") if (str.empty()) { - node = AstNode::mkconst_int(0, false, 8); + node = AstNode::mkconst_int(loc, 0, false, 8); } else { std::vector data; data.reserve(str.size() * 8); @@ -910,7 +908,7 @@ std::unique_ptr AstNode::mkconst_str(const std::string &str) ch = ch >> 1; } } - node = AstNode::mkconst_bits(data, false); + node = AstNode::mkconst_bits(loc, data, false); } node->is_string = true; @@ -919,19 +917,19 @@ std::unique_ptr AstNode::mkconst_str(const std::string &str) } // create a temporary register -std::unique_ptr AstNode::mktemp_logic(const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed) +std::unique_ptr AstNode::mktemp_logic(AstSrcLocType loc, const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed) { - auto wire_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(range_left, true), mkconst_int(range_right, true))); + auto wire_owned = std::make_unique(loc, AST_WIRE, std::make_unique(loc, AST_RANGE, mkconst_int(loc, range_left, true), mkconst_int(loc, range_right, true))); auto* wire = wire_owned.get(); - wire->str = stringf("%s%s:%d$%d", name.c_str(), RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); + wire->str = stringf("%s%s:%d$%d", name.c_str(), RTLIL::encode_filename(location.filename).c_str(), location.first_line, autoidx++); if (nosync) - wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); + wire->set_attribute(ID::nosync, AstNode::mkconst_int(loc, 1, false)); wire->is_signed = is_signed; wire->is_logic = true; mod->children.push_back(std::move(wire_owned)); while (wire->simplify(true, 1, -1, false)) { } - auto ident = std::make_unique(AST_IDENTIFIER); + auto ident = std::make_unique(loc, AST_IDENTIFIER); ident->str = wire->str; ident->id2ast = wire; @@ -985,7 +983,7 @@ RTLIL::Const AstNode::asParaConst() const { if (type == AST_REALVALUE) { - auto strnode = AstNode::mkconst_str(stringf("%f", realvalue)); + auto strnode = AstNode::mkconst_str(location, stringf("%f", realvalue)); RTLIL::Const val = strnode->asAttrConst(); val.flags |= RTLIL::CONST_FLAG_REAL; return val; @@ -1087,7 +1085,7 @@ RTLIL::Const AstNode::realAsConst(int width) std::string AstNode::loc_string() const { - return stringf("%s:%d.%d-%d.%d", filename.c_str(), location.first_line, location.first_column, location.last_line, location.last_column); + return stringf("%s:%d.%d-%d.%d", location.filename.c_str(), location.first_line, location.first_column, location.last_line, location.last_column); } void AST::set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast) @@ -1445,7 +1443,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump if (design->has(child->str)) { RTLIL::Module *existing_mod = design->module(child->str); if (!nooverwrite && !overwrite && !existing_mod->get_blackbox_attribute()) { - log_file_error(child->filename, child->location.first_line, "Re-definition of module `%s'!\n", child->str.c_str()); + log_file_error(child->location.filename, child->location.first_line, "Re-definition of module `%s'!\n", child->str.c_str()); } else if (nooverwrite) { log("Ignoring re-definition of module `%s' at %s.\n", child->str.c_str(), child->loc_string().c_str()); @@ -1924,7 +1922,7 @@ void AstNode::input_error(const char *format, ...) const { va_list ap; va_start(ap, format); - logv_file_error(filename, location.first_line, format, ap); + logv_file_error(location.filename, location.first_line, format, ap); } YOSYS_NAMESPACE_END diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 4c75b6dfa..f881dfcb7 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -163,10 +163,11 @@ namespace AST }; struct AstSrcLocType { + std::string filename; unsigned int first_line, last_line; unsigned int first_column, last_column; - AstSrcLocType() : first_line(0), last_line(0), first_column(0), last_column(0) {} - AstSrcLocType(int _first_line, int _first_column, int _last_line, int _last_column) : first_line(_first_line), last_line(_last_line), first_column(_first_column), last_column(_last_column) {} + AstSrcLocType() : filename(""), first_line(0), last_line(0), first_column(0), last_column(0) {} + AstSrcLocType(std::string _filename, int _first_line, int _first_column, int _last_line, int _last_column) : filename(_filename), first_line(_first_line), last_line(_last_line), first_column(_first_column), last_column(_last_column) {} }; // convert an node type to a string (e.g. for debug output) @@ -223,7 +224,6 @@ namespace AST // this is the original sourcecode location that resulted in this AST node // it is automatically set by the constructor using AST::current_filename and // the AST::get_line_num() callback function. - std::string filename; AstSrcLocType location; // are we embedded in an lvalue, param? @@ -234,7 +234,7 @@ namespace AST bool in_param_from_above; // creating and deleting nodes - AstNode(AstNodeType type = AST_NONE, std::unique_ptr child1 = nullptr, std::unique_ptr child2 = nullptr, std::unique_ptr child3 = nullptr, std::unique_ptr child4 = nullptr); + AstNode(AstSrcLocType loc, AstNodeType type = AST_NONE, std::unique_ptr child1 = nullptr, std::unique_ptr child2 = nullptr, std::unique_ptr child3 = nullptr, std::unique_ptr child4 = nullptr); std::unique_ptr clone() const; void cloneInto(AstNode &other) const; void delete_children(); @@ -322,14 +322,14 @@ namespace AST AstNode operator=(AstNode) = delete; // helper functions for creating AST nodes for constants - static std::unique_ptr mkconst_int(uint32_t v, bool is_signed, int width = 32); - static std::unique_ptr mkconst_bits(const std::vector &v, bool is_signed, bool is_unsized); - static std::unique_ptr mkconst_bits(const std::vector &v, bool is_signed); - static std::unique_ptr mkconst_str(const std::vector &v); - static std::unique_ptr mkconst_str(const std::string &str); + static std::unique_ptr mkconst_int(AstSrcLocType loc, uint32_t v, bool is_signed, int width = 32); + static std::unique_ptr mkconst_bits(AstSrcLocType loc, const std::vector &v, bool is_signed, bool is_unsized); + static std::unique_ptr mkconst_bits(AstSrcLocType loc, const std::vector &v, bool is_signed); + static std::unique_ptr mkconst_str(AstSrcLocType loc, const std::vector &v); + static std::unique_ptr mkconst_str(AstSrcLocType loc, const std::string &str); // helper function to create an AST node for a temporary register - std::unique_ptr mktemp_logic(const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed); + std::unique_ptr mktemp_logic(AstSrcLocType loc, const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed); // helper function for creating sign-extended const objects RTLIL::Const bitsAsConst(int width, bool is_signed); @@ -409,7 +409,7 @@ namespace AST // to initialize the filename and linenum properties of new nodes extern std::string current_filename; // also set by the language frontend to control some AST processing - extern bool sv_mode; + extern bool sv_mode_but_global_and_used_for_literally_one_condition; // for stats unsigned long long astnode_count(); @@ -419,7 +419,7 @@ namespace AST void use_internal_line_num(); // call a DPI function - std::unique_ptr dpi_call(const std::string &rtype, const std::string &fname, const std::vector &argtypes, const std::vector> &args); + std::unique_ptr dpi_call(AstSrcLocType loc, const std::string &rtype, const std::string &fname, const std::vector &argtypes, const std::vector> &args); // Helper functions related to handling SystemVerilog interfaces std::pair split_modport_from_type(std::string name_type); diff --git a/frontends/ast/dpicall.cc b/frontends/ast/dpicall.cc index 4fa375df7..07314e3d7 100644 --- a/frontends/ast/dpicall.cc +++ b/frontends/ast/dpicall.cc @@ -64,7 +64,7 @@ static ffi_fptr resolve_fn (std::string symbol_name) log_error("unable to resolve '%s'.\n", symbol_name.c_str()); } -std::unique_ptr AST::dpi_call(const std::string &rtype, const std::string &fname, const std::vector &argtypes, const std::vector> &args) +std::unique_ptr AST::dpi_call(AstSrcLocType loc, const std::string &rtype, const std::string &fname, const std::vector &argtypes, const std::vector> &args) { std::unique_ptr newNode = nullptr; union value { double f64; float f32; int32_t i32; void *ptr; }; @@ -125,11 +125,11 @@ std::unique_ptr AST::dpi_call(const std::string &rtype, const std: ffi_call(&cif, resolve_fn(fname.c_str()), values[args.size()], values.data()); if (rtype == "real") { - newNode = std::make_unique(AST_REALVALUE); + newNode = std::make_unique(loc, AST_REALVALUE); newNode->realvalue = value_store[args.size()].f64; log(" return realvalue: %g\n", newNode->asReal(true)); } else if (rtype == "shortreal") { - newNode = std::make_unique(AST_REALVALUE); + newNode = std::make_unique(loc, AST_REALVALUE); newNode->realvalue = value_store[args.size()].f32; log(" return realvalue: %g\n", newNode->asReal(true)); } else if (rtype == "chandle") { @@ -137,10 +137,10 @@ std::unique_ptr AST::dpi_call(const std::string &rtype, const std: std::vector bits(64); for (int i = 0; i < 64; i++) bits.at(i) = (rawval & (1ULL << i)) ? RTLIL::State::S1 : RTLIL::State::S0; - newNode = AstNode::mkconst_bits(bits, false); + newNode = AstNode::mkconst_bits(loc, bits, false); log(" return chandle: %llx\n", (unsigned long long)newNode->asInt(false)); } else { - newNode = AstNode::mkconst_int(value_store[args.size()].i32, false); + newNode = AstNode::mkconst_int(loc, value_store[args.size()].i32, false); log(" return integer: %lld\n", (long long)newNode->asInt(true)); } @@ -153,7 +153,7 @@ YOSYS_NAMESPACE_END YOSYS_NAMESPACE_BEGIN -AST::AstNode *AST::dpi_call(const std::string&, const std::string &fname, const std::vector&, const std::vector&) +AST::AstNode *AST::dpi_call(AstSrcLocType loc, const std::string&, const std::string &fname, const std::vector&, const std::vector&) { log_error("Can't call DPI function `%s': this version of yosys is built without plugin support\n", fname.c_str()); } diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 994c87da6..dadc4129f 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -45,7 +45,7 @@ using namespace AST_INTERNAL; // helper function for creating RTLIL code for unary operations static RTLIL::SigSpec uniop2rtlil(AstNode *that, IdString type, int result_width, const RTLIL::SigSpec &arg, bool gen_attributes = true) { - IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(that->filename).c_str(), that->location.first_line, autoidx++); + IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(that->location.filename).c_str(), that->location.first_line, autoidx++); RTLIL::Cell *cell = current_module->addCell(name, type); set_src_attr(cell, that); @@ -77,7 +77,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s return; } - IdString name = stringf("$extend$%s:%d$%d", RTLIL::encode_filename(that->filename).c_str(), that->location.first_line, autoidx++); + IdString name = stringf("$extend$%s:%d$%d", RTLIL::encode_filename(that->location.filename).c_str(), that->location.first_line, autoidx++); RTLIL::Cell *cell = current_module->addCell(name, ID($pos)); set_src_attr(cell, that); @@ -104,7 +104,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s // helper function for creating RTLIL code for binary operations static RTLIL::SigSpec binop2rtlil(AstNode *that, IdString type, int result_width, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right) { - IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(that->filename).c_str(), that->location.first_line, autoidx++); + IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(that->location.filename).c_str(), that->location.first_line, autoidx++); RTLIL::Cell *cell = current_module->addCell(name, type); set_src_attr(cell, that); @@ -138,7 +138,7 @@ static RTLIL::SigSpec mux2rtlil(AstNode *that, const RTLIL::SigSpec &cond, const log_assert(cond.size() == 1); std::stringstream sstr; - sstr << "$ternary$" << RTLIL::encode_filename(that->filename) << ":" << that->location.first_line << "$" << (autoidx++); + sstr << "$ternary$" << RTLIL::encode_filename(that->location.filename) << ":" << that->location.first_line << "$" << (autoidx++); RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($mux)); set_src_attr(cell, that); @@ -347,7 +347,7 @@ struct AST_INTERNAL::ProcessGenerator LookaheadRewriter la_rewriter(always.get()); // generate process and simple root case - proc = current_module->addProcess(stringf("$proc$%s:%d$%d", RTLIL::encode_filename(always->filename).c_str(), always->location.first_line, autoidx++)); + proc = current_module->addProcess(stringf("$proc$%s:%d$%d", RTLIL::encode_filename(always->location.filename).c_str(), always->location.first_line, autoidx++)); set_src_attr(proc, always.get()); for (auto &attr : always->attributes) { if (attr.second->type != AST_CONSTANT) @@ -723,7 +723,7 @@ struct AST_INTERNAL::ProcessGenerator if (ast->str == "$display" || ast->str == "$displayb" || ast->str == "$displayh" || ast->str == "$displayo" || ast->str == "$write" || ast->str == "$writeb" || ast->str == "$writeh" || ast->str == "$writeo") { std::stringstream sstr; - sstr << ast->str << "$" << ast->filename << ":" << ast->location.first_line << "$" << (autoidx++); + sstr << ast->str << "$" << ast->location.filename << ":" << ast->location.first_line << "$" << (autoidx++); Wire *en = current_module->addWire(sstr.str() + "_EN", 1); set_src_attr(en, ast); @@ -766,7 +766,7 @@ struct AST_INTERNAL::ProcessGenerator node->detectSignWidth(width, is_signed, nullptr); VerilogFmtArg arg = {}; - arg.filename = node->filename; + arg.filename = node->location.filename; arg.first_line = node->location.first_line; if (node->type == AST_CONSTANT && node->is_string) { arg.type = VerilogFmtArg::STRING; @@ -793,7 +793,7 @@ struct AST_INTERNAL::ProcessGenerator fmt.append_literal("\n"); fmt.emit_rtlil(cell); } else if (!ast->str.empty()) { - log_file_error(ast->filename, ast->location.first_line, "Found unsupported invocation of system task `%s'!\n", ast->str.c_str()); + log_file_error(ast->location.filename, ast->location.first_line, "Found unsupported invocation of system task `%s'!\n", ast->str.c_str()); } break; @@ -813,7 +813,7 @@ struct AST_INTERNAL::ProcessGenerator IdString cellname; if (ast->str.empty()) - cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(ast->filename).c_str(), ast->location.first_line, autoidx++); + cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(ast->location.filename).c_str(), ast->location.first_line, autoidx++); else cellname = ast->str; check_unique_id(current_module, cellname, ast, "procedural assertion"); @@ -843,7 +843,7 @@ struct AST_INTERNAL::ProcessGenerator set_src_attr(cell, ast); for (auto &attr : ast->attributes) { if (attr.second->type != AST_CONSTANT) - log_file_error(ast->filename, ast->location.first_line, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); + log_file_error(ast->location.filename, ast->location.first_line, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); cell->attributes[attr.first] = attr.second->asAttrConst(); } cell->setParam(ID::FLAVOR, flavor); @@ -1503,7 +1503,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) } RTLIL::SigSpec sig = realAsConst(width_hint); - log_file_warning(filename, location.first_line, "converting real value %e to binary %s.\n", realvalue, log_signal(sig)); + log_file_warning(location.filename, location.first_line, "converting real value %e to binary %s.\n", realvalue, log_signal(sig)); return sig; } @@ -1535,7 +1535,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (dynamic_cast(current_module)) { /* nothing to do here */ } else if (flag_autowire) - log_file_warning(filename, location.first_line, "Identifier `%s' is implicitly declared.\n", str.c_str()); + log_file_warning(location.filename, location.first_line, "Identifier `%s' is implicitly declared.\n", str.c_str()); else input_error("Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str()); } @@ -1640,10 +1640,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) chunk.offset = source_width - (chunk.offset + chunk.width); if (chunk.offset > chunk_left || chunk.offset + chunk.width < chunk_right) { if (chunk.width == 1) - log_file_warning(filename, location.first_line, "Range select out of bounds on signal `%s': Setting result bit to undef.\n", + log_file_warning(location.filename, location.first_line, "Range select out of bounds on signal `%s': Setting result bit to undef.\n", str.c_str()); else - log_file_warning(filename, location.first_line, "Range select [%d:%d] out of bounds on signal `%s': Setting all %d result bits to undef.\n", + log_file_warning(location.filename, location.first_line, "Range select [%d:%d] out of bounds on signal `%s': Setting all %d result bits to undef.\n", children[0]->range_left, children[0]->range_right, str.c_str(), chunk.width); chunk = RTLIL::SigChunk(RTLIL::State::Sx, chunk.width); } else { @@ -1657,10 +1657,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) chunk.offset += add_undef_bits_lsb; } if (add_undef_bits_lsb) - log_file_warning(filename, location.first_line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d LSB bits to undef.\n", + log_file_warning(location.filename, location.first_line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d LSB bits to undef.\n", children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_lsb); if (add_undef_bits_msb) - log_file_warning(filename, location.first_line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d MSB bits to undef.\n", + log_file_warning(location.filename, location.first_line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d MSB bits to undef.\n", children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_msb); } } @@ -1934,7 +1934,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) case AST_MEMRD: { std::stringstream sstr; - sstr << "$memrd$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); + sstr << "$memrd$" << str << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++); RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($memrd)); set_src_attr(cell, this); @@ -1972,7 +1972,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) case AST_MEMINIT: { std::stringstream sstr; - sstr << "$meminit$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); + sstr << "$meminit$" << str << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++); SigSpec en_sig = children[2]->genRTLIL(); @@ -2017,7 +2017,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) IdString cellname; if (str.empty()) - cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); + cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(location.filename).c_str(), location.first_line, autoidx++); else cellname = str; check_unique_id(current_module, cellname, this, "procedural assertion"); @@ -2060,7 +2060,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) new_left.append(left[i]); new_right.append(right[i]); } - log_file_warning(filename, location.first_line, "Ignoring assignment to constant bits:\n" + log_file_warning(location.filename, location.first_line, "Ignoring assignment to constant bits:\n" " old assignment: %s = %s\n new assignment: %s = %s.\n", log_signal(left), log_signal(right), log_signal(new_left), log_signal(new_right)); @@ -2095,7 +2095,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str; const AstNode *value = child->children[0].get(); if (value->type == AST_REALVALUE) - log_file_warning(filename, location.first_line, "Replacing floating point parameter %s.%s = %f with string.\n", + log_file_warning(location.filename, location.first_line, "Replacing floating point parameter %s.%s = %f with string.\n", log_id(cell), log_id(paraname), value->realvalue); else if (value->type != AST_CONSTANT) input_error("Parameter %s.%s with non-constant value!\n", @@ -2192,14 +2192,14 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) int sz = children.size(); if (str == "$info") { if (sz > 0) - log_file_info(filename, location.first_line, "%s.\n", children[0]->str.c_str()); + log_file_info(location.filename, location.first_line, "%s.\n", children[0]->str.c_str()); else - log_file_info(filename, location.first_line, "\n"); + log_file_info(location.filename, location.first_line, "\n"); } else if (str == "$warning") { if (sz > 0) - log_file_warning(filename, location.first_line, "%s.\n", children[0]->str.c_str()); + log_file_warning(location.filename, location.first_line, "%s.\n", children[0]->str.c_str()); else - log_file_warning(filename, location.first_line, "\n"); + log_file_warning(location.filename, location.first_line, "\n"); } else if (str == "$error") { if (sz > 0) input_error("%s.\n", children[0]->str.c_str()); diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index f4c27caf4..402dcb1e0 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -155,7 +155,7 @@ Fmt AstNode::processFormat(int stage, bool sformat_like, int default_base, size_ while (node_arg->simplify(true, stage, -1, false)) { } VerilogFmtArg arg = {}; - arg.filename = filename; + arg.filename = location.filename; arg.first_line = location.first_line; if (node_arg->type == AST_CONSTANT && node_arg->is_string) { arg.type = VerilogFmtArg::STRING; @@ -173,10 +173,10 @@ Fmt AstNode::processFormat(int stage, bool sformat_like, int default_base, size_ arg.sig = node_arg->bitsAsConst(); arg.signed_ = node_arg->is_signed; } else if (may_fail) { - log_file_info(filename, location.first_line, "Skipping system task `%s' with non-constant argument at position %zu.\n", str.c_str(), index + 1); + log_file_info(location.filename, location.first_line, "Skipping system task `%s' with non-constant argument at position %zu.\n", str.c_str(), index + 1); return Fmt(); } else { - log_file_error(filename, location.first_line, "Failed to evaluate system task `%s' with non-constant argument at position %zu.\n", str.c_str(), index + 1); + log_file_error(location.filename, location.first_line, "Failed to evaluate system task `%s' with non-constant argument at position %zu.\n", str.c_str(), index + 1); } args.push_back(arg); } @@ -240,20 +240,20 @@ void AstNode::annotateTypedEnums(AstNode *template_node) RTLIL::Const val = enum_item->children[0]->bitsAsConst(width, is_signed); enum_item_str.append(val.as_string()); //set attribute for available val to enum item name mappings - set_attribute(enum_item_str.c_str(), mkconst_str(enum_item->str)); + set_attribute(enum_item_str.c_str(), mkconst_str(location, enum_item->str)); } } } -static std::unique_ptr make_range(int left, int right, bool is_signed = false) +static std::unique_ptr make_range(AstSrcLocType loc, int left, int right, bool is_signed = false) { // generate a pre-validated range node for a fixed signal range. - auto range = std::make_unique(AST_RANGE); + auto range = std::make_unique(loc, AST_RANGE); range->range_left = left; range->range_right = right; range->range_valid = true; - range->children.push_back(AstNode::mkconst_int(left, true)); - range->children.push_back(AstNode::mkconst_int(right, true)); + range->children.push_back(AstNode::mkconst_int(loc, left, true)); + range->children.push_back(AstNode::mkconst_int(loc, right, true)); range->is_signed = is_signed; return range; } @@ -388,30 +388,32 @@ static int size_packed_struct(AstNode *snode, int base_offset) return width; } -static std::unique_ptr node_int(int ival) +static std::unique_ptr node_int(AstSrcLocType loc, int ival) { - return AstNode::mkconst_int(ival, true); + return AstNode::mkconst_int(loc, ival, true); } static std::unique_ptr multiply_by_const(std::unique_ptr expr_node, int stride) { - return std::make_unique(AST_MUL, std::move(expr_node), node_int(stride)); + auto loc = expr_node->location; + return std::make_unique(loc, AST_MUL, std::move(expr_node), node_int(loc, stride)); } static std::unique_ptr normalize_index(AstNode *expr, AstNode *decl_node, int dimension) { auto new_expr = expr->clone(); + auto loc = expr->location; int offset = decl_node->dimensions[dimension].range_right; if (offset) { - new_expr = std::make_unique(AST_SUB, std::move(new_expr), node_int(offset)); + new_expr = std::make_unique(loc, AST_SUB, std::move(new_expr), node_int(loc, offset)); } // Packed dimensions are normally indexed by lsb, while unpacked dimensions are normally indexed by msb. if ((dimension < decl_node->unpacked_dimensions) ^ decl_node->dimensions[dimension].range_swapped) { // Swap the index if the dimension is declared the "wrong" way. int left = decl_node->dimensions[dimension].range_width - 1; - new_expr = std::make_unique(AST_SUB, node_int(left), std::move(new_expr)); + new_expr = std::make_unique(loc, AST_SUB, node_int(loc, left), std::move(new_expr)); } return new_expr; @@ -433,7 +435,7 @@ static std::unique_ptr index_msb_offset(std::unique_ptr lsb_of std::unique_ptr add_offset; if (rnode->children.size() == 1) { // Index, e.g. s.a[i] - add_offset = node_int(stride - 1); + add_offset = node_int(rnode->location, stride - 1); } else { // rnode->children.size() == 2 @@ -620,7 +622,7 @@ const RTLIL::Module* AstNode::lookup_cell_module() auto reprocess_after = [this] (const std::string &modname) { if (!attributes.count(ID::reprocess_after)) - set_attribute(ID::reprocess_after, AstNode::mkconst_str(modname)); + set_attribute(ID::reprocess_after, AstNode::mkconst_str(location, modname)); }; const AstNode *celltype = nullptr; @@ -929,7 +931,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin #if 0 log("-------------\n"); - log("AST simplify[%d] depth %d at %s:%d on %s %p:\n", stage, recursion_counter, filename.c_str(), location.first_line, type2str(type).c_str(), this); + log("AST simplify[%d] depth %d at %s:%d on %s %p:\n", stage, recursion_counter, location.filename.c_str(), location.first_line, type2str(type).c_str(), this); log("const_fold=%d, stage=%d, width_hint=%d, sign_hint=%d\n", int(const_fold), int(stage), int(width_hint), int(sign_hint)); // dumpAst(nullptr, "> "); @@ -1020,7 +1022,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin for (auto &it : node->attributes) if (it.first != ID::mem2reg) reg->set_attribute(it.first, it.second->clone()); - reg->filename = node->filename; + reg->location.filename = node->location.filename; reg->location = node->location; while (reg->simplify(true, 1, -1, false)) { } children.push_back(std::move(reg)); @@ -1049,7 +1051,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // note that $display, $finish, and $stop are used for synthesis-time DRC so they're not in this list if ((type == AST_FCALL || type == AST_TCALL) && (str == "$strobe" || str == "$monitor" || str == "$time" || str == "$dumpfile" || str == "$dumpvars" || str == "$dumpon" || str == "$dumpoff" || str == "$dumpall")) { - log_file_warning(filename, location.first_line, "Ignoring call to system %s %s.\n", type == AST_FCALL ? "function" : "task", str.c_str()); + log_file_warning(location.filename, location.first_line, "Ignoring call to system %s %s.\n", type == AST_FCALL ? "function" : "task", str.c_str()); delete_children(); str = std::string(); } @@ -1059,7 +1061,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin str == "$write" || str == "$writeb" || str == "$writeh" || str == "$writeo")) { if (!current_always) { - log_file_warning(filename, location.first_line, "System task `%s' outside initial or always block is unsupported.\n", str.c_str()); + log_file_warning(location.filename, location.first_line, "System task `%s' outside initial or always block is unsupported.\n", str.c_str()); delete_children(); str = std::string(); } else { @@ -1336,7 +1338,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // create the indirection wire std::stringstream sstr; - sstr << "$indirect$" << ref->name.c_str() << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); + sstr << "$indirect$" << ref->name.c_str() << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++); std::string tmp_str = sstr.str(); add_wire_for_ref(ref, tmp_str); @@ -2174,7 +2176,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin int width = std::abs(children[1]->range_left - children[1]->range_right) + 1; if (children[0]->type == AST_REALVALUE) { RTLIL::Const constvalue = children[0]->realAsConst(width); - log_file_warning(filename, location.first_line, "converting real value %e to binary %s.\n", + log_file_warning(location.filename, location.first_line, "converting real value %e to binary %s.\n", children[0]->realvalue, log_signal(constvalue)); children[0] = mkconst_bits(constvalue.to_bits(), sign_hint); fixup_hierarchy_flags(); @@ -2316,7 +2318,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin std::swap(data_range_left, data_range_right); std::stringstream sstr; - sstr << "$mem2bits$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); + sstr << "$mem2bits$" << str << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++); std::string wire_id = sstr.str(); auto wire_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(data_range_left, true), mkconst_int(data_range_right, true))); @@ -2536,7 +2538,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin for (size_t i = 0; i < children.size(); i++) if (children[i]->type == AST_WIRE || children[i]->type == AST_MEMORY || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM || children[i]->type == AST_TYPEDEF) { - log_assert(!sv_mode); + log_assert(!sv_mode_but_global_and_used_for_literally_one_condition); children[i]->input_error("Local declaration in unnamed block is only supported in SystemVerilog mode!\n"); } } @@ -3072,7 +3074,7 @@ skip_dynamic_range_lvalue_expansion:; auto wire_tmp_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(width_hint-1, true), mkconst_int(0, true))); auto wire_tmp = wire_tmp_owned.get(); - wire_tmp->str = stringf("$splitcmplxassign$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); + wire_tmp->str = stringf("$splitcmplxassign$%s:%d$%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line, autoidx++); current_scope[wire_tmp->str] = wire_tmp; current_ast_mod->children.push_back(std::move(wire_tmp_owned)); wire_tmp->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); @@ -3114,7 +3116,7 @@ skip_dynamic_range_lvalue_expansion:; input_error("Insufficient number of array indices for %s.\n", log_id(str)); std::stringstream sstr; - sstr << "$memwr$" << children[0]->str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); + sstr << "$memwr$" << children[0]->str << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++); std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA", id_en = sstr.str() + "_EN"; int mem_width, mem_size, addr_bits; @@ -3385,7 +3387,7 @@ skip_dynamic_range_lvalue_expansion:; auto* reg = reg_owned.get(); current_ast_mod->children.push_back(std::move(reg_owned)); - reg->str = stringf("$past$%s:%d$%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, myidx, i); + reg->str = stringf("$past$%s:%d$%d$%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line, myidx, i); reg->is_reg = true; reg->is_signed = sign_hint; @@ -3761,7 +3763,7 @@ skip_dynamic_range_lvalue_expansion:; input_error("Failed to evaluate DPI function with non-constant argument.\n"); } - newNode = dpi_call(rtype, fname, argtypes, args); + newNode = dpi_call(dpi_decl->location, rtype, fname, argtypes, args); goto apply_newNode; } @@ -3845,7 +3847,7 @@ skip_dynamic_range_lvalue_expansion:; std::stringstream sstr; - sstr << str << "$func$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++) << '.'; + sstr << str << "$func$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++) << '.'; std::string prefix = sstr.str(); auto* decl = current_scope[str]; @@ -4375,7 +4377,7 @@ apply_newNode: // newNode->dumpAst(stderr, "+ "); log_assert(newNode != nullptr); // newNode->null_check(); - newNode->filename = filename; + newNode->location.filename = location.filename; newNode->location = location; newNode->cloneInto(*this); fixup_hierarchy_flags(); @@ -4422,7 +4424,7 @@ std::unique_ptr AstNode::readmem(bool is_readmemh, std::string mem_file #else char slash = '/'; #endif - std::string path = filename.substr(0, filename.find_last_of(slash)+1); + std::string path = location.filename.substr(0, location.filename.find_last_of(slash)+1); f.open(path + mem_filename.c_str()); yosys_input_files.insert(path + mem_filename); } else { @@ -4479,7 +4481,7 @@ std::unique_ptr AstNode::readmem(bool is_readmemh, std::string mem_file continue; } - VERILOG_FRONTEND::ConstParser p{mem_filename, std::nullopt}; + VERILOG_FRONTEND::ConstParser p{memory->location}; auto value = p.const2ast(stringf("%d'%c", mem_width, is_readmemh ? 'h' : 'b') + token); if (unconditional_init) @@ -4701,7 +4703,7 @@ static void mark_memories_assign_lhs_complex(dict> & if (that->type == AST_IDENTIFIER && that->id2ast && that->id2ast->type == AST_MEMORY) { AstNode *mem = that->id2ast; if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_CMPLX_LHS)) - mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(that->filename).c_str(), that->location.first_line)); + mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(that->location.filename).c_str(), that->location.first_line)); mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_CMPLX_LHS; } } @@ -4729,14 +4731,14 @@ void AstNode::mem2reg_as_needed_pass1(dict> &mem2reg // activate mem2reg if this is assigned in an async proc if (flags & AstNode::MEM2REG_FL_ASYNC) { if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_ASYNC)) - mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(filename).c_str(), location.first_line)); + mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line)); mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_SET_ASYNC; } // remember if this is assigned blocking (=) if (type == AST_ASSIGN_EQ) { if (!(proc_flags[mem] & AstNode::MEM2REG_FL_EQ1)) - mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(filename).c_str(), location.first_line)); + mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line)); proc_flags[mem] |= AstNode::MEM2REG_FL_EQ1; } @@ -4753,11 +4755,11 @@ void AstNode::mem2reg_as_needed_pass1(dict> &mem2reg // remember where this is if (flags & MEM2REG_FL_INIT) { if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_INIT)) - mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(filename).c_str(), location.first_line)); + mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line)); mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_SET_INIT; } else { if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_ELSE)) - mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(filename).c_str(), location.first_line)); + mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line)); mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_SET_ELSE; } } @@ -4774,7 +4776,7 @@ void AstNode::mem2reg_as_needed_pass1(dict> &mem2reg // flag if used after blocking assignment (in same proc) if ((proc_flags[mem] & AstNode::MEM2REG_FL_EQ1) && !(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_EQ2)) { - mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(filename).c_str(), location.first_line)); + mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line)); mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_EQ2; } } @@ -4960,7 +4962,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, children[0]->children[0]->children[0]->type != AST_CONSTANT) { std::stringstream sstr; - sstr << "$mem2reg_wr$" << children[0]->str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); + sstr << "$mem2reg_wr$" << children[0]->str << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++); std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA"; int mem_width, mem_size, addr_bits; @@ -5079,7 +5081,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, else { std::stringstream sstr; - sstr << "$mem2reg_rd$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); + sstr << "$mem2reg_rd$" << str << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++); std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA"; int mem_width, mem_size, addr_bits; diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc index cc8baf6aa..338b13e4b 100644 --- a/frontends/verilog/Makefile.inc +++ b/frontends/verilog/Makefile.inc @@ -13,6 +13,7 @@ frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y frontends/verilog/verilog_parser.tab.hh: frontends/verilog/verilog_parser.tab.cc frontends/verilog/verilog_frontend.h: frontends/verilog/verilog_parser.tab.hh +frontends/verilog/verilog_error.h: frontends/verilog/verilog_parser.tab.hh frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l frontends/verilog/verilog_parser.tab.cc $(Q) mkdir -p $(dir $@) @@ -24,5 +25,6 @@ OBJS += frontends/verilog/verilog_parser.tab.o OBJS += frontends/verilog/verilog_lexer.o OBJS += frontends/verilog/preproc.o OBJS += frontends/verilog/verilog_frontend.o +OBJS += frontends/verilog/verilog_error.o OBJS += frontends/verilog/const2ast.o diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc index 9c4a2e76c..cd8f05b9b 100644 --- a/frontends/verilog/const2ast.cc +++ b/frontends/verilog/const2ast.cc @@ -46,11 +46,8 @@ using namespace VERILOG_FRONTEND; std::string ConstParser::fmt_maybe_loc(std::string msg) { std::string s; - s += filename.value_or("INTERNAL"); - if (loc) - s += stringf("%d", loc->first_line); - s += ": "; + s += stringf("%s:%d:", loc.filename, loc.first_line); s += msg; return s; @@ -191,7 +188,7 @@ std::unique_ptr ConstParser::const2ast(std::string code, char case_type ch = ch >> 1; } } - auto ast = AstNode::mkconst_bits(data, false); + auto ast = AstNode::mkconst_bits(loc, data, false); ast->str = code; return ast; } @@ -210,7 +207,7 @@ std::unique_ptr ConstParser::const2ast(std::string code, char case_type my_strtobin(data, str, -1, 10, case_type, false); if (data.back() == State::S1) data.push_back(State::S0); - return AstNode::mkconst_bits(data, true); + return AstNode::mkconst_bits(loc, data, true); } // unsized constant @@ -258,7 +255,7 @@ std::unique_ptr ConstParser::const2ast(std::string code, char case_type if (is_signed && data.back() == State::S1) data.push_back(State::S0); } - return AstNode::mkconst_bits(data, is_signed, is_unsized); + return AstNode::mkconst_bits(loc, data, is_signed, is_unsized); } return NULL; diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index d4bee02da..d05f87aff 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -32,10 +32,12 @@ #include "verilog_frontend.h" #include "verilog_lexer.h" +#include "verilog_error.h" #include "preproc.h" #include "kernel/yosys.h" #include "libs/sha1/sha1.h" #include +#include YOSYS_NAMESPACE_BEGIN using namespace VERILOG_FRONTEND; @@ -47,10 +49,10 @@ static std::list> verilog_defaults_stack; static void error_on_dpi_function(AST::AstNode *node) { - if (node->type == AST::AST_DPI_FUNCTION) - log_file_error(node->filename, node->location.first_line, "Found DPI function %s.\n", node->str.c_str()); - for (auto& child : node->children) - error_on_dpi_function(child.get()); + if (node->type == AST::AST_DPI_FUNCTION) + err_at_ast(node->location, "Found DPI function %s.\n", node->str.c_str()); + for (auto& child : node->children) + error_on_dpi_function(child.get()); } static void add_package_types(dict &user_types, std::vector> &package_list) @@ -69,15 +71,7 @@ static void add_package_types(dict &user_types, std } struct VerilogFrontend : public Frontend { - ParseMode parse_mode; - ParseState parse_state; - VerilogLexer lexer; - frontend_verilog_yy::parser parser; - VerilogFrontend() : Frontend("verilog", "read modules from Verilog file"), - parse_mode(), - parse_state(), - lexer(&parse_state, &parse_mode), - parser(&lexer, &parse_state, &parse_mode) { } + VerilogFrontend() : Frontend("verilog", "read modules from Verilog file") { } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| @@ -259,6 +253,8 @@ struct VerilogFrontend : public Frontend { bool flag_dump_vlog1 = false; bool flag_dump_vlog2 = false; bool flag_dump_rtlil = false; + bool flag_debug_lexer = false; + bool flag_debug_parser = false; bool flag_nolatches = false; bool flag_nomeminit = false; bool flag_nomem2reg = false; @@ -281,8 +277,8 @@ struct VerilogFrontend : public Frontend { std::list include_dirs; std::list attributes; - lexer.set_debug(false); - parser.set_debug_level(0); + ParseMode parse_mode; + ParseState parse_state; parse_mode.sv = false; parse_mode.formal = false; parse_mode.noassert = false; @@ -340,8 +336,8 @@ struct VerilogFrontend : public Frontend { flag_dump_ast2 = true; flag_dump_vlog1 = true; flag_dump_vlog2 = true; - lexer.set_debug(true); - parser.set_debug_level(1); + flag_debug_lexer = true; + flag_debug_parser = true; continue; } if (arg == "-dump_ast1") { @@ -370,6 +366,8 @@ struct VerilogFrontend : public Frontend { } if (arg == "-yydebug") { flag_yydebug = true; + flag_debug_lexer = true; + flag_debug_parser = true; continue; } if (arg == "-nolatches") { @@ -481,6 +479,11 @@ struct VerilogFrontend : public Frontend { break; } + VerilogLexer lexer(&parse_state, &parse_mode, &filename); + frontend_verilog_yy::parser parser(&lexer, &parse_state, &parse_mode); + lexer.set_debug(flag_debug_lexer); + parser.set_debug_level(flag_debug_parser ? 1 : 0); + if (parse_mode.formal || !flag_nosynthesis) defines_map.add(parse_mode.formal ? "FORMAL" : "SYNTHESIS", "1"); @@ -491,10 +494,10 @@ struct VerilogFrontend : public Frontend { log("Parsing %s%s input from `%s' to AST representation.\n", parse_mode.formal ? "formal " : "", parse_mode.sv ? "SystemVerilog" : "Verilog", filename.c_str()); - AST::current_filename = filename; - AST::sv_mode = parse_mode.sv; + AST::sv_mode_but_global_and_used_for_literally_one_condition = parse_mode.sv; - parse_state.current_ast = new AST::AstNode(AST::AST_DESIGN); + AstSrcLocType top_loc = AstSrcLocType ( "read_verilog", 0, 0, 0, 0); + parse_state.current_ast = new AST::AstNode(top_loc, AST::AST_DESIGN); parse_state.lexin = f; std::string code_after_preproc; @@ -522,10 +525,6 @@ struct VerilogFrontend : public Frontend { // add a new empty type map to allow overriding existing global definitions parse_state.user_type_stack.push_back(UserTypeMap()); - parser.~parser(); - lexer.~VerilogLexer(); - new (&lexer) VerilogLexer(&parse_state, &parse_mode); - new (&parser) frontend_verilog_yy::parser(&lexer, &parse_state, &parse_mode); if (flag_yydebug) { lexer.set_debug(true); parser.set_debug_level(1); @@ -537,7 +536,7 @@ struct VerilogFrontend : public Frontend { if (child->type == AST::AST_MODULE) for (auto &attr : attributes) if (child->attributes.count(attr) == 0) - child->attributes[attr] = AST::AstNode::mkconst_int(1, false); + child->attributes[attr] = AST::AstNode::mkconst_int(top_loc, 1, false); } if (flag_nodpi) @@ -776,24 +775,4 @@ struct VerilogFileList : public Pass { #endif -[[noreturn]] -void VERILOG_FRONTEND::verr_at(std::string filename, int begin_line, char const *fmt, va_list ap) -{ - char buffer[1024]; - char *p = buffer; - p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap); - p += snprintf(p, buffer + sizeof(buffer) - p, "\n"); - YOSYS_NAMESPACE_PREFIX log_file_error(filename, begin_line, "%s", buffer); - exit(1); -} - -[[noreturn]] -void VERILOG_FRONTEND::err_at_ast(AstSrcLocType loc, char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - verr_at(AST::current_filename, loc.first_line, fmt, args); - va_end(args); -} - YOSYS_NAMESPACE_END diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h index 29c16c039..e97cee4fc 100644 --- a/frontends/verilog/verilog_frontend.h +++ b/frontends/verilog/verilog_frontend.h @@ -39,7 +39,6 @@ #include #include -#include YOSYS_NAMESPACE_BEGIN @@ -47,8 +46,7 @@ namespace VERILOG_FRONTEND { /* Ephemeral context class */ struct ConstParser { - std::optional filename; - std::optional loc; + AST::AstSrcLocType loc; private: std::string fmt_maybe_loc(std::string msg); void log_maybe_loc_error(std::string msg); @@ -64,8 +62,6 @@ namespace VERILOG_FRONTEND std::unique_ptr const2ast(std::string code, char case_type = 0, bool warn_z = false); }; - [[noreturn]] - extern void err_at_ast(AST::AstSrcLocType loc, char const *fmt, ...); }; YOSYS_NAMESPACE_END diff --git a/frontends/verilog/verilog_lexer.h b/frontends/verilog/verilog_lexer.h index 2c31160dd..a4f3d9bfb 100644 --- a/frontends/verilog/verilog_lexer.h +++ b/frontends/verilog/verilog_lexer.h @@ -4,18 +4,20 @@ #include "kernel/yosys.h" #include "frontends/ast/ast.h" #include "frontends/verilog/verilog_parser.tab.hh" +#include YOSYS_NAMESPACE_BEGIN namespace VERILOG_FRONTEND { - [[noreturn]] - extern void verr_at(std::string filename, int begin_line, char const *fmt, va_list ap); using parser = frontend_verilog_yy::parser; class VerilogLexer : public frontend_verilog_yyFlexLexer { ParseState* extra; ParseMode* mode; public: - VerilogLexer(ParseState* e, ParseMode* m) : frontend_verilog_yyFlexLexer(e->lexin), extra(e), mode(m) {} + parser::location_type out_loc; // TODO private? + VerilogLexer(ParseState* e, ParseMode* m, std::string* filename) : frontend_verilog_yyFlexLexer(e->lexin), extra(e), mode(m) { + out_loc.begin.filename = filename; + } ~VerilogLexer() override {} // autogenerated body due to YY_DECL parser::symbol_type nextToken(); @@ -24,19 +26,9 @@ namespace VERILOG_FRONTEND { parser::symbol_type terminate() { return parser::make_FRONTEND_VERILOG_YYEOF(out_loc); } - parser::location_type out_loc; - [[noreturn]] - void err(char const *fmt, ...) - { - va_list args; - va_start(args, fmt); - verr_at(AST::current_filename, yylineno, fmt, args); - } private: std::vector fn_stack; std::vector ln_stack; - parser::location_type real_loc; - parser::location_type old_loc; int LexerInput(char* buf, int max_size) override { return readsome(*extra->lexin, buf, max_size); } diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index d57912265..f9e9dc2df 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -85,17 +85,16 @@ YOSYS_NAMESPACE_END // result = readsome(*extra->lexin, buf, max_size) #define YY_USER_ACTION \ - real_loc.begin = real_loc.end; \ + out_loc.begin = out_loc.end; \ for(int i = 0; YYText()[i] != '\0'; ++i){ \ if(YYText()[i] == '\n') { \ - real_loc.end.line++; \ - real_loc.end.column = 1; \ + out_loc.end.line++; \ + out_loc.end.column = 1; \ } \ else { \ - real_loc.end.column++; \ + out_loc.end.column++; \ } \ - } \ - out_loc = real_loc; + } #define YY_BREAK \ break; @@ -183,7 +182,6 @@ TIME_SCALE_SUFFIX [munpf]?s current_filename = current_filename.substr(0, current_filename.size()-1); yylineno = (0); out_loc.begin.line = out_loc.end.line = 0; - real_loc.begin.line = real_loc.end.line = 0; } "`file_pop"[^\n]*\n { @@ -191,7 +189,6 @@ TIME_SCALE_SUFFIX [munpf]?s fn_stack.pop_back(); yylineno = (ln_stack.back()); out_loc.begin.line = out_loc.end.line = ln_stack.back(); - real_loc.begin.line = real_loc.end.line = ln_stack.back(); ln_stack.pop_back(); } @@ -200,7 +197,6 @@ TIME_SCALE_SUFFIX [munpf]?s while (*p == ' ' || *p == '\t') p++; yylineno = (atoi(p)); out_loc.begin.line = out_loc.end.line = atoi(p); - real_loc.begin.line = real_loc.end.line = atoi(p); while (*p && *p != ' ' && *p != '\t') p++; while (*p == ' ' || *p == '\t') p++; const char *q = *p ? p + 1 : p; @@ -226,14 +222,14 @@ TIME_SCALE_SUFFIX [munpf]?s else if (!strcmp(p, "wire")) extra->default_nettype_wire = true; else - err("Unsupported default nettype: %s", p); + err_at_loc(out_loc, "Unsupported default nettype: %s", p); } "`protect"[^\n]* /* ignore `protect*/ "`endprotect"[^\n]* /* ignore `endprotect*/ "`"[a-zA-Z_$][a-zA-Z0-9_$]* { - err("Unimplemented compiler directive or undefined macro %s.", YYText()); + err_at_loc(out_loc, "Unimplemented compiler directive or undefined macro %s.", YYText()); } "module" { return parser::make_TOK_MODULE(out_loc); } diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 24a21a740..527d01247 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -45,7 +45,7 @@ %code requires { #include "kernel/yosys_common.h" - // #include "frontends/verilog/verilog_lexer.h" + #include "frontends/verilog/verilog_error.h" // start requires YOSYS_NAMESPACE_BEGIN namespace VERILOG_FRONTEND { @@ -157,8 +157,7 @@ static ConstParser make_ConstParser_here(parser::location_type flex_loc) { AstSrcLocType loc; SET_LOC(loc, flex_loc, flex_loc); - std::optional filename = flex_loc.begin.filename ? std::make_optional(*(flex_loc.begin.filename)) : std::nullopt; - ConstParser p{filename, loc}; + ConstParser p{loc}; return p; } static void append_attr(AstNode *ast, dict> *al) @@ -244,17 +243,6 @@ node->children.push_back(std::move(rangeNode)); } - [[noreturn]] - extern void verr_at(std::string filename, int begin_line, char const *fmt, va_list ap); - [[noreturn]] - static void err_at_loc(frontend_verilog_yy::parser::location_type loc, char const *fmt, ...) - { - va_list args; - va_start(args, fmt); - verr_at(AST::current_filename, loc.begin.line, fmt, args); - va_end(args); - } - static void checkLabelsMatch(const frontend_verilog_yy::parser::location_type& loc, const char *element, const std::string* before, const std::string *after) { if (!before && after) @@ -731,7 +719,7 @@ module: append_attr(mod, $1); } module_para_opt module_args_opt TOK_SEMICOL module_body TOK_ENDMODULE opt_label { if (extra->port_stubs.size() != 0) - lexer->err("Missing details for module port `%s'.", + err_at_loc(@7, "Missing details for module port `%s'.", extra->port_stubs.begin()->first.c_str()); SET_AST_NODE_LOC(extra->ast_stack.back(), @2, @$); extra->ast_stack.pop_back(); @@ -785,7 +773,7 @@ module_arg_opt_assignment: extra->ast_stack.back()->children.push_back(std::make_unique(AST_ASSIGN, std::move(wire), std::move($2))); } } else - lexer->err("SystemVerilog interface in module port list cannot have a default value."); + err_at_loc(@2, "SystemVerilog interface in module port list cannot have a default value."); } | %empty; @@ -799,7 +787,7 @@ module_arg: extra->ast_stack.back()->children.push_back(std::move(node)); } else { if (extra->port_stubs.count(*$1) != 0) - lexer->err("Duplicate module port `%s'.", $1->c_str()); + err_at_loc(@1, "Duplicate module port `%s'.", $1->c_str()); extra->port_stubs[*$1] = ++extra->port_counter; } } module_arg_opt_assignment | @@ -809,7 +797,7 @@ module_arg: extra->astbuf1->children[0]->str = *$1; } TOK_ID { /* SV interfaces */ if (!mode->sv) - lexer->err("Interface found in port list (%s). This is not supported unless read_verilog is called with -sv!", $3->c_str()); + err_at_loc(@3, "Interface found in port list (%s). This is not supported unless read_verilog is called with -sv!", $3->c_str()); extra->astbuf2 = extra->astbuf1->clone(); // really only needed if multiple instances of same type. extra->astbuf2->str = *$3; extra->astbuf2->port_id = ++extra->port_counter; @@ -824,9 +812,9 @@ module_arg: if (range != nullptr) node->children.push_back(std::move(range)); if (!node->is_input && !node->is_output) - lexer->err("Module port `%s' is neither input nor output.", $4->c_str()); + err_at_loc(@4, "Module port `%s' is neither input nor output.", $4->c_str()); if (node->is_reg && node->is_input && !node->is_output && !mode->sv) - lexer->err("Input port `%s' is declared as register.", $4->c_str()); + err_at_loc(@4, "Input port `%s' is declared as register.", $4->c_str()); append_attr(node.get(), $1); extra->ast_stack.back()->children.push_back(std::move(node)); } module_arg_opt_assignment | @@ -867,7 +855,7 @@ interface: intf->str = *$3; } module_para_opt module_args_opt TOK_SEMICOL interface_body TOK_ENDINTERFACE { if (extra->port_stubs.size() != 0) - lexer->err("Missing details for module port `%s'.", + err_at_loc(@6, "Missing details for module port `%s'.", extra->port_stubs.begin()->first.c_str()); extra->ast_stack.pop_back(); log_assert(extra->ast_stack.size() == 1); @@ -1284,7 +1272,7 @@ task_func_port: extra->astbuf2 = checkRange(extra->astbuf1.get(), std::move($3)); if (!extra->astbuf1->is_input && !extra->astbuf1->is_output) { if (!mode->sv) - lexer->err("task/function argument direction missing"); + err_at_loc(@2, "task/function argument direction missing"); extra->astbuf1->is_input = prev_was_input; extra->astbuf1->is_output = prev_was_output; } @@ -1292,7 +1280,7 @@ task_func_port: { if (!extra->astbuf1) { if (!mode->sv) - lexer->err("task/function argument direction missing"); + err_at_loc(@$, "task/function argument direction missing"); extra->albuf = new dict>; extra->astbuf1 = std::make_unique(AST_WIRE); extra->current_wire_rand = false; @@ -1325,7 +1313,7 @@ specify_item: specify_rise_fall_ptr_t timing = std::move($9); if (specify_edge != 0 && target->dat == nullptr) - lexer->err("Found specify edge but no data spec.\n"); + err_at_loc(@3, "Found specify edge but no data spec.\n"); auto cell_owned = std::make_unique(AST_CELL); auto cell = cell_owned.get(); @@ -1400,7 +1388,7 @@ specify_item: TOK_ID TOK_LPAREN specify_edge expr specify_condition TOK_COMMA specify_edge expr specify_condition TOK_COMMA specify_triple specify_opt_triple TOK_RPAREN TOK_SEMICOL { if (*$1 != "$setup" && *$1 != "$hold" && *$1 != "$setuphold" && *$1 != "$removal" && *$1 != "$recovery" && *$1 != "$recrem" && *$1 != "$skew" && *$1 != "$timeskew" && *$1 != "$fullskew" && *$1 != "$nochange") - lexer->err("Unsupported specify rule type: %s\n", $1->c_str()); + err_at_loc(@1, "Unsupported specify rule type: %s\n", $1->c_str()); auto src_pen = AstNode::mkconst_int($3 != 0, false, 1); auto src_pol = AstNode::mkconst_int($3 == 'p', false, 1); @@ -1766,10 +1754,10 @@ single_param_decl: AstNode *decl = extra->ast_stack.back()->children.back().get(); if (decl->type != AST_PARAMETER) { log_assert(decl->type == AST_LOCALPARAM); - lexer->err("localparam initialization is missing!"); + err_at_loc(@1, "localparam initialization is missing!"); } if (!mode->sv) - lexer->err("Parameter defaults can only be omitted in SystemVerilog mode!"); + err_at_loc(@1, "Parameter defaults can only be omitted in SystemVerilog mode!"); decl->children.erase(decl->children.begin()); }; @@ -1778,7 +1766,7 @@ single_param_decl_ident: std::unique_ptr node_owned; if (extra->astbuf1 == nullptr) { if (!mode->sv) - lexer->err("In pure Verilog (not SystemVerilog), parameter/localparam with an initializer must use the parameter/localparam keyword"); + err_at_loc(@1, "In pure Verilog (not SystemVerilog), parameter/localparam with an initializer must use the parameter/localparam keyword"); node_owned = std::make_unique(AST_PARAMETER); node_owned->children.push_back(AstNode::mkconst_int(0, true)); } else { @@ -1929,7 +1917,7 @@ struct_body: opt_packed TOK_LCURL struct_member_list TOK_RCURL opt_packed: TOK_PACKED opt_signed_struct | - %empty { lexer->err("Only PACKED supported at this time"); }; + %empty { err_at_loc(@$, "Only PACKED supported at this time"); }; opt_signed_struct: TOK_SIGNED { extra->astbuf2->is_signed = true; } @@ -2114,7 +2102,7 @@ wire_name_and_opt_assign: wire_name: TOK_ID range_or_multirange { if (extra->astbuf1 == nullptr) - lexer->err("Internal error - should not happen - no AST_WIRE node."); + err_at_loc(@1, "Internal error - should not happen - no AST_WIRE node."); auto node = extra->astbuf1->clone(); node->str = *$1; append_attr_clone(node.get(), extra->albuf); @@ -2122,7 +2110,7 @@ wire_name: node->children.push_back(extra->astbuf2->clone()); if ($2 != nullptr) { if (node->is_input || node->is_output) - lexer->err("input/output/inout ports cannot have unpacked dimensions."); + err_at_loc(@2, "input/output/inout ports cannot have unpacked dimensions."); if (!extra->astbuf2 && !node->is_custom_type) { addRange(node.get(), 0, 0, false); } @@ -2133,21 +2121,21 @@ wire_name: node->port_id = extra->current_function_or_task_port_id++; } else if (extra->ast_stack.back()->type == AST_GENBLOCK) { if (node->is_input || node->is_output) - lexer->err("Cannot declare module port `%s' within a generate block.", $1->c_str()); + err_at_loc(@1, "Cannot declare module port `%s' within a generate block.", $1->c_str()); } else { if (extra->do_not_require_port_stubs && (node->is_input || node->is_output) && extra->port_stubs.count(*$1) == 0) { extra->port_stubs[*$1] = ++extra->port_counter; } if (extra->port_stubs.count(*$1) != 0) { if (!node->is_input && !node->is_output) - lexer->err("Module port `%s' is neither input nor output.", $1->c_str()); + err_at_loc(@1, "Module port `%s' is neither input nor output.", $1->c_str()); if (node->is_reg && node->is_input && !node->is_output && !mode->sv) - lexer->err("Input port `%s' is declared as register.", $1->c_str()); + err_at_loc(@1, "Input port `%s' is declared as register.", $1->c_str()); node->port_id = extra->port_stubs[*$1]; extra->port_stubs.erase(*$1); } else { if (node->is_input || node->is_output) - lexer->err("Module port `%s' is not declared in module header.", $1->c_str()); + err_at_loc(@1, "Module port `%s' is not declared in module header.", $1->c_str()); } } //FIXME: for some reason, TOK_ID has a location which always points to one column *after* the real last column... @@ -2169,7 +2157,7 @@ assign_expr: }; type_name: TOK_ID { $$ = std::move($1); } // first time seen - | TOK_USER_TYPE { if (extra->isInLocalScope($1.get())) lexer->err("Duplicate declaration of TYPEDEF '%s'", $1->c_str()+1); $$ = std::move($1); } + | TOK_USER_TYPE { if (extra->isInLocalScope($1.get())) err_at_loc(@1, "Duplicate declaration of TYPEDEF '%s'", $1->c_str()+1); $$ = std::move($1); } ; typedef_decl: @@ -2347,7 +2335,7 @@ cell_port_list: } if (has_positional_args && has_named_args) - lexer->err("Mix of positional and named cell ports."); + err_at_loc(@1, "Mix of positional and named cell ports."); }; cell_port_list_rules: @@ -2388,7 +2376,7 @@ cell_port: } | attr TOK_WILDCARD_CONNECT { if (!mode->sv) - lexer->err("Wildcard port connections are only supported in SystemVerilog mode."); + err_at_loc(@2, "Wildcard port connections are only supported in SystemVerilog mode."); extra->cell_hack->attributes[ID::wildcard_port_conns] = AstNode::mkconst_int(1, false); free_attr($1); }; @@ -2727,11 +2715,11 @@ for_initialization: extra->ast_stack.back()->children.push_back(std::move(node)); } | non_io_wire_type range TOK_ID { - lexer->err("For loop variable declaration is missing initialization!"); + err_at_loc(@3, "For loop variable declaration is missing initialization!"); } | non_io_wire_type range TOK_ID TOK_EQ expr { if (!mode->sv) - lexer->err("For loop inline variable declaration is only supported in SystemVerilog mode!"); + err_at_loc(@4, "For loop inline variable declaration is only supported in SystemVerilog mode!"); // loop variable declaration auto wire = std::move($1); @@ -2915,21 +2903,21 @@ if_attr: attr TOK_UNIQUE0 { AstNode *context = extra->ast_stack.back(); if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if)) - lexer->err("unique0 keyword cannot be used for 'else if' branch."); + err_at_loc(@2, "unique0 keyword cannot be used for 'else if' branch."); (*$1)[ID::parallel_case] = AstNode::mkconst_int(1, false); $$ = $1; } | attr TOK_PRIORITY { AstNode *context = extra->ast_stack.back(); if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if)) - lexer->err("priority keyword cannot be used for 'else if' branch."); + err_at_loc(@2, "priority keyword cannot be used for 'else if' branch."); (*$1)[ID::full_case] = AstNode::mkconst_int(1, false); $$ = $1; } | attr TOK_UNIQUE { AstNode *context = extra->ast_stack.back(); if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if)) - lexer->err("unique keyword cannot be used for 'else if' branch."); + err_at_loc(@2, "unique keyword cannot be used for 'else if' branch."); (*$1)[ID::full_case] = AstNode::mkconst_int(1, false); (*$1)[ID::parallel_case] = AstNode::mkconst_int(1, false); $$ = $1; @@ -3127,11 +3115,11 @@ genvar_identifier: genvar_initialization: TOK_GENVAR genvar_identifier { - lexer->err("Generate for loop variable declaration is missing initialization!"); + err_at_loc(@2, "Generate for loop variable declaration is missing initialization!"); } | TOK_GENVAR genvar_identifier TOK_EQ expr { if (!mode->sv) - lexer->err("Generate for loop inline variable declaration is only supported in SystemVerilog mode!"); + err_at_loc(@3, "Generate for loop inline variable declaration is only supported in SystemVerilog mode!"); AstNode* node = extra->saveChild(std::make_unique(AST_GENVAR)); node->is_reg = true; node->is_signed = true; @@ -3233,7 +3221,7 @@ basic_expr: } | TOK_LPAREN expr TOK_RPAREN integral_number { if ($4->compare(0, 1, "'") != 0) - lexer->err("Cast operation must be applied on sized constants e.g. () , while %s is not a sized constant.", $4->c_str()); + err_at_loc(@4, "Cast operation must be applied on sized constants e.g. () , while %s is not a sized constant.", $4->c_str()); auto p = make_ConstParser_here(@4); auto val = p.const2ast(*$4, extra->case_type_stack.size() == 0 ? 0 : extra->case_type_stack.back(), !mode->lib); if (val == nullptr) @@ -3242,7 +3230,7 @@ basic_expr: } | hierarchical_id integral_number { if ($2->compare(0, 1, "'") != 0) - lexer->err("Cast operation must be applied on sized constants, e.g. \'d0, while %s is not a sized constant.", $2->c_str()); + err_at_loc(@2, "Cast operation must be applied on sized constants, e.g. \'d0, while %s is not a sized constant.", $2->c_str()); auto bits = std::make_unique(AST_IDENTIFIER); bits->str = *$1; SET_AST_NODE_LOC(bits.get(), @1, @1); @@ -3491,25 +3479,25 @@ basic_expr: } | TOK_SIGNED OP_CAST TOK_LPAREN expr TOK_RPAREN { if (!mode->sv) - lexer->err("Static cast is only supported in SystemVerilog mode."); + err_at_loc(@2, "Static cast is only supported in SystemVerilog mode."); $$ = std::make_unique(AST_TO_SIGNED, std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); } | TOK_UNSIGNED OP_CAST TOK_LPAREN expr TOK_RPAREN { if (!mode->sv) - lexer->err("Static cast is only supported in SystemVerilog mode."); + err_at_loc(@2, "Static cast is only supported in SystemVerilog mode."); $$ = std::make_unique(AST_TO_UNSIGNED, std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); } | basic_expr OP_CAST TOK_LPAREN expr TOK_RPAREN { if (!mode->sv) - lexer->err("Static cast is only supported in SystemVerilog mode."); + err_at_loc(@2, "Static cast is only supported in SystemVerilog mode."); $$ = std::make_unique(AST_CAST_SIZE, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); } | typedef_base_type OP_CAST TOK_LPAREN expr TOK_RPAREN { if (!mode->sv) - lexer->err("Static cast is only supported in SystemVerilog mode."); + err_at_loc(@2, "Static cast is only supported in SystemVerilog mode."); $$ = std::make_unique(AST_CAST_SIZE, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); } | From 81e52704846e77d0badcde06a10eac6eac42fba8 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 18 Jun 2025 22:50:46 +0200 Subject: [PATCH 09/38] ast, read_verilog: unify location types, reduce filename copying --- frontends/ast/ast.cc | 37 +- frontends/ast/ast.h | 11 +- frontends/ast/genrtlil.cc | 67 +-- frontends/ast/simplify.cc | 562 +++++++++++----------- frontends/verilog/.gitignore | 2 - frontends/verilog/Makefile.inc | 4 +- frontends/verilog/const2ast.cc | 2 +- frontends/verilog/verilog_frontend.cc | 25 +- frontends/verilog/verilog_lexer.h | 6 +- frontends/verilog/verilog_lexer.l | 38 +- frontends/verilog/verilog_parser.y | 650 +++++++++++++------------- kernel/rtlil.cc | 4 +- 12 files changed, 715 insertions(+), 693 deletions(-) diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 28a6fce99..92f5fafdd 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -207,7 +207,7 @@ AstNode::AstNode(AstSrcLocType loc, AstNodeType type, std::unique_ptr c astnodes++; this->type = type; - loc = loc; + location = loc; is_input = false; is_output = false; is_reg = false; @@ -921,7 +921,7 @@ std::unique_ptr AstNode::mktemp_logic(AstSrcLocType loc, const std::str { auto wire_owned = std::make_unique(loc, AST_WIRE, std::make_unique(loc, AST_RANGE, mkconst_int(loc, range_left, true), mkconst_int(loc, range_right, true))); auto* wire = wire_owned.get(); - wire->str = stringf("%s%s:%d$%d", name.c_str(), RTLIL::encode_filename(location.filename).c_str(), location.first_line, autoidx++); + wire->str = stringf("%s%s:%d$%d", name.c_str(), RTLIL::encode_filename(*location.begin.filename).c_str(), location.begin.line, autoidx++); if (nosync) wire->set_attribute(ID::nosync, AstNode::mkconst_int(loc, 1, false)); wire->is_signed = is_signed; @@ -1085,7 +1085,7 @@ RTLIL::Const AstNode::realAsConst(int width) std::string AstNode::loc_string() const { - return stringf("%s:%d.%d-%d.%d", location.filename.c_str(), location.first_line, location.first_column, location.last_line, location.last_column); + return stringf("%s:%d.%d-%d.%d", location.begin.filename->c_str(), location.begin.line, location.begin.column, location.end.line, location.end.column); } void AST::set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast) @@ -1246,7 +1246,7 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d ast->children.swap(new_children); if (ast->attributes.count(ID::blackbox) == 0) { - ast->set_attribute(ID::blackbox, AstNode::mkconst_int(1, false)); + ast->set_attribute(ID::blackbox, AstNode::mkconst_int(ast->location, 1, false)); } } @@ -1443,7 +1443,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump if (design->has(child->str)) { RTLIL::Module *existing_mod = design->module(child->str); if (!nooverwrite && !overwrite && !existing_mod->get_blackbox_attribute()) { - log_file_error(child->location.filename, child->location.first_line, "Re-definition of module `%s'!\n", child->str.c_str()); + log_file_error(*child->location.begin.filename, child->location.begin.line, "Re-definition of module `%s'!\n", child->str.c_str()); } else if (nooverwrite) { log("Ignoring re-definition of module `%s' at %s.\n", child->str.c_str(), child->loc_string().c_str()); @@ -1526,7 +1526,8 @@ AstNode * AST::find_modport(AstNode *intf, std::string name) void AST::explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule, std::string intfname, AstNode *modport) { for (auto w : intfmodule->wires()){ - auto wire = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, AstNode::mkconst_int(w->width -1, true), AstNode::mkconst_int(0, true))); + auto loc = module_ast->location; + auto wire = std::make_unique(loc, AST_WIRE, std::make_unique(loc, AST_RANGE, AstNode::mkconst_int(loc, w->width -1, true), AstNode::mkconst_int(loc, 0, true))); std::string origname = log_id(w->name); std::string newname = intfname + "." + origname; wire->str = newname; @@ -1583,11 +1584,12 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dictclone(); + auto loc = ast->location; for (auto &intf : local_interfaces) { std::string intfname = intf.first.str(); RTLIL::Module *intfmodule = intf.second; for (auto w : intfmodule->wires()){ - auto wire = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, AstNode::mkconst_int(w->width -1, true), AstNode::mkconst_int(0, true))); + auto wire = std::make_unique(loc, AST_WIRE, std::make_unique(loc, AST_RANGE, AstNode::mkconst_int(loc, w->width -1, true), AstNode::mkconst_int(loc, 0, true))); std::string newname = log_id(w->name); newname = intfname + "." + newname; wire->str = newname; @@ -1615,9 +1617,9 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dictmodule(interface_type) != nullptr) { // Add a cell to the module corresponding to the interface port such that // it can further propagated down if needed: - auto celltype_for_intf = std::make_unique(AST_CELLTYPE); + auto celltype_for_intf = std::make_unique(loc, AST_CELLTYPE); celltype_for_intf->str = interface_type; - auto cell_for_intf = std::make_unique(AST_CELL, std::move(celltype_for_intf)); + auto cell_for_intf = std::make_unique(loc, AST_CELL, std::move(celltype_for_intf)); cell_for_intf->str = name_port + "_inst_from_top_dummy"; new_ast->children.push_back(std::move(cell_for_intf)); @@ -1824,8 +1826,9 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dictclone(); + auto loc = ast->location; if (!new_ast->attributes.count(ID::hdlname)) - new_ast->set_attribute(ID::hdlname, AstNode::mkconst_str(stripped_name.substr(1))); + new_ast->set_attribute(ID::hdlname, AstNode::mkconst_str(loc, stripped_name.substr(1))); para_counter = 0; for (auto& child : new_ast->children) { @@ -1849,12 +1852,12 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dictchildren.insert(child->children.begin(), nullptr); if ((it->second.flags & RTLIL::CONST_FLAG_REAL) != 0) { - child->children[0] = std::make_unique(AST_REALVALUE); + child->children[0] = std::make_unique(loc, AST_REALVALUE); child->children[0]->realvalue = std::stod(it->second.decode_string()); } else if ((it->second.flags & RTLIL::CONST_FLAG_STRING) != 0) - child->children[0] = AstNode::mkconst_str(it->second.decode_string()); + child->children[0] = AstNode::mkconst_str(loc, it->second.decode_string()); else - child->children[0] = AstNode::mkconst_bits(it->second.to_bits(), (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0); + child->children[0] = AstNode::mkconst_bits(loc, it->second.to_bits(), (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0); rewritten.insert(it->first); } @@ -1862,12 +1865,12 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict(AST_DEFPARAM, std::make_unique(AST_IDENTIFIER)); + auto defparam = std::make_unique(loc, AST_DEFPARAM, std::make_unique(loc, AST_IDENTIFIER)); defparam->children[0]->str = param.first.str(); if ((param.second.flags & RTLIL::CONST_FLAG_STRING) != 0) - defparam->children.push_back(AstNode::mkconst_str(param.second.decode_string())); + defparam->children.push_back(AstNode::mkconst_str(loc, param.second.decode_string())); else - defparam->children.push_back(AstNode::mkconst_bits(param.second.to_bits(), (param.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0)); + defparam->children.push_back(AstNode::mkconst_bits(loc, param.second.to_bits(), (param.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0)); new_ast->children.push_back(std::move(defparam)); } @@ -1922,7 +1925,7 @@ void AstNode::input_error(const char *format, ...) const { va_list ap; va_start(ap, format); - logv_file_error(location.filename, location.first_line, format, ap); + logv_file_error(*location.begin.filename, location.begin.line, format, ap); } YOSYS_NAMESPACE_END diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index f881dfcb7..f4cbd4ad4 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -28,6 +28,7 @@ #include "kernel/rtlil.h" #include "kernel/fmt.h" +#include "frontends/verilog/verilog_location.h" #include #include @@ -162,13 +163,7 @@ namespace AST AST_BIND }; - struct AstSrcLocType { - std::string filename; - unsigned int first_line, last_line; - unsigned int first_column, last_column; - AstSrcLocType() : filename(""), first_line(0), last_line(0), first_column(0), last_column(0) {} - AstSrcLocType(std::string _filename, int _first_line, int _first_column, int _last_line, int _last_column) : filename(_filename), first_line(_first_line), last_line(_last_line), first_column(_first_column), last_column(_last_column) {} - }; + using AstSrcLocType = location; // convert an node type to a string (e.g. for debug output) std::string type2str(AstNodeType type); @@ -407,7 +402,7 @@ namespace AST // this must be set by the language frontend before parsing the sources // the AstNode constructor then uses current_filename and get_line_num() // to initialize the filename and linenum properties of new nodes - extern std::string current_filename; + // extern std::string current_filename; // also set by the language frontend to control some AST processing extern bool sv_mode_but_global_and_used_for_literally_one_condition; diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index dadc4129f..2c2f8e1c4 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -45,7 +45,7 @@ using namespace AST_INTERNAL; // helper function for creating RTLIL code for unary operations static RTLIL::SigSpec uniop2rtlil(AstNode *that, IdString type, int result_width, const RTLIL::SigSpec &arg, bool gen_attributes = true) { - IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(that->location.filename).c_str(), that->location.first_line, autoidx++); + IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(*that->location.begin.filename).c_str(), that->location.begin.line, autoidx++); RTLIL::Cell *cell = current_module->addCell(name, type); set_src_attr(cell, that); @@ -77,7 +77,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s return; } - IdString name = stringf("$extend$%s:%d$%d", RTLIL::encode_filename(that->location.filename).c_str(), that->location.first_line, autoidx++); + IdString name = stringf("$extend$%s:%d$%d", RTLIL::encode_filename(*that->location.begin.filename).c_str(), that->location.begin.line, autoidx++); RTLIL::Cell *cell = current_module->addCell(name, ID($pos)); set_src_attr(cell, that); @@ -104,7 +104,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s // helper function for creating RTLIL code for binary operations static RTLIL::SigSpec binop2rtlil(AstNode *that, IdString type, int result_width, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right) { - IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(that->location.filename).c_str(), that->location.first_line, autoidx++); + IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(*that->location.begin.filename).c_str(), that->location.begin.line, autoidx++); RTLIL::Cell *cell = current_module->addCell(name, type); set_src_attr(cell, that); @@ -138,7 +138,7 @@ static RTLIL::SigSpec mux2rtlil(AstNode *that, const RTLIL::SigSpec &cond, const log_assert(cond.size() == 1); std::stringstream sstr; - sstr << "$ternary$" << RTLIL::encode_filename(that->location.filename) << ":" << that->location.first_line << "$" << (autoidx++); + sstr << "$ternary$" << RTLIL::encode_filename(*that->location.begin.filename) << ":" << that->location.begin.line << "$" << (autoidx++); RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($mux)); set_src_attr(cell, that); @@ -195,12 +195,12 @@ struct AST_INTERNAL::LookaheadRewriter if (node->lookahead) { log_assert(node->type == AST_IDENTIFIER); if (!lookaheadids.count(node->str)) { - auto wire = std::make_unique(AST_WIRE); + auto wire = std::make_unique(node->location, AST_WIRE); for (auto& c : node->id2ast->children) wire->children.push_back(c->clone()); wire->fixup_hierarchy_flags(); wire->str = stringf("$lookahead%s$%d", node->str.c_str(), autoidx++); - wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); + wire->set_attribute(ID::nosync, AstNode::mkconst_int(node->location, 1, false)); wire->is_logic = true; while (wire->simplify(true, 1, -1, false)) { } lookaheadids[node->str] = make_pair(node->id2ast, wire.get()); @@ -271,6 +271,7 @@ struct AST_INTERNAL::LookaheadRewriter // top->dumpVlog(nullptr, "REWRITE-BEFORE> "); AstNode *block = nullptr; + auto loc = top->location; for (auto& c : top->children) if (c->type == AST_BLOCK) { @@ -284,18 +285,18 @@ struct AST_INTERNAL::LookaheadRewriter for (auto it : lookaheadids) { - auto ref_orig = std::make_unique(AST_IDENTIFIER); + auto ref_orig = std::make_unique(loc, AST_IDENTIFIER); ref_orig->str = it.second.first->str; ref_orig->id2ast = it.second.first; ref_orig->was_checked = true; - auto ref_temp = std::make_unique(AST_IDENTIFIER); + auto ref_temp = std::make_unique(loc, AST_IDENTIFIER); ref_temp->str = it.second.second->str; ref_temp->id2ast = it.second.second; ref_temp->was_checked = true; - auto init_assign = std::make_unique(AST_ASSIGN_EQ, ref_temp->clone(), ref_orig->clone()); - auto final_assign = std::make_unique(AST_ASSIGN_LE, std::move(ref_orig), std::move(ref_temp)); + auto init_assign = std::make_unique(loc, AST_ASSIGN_EQ, ref_temp->clone(), ref_orig->clone()); + auto final_assign = std::make_unique(loc, AST_ASSIGN_LE, std::move(ref_orig), std::move(ref_temp)); block->children.insert(block->children.begin(), std::move(init_assign)); block->children.push_back(std::move(final_assign)); @@ -347,7 +348,7 @@ struct AST_INTERNAL::ProcessGenerator LookaheadRewriter la_rewriter(always.get()); // generate process and simple root case - proc = current_module->addProcess(stringf("$proc$%s:%d$%d", RTLIL::encode_filename(always->location.filename).c_str(), always->location.first_line, autoidx++)); + proc = current_module->addProcess(stringf("$proc$%s:%d$%d", RTLIL::encode_filename(*always->location.begin.filename).c_str(), always->location.begin.line, autoidx++)); set_src_attr(proc, always.get()); for (auto &attr : always->attributes) { if (attr.second->type != AST_CONSTANT) @@ -723,7 +724,7 @@ struct AST_INTERNAL::ProcessGenerator if (ast->str == "$display" || ast->str == "$displayb" || ast->str == "$displayh" || ast->str == "$displayo" || ast->str == "$write" || ast->str == "$writeb" || ast->str == "$writeh" || ast->str == "$writeo") { std::stringstream sstr; - sstr << ast->str << "$" << ast->location.filename << ":" << ast->location.first_line << "$" << (autoidx++); + sstr << ast->str << "$" << ast->location.begin.filename << ":" << ast->location.begin.line << "$" << (autoidx++); Wire *en = current_module->addWire(sstr.str() + "_EN", 1); set_src_attr(en, ast); @@ -766,8 +767,8 @@ struct AST_INTERNAL::ProcessGenerator node->detectSignWidth(width, is_signed, nullptr); VerilogFmtArg arg = {}; - arg.filename = node->location.filename; - arg.first_line = node->location.first_line; + arg.filename = *node->location.begin.filename; + arg.first_line = node->location.begin.line; if (node->type == AST_CONSTANT && node->is_string) { arg.type = VerilogFmtArg::STRING; arg.str = node->bitsAsConst().decode_string(); @@ -793,7 +794,7 @@ struct AST_INTERNAL::ProcessGenerator fmt.append_literal("\n"); fmt.emit_rtlil(cell); } else if (!ast->str.empty()) { - log_file_error(ast->location.filename, ast->location.first_line, "Found unsupported invocation of system task `%s'!\n", ast->str.c_str()); + log_file_error(*ast->location.begin.filename, ast->location.begin.line, "Found unsupported invocation of system task `%s'!\n", ast->str.c_str()); } break; @@ -813,7 +814,7 @@ struct AST_INTERNAL::ProcessGenerator IdString cellname; if (ast->str.empty()) - cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(ast->location.filename).c_str(), ast->location.first_line, autoidx++); + cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(*ast->location.begin.filename).c_str(), ast->location.begin.line, autoidx++); else cellname = ast->str; check_unique_id(current_module, cellname, ast, "procedural assertion"); @@ -843,7 +844,7 @@ struct AST_INTERNAL::ProcessGenerator set_src_attr(cell, ast); for (auto &attr : ast->attributes) { if (attr.second->type != AST_CONSTANT) - log_file_error(ast->location.filename, ast->location.first_line, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); + log_file_error(*ast->location.begin.filename, ast->location.begin.line, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); cell->attributes[attr.first] = attr.second->asAttrConst(); } cell->setParam(ID::FLAVOR, flavor); @@ -1503,7 +1504,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) } RTLIL::SigSpec sig = realAsConst(width_hint); - log_file_warning(location.filename, location.first_line, "converting real value %e to binary %s.\n", realvalue, log_signal(sig)); + log_file_warning(*location.begin.filename, location.begin.line, "converting real value %e to binary %s.\n", realvalue, log_signal(sig)); return sig; } @@ -1535,7 +1536,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (dynamic_cast(current_module)) { /* nothing to do here */ } else if (flag_autowire) - log_file_warning(location.filename, location.first_line, "Identifier `%s' is implicitly declared.\n", str.c_str()); + log_file_warning(*location.begin.filename, location.begin.line, "Identifier `%s' is implicitly declared.\n", str.c_str()); else input_error("Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str()); } @@ -1610,7 +1611,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) input_error("Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; - auto fake_ast = std::make_unique(AST_NONE, clone(), children[0]->children.size() >= 2 ? + auto fake_ast = std::make_unique(children[0]->location, AST_NONE, clone(), children[0]->children.size() >= 2 ? children[0]->children[1]->clone() : children[0]->children[0]->clone()); fake_ast->children[0]->delete_children(); if (member_node) @@ -1640,10 +1641,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) chunk.offset = source_width - (chunk.offset + chunk.width); if (chunk.offset > chunk_left || chunk.offset + chunk.width < chunk_right) { if (chunk.width == 1) - log_file_warning(location.filename, location.first_line, "Range select out of bounds on signal `%s': Setting result bit to undef.\n", + log_file_warning(*location.begin.filename, location.begin.line, "Range select out of bounds on signal `%s': Setting result bit to undef.\n", str.c_str()); else - log_file_warning(location.filename, location.first_line, "Range select [%d:%d] out of bounds on signal `%s': Setting all %d result bits to undef.\n", + log_file_warning(*location.begin.filename, location.begin.line, "Range select [%d:%d] out of bounds on signal `%s': Setting all %d result bits to undef.\n", children[0]->range_left, children[0]->range_right, str.c_str(), chunk.width); chunk = RTLIL::SigChunk(RTLIL::State::Sx, chunk.width); } else { @@ -1657,10 +1658,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) chunk.offset += add_undef_bits_lsb; } if (add_undef_bits_lsb) - log_file_warning(location.filename, location.first_line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d LSB bits to undef.\n", + log_file_warning(*location.begin.filename, location.begin.line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d LSB bits to undef.\n", children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_lsb); if (add_undef_bits_msb) - log_file_warning(location.filename, location.first_line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d MSB bits to undef.\n", + log_file_warning(*location.begin.filename, location.begin.line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d MSB bits to undef.\n", children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_msb); } } @@ -1934,7 +1935,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) case AST_MEMRD: { std::stringstream sstr; - sstr << "$memrd$" << str << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++); + sstr << "$memrd$" << str << "$" << RTLIL::encode_filename(*location.begin.filename) << ":" << location.begin.line << "$" << (autoidx++); RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($memrd)); set_src_attr(cell, this); @@ -1972,7 +1973,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) case AST_MEMINIT: { std::stringstream sstr; - sstr << "$meminit$" << str << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++); + sstr << "$meminit$" << str << "$" << RTLIL::encode_filename(*location.begin.filename) << ":" << location.begin.line << "$" << (autoidx++); SigSpec en_sig = children[2]->genRTLIL(); @@ -2017,7 +2018,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) IdString cellname; if (str.empty()) - cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(location.filename).c_str(), location.first_line, autoidx++); + cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(*location.begin.filename).c_str(), location.begin.line, autoidx++); else cellname = str; check_unique_id(current_module, cellname, this, "procedural assertion"); @@ -2060,7 +2061,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) new_left.append(left[i]); new_right.append(right[i]); } - log_file_warning(location.filename, location.first_line, "Ignoring assignment to constant bits:\n" + log_file_warning(*location.begin.filename, location.begin.line, "Ignoring assignment to constant bits:\n" " old assignment: %s = %s\n new assignment: %s = %s.\n", log_signal(left), log_signal(right), log_signal(new_left), log_signal(new_right)); @@ -2095,7 +2096,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str; const AstNode *value = child->children[0].get(); if (value->type == AST_REALVALUE) - log_file_warning(location.filename, location.first_line, "Replacing floating point parameter %s.%s = %f with string.\n", + log_file_warning(*location.begin.filename, location.begin.line, "Replacing floating point parameter %s.%s = %f with string.\n", log_id(cell), log_id(paraname), value->realvalue); else if (value->type != AST_CONSTANT) input_error("Parameter %s.%s with non-constant value!\n", @@ -2192,14 +2193,14 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) int sz = children.size(); if (str == "$info") { if (sz > 0) - log_file_info(location.filename, location.first_line, "%s.\n", children[0]->str.c_str()); + log_file_info(*location.begin.filename, location.begin.line, "%s.\n", children[0]->str.c_str()); else - log_file_info(location.filename, location.first_line, "\n"); + log_file_info(*location.begin.filename, location.begin.line, "\n"); } else if (str == "$warning") { if (sz > 0) - log_file_warning(location.filename, location.first_line, "%s.\n", children[0]->str.c_str()); + log_file_warning(*location.begin.filename, location.begin.line, "%s.\n", children[0]->str.c_str()); else - log_file_warning(location.filename, location.first_line, "\n"); + log_file_warning(*location.begin.filename, location.begin.line, "\n"); } else if (str == "$error") { if (sz > 0) input_error("%s.\n", children[0]->str.c_str()); diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 402dcb1e0..4b5cc178c 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -155,8 +155,8 @@ Fmt AstNode::processFormat(int stage, bool sformat_like, int default_base, size_ while (node_arg->simplify(true, stage, -1, false)) { } VerilogFmtArg arg = {}; - arg.filename = location.filename; - arg.first_line = location.first_line; + arg.filename = *location.begin.filename; + arg.first_line = location.begin.line; if (node_arg->type == AST_CONSTANT && node_arg->is_string) { arg.type = VerilogFmtArg::STRING; arg.str = node_arg->bitsAsConst().decode_string(); @@ -173,10 +173,10 @@ Fmt AstNode::processFormat(int stage, bool sformat_like, int default_base, size_ arg.sig = node_arg->bitsAsConst(); arg.signed_ = node_arg->is_signed; } else if (may_fail) { - log_file_info(location.filename, location.first_line, "Skipping system task `%s' with non-constant argument at position %zu.\n", str.c_str(), index + 1); + log_file_info(*location.begin.filename, location.begin.line, "Skipping system task `%s' with non-constant argument at position %zu.\n", str.c_str(), index + 1); return Fmt(); } else { - log_file_error(location.filename, location.first_line, "Failed to evaluate system task `%s' with non-constant argument at position %zu.\n", str.c_str(), index + 1); + log_file_error(*location.begin.filename, location.begin.line, "Failed to evaluate system task `%s' with non-constant argument at position %zu.\n", str.c_str(), index + 1); } args.push_back(arg); } @@ -424,12 +424,13 @@ static std::unique_ptr index_offset(std::unique_ptr offset, As stride /= decl_node->dimensions[dimension].range_width; auto right = normalize_index(rnode->children.back().get(), decl_node, dimension); auto add_offset = stride > 1 ? multiply_by_const(std::move(right), stride) : std::move(right); - return offset ? std::make_unique(AST_ADD, std::move(offset), std::move(add_offset)) : std::move(add_offset); + return offset ? std::make_unique(rnode->location, AST_ADD, std::move(offset), std::move(add_offset)) : std::move(add_offset); } static std::unique_ptr index_msb_offset(std::unique_ptr lsb_offset, AstNode *rnode, AstNode *decl_node, int dimension, int stride) { log_assert(rnode->children.size() <= 2); + auto loc = rnode->location; // Offset to add to LSB std::unique_ptr add_offset; @@ -442,15 +443,15 @@ static std::unique_ptr index_msb_offset(std::unique_ptr lsb_of // Slice, e.g. s.a[i:j] auto left = normalize_index(rnode->children[0].get(), decl_node, dimension); auto right = normalize_index(rnode->children[1].get(), decl_node, dimension); - add_offset = std::make_unique(AST_SUB, std::move(left), std::move(right)); + add_offset = std::make_unique(loc, AST_SUB, std::move(left), std::move(right)); if (stride > 1) { // offset = (msb - lsb + 1)*stride - 1 - auto slice_width = std::make_unique(AST_ADD, std::move(add_offset), node_int(1)); - add_offset = std::make_unique(AST_SUB, multiply_by_const(std::move(slice_width), stride), node_int(1)); + auto slice_width = std::make_unique(loc, AST_ADD, std::move(add_offset), node_int(loc, 1)); + add_offset = std::make_unique(loc, AST_SUB, multiply_by_const(std::move(slice_width), stride), node_int(loc, 1)); } } - return std::make_unique(AST_ADD, std::move(lsb_offset), std::move(add_offset)); + return std::make_unique(loc, AST_ADD, std::move(lsb_offset), std::move(add_offset)); } @@ -461,7 +462,7 @@ std::unique_ptr AstNode::make_index_range(AstNode *decl_node, bool unpa // such as array indexing or slicing if (children.empty()) { // no range operations apply, return the whole width - return make_range(decl_node->range_left - decl_node->range_right, 0); + return make_range(decl_node->location, decl_node->range_left - decl_node->range_right, 0); } log_assert(children.size() == 1); @@ -495,7 +496,7 @@ std::unique_ptr AstNode::make_index_range(AstNode *decl_node, bool unpa input_error("Unsupported range operation for %s\n", str.c_str()); } - std::unique_ptrindex_range = std::make_unique(AST_RANGE); + std::unique_ptr index_range = std::make_unique(rnode->location, AST_RANGE); if (!unpacked_range && (stride > 1 || GetSize(rnode->children) == 2)) { // Calculate MSB offset for the final index / slice of packed dimensions. @@ -537,7 +538,8 @@ static void add_members_to_scope(AstNode *snode, std::string name) std::unique_ptr make_packed_struct(AstNode *template_node, std::string &name, decltype(AstNode::attributes) &attributes) { // create a wire for the packed struct - auto wnode = std::make_unique(AST_WIRE, make_range(template_node->range_left, 0)); + auto loc = template_node->location; + auto wnode = std::make_unique(loc, AST_WIRE, make_range(loc, template_node->range_left, 0)); wnode->str = name; wnode->is_logic = true; wnode->range_valid = true; @@ -557,8 +559,9 @@ std::unique_ptr make_packed_struct(AstNode *template_node, std::string static void prepend_ranges(std::unique_ptr &range, AstNode *range_add) { // Convert range to multirange. + auto loc = range->location; if (range->type == AST_RANGE) - range = std::make_unique(AST_MULTIRANGE, std::move(range)); + range = std::make_unique(loc, AST_MULTIRANGE, std::move(range)); // Add range or ranges. if (range_add->type == AST_RANGE) @@ -693,15 +696,15 @@ static bool contains_unbased_unsized(const AstNode *node) // adds a wire to the current module with the given name that matches the // dimensions of the given wire reference -void add_wire_for_ref(const RTLIL::Wire *ref, const std::string &str) +void add_wire_for_ref(location loc, const RTLIL::Wire *ref, const std::string &str) { - std::unique_ptr left = AstNode::mkconst_int(ref->width - 1 + ref->start_offset, true); - std::unique_ptr right = AstNode::mkconst_int(ref->start_offset, true); + std::unique_ptr left = AstNode::mkconst_int(loc, ref->width - 1 + ref->start_offset, true); + std::unique_ptr right = AstNode::mkconst_int(loc, ref->start_offset, true); if (ref->upto) std::swap(left, right); - std::unique_ptr range = std::make_unique(AST_RANGE, std::move(left), std::move(right)); + std::unique_ptr range = std::make_unique(loc, AST_RANGE, std::move(left), std::move(right)); - std::unique_ptr wire = std::make_unique(AST_WIRE, std::move(range)); + std::unique_ptr wire = std::make_unique(loc, AST_WIRE, std::move(range)); wire->is_signed = ref->is_signed; wire->is_logic = true; wire->str = str; @@ -790,7 +793,7 @@ std::unique_ptr AstNode::clone_at_zero() YS_FALLTHROUGH case AST_MEMRD: detectSignWidth(width_hint, sign_hint); - return mkconst_int(0, sign_hint, width_hint); + return mkconst_int(location, 0, sign_hint, width_hint); default: break; @@ -842,7 +845,7 @@ static void mark_auto_nosync(AstNode *block, const AstNode *wire) { log_assert(block->type == AST_BLOCK); log_assert(wire->type == AST_WIRE); - block->set_attribute(auto_nosync_prefix + wire->str, AstNode::mkconst_int(1, false)); + block->set_attribute(auto_nosync_prefix + wire->str, AstNode::mkconst_int(block->location, 1, false)); } // block names can be prefixed with an explicit scope during elaboration @@ -883,7 +886,7 @@ static void check_auto_nosync(AstNode *node) // mark the wire with `nosync` AstNode *wire = it->second; log_assert(wire->type == AST_WIRE); - wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); + wire->set_attribute(ID::nosync, AstNode::mkconst_int(wire->location, 1, false)); } // remove the attributes we've "consumed" @@ -931,7 +934,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin #if 0 log("-------------\n"); - log("AST simplify[%d] depth %d at %s:%d on %s %p:\n", stage, recursion_counter, location.filename.c_str(), location.first_line, type2str(type).c_str(), this); + log("AST simplify[%d] depth %d at %s:%d on %s %p:\n", stage, recursion_counter, location.begin.filename->c_str(), location.begin.line, type2str(type).c_str(), this); log("const_fold=%d, stage=%d, width_hint=%d, sign_hint=%d\n", int(const_fold), int(stage), int(width_hint), int(sign_hint)); // dumpAst(nullptr, "> "); @@ -1013,16 +1016,17 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (node->children[0]->range_swapped) std::swap(data_range_left, data_range_right); + auto loc = node->location; for (int i = 0; i < mem_size; i++) { - auto reg = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, - mkconst_int(data_range_left, true), mkconst_int(data_range_right, true))); + auto reg = std::make_unique(loc, AST_WIRE, std::make_unique(loc, AST_RANGE, + mkconst_int(loc, data_range_left, true), mkconst_int(loc, data_range_right, true))); reg->str = stringf("%s[%d]", node->str.c_str(), i); reg->is_reg = true; reg->is_signed = node->is_signed; for (auto &it : node->attributes) if (it.first != ID::mem2reg) reg->set_attribute(it.first, it.second->clone()); - reg->location.filename = node->location.filename; + reg->location.begin.filename = node->location.begin.filename; reg->location = node->location; while (reg->simplify(true, 1, -1, false)) { } children.push_back(std::move(reg)); @@ -1051,7 +1055,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // note that $display, $finish, and $stop are used for synthesis-time DRC so they're not in this list if ((type == AST_FCALL || type == AST_TCALL) && (str == "$strobe" || str == "$monitor" || str == "$time" || str == "$dumpfile" || str == "$dumpvars" || str == "$dumpon" || str == "$dumpoff" || str == "$dumpall")) { - log_file_warning(location.filename, location.first_line, "Ignoring call to system %s %s.\n", type == AST_FCALL ? "function" : "task", str.c_str()); + log_file_warning(*location.begin.filename, location.begin.line, "Ignoring call to system %s %s.\n", type == AST_FCALL ? "function" : "task", str.c_str()); delete_children(); str = std::string(); } @@ -1061,7 +1065,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin str == "$write" || str == "$writeb" || str == "$writeh" || str == "$writeo")) { if (!current_always) { - log_file_warning(location.filename, location.first_line, "System task `%s' outside initial or always block is unsupported.\n", str.c_str()); + log_file_warning(*location.begin.filename, location.begin.line, "System task `%s' outside initial or always block is unsupported.\n", str.c_str()); delete_children(); str = std::string(); } else { @@ -1112,7 +1116,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (node->children.size() == 1 && node->children[0]->type == AST_RANGE) { for (auto& c : node->children[0]->children) { if (!c->is_simple_const_expr()) - set_attribute(ID::dynports, AstNode::mkconst_int(1, true)); + set_attribute(ID::dynports, AstNode::mkconst_int(c->location, 1, true)); } } if (this_wire_scope.count(node->str) > 0) { @@ -1338,15 +1342,15 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // create the indirection wire std::stringstream sstr; - sstr << "$indirect$" << ref->name.c_str() << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++); + sstr << "$indirect$" << ref->name.c_str() << "$" << RTLIL::encode_filename(*location.begin.filename) << ":" << location.begin.line << "$" << (autoidx++); std::string tmp_str = sstr.str(); - add_wire_for_ref(ref, tmp_str); + add_wire_for_ref(location, ref, tmp_str); - auto asgn_owned = std::make_unique(AST_ASSIGN); + auto asgn_owned = std::make_unique(child->location, AST_ASSIGN); auto* asgn = asgn_owned.get(); current_ast_mod->children.push_back(std::move(asgn_owned)); - auto ident = std::make_unique(AST_IDENTIFIER); + auto ident = std::make_unique(child->location, AST_IDENTIFIER); ident->str = tmp_str; child->children[0] = ident->clone(); @@ -1509,7 +1513,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (child->children.size() == 0) { // Base type (e.g., int) width = child->range_left - child->range_right +1; - node = mkconst_int(width, child->is_signed); + node = mkconst_int(child->location, width, child->is_signed); } else { // User defined type log_assert(child->children[0]->type == AST_WIRETYPE); @@ -1532,7 +1536,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (template_node->children.size() > 0 && template_node->children[0]->type == AST_RANGE) width = range_width(this, template_node->children[0].get()); child->delete_children(); - node = mkconst_int(width, true); + node = mkconst_int(child->location, width, true); break; } @@ -1540,7 +1544,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin case AST_UNION: { child->delete_children(); width = size_packed_struct(template_node, 0); - node = mkconst_int(width, false); + node = mkconst_int(child->location, width, false); break; } @@ -1872,7 +1876,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin input_error("Defparam argument `%s . %s` does not match a cell!\n", RTLIL::unescape_id(modname).c_str(), RTLIL::unescape_id(paramname).c_str()); - auto paraset = std::make_unique(AST_PARASET, children[1]->clone(), GetSize(children) > 2 ? children[2]->clone() : nullptr); + auto paraset = std::make_unique(location, AST_PARASET, children[1]->clone(), GetSize(children) > 2 ? children[2]->clone() : nullptr); paraset->str = paramname; AstNode *cell = current_scope.at(modname); @@ -1914,7 +1918,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (!str.empty() && str[0] == '\\' && (template_node->type == AST_STRUCT || template_node->type == AST_UNION)) { // replace instance with wire representing the packed structure newNode = make_packed_struct(template_node.get(), str, attributes); - newNode->set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str)); + newNode->set_attribute(ID::wiretype, mkconst_str(newNode->location, resolved_type_node->str)); // add original input/output attribute to resolved wire newNode->is_input = this->is_input; newNode->is_output = this->is_output; @@ -1925,7 +1929,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // Prepare replacement node. newNode = template_node->clone(); newNode->str = str; - newNode->set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str)); + newNode->set_attribute(ID::wiretype, mkconst_str(newNode->location, resolved_type_node->str)); newNode->is_input = is_input; newNode->is_output = is_output; newNode->is_wand = is_wand; @@ -2016,7 +2020,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (children[1]->type != AST_CONSTANT) input_error("Right operand of to_bits expression is not constant!\n"); RTLIL::Const new_value = children[1]->bitsAsConst(children[0]->bitsAsConst().as_int(), children[1]->is_signed); - newNode = mkconst_bits(new_value.to_bits(), children[1]->is_signed); + newNode = mkconst_bits(location, new_value.to_bits(), children[1]->is_signed); goto apply_newNode; } @@ -2078,7 +2082,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin range_swapped = force_upto; } if (range_left == range_right && !attributes.count(ID::single_bit_vector)) - set_attribute(ID::single_bit_vector, mkconst_int(1, false)); + set_attribute(ID::single_bit_vector, mkconst_int(location, 1, false)); } } else { if (!range_valid) @@ -2105,7 +2109,8 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin int left = width - 1, right = 0; if (i) std::swap(left, right); - children[i] = std::make_unique(AST_RANGE, mkconst_int(left, true), mkconst_int(right, true)); + auto loc = children[i]->location; + children[i] = std::make_unique(loc, AST_RANGE, mkconst_int(loc, left, true), mkconst_int(loc, right, true)); fixup_hierarchy_flags(); did_something = true; } else if (children[i]->type == AST_RANGE) { @@ -2176,9 +2181,9 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin int width = std::abs(children[1]->range_left - children[1]->range_right) + 1; if (children[0]->type == AST_REALVALUE) { RTLIL::Const constvalue = children[0]->realAsConst(width); - log_file_warning(location.filename, location.first_line, "converting real value %e to binary %s.\n", + log_file_warning(*location.begin.filename, location.begin.line, "converting real value %e to binary %s.\n", children[0]->realvalue, log_signal(constvalue)); - children[0] = mkconst_bits(constvalue.to_bits(), sign_hint); + children[0] = mkconst_bits(location, constvalue.to_bits(), sign_hint); fixup_hierarchy_flags(); did_something = true; } @@ -2186,7 +2191,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (width != int(children[0]->bits.size())) { RTLIL::SigSpec sig(children[0]->bits); sig.extend_u0(width, children[0]->is_signed); - children[0] = mkconst_bits(sig.as_const().to_bits(), is_signed); + children[0] = mkconst_bits(location, sig.as_const().to_bits(), is_signed); fixup_hierarchy_flags(); } children[0]->is_signed = is_signed; @@ -2198,7 +2203,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } else if (children.size() > 1 && children[1]->type == AST_REALVALUE && children[0]->type == AST_CONSTANT) { double as_realvalue = children[0]->asReal(sign_hint); - children[0] = std::make_unique(AST_REALVALUE); + children[0] = std::make_unique(location, AST_REALVALUE); children[0]->realvalue = as_realvalue; fixup_hierarchy_flags(); did_something = true; @@ -2227,7 +2232,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (found_sname) { // structure member, rewrite this node to reference the packed struct wire auto range = make_index_range(item_node); - newNode = std::make_unique(AST_IDENTIFIER, std::move(range)); + newNode = std::make_unique(location, AST_IDENTIFIER, std::move(range)); newNode->str = sname; // save type and original number of dimensions for $size() etc. newNode->set_attribute(ID::wiretype, item_node->clone()); @@ -2239,7 +2244,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } newNode->basic_prep = true; if (item_node->is_signed) - newNode = std::make_unique(AST_TO_SIGNED, std::move(newNode)); + newNode = std::make_unique(location, AST_TO_SIGNED, std::move(newNode)); goto apply_newNode; } } @@ -2287,7 +2292,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (current_ast_mod == nullptr) { input_error("Identifier `%s' is implicitly declared outside of a module.\n", str.c_str()); } else if (flag_autowire || str == "\\$global_clock") { - auto auto_wire = std::make_unique(AST_AUTOWIRE); + auto auto_wire = std::make_unique(location, AST_AUTOWIRE); auto_wire->str = str; current_scope[str] = auto_wire.get(); current_ast_mod->children.push_back(std::move(auto_wire)); @@ -2318,21 +2323,21 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin std::swap(data_range_left, data_range_right); std::stringstream sstr; - sstr << "$mem2bits$" << str << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++); + sstr << "$mem2bits$" << str << "$" << RTLIL::encode_filename(*location.begin.filename) << ":" << location.begin.line << "$" << (autoidx++); std::string wire_id = sstr.str(); - auto wire_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(data_range_left, true), mkconst_int(data_range_right, true))); + auto wire_owned = std::make_unique(location, AST_WIRE, std::make_unique(location, AST_RANGE, mkconst_int(location, data_range_left, true), mkconst_int(location, data_range_right, true))); auto* wire = wire_owned.get(); current_ast_mod->children.push_back(std::move(wire_owned)); wire->str = wire_id; if (current_block) - wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); + wire->set_attribute(ID::nosync, AstNode::mkconst_int(location, 1, false)); while (wire->simplify(true, 1, -1, false)) { } auto data = clone(); data->children.pop_back(); - auto assign = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), std::move(data)); + auto assign = std::make_unique(location, AST_ASSIGN_EQ, std::make_unique(location, AST_IDENTIFIER), std::move(data)); assign->children[0]->str = wire_id; assign->children[0]->was_checked = true; @@ -2347,12 +2352,12 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } else { - auto proc = std::make_unique(AST_ALWAYS, std::make_unique(AST_BLOCK)); + auto proc = std::make_unique(location, AST_ALWAYS, std::make_unique(location, AST_BLOCK)); proc->children[0]->children.push_back(std::move(assign)); current_ast_mod->children.push_back(std::move(proc)); } - newNode = std::make_unique(AST_IDENTIFIER, children[1]->clone()); + newNode = std::make_unique(location, AST_IDENTIFIER, children[1]->clone()); newNode->str = wire_id; newNode->integer = integer; // save original number of dimensions for $size() etc. newNode->id2ast = wire; @@ -2442,7 +2447,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } } - varbuf = std::make_unique(AST_LOCALPARAM, std::move(varbuf)); + varbuf = std::make_unique(location, AST_LOCALPARAM, std::move(varbuf)); varbuf->str = init_ast->children[0]->str; AstNode *backup_scope_varbuf = current_scope[varbuf->str]; @@ -2607,7 +2612,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (buf) { if (buf->type != AST_GENBLOCK) - buf = std::make_unique(AST_GENBLOCK, std::move(buf)); + buf = std::make_unique(location, AST_GENBLOCK, std::move(buf)); if (!buf->str.empty()) { buf->expand_genblock(buf->str + "."); @@ -2707,7 +2712,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (!children.at(0)->range_valid) input_error("Non-constant array range on cell array.\n"); - newNode = std::make_unique(AST_GENBLOCK); + newNode = std::make_unique(location, AST_GENBLOCK); int num = max(children.at(0)->range_left, children.at(0)->range_right) - min(children.at(0)->range_left, children.at(0)->range_right) + 1; for (int i = 0; i < num; i++) { @@ -2751,15 +2756,15 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin auto& mux_input = children_list.at(1); if (str == "notif0" || str == "notif1") { - mux_input = std::make_unique(AST_BIT_NOT, std::move(mux_input)); + mux_input = std::make_unique(location, AST_BIT_NOT, std::move(mux_input)); } - auto node = std::make_unique(AST_TERNARY, std::move(children_list.at(2))); + auto node = std::make_unique(location, AST_TERNARY, std::move(children_list.at(2))); if (str == "bufif0") { - node->children.push_back(AstNode::mkconst_bits(z_const, false)); + node->children.push_back(AstNode::mkconst_bits(location, z_const, false)); node->children.push_back(std::move(mux_input)); } else { node->children.push_back(std::move(mux_input)); - node->children.push_back(AstNode::mkconst_bits(z_const, false)); + node->children.push_back(AstNode::mkconst_bits(location, z_const, false)); } str.clear(); @@ -2774,11 +2779,11 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin { auto& input = children_list.back(); if (str == "not") - input = std::make_unique(AST_BIT_NOT, std::move(input)); + input = std::make_unique(location, AST_BIT_NOT, std::move(input)); - newNode = std::make_unique(AST_GENBLOCK); + newNode = std::make_unique(location, AST_GENBLOCK); for (auto it = children_list.begin(); it != std::prev(children_list.end()); it++) { - newNode->children.push_back(std::make_unique(AST_ASSIGN, std::move(*it), input->clone())); + newNode->children.push_back(std::make_unique(location, AST_ASSIGN, std::move(*it), input->clone())); newNode->children.back()->was_checked = true; } @@ -2806,11 +2811,11 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin auto& node = children_list[1]; if (op_type != AST_POS) for (size_t i = 2; i < children_list.size(); i++) { - node = std::make_unique(op_type, std::move(node), std::move(children_list[i])); + node = std::make_unique(location, op_type, std::move(node), std::move(children_list[i])); node->location = location; } if (invert_results) - node = std::make_unique(AST_BIT_NOT, std::move(node)); + node = std::make_unique(location, AST_BIT_NOT, std::move(node)); str.clear(); type = AST_ASSIGN; @@ -2945,13 +2950,13 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin int rvalue_width; bool rvalue_sign; children[1]->detectSignWidth(rvalue_width, rvalue_sign); - auto rvalue = mktemp_logic("$bitselwrite$rvalue$", current_ast_mod, true, rvalue_width - 1, 0, rvalue_sign); + auto rvalue = mktemp_logic(location, "$bitselwrite$rvalue$", current_ast_mod, true, rvalue_width - 1, 0, rvalue_sign); auto* rvalue_leaky = rvalue.get(); log("make 1\n"); - auto case_node_owned = std::make_unique(AST_CASE, std::move(shift_expr)); + auto case_node_owned = std::make_unique(location, AST_CASE, std::move(shift_expr)); auto* case_node = case_node_owned.get(); - newNode = std::make_unique(AST_BLOCK, - std::make_unique(AST_ASSIGN_EQ, std::move(rvalue), children[1]->clone()), + newNode = std::make_unique(location, AST_BLOCK, + std::make_unique(location, AST_ASSIGN_EQ, std::move(rvalue), children[1]->clone()), std::move(case_node_owned)); did_something = true; @@ -2965,14 +2970,14 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (start_bit%bitno_div != 0 || (stride == 0 && start_bit != 0)) continue; - auto cond = std::make_unique(AST_COND, mkconst_int(start_bit, case_sign_hint, max_width)); + auto cond = std::make_unique(location, AST_COND, mkconst_int(location, start_bit, case_sign_hint, max_width)); auto lvalue = children[0]->clone(); lvalue->delete_children(); if (member_node) lvalue->set_attribute(ID::wiretype, member_node->clone()); - lvalue->children.push_back(std::make_unique(AST_RANGE, - mkconst_int(end_bit, true), mkconst_int(start_bit, true))); - cond->children.push_back(std::make_unique(AST_BLOCK, std::make_unique(std::move(type), std::move(lvalue), rvalue_leaky->clone()))); + lvalue->children.push_back(std::make_unique(location, AST_RANGE, + mkconst_int(location, end_bit, true), mkconst_int(location, start_bit, true))); + cond->children.push_back(std::make_unique(location, AST_BLOCK, std::make_unique(location, std::move(type), std::move(lvalue), rvalue_leaky->clone()))); case_node->children.push_back(std::move(cond)); } } else { @@ -2993,50 +2998,50 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin shift_expr->detectSignWidth(shift_width_hint, shift_sign_hint); // All operations are carried out in a new block. - newNode = std::make_unique(AST_BLOCK); + newNode = std::make_unique(location, AST_BLOCK); // Temporary register holding the result of the bit- or part-select position expression. - auto pos = mktemp_logic("$bitselwrite$pos$", current_ast_mod, true, shift_width_hint - 1, 0, shift_sign_hint); + auto pos = mktemp_logic(location, "$bitselwrite$pos$", current_ast_mod, true, shift_width_hint - 1, 0, shift_sign_hint); // Calculate lsb from position. auto shift_val = pos->clone(); - newNode->children.push_back(std::make_unique(AST_ASSIGN_EQ, std::move(pos), std::move(shift_expr))); + newNode->children.push_back(std::make_unique(location, AST_ASSIGN_EQ, std::move(pos), std::move(shift_expr))); // If the expression is signed, we must add an extra bit for possible negation of the most negative number. // If the expression is unsigned, we must add an extra bit for sign. - shift_val = std::make_unique(AST_CAST_SIZE, mkconst_int(shift_width_hint + 1, true), std::move(shift_val)); + shift_val = std::make_unique(location, AST_CAST_SIZE, mkconst_int(location, shift_width_hint + 1, true), std::move(shift_val)); if (!shift_sign_hint) - shift_val = std::make_unique(AST_TO_SIGNED, std::move(shift_val)); + shift_val = std::make_unique(location, AST_TO_SIGNED, std::move(shift_val)); // offset the shift amount by the lower bound of the dimension if (wire_offset != 0) - shift_val = std::make_unique(AST_SUB, std::move(shift_val), mkconst_int(wire_offset, true)); + shift_val = std::make_unique(location, AST_SUB, std::move(shift_val), mkconst_int(location, wire_offset, true)); // reflect the shift amount if the dimension is swapped if (children[0]->id2ast->range_swapped) - shift_val = std::make_unique(AST_SUB, mkconst_int(wire_width - result_width, true), std::move(shift_val)); + shift_val = std::make_unique(location, AST_SUB, mkconst_int(location, wire_width - result_width, true), std::move(shift_val)); // AST_SHIFT uses negative amounts for shifting left - shift_val = std::make_unique(AST_NEG, std::move(shift_val)); + shift_val = std::make_unique(location, AST_NEG, std::move(shift_val)); auto also_shift_val = shift_val->clone(); // dst = (dst & ~(width'1 << lsb)) | unsigned'(width'(src)) << lsb) did_something = true; - auto bitmask = mkconst_bits(std::vector(result_width, State::S1), false); + auto bitmask = mkconst_bits(location, std::vector(result_width, State::S1), false); newNode->children.push_back( - std::make_unique(std::move(type), + std::make_unique(location, std::move(type), std::move(lvalue), - std::make_unique(AST_BIT_OR, - std::make_unique(AST_BIT_AND, + std::make_unique(location, AST_BIT_OR, + std::make_unique(location, AST_BIT_AND, std::move(old_data), - std::make_unique(AST_BIT_NOT, - std::make_unique(AST_SHIFT, + std::make_unique(location, AST_BIT_NOT, + std::make_unique(location, AST_SHIFT, std::move(bitmask), std::move(shift_val)))), - std::make_unique(AST_SHIFT, - std::make_unique(AST_TO_UNSIGNED, - std::make_unique(AST_CAST_SIZE, - mkconst_int(result_width, true), + std::make_unique(location, AST_SHIFT, + std::make_unique(location, AST_TO_UNSIGNED, + std::make_unique(location, AST_CAST_SIZE, + mkconst_int(location, result_width, true), children[1]->clone())), std::move(also_shift_val))))); @@ -3052,7 +3057,7 @@ skip_dynamic_range_lvalue_expansion:; children.size() == 1 && children[0]->type == AST_RANGE && children[0]->children.size() == 1) { if (integer < (unsigned)id2ast->unpacked_dimensions) input_error("Insufficient number of array indices for %s.\n", log_id(str)); - newNode = std::make_unique(AST_MEMRD, children[0]->children[0]->clone()); + newNode = std::make_unique(location, AST_MEMRD, children[0]->children[0]->clone()); newNode->str = str; newNode->id2ast = id2ast; goto apply_newNode; @@ -3070,22 +3075,22 @@ skip_dynamic_range_lvalue_expansion:; if (found_nontrivial_member) { - newNode = std::make_unique(AST_BLOCK); + newNode = std::make_unique(location, AST_BLOCK); - auto wire_tmp_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(width_hint-1, true), mkconst_int(0, true))); + auto wire_tmp_owned = std::make_unique(location, AST_WIRE, std::make_unique(location, AST_RANGE, mkconst_int(location, width_hint-1, true), mkconst_int(location, 0, true))); auto wire_tmp = wire_tmp_owned.get(); - wire_tmp->str = stringf("$splitcmplxassign$%s:%d$%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line, autoidx++); + wire_tmp->str = stringf("$splitcmplxassign$%s:%d$%d", RTLIL::encode_filename(*location.begin.filename).c_str(), location.begin.line, autoidx++); current_scope[wire_tmp->str] = wire_tmp; current_ast_mod->children.push_back(std::move(wire_tmp_owned)); - wire_tmp->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); + wire_tmp->set_attribute(ID::nosync, AstNode::mkconst_int(location, 1, false)); while (wire_tmp->simplify(true, 1, -1, false)) { } wire_tmp->is_logic = true; - auto wire_tmp_id_owned = std::make_unique(AST_IDENTIFIER); + auto wire_tmp_id_owned = std::make_unique(location, AST_IDENTIFIER); auto* wire_tmp_id = wire_tmp_id_owned.get(); wire_tmp_id->str = wire_tmp->str; - newNode->children.push_back(std::make_unique(AST_ASSIGN_EQ, std::move(wire_tmp_id_owned), children[1]->clone())); + newNode->children.push_back(std::make_unique(location, AST_ASSIGN_EQ, std::move(wire_tmp_id_owned), children[1]->clone())); newNode->children.back()->was_checked = true; int cursor = 0; @@ -3096,8 +3101,8 @@ skip_dynamic_range_lvalue_expansion:; child->detectSignWidth(child_width_hint, child_sign_hint); auto rhs = wire_tmp_id->clone(); - rhs->children.push_back(std::make_unique(AST_RANGE, AstNode::mkconst_int(cursor+child_width_hint-1, true), AstNode::mkconst_int(cursor, true))); - newNode->children.push_back(std::make_unique(type, child->clone(), std::move(rhs))); + rhs->children.push_back(std::make_unique(location, AST_RANGE, AstNode::mkconst_int(location, cursor+child_width_hint-1, true), AstNode::mkconst_int(location, cursor, true))); + newNode->children.push_back(std::make_unique(location, type, child->clone(), std::move(rhs))); cursor += child_width_hint; } @@ -3116,15 +3121,15 @@ skip_dynamic_range_lvalue_expansion:; input_error("Insufficient number of array indices for %s.\n", log_id(str)); std::stringstream sstr; - sstr << "$memwr$" << children[0]->str << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++); + sstr << "$memwr$" << children[0]->str << "$" << RTLIL::encode_filename(*location.begin.filename) << ":" << location.begin.line << "$" << (autoidx++); std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA", id_en = sstr.str() + "_EN"; int mem_width, mem_size, addr_bits; bool mem_signed = children[0]->id2ast->is_signed; children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits); - newNode = std::make_unique(AST_BLOCK); - auto defNode = std::make_unique(AST_BLOCK); + newNode = std::make_unique(location, AST_BLOCK); + auto defNode = std::make_unique(location, AST_BLOCK); int data_range_left = children[0]->id2ast->children[0]->range_left; int data_range_right = children[0]->id2ast->children[0]->range_right; @@ -3147,7 +3152,7 @@ skip_dynamic_range_lvalue_expansion:; if (children[0]->children[0]->children[0]->isConst()) { node_addr = children[0]->children[0]->children[0]->clone(); } else { - auto wire_addr_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); + auto wire_addr_owned = std::make_unique(location, AST_WIRE, std::make_unique(location, AST_RANGE, mkconst_int(location, addr_bits-1, true), mkconst_int(location, 0, true))); auto* wire_addr = wire_addr_owned.get(); wire_addr->str = id_addr; wire_addr->was_checked = true; @@ -3155,17 +3160,17 @@ skip_dynamic_range_lvalue_expansion:; current_scope[wire_addr->str] = wire_addr; while (wire_addr->simplify(true, 1, -1, false)) { } - auto assign_addr = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), mkconst_bits(x_bits_addr, false)); + auto assign_addr = std::make_unique(location, AST_ASSIGN_EQ, std::make_unique(location, AST_IDENTIFIER), mkconst_bits(location, x_bits_addr, false)); assign_addr->children[0]->str = id_addr; assign_addr->children[0]->was_checked = true; defNode->children.push_back(std::move(assign_addr)); - assign_addr = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone()); + assign_addr = std::make_unique(location, AST_ASSIGN_EQ, std::make_unique(location, AST_IDENTIFIER), children[0]->children[0]->children[0]->clone()); assign_addr->children[0]->str = id_addr; assign_addr->children[0]->was_checked = true; newNode->children.push_back(std::move(assign_addr)); - node_addr = std::make_unique(AST_IDENTIFIER); + node_addr = std::make_unique(location, AST_IDENTIFIER); node_addr->str = id_addr; } @@ -3173,7 +3178,7 @@ skip_dynamic_range_lvalue_expansion:; if (children[0]->children.size() == 1 && children[1]->isConst()) { node_data = children[1]->clone(); } else { - auto wire_data_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); + auto wire_data_owned = std::make_unique(location, AST_WIRE, std::make_unique(location, AST_RANGE, mkconst_int(location, mem_width-1, true), mkconst_int(location, 0, true))); auto* wire_data = wire_data_owned.get(); wire_data->str = id_data; wire_data->was_checked = true; @@ -3182,16 +3187,16 @@ skip_dynamic_range_lvalue_expansion:; current_ast_mod->children.push_back(std::move(wire_data_owned)); while (wire_data->simplify(true, 1, -1, false)) { } - auto assign_data = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), mkconst_bits(x_bits_data, false)); + auto assign_data = std::make_unique(location, AST_ASSIGN_EQ, std::make_unique(location, AST_IDENTIFIER), mkconst_bits(location, x_bits_data, false)); assign_data->children[0]->str = id_data; assign_data->children[0]->was_checked = true; defNode->children.push_back(std::move(assign_data)); - node_data = std::make_unique(AST_IDENTIFIER); + node_data = std::make_unique(location, AST_IDENTIFIER); node_data->str = id_data; } - auto wire_en_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); + auto wire_en_owned = std::make_unique(location, AST_WIRE, std::make_unique(location, AST_RANGE, mkconst_int(location, mem_width-1, true), mkconst_int(location, 0, true))); auto* wire_en = wire_en_owned.get(); wire_en->str = id_en; wire_en->was_checked = true; @@ -3199,12 +3204,12 @@ skip_dynamic_range_lvalue_expansion:; current_ast_mod->children.push_back(std::move(wire_en_owned)); while (wire_en->simplify(true, 1, -1, false)) { } - auto assign_en_first = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), mkconst_int(0, false, mem_width)); + auto assign_en_first = std::make_unique(location, AST_ASSIGN_EQ, std::make_unique(location, AST_IDENTIFIER), mkconst_int(location, 0, false, mem_width)); assign_en_first->children[0]->str = id_en; assign_en_first->children[0]->was_checked = true; defNode->children.push_back(std::move(assign_en_first)); - auto node_en = std::make_unique(AST_IDENTIFIER); + auto node_en = std::make_unique(location, AST_IDENTIFIER); node_en->str = id_en; if (!defNode->children.empty()) @@ -3222,14 +3227,14 @@ skip_dynamic_range_lvalue_expansion:; std::vector padding_x(offset, RTLIL::State::Sx); - assign_data = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), - std::make_unique(AST_CONCAT, mkconst_bits(padding_x, false), children[1]->clone())); + assign_data = std::make_unique(location, AST_ASSIGN_EQ, std::make_unique(location, AST_IDENTIFIER), + std::make_unique(location, AST_CONCAT, mkconst_bits(location, padding_x, false), children[1]->clone())); assign_data->children[0]->str = id_data; assign_data->children[0]->was_checked = true; for (int i = 0; i < mem_width; i++) set_bits_en[i] = offset <= i && i < offset+width ? RTLIL::State::S1 : RTLIL::State::S0; - assign_en = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); + assign_en = std::make_unique(location, AST_ASSIGN_EQ, std::make_unique(location, AST_IDENTIFIER), mkconst_bits(location, set_bits_en, false)); assign_en->children[0]->str = id_en; assign_en->children[0]->was_checked = true; } @@ -3248,17 +3253,17 @@ skip_dynamic_range_lvalue_expansion:; offset_ast = the_range->children[0]->clone(); if (mem_data_range_offset) - offset_ast = std::make_unique(AST_SUB, std::move(offset_ast), mkconst_int(mem_data_range_offset, true)); + offset_ast = std::make_unique(location, AST_SUB, std::move(offset_ast), mkconst_int(location, mem_data_range_offset, true)); - assign_data = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), - std::make_unique(AST_SHIFT_LEFT, children[1]->clone(), offset_ast->clone())); + assign_data = std::make_unique(location, AST_ASSIGN_EQ, std::make_unique(location, AST_IDENTIFIER), + std::make_unique(location, AST_SHIFT_LEFT, children[1]->clone(), offset_ast->clone())); assign_data->children[0]->str = id_data; assign_data->children[0]->was_checked = true; for (int i = 0; i < mem_width; i++) set_bits_en[i] = i < width ? RTLIL::State::S1 : RTLIL::State::S0; - assign_en = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), - std::make_unique(AST_SHIFT_LEFT, mkconst_bits(set_bits_en, false), offset_ast->clone())); + assign_en = std::make_unique(location, AST_ASSIGN_EQ, std::make_unique(location, AST_IDENTIFIER), + std::make_unique(location, AST_SHIFT_LEFT, mkconst_bits(location, set_bits_en, false), offset_ast->clone())); assign_en->children[0]->str = id_en; assign_en->children[0]->was_checked = true; } @@ -3266,12 +3271,12 @@ skip_dynamic_range_lvalue_expansion:; else { if (!(children[0]->children.size() == 1 && children[1]->isConst())) { - assign_data = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), children[1]->clone()); + assign_data = std::make_unique(location, AST_ASSIGN_EQ, std::make_unique(location, AST_IDENTIFIER), children[1]->clone()); assign_data->children[0]->str = id_data; assign_data->children[0]->was_checked = true; } - assign_en = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); + assign_en = std::make_unique(location, AST_ASSIGN_EQ, std::make_unique(location, AST_IDENTIFIER), mkconst_bits(location, set_bits_en, false)); assign_en->children[0]->str = id_en; assign_en->children[0]->was_checked = true; } @@ -3282,21 +3287,21 @@ skip_dynamic_range_lvalue_expansion:; std::unique_ptr wrnode; if (current_always->type == AST_INITIAL) - wrnode = std::make_unique(AST_MEMINIT, std::move(node_addr), std::move(node_data), std::move(node_en), mkconst_int(1, false)); + wrnode = std::make_unique(location, AST_MEMINIT, std::move(node_addr), std::move(node_data), std::move(node_en), mkconst_int(location, 1, false)); else - wrnode = std::make_unique(AST_MEMWR, std::move(node_addr), std::move(node_data), std::move(node_en)); + wrnode = std::make_unique(location, AST_MEMWR, std::move(node_addr), std::move(node_data), std::move(node_en)); wrnode->str = children[0]->str; wrnode->id2ast = children[0]->id2ast; wrnode->location = location; if (wrnode->type == AST_MEMWR) { int portid = current_memwr_count[wrnode->str]++; - wrnode->children.push_back(mkconst_int(portid, false)); + wrnode->children.push_back(mkconst_int(location, portid, false)); std::vector priority_mask; for (int i = 0; i < portid; i++) { bool has_prio = current_memwr_visible[wrnode->str].count(i); priority_mask.push_back(State(has_prio)); } - wrnode->children.push_back(mkconst_bits(priority_mask, false)); + wrnode->children.push_back(mkconst_bits(location, priority_mask, false)); current_memwr_visible[wrnode->str].insert(portid); current_always->children.push_back(std::move(wrnode)); } else { @@ -3304,7 +3309,7 @@ skip_dynamic_range_lvalue_expansion:; } if (newNode->children.empty()) { - newNode = std::make_unique(); + newNode = std::make_unique(location); } goto apply_newNode; } @@ -3318,13 +3323,13 @@ skip_dynamic_range_lvalue_expansion:; { int myidx = autoidx++; - auto wire_owned = std::make_unique(AST_WIRE); + auto wire_owned = std::make_unique(location, AST_WIRE); auto* wire = wire_owned.get(); current_ast_mod->children.push_back(std::move(wire_owned)); wire->str = stringf("$initstate$%d_wire", myidx); while (wire->simplify(true, 1, -1, false)) { } - auto cell = std::make_unique(AST_CELL, std::make_unique(AST_CELLTYPE), std::make_unique(AST_ARGUMENT, std::make_unique(AST_IDENTIFIER))); + auto cell = std::make_unique(location, AST_CELL, std::make_unique(location, AST_CELLTYPE), std::make_unique(location, AST_ARGUMENT, std::make_unique(location, AST_IDENTIFIER))); cell->str = stringf("$initstate$%d", myidx); cell->children[0]->str = "$initstate"; cell->children[1]->str = "\\Y"; @@ -3333,7 +3338,7 @@ skip_dynamic_range_lvalue_expansion:; current_ast_mod->children.push_back(std::move(cell)); while (cell->simplify(true, 1, -1, false)) { } - newNode = std::make_unique(AST_IDENTIFIER); + newNode = std::make_unique(location, AST_IDENTIFIER); newNode->str = wire->str; newNode->id2ast = wire; goto apply_newNode; @@ -3382,19 +3387,19 @@ skip_dynamic_range_lvalue_expansion:; for (int i = 0; i < num_steps; i++) { - auto reg_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, - mkconst_int(width_hint-1, true), mkconst_int(0, true))); + auto reg_owned = std::make_unique(location, AST_WIRE, std::make_unique(location, AST_RANGE, + mkconst_int(location, width_hint-1, true), mkconst_int(location, 0, true))); auto* reg = reg_owned.get(); current_ast_mod->children.push_back(std::move(reg_owned)); - reg->str = stringf("$past$%s:%d$%d$%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line, myidx, i); + reg->str = stringf("$past$%s:%d$%d$%d", RTLIL::encode_filename(*location.begin.filename).c_str(), location.begin.line, myidx, i); reg->is_reg = true; reg->is_signed = sign_hint; while (reg->simplify(true, 1, -1, false)) { } - auto regid = std::make_unique(AST_IDENTIFIER); + auto regid = std::make_unique(location, AST_IDENTIFIER); regid->str = reg->str; regid->id2ast = reg; regid->was_checked = true; @@ -3404,16 +3409,16 @@ skip_dynamic_range_lvalue_expansion:; if (outreg == nullptr) { rhs = children.at(0)->clone(); } else { - rhs = std::make_unique(AST_IDENTIFIER); + rhs = std::make_unique(location, AST_IDENTIFIER); rhs->str = outreg->str; rhs->id2ast = outreg; } - block->children.push_back(std::make_unique(AST_ASSIGN_LE, std::move(regid), std::move(rhs))); + block->children.push_back(std::make_unique(location, AST_ASSIGN_LE, std::move(regid), std::move(rhs))); outreg = reg; } - newNode = std::make_unique(AST_IDENTIFIER); + newNode = std::make_unique(location, AST_IDENTIFIER); newNode->str = outreg->str; newNode->id2ast = outreg; goto apply_newNode; @@ -3434,20 +3439,20 @@ skip_dynamic_range_lvalue_expansion:; past->str = "\\$past"; if (str == "\\$stable") - newNode = std::make_unique(AST_EQ, std::move(past), std::move(present)); + newNode = std::make_unique(location, AST_EQ, std::move(past), std::move(present)); else if (str == "\\$changed") - newNode = std::make_unique(AST_NE, std::move(past), std::move(present)); + newNode = std::make_unique(location, AST_NE, std::move(past), std::move(present)); else if (str == "\\$rose") - newNode = std::make_unique(AST_LOGIC_AND, - std::make_unique(AST_LOGIC_NOT, std::make_unique(AST_BIT_AND, std::move(past), mkconst_int(1,false))), - std::make_unique(AST_BIT_AND, std::move(present), mkconst_int(1,false))); + newNode = std::make_unique(location, AST_LOGIC_AND, + std::make_unique(location, AST_LOGIC_NOT, std::make_unique(location, AST_BIT_AND, std::move(past), mkconst_int(location, 1, false))), + std::make_unique(location, AST_BIT_AND, std::move(present), mkconst_int(location, 1, false))); else if (str == "\\$fell") - newNode = std::make_unique(AST_LOGIC_AND, - std::make_unique(AST_BIT_AND, std::move(past), mkconst_int(1,false)), - std::make_unique(AST_LOGIC_NOT, std::make_unique(AST_BIT_AND, std::move(present), mkconst_int(1,false)))); + newNode = std::make_unique(location, AST_LOGIC_AND, + std::make_unique(location, AST_BIT_AND, std::move(past), mkconst_int(location, 1, false)), + std::make_unique(location, AST_LOGIC_NOT, std::make_unique(location, AST_BIT_AND, std::move(present), mkconst_int(location, 1, false)))); else log_abort(); @@ -3481,7 +3486,7 @@ skip_dynamic_range_lvalue_expansion:; if (arg_value.at(i) == RTLIL::State::S1) result = i + 1; - newNode = mkconst_int(result, true); + newNode = mkconst_int(location, result, true); goto apply_newNode; } @@ -3572,7 +3577,7 @@ skip_dynamic_range_lvalue_expansion:; else { // str == "\\$bits" result = width * mem_depth; } - newNode = mkconst_int(result, true); + newNode = mkconst_int(location, result, true); goto apply_newNode; } @@ -3618,9 +3623,9 @@ skip_dynamic_range_lvalue_expansion:; } if (str == "\\$rtoi") { - newNode = AstNode::mkconst_int(x, true); + newNode = AstNode::mkconst_int(location, x, true); } else { - newNode = std::make_unique(AST_REALVALUE); + newNode = std::make_unique(location, AST_REALVALUE); if (str == "\\$ln") newNode->realvalue = ::log(x); else if (str == "\\$log10") newNode->realvalue = ::log10(x); else if (str == "\\$exp") newNode->realvalue = ::exp(x); @@ -3650,7 +3655,7 @@ skip_dynamic_range_lvalue_expansion:; if (str == "\\$sformatf") { Fmt fmt = processFormat(stage, /*sformat_like=*/true); - newNode = AstNode::mkconst_str(fmt.render()); + newNode = AstNode::mkconst_str(location, fmt.render()); goto apply_newNode; } @@ -3678,24 +3683,24 @@ skip_dynamic_range_lvalue_expansion:; auto& exp = children[0]; exp->detectSignWidth(exp_width, exp_sign, nullptr); - newNode = mkconst_int(0, false); + newNode = mkconst_int(location, 0, false); for (int i = 0; i < exp_width; i++) { // Generate nodes for: exp << i >> ($size(exp) - 1) // ^^ ^^ - auto lsh_node = std::make_unique(AST_SHIFT_LEFT, exp->clone(), mkconst_int(i, false)); - auto rsh_node = std::make_unique(AST_SHIFT_RIGHT, std::move(lsh_node), mkconst_int(exp_width - 1, false)); + auto lsh_node = std::make_unique(location, AST_SHIFT_LEFT, exp->clone(), mkconst_int(location, i, false)); + auto rsh_node = std::make_unique(location, AST_SHIFT_RIGHT, std::move(lsh_node), mkconst_int(location, exp_width - 1, false)); std::unique_ptr or_node = nullptr; for (RTLIL::State control_bit : control_bits) { // Generate node for: (exp << i >> ($size(exp) - 1)) === control_bit // ^^^ - auto eq_node = std::make_unique(AST_EQX, rsh_node->clone(), mkconst_bits({control_bit}, false)); + auto eq_node = std::make_unique(location, AST_EQX, rsh_node->clone(), mkconst_bits(location, {control_bit}, false)); // Or the result for each checked bit value if (or_node) - or_node = std::make_unique(AST_LOGIC_OR, std::move(or_node), std::move(eq_node)); + or_node = std::make_unique(location, AST_LOGIC_OR, std::move(or_node), std::move(eq_node)); else or_node = std::move(eq_node); } @@ -3705,7 +3710,7 @@ skip_dynamic_range_lvalue_expansion:; log_assert(or_node != nullptr); // Generate node for adding with result of previous bit - newNode = std::make_unique(AST_ADD, std::move(newNode), std::move(or_node)); + newNode = std::make_unique(location, AST_ADD, std::move(newNode), std::move(or_node)); } goto apply_newNode; @@ -3720,18 +3725,18 @@ skip_dynamic_range_lvalue_expansion:; countbits->str = "\\$countbits"; if (str == "\\$countones") { - countbits->children.push_back(mkconst_bits({RTLIL::State::S1}, false)); + countbits->children.push_back(mkconst_bits(location, {RTLIL::State::S1}, false)); newNode = std::move(countbits); } else if (str == "\\$isunknown") { - countbits->children.push_back(mkconst_bits({RTLIL::Sx}, false)); - countbits->children.push_back(mkconst_bits({RTLIL::Sz}, false)); - newNode = std::make_unique(AST_GT, std::move(countbits), mkconst_int(0, false)); + countbits->children.push_back(mkconst_bits(location, {RTLIL::Sx}, false)); + countbits->children.push_back(mkconst_bits(location, {RTLIL::Sz}, false)); + newNode = std::make_unique(location, AST_GT, std::move(countbits), mkconst_int(location, 0, false)); } else if (str == "\\$onehot") { - countbits->children.push_back(mkconst_bits({RTLIL::State::S1}, false)); - newNode = std::make_unique(AST_EQ, std::move(countbits), mkconst_int(1, false)); + countbits->children.push_back(mkconst_bits(location, {RTLIL::State::S1}, false)); + newNode = std::make_unique(location, AST_EQ, std::move(countbits), mkconst_int(location, 1, false)); } else if (str == "\\$onehot0") { - countbits->children.push_back(mkconst_bits({RTLIL::State::S1}, false)); - newNode = std::make_unique(AST_LE, std::move(countbits), mkconst_int(1, false)); + countbits->children.push_back(mkconst_bits(location, {RTLIL::State::S1}, false)); + newNode = std::make_unique(location, AST_LE, std::move(countbits), mkconst_int(location, 1, false)); } else { log_abort(); } @@ -3847,7 +3852,7 @@ skip_dynamic_range_lvalue_expansion:; std::stringstream sstr; - sstr << str << "$func$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++) << '.'; + sstr << str << "$func$" << RTLIL::encode_filename(*location.begin.filename) << ":" << location.begin.line << "$" << (autoidx++) << '.'; std::string prefix = sstr.str(); auto* decl = current_scope[str]; @@ -3910,11 +3915,11 @@ skip_dynamic_range_lvalue_expansion:; current_ast_mod->children.push_back(std::move(wire)); while (wire_leaky->simplify(true, 1, -1, false)) { } - auto lvalue = std::make_unique(AST_IDENTIFIER); + auto lvalue = std::make_unique(location, AST_IDENTIFIER); lvalue->str = wire_leaky->str; - auto always = std::make_unique(AST_ALWAYS, std::make_unique(AST_BLOCK, - std::make_unique(AST_ASSIGN_EQ, std::move(lvalue), clone()))); + auto always = std::make_unique(location, AST_ALWAYS, std::make_unique(location, AST_BLOCK, + std::make_unique(location, AST_ASSIGN_EQ, std::move(lvalue), clone()))); always->children[0]->children[0]->was_checked = true; current_ast_mod->children.push_back(std::move(always)); @@ -3934,14 +3939,14 @@ skip_dynamic_range_lvalue_expansion:; } else celltype = RTLIL::escape_id(celltype); - auto cell = std::make_unique(AST_CELL, std::make_unique(AST_CELLTYPE)); + auto cell = std::make_unique(location, AST_CELL, std::make_unique(location, AST_CELLTYPE)); cell->str = prefix.substr(0, GetSize(prefix)-1); cell->children[0]->str = celltype; for (auto& attr : decl->attributes) if (attr.first.str().rfind("\\via_celltype_defparam_", 0) == 0) { - auto cell_arg = std::make_unique(AST_PARASET, attr.second->clone()); + auto cell_arg = std::make_unique(location, AST_PARASET, attr.second->clone()); cell_arg->str = RTLIL::escape_id(attr.first.substr(strlen("\\via_celltype_defparam_"))); cell->children.push_back(std::move(cell_arg)); } @@ -3956,15 +3961,15 @@ skip_dynamic_range_lvalue_expansion:; current_ast_mod->children.push_back(std::move(wire)); while (wire->simplify(true, 1, -1, false)) { } - auto wire_id = std::make_unique(AST_IDENTIFIER); + auto wire_id = std::make_unique(location, AST_IDENTIFIER); wire_id->str = wire->str; if ((child->is_input || child->is_output) && arg_count < children.size()) { auto arg = children[arg_count++]->clone(); auto assign = child->is_input ? - std::make_unique(AST_ASSIGN_EQ, wire_id->clone(), std::move(arg)) : - std::make_unique(AST_ASSIGN_EQ, std::move(arg), wire_id->clone()); + std::make_unique(location, AST_ASSIGN_EQ, wire_id->clone(), std::move(arg)) : + std::make_unique(location, AST_ASSIGN_EQ, std::move(arg), wire_id->clone()); assign->children[0]->was_checked = true; for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) { @@ -3975,7 +3980,7 @@ skip_dynamic_range_lvalue_expansion:; } } - auto cell_arg = std::make_unique(AST_ARGUMENT, std::move(wire_id)); + auto cell_arg = std::make_unique(location, AST_ARGUMENT, std::move(wire_id)); cell_arg->str = child->str == str ? outport : child->str; cell->children.push_back(std::move(cell_arg)); } @@ -4016,7 +4021,7 @@ skip_dynamic_range_lvalue_expansion:; wire->is_input = false; wire->is_output = false; wire->is_reg = true; - wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); + wire->set_attribute(ID::nosync, AstNode::mkconst_int(location, 1, false)); if (child->type == AST_ENUM_ITEM) wire->set_attribute(ID::enum_base_type, std::move(child->attributes[ID::enum_base_type])); @@ -4047,10 +4052,10 @@ skip_dynamic_range_lvalue_expansion:; break; } if (!uses_explicit_size) { - auto range = std::make_unique(); + auto range = std::make_unique(location); range->type = AST_RANGE; - range->children.push_back(mkconst_int(0, true)); - range->children.push_back(mkconst_int(0, true)); + range->children.push_back(mkconst_int(location, 0, true)); + range->children.push_back(mkconst_int(location, 0, true)); wire->children.push_back(std::move(range)); } } @@ -4060,16 +4065,16 @@ skip_dynamic_range_lvalue_expansion:; continue; } - auto wire_id = std::make_unique(AST_IDENTIFIER); + auto wire_id = std::make_unique(location, AST_IDENTIFIER); wire_id->str = wire->str; if (child->is_input) { - auto assign = std::make_unique(AST_ASSIGN_EQ, wire_id->clone(), arg->clone()); + auto assign = std::make_unique(location, AST_ASSIGN_EQ, wire_id->clone(), arg->clone()); assign->children[0]->was_checked = true; new_stmts.push_back(std::move(assign)); } if (child->is_output) { - auto assign = std::make_unique(AST_ASSIGN_EQ, arg->clone(), wire_id->clone()); + auto assign = std::make_unique(location, AST_ASSIGN_EQ, arg->clone(), wire_id->clone()); assign->children[0]->was_checked = true; output_assignments.push_back(std::move(assign)); } @@ -4140,7 +4145,7 @@ replace_fcall_later:; else data.push_back(RTLIL::State::Sx); } - newNode = mkconst_bits(data, false); + newNode = mkconst_bits(location, data, false); } else if (children.size() == 0) newNode = current_scope[str]->children[0]->clone(); @@ -4152,14 +4157,14 @@ replace_fcall_later:; case AST_BIT_NOT: if (children[0]->type == AST_CONSTANT) { RTLIL::Const y = RTLIL::const_not(children[0]->bitsAsConst(width_hint, sign_hint), dummy_arg, sign_hint, false, width_hint); - newNode = mkconst_bits(y.to_bits(), sign_hint); + newNode = mkconst_bits(location, y.to_bits(), sign_hint); } break; case AST_TO_SIGNED: case AST_TO_UNSIGNED: if (children[0]->type == AST_CONSTANT) { RTLIL::Const y = children[0]->bitsAsConst(width_hint, sign_hint); - newNode = mkconst_bits(y.to_bits(), type == AST_TO_SIGNED); + newNode = mkconst_bits(location, y.to_bits(), type == AST_TO_SIGNED); } break; if (0) { case AST_BIT_AND: const_func = RTLIL::const_and; } @@ -4169,7 +4174,7 @@ replace_fcall_later:; if (children[0]->type == AST_CONSTANT && children[1]->type == AST_CONSTANT) { RTLIL::Const y = const_func(children[0]->bitsAsConst(width_hint, sign_hint), children[1]->bitsAsConst(width_hint, sign_hint), sign_hint, sign_hint, width_hint); - newNode = mkconst_bits(y.to_bits(), sign_hint); + newNode = mkconst_bits(location, y.to_bits(), sign_hint); } break; if (0) { case AST_REDUCE_AND: const_func = RTLIL::const_reduce_and; } @@ -4179,16 +4184,16 @@ replace_fcall_later:; if (0) { case AST_REDUCE_BOOL: const_func = RTLIL::const_reduce_bool; } if (children[0]->type == AST_CONSTANT) { RTLIL::Const y = const_func(RTLIL::Const(children[0]->bits), dummy_arg, false, false, -1); - newNode = mkconst_bits(y.to_bits(), false); + newNode = mkconst_bits(location, y.to_bits(), false); } break; case AST_LOGIC_NOT: if (children[0]->type == AST_CONSTANT) { RTLIL::Const y = RTLIL::const_logic_not(RTLIL::Const(children[0]->bits), dummy_arg, children[0]->is_signed, false, -1); - newNode = mkconst_bits(y.to_bits(), false); + newNode = mkconst_bits(location, y.to_bits(), false); } else if (children[0]->isConst()) { - newNode = mkconst_int(children[0]->asReal(sign_hint) == 0, false, 1); + newNode = mkconst_int(location, children[0]->asReal(sign_hint) == 0, false, 1); } break; if (0) { case AST_LOGIC_AND: const_func = RTLIL::const_logic_and; } @@ -4196,13 +4201,13 @@ replace_fcall_later:; if (children[0]->type == AST_CONSTANT && children[1]->type == AST_CONSTANT) { RTLIL::Const y = const_func(RTLIL::Const(children[0]->bits), RTLIL::Const(children[1]->bits), children[0]->is_signed, children[1]->is_signed, -1); - newNode = mkconst_bits(y.to_bits(), false); + newNode = mkconst_bits(location, y.to_bits(), false); } else if (children[0]->isConst() && children[1]->isConst()) { if (type == AST_LOGIC_AND) - newNode = mkconst_int((children[0]->asReal(sign_hint) != 0) && (children[1]->asReal(sign_hint) != 0), false, 1); + newNode = mkconst_int(location, (children[0]->asReal(sign_hint) != 0) && (children[1]->asReal(sign_hint) != 0), false, 1); else - newNode = mkconst_int((children[0]->asReal(sign_hint) != 0) || (children[1]->asReal(sign_hint) != 0), false, 1); + newNode = mkconst_int(location, (children[0]->asReal(sign_hint) != 0) || (children[1]->asReal(sign_hint) != 0), false, 1); } break; if (0) { case AST_SHIFT_LEFT: const_func = RTLIL::const_shl; } @@ -4213,10 +4218,10 @@ replace_fcall_later:; if (children[0]->type == AST_CONSTANT && children[1]->type == AST_CONSTANT) { RTLIL::Const y = const_func(children[0]->bitsAsConst(width_hint, sign_hint), RTLIL::Const(children[1]->bits), sign_hint, type == AST_POW ? children[1]->is_signed : false, width_hint); - newNode = mkconst_bits(y.to_bits(), sign_hint); + newNode = mkconst_bits(location, y.to_bits(), sign_hint); } else if (type == AST_POW && children[0]->isConst() && children[1]->isConst()) { - newNode = std::make_unique(AST_REALVALUE); + newNode = std::make_unique(location, AST_REALVALUE); newNode->realvalue = pow(children[0]->asReal(sign_hint), children[1]->asReal(sign_hint)); } break; @@ -4233,19 +4238,19 @@ replace_fcall_later:; bool cmp_signed = children[0]->is_signed && children[1]->is_signed; RTLIL::Const y = const_func(children[0]->bitsAsConst(cmp_width, cmp_signed), children[1]->bitsAsConst(cmp_width, cmp_signed), cmp_signed, cmp_signed, 1); - newNode = mkconst_bits(y.to_bits(), false); + newNode = mkconst_bits(location, y.to_bits(), false); } else if (children[0]->isConst() && children[1]->isConst()) { bool cmp_signed = (children[0]->type == AST_REALVALUE || children[0]->is_signed) && (children[1]->type == AST_REALVALUE || children[1]->is_signed); switch (type) { - case AST_LT: newNode = mkconst_int(children[0]->asReal(cmp_signed) < children[1]->asReal(cmp_signed), false, 1); break; - case AST_LE: newNode = mkconst_int(children[0]->asReal(cmp_signed) <= children[1]->asReal(cmp_signed), false, 1); break; - case AST_EQ: newNode = mkconst_int(children[0]->asReal(cmp_signed) == children[1]->asReal(cmp_signed), false, 1); break; - case AST_NE: newNode = mkconst_int(children[0]->asReal(cmp_signed) != children[1]->asReal(cmp_signed), false, 1); break; - case AST_EQX: newNode = mkconst_int(children[0]->asReal(cmp_signed) == children[1]->asReal(cmp_signed), false, 1); break; - case AST_NEX: newNode = mkconst_int(children[0]->asReal(cmp_signed) != children[1]->asReal(cmp_signed), false, 1); break; - case AST_GE: newNode = mkconst_int(children[0]->asReal(cmp_signed) >= children[1]->asReal(cmp_signed), false, 1); break; - case AST_GT: newNode = mkconst_int(children[0]->asReal(cmp_signed) > children[1]->asReal(cmp_signed), false, 1); break; + case AST_LT: newNode = mkconst_int(location, children[0]->asReal(cmp_signed) < children[1]->asReal(cmp_signed), false, 1); break; + case AST_LE: newNode = mkconst_int(location, children[0]->asReal(cmp_signed) <= children[1]->asReal(cmp_signed), false, 1); break; + case AST_EQ: newNode = mkconst_int(location, children[0]->asReal(cmp_signed) == children[1]->asReal(cmp_signed), false, 1); break; + case AST_NE: newNode = mkconst_int(location, children[0]->asReal(cmp_signed) != children[1]->asReal(cmp_signed), false, 1); break; + case AST_EQX: newNode = mkconst_int(location, children[0]->asReal(cmp_signed) == children[1]->asReal(cmp_signed), false, 1); break; + case AST_NEX: newNode = mkconst_int(location, children[0]->asReal(cmp_signed) != children[1]->asReal(cmp_signed), false, 1); break; + case AST_GE: newNode = mkconst_int(location, children[0]->asReal(cmp_signed) >= children[1]->asReal(cmp_signed), false, 1); break; + case AST_GT: newNode = mkconst_int(location, children[0]->asReal(cmp_signed) > children[1]->asReal(cmp_signed), false, 1); break; default: log_abort(); } } @@ -4258,10 +4263,10 @@ replace_fcall_later:; if (children[0]->type == AST_CONSTANT && children[1]->type == AST_CONSTANT) { RTLIL::Const y = const_func(children[0]->bitsAsConst(width_hint, sign_hint), children[1]->bitsAsConst(width_hint, sign_hint), sign_hint, sign_hint, width_hint); - newNode = mkconst_bits(y.to_bits(), sign_hint); + newNode = mkconst_bits(location, y.to_bits(), sign_hint); } else if (children[0]->isConst() && children[1]->isConst()) { - newNode = std::make_unique(AST_REALVALUE); + newNode = std::make_unique(location, AST_REALVALUE); switch (type) { case AST_ADD: newNode->realvalue = children[0]->asReal(sign_hint) + children[1]->asReal(sign_hint); break; case AST_SUB: newNode->realvalue = children[0]->asReal(sign_hint) - children[1]->asReal(sign_hint); break; @@ -4277,10 +4282,10 @@ replace_fcall_later:; if (0) { case AST_NEG: const_func = RTLIL::const_neg; } if (children[0]->type == AST_CONSTANT) { RTLIL::Const y = const_func(children[0]->bitsAsConst(width_hint, sign_hint), dummy_arg, sign_hint, false, width_hint); - newNode = mkconst_bits(y.to_bits(), sign_hint); + newNode = mkconst_bits(location, y.to_bits(), sign_hint); } else if (children[0]->isConst()) { - newNode = std::make_unique(AST_REALVALUE); + newNode = std::make_unique(location, AST_REALVALUE); if (type == AST_NEG) newNode->realvalue = -children[0]->asReal(sign_hint); else @@ -4300,15 +4305,15 @@ replace_fcall_later:; bool other_sign_hint = sign_hint, other_real = false; not_choice->detectSignWidth(other_width_hint, other_sign_hint, &other_real); if (other_real) { - newNode = std::make_unique(AST_REALVALUE); + newNode = std::make_unique(location, AST_REALVALUE); choice->detectSignWidth(width_hint, sign_hint); newNode->realvalue = choice->asReal(sign_hint); } else { RTLIL::Const y = choice->bitsAsConst(width_hint, sign_hint); if (choice->is_string && y.size() % 8 == 0 && sign_hint == false) - newNode = mkconst_str(y.to_bits()); + newNode = mkconst_str(location, y.to_bits()); else - newNode = mkconst_bits(y.to_bits(), sign_hint); + newNode = mkconst_bits(location, y.to_bits(), sign_hint); } } else if (choice->isConst()) { @@ -4321,9 +4326,9 @@ replace_fcall_later:; for (auto i = 0; i < a.size(); i++) if (a[i] != b[i]) a.bits()[i] = RTLIL::State::Sx; - newNode = mkconst_bits(a.to_bits(), sign_hint); + newNode = mkconst_bits(location, a.to_bits(), sign_hint); } else if (children[1]->isConst() && children[2]->isConst()) { - newNode = std::make_unique(AST_REALVALUE); + newNode = std::make_unique(location, AST_REALVALUE); if (children[1]->asReal(sign_hint) == children[2]->asReal(sign_hint)) newNode->realvalue = children[1]->asReal(sign_hint); else @@ -4342,7 +4347,7 @@ replace_fcall_later:; val = children[1]->bitsAsUnsizedConst(width); else val = children[1]->bitsAsConst(width); - newNode = mkconst_bits(val.to_bits(), children[1]->is_signed); + newNode = mkconst_bits(location, val.to_bits(), children[1]->is_signed); } break; case AST_CONCAT: @@ -4354,14 +4359,14 @@ replace_fcall_later:; string_op = false; tmp_bits.insert(tmp_bits.end(), (*it)->bits.begin(), (*it)->bits.end()); } - newNode = string_op ? mkconst_str(tmp_bits) : mkconst_bits(tmp_bits, false); + newNode = string_op ? mkconst_str(location, tmp_bits) : mkconst_bits(location, tmp_bits, false); break; case AST_REPLICATE: if (children.at(0)->type != AST_CONSTANT || children.at(1)->type != AST_CONSTANT) goto not_const; for (int i = 0; i < children[0]->bitsAsConst().as_int(); i++) tmp_bits.insert(tmp_bits.end(), children.at(1)->bits.begin(), children.at(1)->bits.end()); - newNode = children.at(1)->is_string ? mkconst_str(tmp_bits) : mkconst_bits(tmp_bits, false); + newNode = children.at(1)->is_string ? mkconst_str(location, tmp_bits) : mkconst_bits(location, tmp_bits, false); break; default: not_const: @@ -4377,7 +4382,7 @@ apply_newNode: // newNode->dumpAst(stderr, "+ "); log_assert(newNode != nullptr); // newNode->null_check(); - newNode->location.filename = location.filename; + newNode->location.begin.filename = location.begin.filename; newNode->location = location; newNode->cloneInto(*this); fixup_hierarchy_flags(); @@ -4405,7 +4410,7 @@ std::unique_ptr AstNode::readmem(bool is_readmemh, std::string mem_file int mem_width, mem_size, addr_bits; memory->meminfo(mem_width, mem_size, addr_bits); - auto block = std::make_unique(AST_BLOCK); + auto block = std::make_unique(location, AST_BLOCK); AstNode* meminit = nullptr; int next_meminit_cursor=0; @@ -4424,7 +4429,7 @@ std::unique_ptr AstNode::readmem(bool is_readmemh, std::string mem_file #else char slash = '/'; #endif - std::string path = location.filename.substr(0, location.filename.find_last_of(slash)+1); + std::string path = location.begin.filename->substr(0, location.begin.filename->find_last_of(slash)+1); f.open(path + mem_filename.c_str()); yosys_input_files.insert(path + mem_filename); } else { @@ -4489,15 +4494,15 @@ std::unique_ptr AstNode::readmem(bool is_readmemh, std::string mem_file if (meminit == nullptr || cursor != next_meminit_cursor) { if (meminit != nullptr) { - meminit->children[1] = AstNode::mkconst_bits(meminit_bits, false); - meminit->children[3] = AstNode::mkconst_int(meminit_size, false); + meminit->children[1] = AstNode::mkconst_bits(location, meminit_bits, false); + meminit->children[3] = AstNode::mkconst_int(location, meminit_size, false); } - auto meminit_owned = std::make_unique(AST_MEMINIT); + auto meminit_owned = std::make_unique(location, AST_MEMINIT); meminit = meminit_owned.get(); - meminit->children.push_back(AstNode::mkconst_int(cursor, false)); + meminit->children.push_back(AstNode::mkconst_int(location, cursor, false)); meminit->children.push_back(nullptr); - meminit->children.push_back(AstNode::mkconst_bits(en_bits, false)); + meminit->children.push_back(AstNode::mkconst_bits(location, en_bits, false)); meminit->children.push_back(nullptr); meminit->str = memory->str; meminit->id2ast = memory; @@ -4514,7 +4519,13 @@ std::unique_ptr AstNode::readmem(bool is_readmemh, std::string mem_file } else { - block->children.push_back(std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER, std::make_unique(AST_RANGE, AstNode::mkconst_int(cursor, false))), std::move(value))); + block->children.push_back( + std::make_unique(location, + AST_ASSIGN_EQ, std::make_unique(location, + AST_IDENTIFIER, std::make_unique(location, + AST_RANGE, AstNode::mkconst_int(location, + cursor, false))), + std::move(value))); block->children.back()->children[0]->str = memory->str; block->children.back()->children[0]->id2ast = memory; block->children.back()->children[0]->was_checked = true; @@ -4530,8 +4541,8 @@ std::unique_ptr AstNode::readmem(bool is_readmemh, std::string mem_file } if (meminit != nullptr) { - meminit->children[1] = AstNode::mkconst_bits(meminit_bits, false); - meminit->children[3] = AstNode::mkconst_int(meminit_size, false); + meminit->children[1] = AstNode::mkconst_bits(location, meminit_bits, false); + meminit->children[3] = AstNode::mkconst_int(location, meminit_size, false); } return block; @@ -4703,7 +4714,7 @@ static void mark_memories_assign_lhs_complex(dict> & if (that->type == AST_IDENTIFIER && that->id2ast && that->id2ast->type == AST_MEMORY) { AstNode *mem = that->id2ast; if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_CMPLX_LHS)) - mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(that->location.filename).c_str(), that->location.first_line)); + mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(*that->location.begin.filename).c_str(), that->location.begin.line)); mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_CMPLX_LHS; } } @@ -4731,14 +4742,14 @@ void AstNode::mem2reg_as_needed_pass1(dict> &mem2reg // activate mem2reg if this is assigned in an async proc if (flags & AstNode::MEM2REG_FL_ASYNC) { if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_ASYNC)) - mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line)); + mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(*location.begin.filename).c_str(), location.begin.line)); mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_SET_ASYNC; } // remember if this is assigned blocking (=) if (type == AST_ASSIGN_EQ) { if (!(proc_flags[mem] & AstNode::MEM2REG_FL_EQ1)) - mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line)); + mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(*location.begin.filename).c_str(), location.begin.line)); proc_flags[mem] |= AstNode::MEM2REG_FL_EQ1; } @@ -4755,11 +4766,11 @@ void AstNode::mem2reg_as_needed_pass1(dict> &mem2reg // remember where this is if (flags & MEM2REG_FL_INIT) { if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_INIT)) - mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line)); + mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(*location.begin.filename).c_str(), location.begin.line)); mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_SET_INIT; } else { if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_ELSE)) - mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line)); + mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(*location.begin.filename).c_str(), location.begin.line)); mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_SET_ELSE; } } @@ -4776,7 +4787,7 @@ void AstNode::mem2reg_as_needed_pass1(dict> &mem2reg // flag if used after blocking assignment (in same proc) if ((proc_flags[mem] & AstNode::MEM2REG_FL_EQ1) && !(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_EQ2)) { - mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line)); + mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(*location.begin.filename).c_str(), location.begin.line)); mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_EQ2; } } @@ -4893,7 +4904,9 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, if (length != 0) { - auto block_owned = std::make_unique(AST_INITIAL, std::make_unique(AST_BLOCK)); + auto block_owned = std::make_unique(location, + AST_INITIAL, std::make_unique(location, + AST_BLOCK)); auto block = block_owned.get(); mod->children.push_back(std::move(block_owned)); block = block->children[0].get(); @@ -4910,7 +4923,9 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, while (epos < wordsz && en[epos] == State::S1) epos++; int clen = epos - pos; - auto range = std::make_unique(AST_RANGE, AstNode::mkconst_int(cursor+i, false)); + auto range = std::make_unique(location, + AST_RANGE, AstNode::mkconst_int(location, + cursor+i, false)); if (pos != 0 || epos != wordsz) { int left; int right; @@ -4922,20 +4937,29 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, right = mrange->range_right + pos; left = mrange->range_right + epos - 1; } - range = std::make_unique(AST_MULTIRANGE, std::move(range), std::make_unique(AST_RANGE, AstNode::mkconst_int(left, true), AstNode::mkconst_int(right, true))); + range = std::make_unique(location, + AST_MULTIRANGE, std::move(range), std::make_unique(location, + AST_RANGE, + AstNode::mkconst_int(location, left, true), + AstNode::mkconst_int(location, right, true))); } - auto target = std::make_unique(AST_IDENTIFIER, std::move(range)); + auto target = std::make_unique(location, AST_IDENTIFIER, std::move(range)); target->str = str; target->id2ast = id2ast; target->was_checked = true; - block->children.push_back(std::make_unique(AST_ASSIGN_EQ, std::move(target), mkconst_bits(data.extract(i*wordsz + pos, clen).to_bits(), false))); + block->children.push_back(std::make_unique(location, + AST_ASSIGN_EQ, + std::move(target), + mkconst_bits(location, + data.extract(i*wordsz + pos, clen).to_bits(), + false))); pos = epos; } } } } - auto newNode = std::make_unique(AST_NONE); + auto newNode = std::make_unique(location, AST_NONE); newNode->cloneInto(*this); did_something = true; } @@ -4943,7 +4967,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, if (type == AST_ASSIGN && block == nullptr && children[0]->mem2reg_check(mem2reg_set)) { if (async_block == nullptr) { - auto async_block_owned = std::make_unique(AST_ALWAYS, std::make_unique(AST_BLOCK)); + auto async_block_owned = std::make_unique(location, AST_ALWAYS, std::make_unique(location, AST_BLOCK)); async_block = async_block_owned.get(); mod->children.push_back(std::move(async_block_owned)); } @@ -4953,7 +4977,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, newNode->children[0]->was_checked = true; async_block->children[0]->children.push_back(std::move(newNode)); - newNode = std::make_unique(AST_NONE); + newNode = std::make_unique(location, AST_NONE); newNode->cloneInto(*this); did_something = true; } @@ -4962,27 +4986,27 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, children[0]->children[0]->children[0]->type != AST_CONSTANT) { std::stringstream sstr; - sstr << "$mem2reg_wr$" << children[0]->str << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++); + sstr << "$mem2reg_wr$" << children[0]->str << "$" << RTLIL::encode_filename(*location.begin.filename) << ":" << location.begin.line << "$" << (autoidx++); std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA"; int mem_width, mem_size, addr_bits; bool mem_signed = children[0]->id2ast->is_signed; children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits); - auto wire_addr = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); + auto wire_addr = std::make_unique(location, AST_WIRE, std::make_unique(location, AST_RANGE, mkconst_int(location, addr_bits-1, true), mkconst_int(location, 0, true))); wire_addr->str = id_addr; wire_addr->is_reg = true; wire_addr->was_checked = true; - wire_addr->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); + wire_addr->set_attribute(ID::nosync, AstNode::mkconst_int(location, 1, false)); while (wire_addr->simplify(true, 1, -1, false)) { } mod->children.push_back(std::move(wire_addr)); - auto wire_data = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); + auto wire_data = std::make_unique(location, AST_WIRE, std::make_unique(location, AST_RANGE, mkconst_int(location, mem_width-1, true), mkconst_int(location, 0, true))); wire_data->str = id_data; wire_data->is_reg = true; wire_data->was_checked = true; wire_data->is_signed = mem_signed; - wire_data->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); + wire_data->set_attribute(ID::nosync, AstNode::mkconst_int(location, 1, false)); while (wire_data->simplify(true, 1, -1, false)) { } mod->children.push_back(std::move(wire_data)); @@ -4992,18 +5016,18 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, assign_idx++; log_assert(assign_idx < block->children.size()); - auto assign_addr = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone()); + auto assign_addr = std::make_unique(location, AST_ASSIGN_EQ, std::make_unique(location, AST_IDENTIFIER), children[0]->children[0]->children[0]->clone()); assign_addr->children[0]->str = id_addr; assign_addr->children[0]->was_checked = true; block->children.insert(block->children.begin()+assign_idx+1, std::move(assign_addr)); - auto case_node = std::make_unique(AST_CASE, std::make_unique(AST_IDENTIFIER)); + auto case_node = std::make_unique(location, AST_CASE, std::make_unique(location, AST_IDENTIFIER)); case_node->children[0]->str = id_addr; for (int i = 0; i < mem_size; i++) { if (children[0]->children[0]->children[0]->type == AST_CONSTANT && int(children[0]->children[0]->children[0]->integer) != i) continue; - auto cond_node = std::make_unique(AST_COND, AstNode::mkconst_int(i, false, addr_bits), std::make_unique(AST_BLOCK)); - auto assign_reg = std::make_unique(type, std::make_unique(AST_IDENTIFIER), std::make_unique(AST_IDENTIFIER)); + auto cond_node = std::make_unique(location, AST_COND, AstNode::mkconst_int(location, i, false, addr_bits), std::make_unique(location, AST_BLOCK)); + auto assign_reg = std::make_unique(location, type, std::make_unique(location, AST_IDENTIFIER), std::make_unique(location, AST_IDENTIFIER)); if (children[0]->children.size() == 2) assign_reg->children[0]->children.push_back(children[0]->children[1]->clone()); assign_reg->children[0]->str = stringf("%s[%d]", children[0]->str.c_str(), i); @@ -5074,51 +5098,51 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, std::vector x_bits; for (int i = 0; i < width; i++) x_bits.push_back(RTLIL::State::Sx); - std::unique_ptr constant = AstNode::mkconst_bits(x_bits, false); + std::unique_ptr constant = AstNode::mkconst_bits(location, x_bits, false); constant->cloneInto(*this); } } else { std::stringstream sstr; - sstr << "$mem2reg_rd$" << str << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++); + sstr << "$mem2reg_rd$" << str << "$" << RTLIL::encode_filename(*location.begin.filename) << ":" << location.begin.line << "$" << (autoidx++); std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA"; int mem_width, mem_size, addr_bits; bool mem_signed = id2ast->is_signed; id2ast->meminfo(mem_width, mem_size, addr_bits); - auto wire_addr = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); + auto wire_addr = std::make_unique(location, AST_WIRE, std::make_unique(location, AST_RANGE, mkconst_int(location, addr_bits-1, true), mkconst_int(location, 0, true))); wire_addr->str = id_addr; wire_addr->is_reg = true; wire_addr->was_checked = true; if (block) - wire_addr->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); + wire_addr->set_attribute(ID::nosync, AstNode::mkconst_int(location, 1, false)); while (wire_addr->simplify(true, 1, -1, false)) { } mod->children.push_back(std::move(wire_addr)); - auto wire_data = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); + auto wire_data = std::make_unique(location, AST_WIRE, std::make_unique(location, AST_RANGE, mkconst_int(location, mem_width-1, true), mkconst_int(location, 0, true))); wire_data->str = id_data; wire_data->is_reg = true; wire_data->was_checked = true; wire_data->is_signed = mem_signed; if (block) - wire_data->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); + wire_data->set_attribute(ID::nosync, AstNode::mkconst_int(location, 1, false)); while (wire_data->simplify(true, 1, -1, false)) { } mod->children.push_back(std::move(wire_data)); - auto assign_addr = std::make_unique(block ? AST_ASSIGN_EQ : AST_ASSIGN, std::make_unique(AST_IDENTIFIER), children[0]->children[0]->clone()); + auto assign_addr = std::make_unique(location, block ? AST_ASSIGN_EQ : AST_ASSIGN, std::make_unique(location, AST_IDENTIFIER), children[0]->children[0]->clone()); assign_addr->children[0]->str = id_addr; assign_addr->children[0]->was_checked = true; - auto case_node = std::make_unique(AST_CASE, std::make_unique(AST_IDENTIFIER)); + auto case_node = std::make_unique(location, AST_CASE, std::make_unique(location, AST_IDENTIFIER)); case_node->children[0]->str = id_addr; for (int i = 0; i < mem_size; i++) { if (children[0]->children[0]->type == AST_CONSTANT && int(children[0]->children[0]->integer) != i) continue; - auto cond_node = std::make_unique(AST_COND, AstNode::mkconst_int(i, false, addr_bits), std::make_unique(AST_BLOCK)); - auto assign_reg = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), std::make_unique(AST_IDENTIFIER)); + auto cond_node = std::make_unique(location, AST_COND, AstNode::mkconst_int(location, i, false, addr_bits), std::make_unique(location, AST_BLOCK)); + auto assign_reg = std::make_unique(location, AST_ASSIGN_EQ, std::make_unique(location, AST_IDENTIFIER), std::make_unique(location, AST_IDENTIFIER)); assign_reg->children[0]->str = id_data; assign_reg->children[0]->was_checked = true; assign_reg->children[1]->str = stringf("%s[%d]", str.c_str(), i); @@ -5130,8 +5154,8 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, for (int i = 0; i < mem_width; i++) x_bits.push_back(RTLIL::State::Sx); - auto cond_node = std::make_unique(AST_COND, std::make_unique(AST_DEFAULT), std::make_unique(AST_BLOCK)); - auto assign_reg = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), AstNode::mkconst_bits(x_bits, false)); + auto cond_node = std::make_unique(location, AST_COND, std::make_unique(location, AST_DEFAULT), std::make_unique(location, AST_BLOCK)); + auto assign_reg = std::make_unique(location, AST_ASSIGN_EQ, std::make_unique(location, AST_IDENTIFIER), AstNode::mkconst_bits(location, x_bits, false)); assign_reg->children[0]->str = id_data; assign_reg->children[0]->was_checked = true; cond_node->children[1]->children.push_back(std::move(assign_reg)); @@ -5151,7 +5175,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, } else { - auto proc = std::make_unique(AST_ALWAYS, std::make_unique(AST_BLOCK, std::move(case_node))); + auto proc = std::make_unique(location, AST_ALWAYS, std::make_unique(location, AST_BLOCK, std::move(case_node))); mod->children.push_back(std::move(proc)); mod->children.push_back(std::move(assign_addr)); mod->fixup_hierarchy_flags(); @@ -5306,7 +5330,7 @@ bool AstNode::replace_variables(std::map &varia offset = -offset; std::vector &var_bits = variables.at(str).val.bits(); std::vector new_bits(var_bits.begin() + offset, var_bits.begin() + offset + width); - auto newNode = mkconst_bits(new_bits, variables.at(str).is_signed); + auto newNode = mkconst_bits(location, new_bits, variables.at(str).is_signed); newNode->cloneInto(*this); return true; } @@ -5322,7 +5346,7 @@ std::unique_ptr AstNode::eval_const_function(AstNode *fcall, bool must_ { std::map backup_scope = current_scope; std::map variables; - auto block = std::make_unique(AST_BLOCK); + auto block = std::make_unique(location, AST_BLOCK); std::unique_ptr result = nullptr; size_t argidx = 0; @@ -5547,7 +5571,7 @@ std::unique_ptr AstNode::eval_const_function(AstNode *fcall, bool must_ if (!cond->replace_variables(variables, fcall, must_succeed)) goto finished; - cond = std::make_unique(AST_EQ, expr->clone(), std::move(cond)); + cond = std::make_unique(location, AST_EQ, expr->clone(), std::move(cond)); cond->set_in_param_flag(true); while (cond->simplify(true, 1, -1, false)) { } @@ -5599,7 +5623,7 @@ std::unique_ptr AstNode::eval_const_function(AstNode *fcall, bool must_ log_abort(); } - result = AstNode::mkconst_bits(variables.at(str).val.to_bits(), variables.at(str).is_signed); + result = AstNode::mkconst_bits(location, variables.at(str).val.to_bits(), variables.at(str).is_signed); finished: current_scope = backup_scope; @@ -5615,12 +5639,12 @@ void AstNode::allocateDefaultEnumValues() int last_enum_int = -1; for (auto& node : children) { log_assert(node->type==AST_ENUM_ITEM); - node->set_attribute(ID::enum_base_type, mkconst_str(str)); + node->set_attribute(ID::enum_base_type, mkconst_str(node->location, str)); for (size_t i = 0; i < node->children.size(); i++) { switch (node->children[i]->type) { case AST_NONE: // replace with auto-incremented constant - node->children[i] = AstNode::mkconst_int(++last_enum_int, true); + node->children[i] = AstNode::mkconst_int(node->location, ++last_enum_int, true); break; case AST_CONSTANT: // explicit constant (or folded expression) diff --git a/frontends/verilog/.gitignore b/frontends/verilog/.gitignore index a6d4c8b86..cb6775cbc 100644 --- a/frontends/verilog/.gitignore +++ b/frontends/verilog/.gitignore @@ -2,6 +2,4 @@ verilog_lexer.cc verilog_parser.output verilog_parser.tab.cc verilog_parser.tab.hh -position.hh -location.hh stack.hh diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc index 338b13e4b..a563c899c 100644 --- a/frontends/verilog/Makefile.inc +++ b/frontends/verilog/Makefile.inc @@ -3,11 +3,9 @@ GENFILES += frontends/verilog/verilog_parser.tab.cc GENFILES += frontends/verilog/verilog_parser.tab.hh GENFILES += frontends/verilog/verilog_parser.output GENFILES += frontends/verilog/verilog_lexer.cc -GENFILES += frontends/verilog/location.hh -GENFILES += frontends/verilog/position.hh GENFILES += frontends/verilog/stack.hh -frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y +frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y frontends/verilog/verilog_location.h $(Q) mkdir -p $(dir $@) $(P) $(BISON) -Wall -Werror -o $@ -d -r all -b frontends/verilog/verilog_parser $< diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc index cd8f05b9b..5d906cb0f 100644 --- a/frontends/verilog/const2ast.cc +++ b/frontends/verilog/const2ast.cc @@ -47,7 +47,7 @@ using namespace VERILOG_FRONTEND; std::string ConstParser::fmt_maybe_loc(std::string msg) { std::string s; - s += stringf("%s:%d:", loc.filename, loc.first_line); + s += stringf("%s:%d:", loc.begin.filename->c_str(), loc.begin.line); s += msg; return s; diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index d05f87aff..733ec8ba7 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -33,6 +33,7 @@ #include "verilog_frontend.h" #include "verilog_lexer.h" #include "verilog_error.h" +#include "verilog_location.h" #include "preproc.h" #include "kernel/yosys.h" #include "libs/sha1/sha1.h" @@ -277,8 +278,8 @@ struct VerilogFrontend : public Frontend { std::list include_dirs; std::list attributes; - ParseMode parse_mode; - ParseState parse_state; + ParseMode parse_mode = {}; + ParseState parse_state = {}; parse_mode.sv = false; parse_mode.formal = false; parse_mode.noassert = false; @@ -479,11 +480,6 @@ struct VerilogFrontend : public Frontend { break; } - VerilogLexer lexer(&parse_state, &parse_mode, &filename); - frontend_verilog_yy::parser parser(&lexer, &parse_state, &parse_mode); - lexer.set_debug(flag_debug_lexer); - parser.set_debug_level(flag_debug_parser ? 1 : 0); - if (parse_mode.formal || !flag_nosynthesis) defines_map.add(parse_mode.formal ? "FORMAL" : "SYNTHESIS", "1"); @@ -495,13 +491,9 @@ struct VerilogFrontend : public Frontend { parse_mode.formal ? "formal " : "", parse_mode.sv ? "SystemVerilog" : "Verilog", filename.c_str()); AST::sv_mode_but_global_and_used_for_literally_one_condition = parse_mode.sv; - - AstSrcLocType top_loc = AstSrcLocType ( "read_verilog", 0, 0, 0, 0); - parse_state.current_ast = new AST::AstNode(top_loc, AST::AST_DESIGN); - - parse_state.lexin = f; std::string code_after_preproc; + parse_state.lexin = f; if (!flag_nopp) { code_after_preproc = frontend_verilog_preproc(*f, filename, defines_map, *design->verilog_defines, include_dirs, parse_state, parse_mode); if (flag_ppdump) @@ -509,6 +501,15 @@ struct VerilogFrontend : public Frontend { parse_state.lexin = new std::istringstream(code_after_preproc); } + auto filename_shared = std::make_shared(filename); + auto top_loc = location(); + top_loc.begin.filename = filename_shared; + parse_state.current_ast = new AST::AstNode(top_loc, AST::AST_DESIGN); + VerilogLexer lexer(&parse_state, &parse_mode, filename_shared); + frontend_verilog_yy::parser parser(&lexer, &parse_state, &parse_mode); + lexer.set_debug(flag_debug_lexer); + parser.set_debug_level(flag_debug_parser ? 1 : 0); + // make package typedefs available to parser add_package_types(parse_state.pkg_user_types, design->verilog_packages); diff --git a/frontends/verilog/verilog_lexer.h b/frontends/verilog/verilog_lexer.h index a4f3d9bfb..b7885181c 100644 --- a/frontends/verilog/verilog_lexer.h +++ b/frontends/verilog/verilog_lexer.h @@ -5,6 +5,7 @@ #include "frontends/ast/ast.h" #include "frontends/verilog/verilog_parser.tab.hh" #include +#include YOSYS_NAMESPACE_BEGIN @@ -15,7 +16,7 @@ namespace VERILOG_FRONTEND { ParseMode* mode; public: parser::location_type out_loc; // TODO private? - VerilogLexer(ParseState* e, ParseMode* m, std::string* filename) : frontend_verilog_yyFlexLexer(e->lexin), extra(e), mode(m) { + VerilogLexer(ParseState* e, ParseMode* m, std::shared_ptr filename) : frontend_verilog_yyFlexLexer(e->lexin), extra(e), mode(m) { out_loc.begin.filename = filename; } ~VerilogLexer() override {} @@ -27,7 +28,8 @@ namespace VERILOG_FRONTEND { return parser::make_FRONTEND_VERILOG_YYEOF(out_loc); } private: - std::vector fn_stack; + std::shared_ptr current_filename; + std::vector> fn_stack; std::vector ln_stack; int LexerInput(char* buf, int max_size) override { return readsome(*extra->lexin, buf, max_size); diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index f9e9dc2df..8e6e022b1 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -50,8 +50,10 @@ #include "frontends/verilog/verilog_lexer.h" #include "frontends/ast/ast.h" +#include "frontends/verilog/verilog_location.h" #include "kernel/log.h" #include +#include USING_YOSYS_NAMESPACE using namespace AST; @@ -73,7 +75,7 @@ YOSYS_NAMESPACE_END if (mode->sv) return _tok; \ log("Lexer warning: The SystemVerilog keyword `%s' (at %s:%d) is not "\ "recognized unless read_verilog is called with -sv!\n", YYText(), \ - AST::current_filename.c_str(), yylineno); \ + current_filename->c_str(), yylineno); \ string_t val = std::make_unique(std::string("\\") + YYText()); \ return parser::make_TOK_ID(std::move(val), out_loc); @@ -85,16 +87,17 @@ YOSYS_NAMESPACE_END // result = readsome(*extra->lexin, buf, max_size) #define YY_USER_ACTION \ - out_loc.begin = out_loc.end; \ - for(int i = 0; YYText()[i] != '\0'; ++i){ \ - if(YYText()[i] == '\n') { \ - out_loc.end.line++; \ - out_loc.end.column = 1; \ - } \ - else { \ - out_loc.end.column++; \ - } \ - } + out_loc.step(); \ + for(int i = 0; YYText()[i] != '\0'; ++i){ \ + if(YYText()[i] == '\n') { \ + out_loc.lines(); \ + } \ + else { \ + out_loc.columns(); \ + } \ + } \ + out_loc.begin.filename = current_filename; \ + out_loc.end.filename = current_filename; #define YY_BREAK \ break; @@ -175,11 +178,12 @@ TIME_SCALE_SUFFIX [munpf]?s "`file_push "[^\n]* { fn_stack.push_back(current_filename); ln_stack.push_back(yylineno); - current_filename = YYText()+11; - if (!current_filename.empty() && current_filename.front() == '"') - current_filename = current_filename.substr(1); - if (!current_filename.empty() && current_filename.back() == '"') - current_filename = current_filename.substr(0, current_filename.size()-1); + std::string filename = YYText()+11; + if (!filename.empty() && filename.front() == '"') + filename = filename.substr(1); + if (!filename.empty() && filename.back() == '"') + filename = filename.substr(0, filename.size()-1); + current_filename = std::make_shared(filename); yylineno = (0); out_loc.begin.line = out_loc.end.line = 0; } @@ -201,7 +205,7 @@ TIME_SCALE_SUFFIX [munpf]?s while (*p == ' ' || *p == '\t') p++; const char *q = *p ? p + 1 : p; while (*q && *q != '"') q++; - current_filename = std::string(p).substr(1, q-p-1); + current_filename = std::make_shared(std::string(p).substr(1, q-p-1)); } "`file_notfound "[^\n]* { diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 527d01247..7ccf404f7 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -38,14 +38,17 @@ %define api.value.type variant %define api.prefix {frontend_verilog_yy} %define api.token.constructor +%define api.location.type {location} %param { YOSYS_NAMESPACE_PREFIX VERILOG_FRONTEND::VerilogLexer* lexer } %parse-param { YOSYS_NAMESPACE_PREFIX VERILOG_FRONTEND::ParseState* extra } %parse-param { YOSYS_NAMESPACE_PREFIX VERILOG_FRONTEND::ParseMode* mode } + %code requires { #include "kernel/yosys_common.h" #include "frontends/verilog/verilog_error.h" + #include "frontends/verilog/verilog_location.h" // start requires YOSYS_NAMESPACE_BEGIN namespace VERILOG_FRONTEND { @@ -101,10 +104,10 @@ const AstNode *addIncOrDecStmt(dict> *stmt_attr, std::unique_ptr lhs, dict> *op_attr, AST::AstNodeType op, - parser::location_type begin, parser::location_type end); - std::unique_ptr addIncOrDecExpr(std::unique_ptr lhs, dict> *attr, AST::AstNodeType op, parser::location_type begin, parser::location_type end, bool undo, bool sv_mode); + parser::location_type loc); + std::unique_ptr addIncOrDecExpr(std::unique_ptr lhs, dict> *attr, AST::AstNodeType op, parser::location_type loc, bool undo, bool sv_mode); // add a binary operator assignment statement, e.g., a += b - std::unique_ptr addAsgnBinopStmt(dict> *attr, std::unique_ptr eq_lhs, AST::AstNodeType op, std::unique_ptr rhs, parser::location_type begin, parser::location_type end); + std::unique_ptr addAsgnBinopStmt(dict> *attr, std::unique_ptr eq_lhs, AST::AstNodeType op, std::unique_ptr rhs); }; struct ParseMode { bool noassert = false; @@ -140,13 +143,7 @@ return lexer->nextToken(); } - #define SET_LOC(WHICH, BEGIN, END) \ - do { WHICH.first_line = (BEGIN).begin.line; \ - WHICH.first_column = (BEGIN).begin.column; \ - WHICH.last_line = (END).end.line; \ - WHICH.last_column = (END).end.column; } while(0) - - #define SET_AST_NODE_LOC(WHICH, BEGIN, END) SET_LOC((WHICH)->location, BEGIN, END) + #define SET_AST_NODE_LOC(WHICH, BEGIN, END) (WHICH)->location = location_range(BEGIN, END) #define SET_RULE_LOC(LHS, BEGIN, END) \ do { (LHS).begin = BEGIN.begin; \ @@ -154,10 +151,13 @@ YOSYS_NAMESPACE_BEGIN namespace VERILOG_FRONTEND { + + static location location_range(location begin, location end) { + return location(begin.begin, end.end); + } + static ConstParser make_ConstParser_here(parser::location_type flex_loc) { - AstSrcLocType loc; - SET_LOC(loc, flex_loc, flex_loc); - ConstParser p{loc}; + ConstParser p{flex_loc}; return p; } static void append_attr(AstNode *ast, dict> *al) @@ -180,18 +180,18 @@ delete al; } - static std::unique_ptr makeRange(int msb = 31, int lsb = 0, bool isSigned = true) + static std::unique_ptr makeRange(parser::location_type loc, int msb = 31, int lsb = 0, bool isSigned = true) { - auto range = std::make_unique(AST_RANGE); - range->children.push_back(AstNode::mkconst_int(msb, true)); - range->children.push_back(AstNode::mkconst_int(lsb, true)); + auto range = std::make_unique(loc, AST_RANGE); + range->children.push_back(AstNode::mkconst_int(loc, msb, true)); + range->children.push_back(AstNode::mkconst_int(loc, lsb, true)); range->is_signed = isSigned; return range; } static void addRange(AstNode *parent, int msb = 31, int lsb = 0, bool isSigned = true) { - auto range = makeRange(msb, lsb, isSigned); + auto range = makeRange(parent->location, msb, lsb, isSigned); parent->children.push_back(std::move(range)); } @@ -203,7 +203,7 @@ err_at_ast(type_node->location, "integer/genvar types cannot have packed dimensions."); } else { - range_node = makeRange(type_node->range_left, type_node->range_right, false); + range_node = makeRange(type_node->location, type_node->range_left, type_node->range_right, false); } } @@ -227,8 +227,8 @@ { if (rangeNode->type == AST_RANGE && rangeNode->children.size() == 1) { // SV array size [n], rewrite as [0:n-1] - rangeNode->children.push_back(std::make_unique(AST_SUB, std::move(rangeNode->children[0]), AstNode::mkconst_int(1, true))); - rangeNode->children[0] = AstNode::mkconst_int(0, false); + rangeNode->children.push_back(std::make_unique(rangeNode->location, AST_SUB, std::move(rangeNode->children[0]), AstNode::mkconst_int(rangeNode->location, 1, true))); + rangeNode->children[0] = AstNode::mkconst_int(rangeNode->location, 0, false); } } @@ -268,14 +268,14 @@ { log_assert(node); node->is_custom_type = true; - node->children.push_back(std::make_unique(AST_WIRETYPE)); + node->children.push_back(std::make_unique(node->location, AST_WIRETYPE)); node->children.back()->str = *name; } void ParseState::addTypedefNode(std::string *name, std::unique_ptr node) { log_assert((bool)node); - AstNode* tnode = saveChild(std::make_unique(AST_TYPEDEF, std::move(node))); + AstNode* tnode = saveChild(std::make_unique(node->location, AST_TYPEDEF, std::move(node))); log_assert((bool)name); tnode->str = *name; auto &user_types = user_type_stack.back(); @@ -342,9 +342,9 @@ // create a new localparam with old name so that the items in the loop // can simply use the old name and shadow it as necessary - auto indirect = std::make_unique(AST_LOCALPARAM); + auto indirect = std::make_unique(loop->location, AST_LOCALPARAM); indirect->str = old_str; - auto ident = std::make_unique(AST_IDENTIFIER); + auto ident = std::make_unique(loop->location, AST_IDENTIFIER); ident->str = new_str; indirect->children.push_back(std::move(ident)); @@ -376,54 +376,48 @@ const AstNode *ParseState::addIncOrDecStmt(dict> *stmt_attr, std::unique_ptr lhs, dict> *op_attr, AST::AstNodeType op, - frontend_verilog_yy::location begin, frontend_verilog_yy::location end) + location loc) { - auto one = AstNode::mkconst_int(1, true); - auto rhs = std::make_unique(op, lhs->clone(), std::move(one)); + auto one = AstNode::mkconst_int(loc, 1, true); + auto rhs = std::make_unique(loc, op, lhs->clone(), std::move(one)); if (op_attr != nullptr) append_attr(rhs.get(), op_attr); - auto stmt_owned = std::make_unique(AST_ASSIGN_EQ, std::move(lhs), std::move(rhs)); + auto stmt_owned = std::make_unique(loc, AST_ASSIGN_EQ, std::move(lhs), std::move(rhs)); auto* stmt = stmt_owned.get(); ast_stack.back()->children.push_back(std::move(stmt_owned)); - SET_AST_NODE_LOC(stmt, begin, end); if (stmt_attr != nullptr) append_attr(stmt, stmt_attr); return stmt; } // create a pre/post-increment/decrement expression, and add the corresponding statement - std::unique_ptr ParseState::addIncOrDecExpr(std::unique_ptr lhs, dict> *attr, AST::AstNodeType op, frontend_verilog_yy::location begin, frontend_verilog_yy::location end, bool undo, bool sv_mode) + std::unique_ptr ParseState::addIncOrDecExpr(std::unique_ptr lhs, dict> *attr, AST::AstNodeType op, location loc, bool undo, bool sv_mode) { - ensureAsgnExprAllowed(begin, sv_mode); - const AstNode *stmt = addIncOrDecStmt(nullptr, std::move(lhs), attr, op, begin, end); + ensureAsgnExprAllowed(loc, sv_mode); + const AstNode *stmt = addIncOrDecStmt(nullptr, std::move(lhs), attr, op, loc); log_assert(stmt->type == AST_ASSIGN_EQ); auto expr = stmt->children[0]->clone(); if (undo) { - auto one = AstNode::mkconst_int(1, false, 1); - auto minus_one = std::make_unique(AST_NEG, std::move(one)); - expr = std::make_unique(op, std::move(expr), std::move(minus_one)); + auto one = AstNode::mkconst_int(loc, 1, false, 1); + auto minus_one = std::make_unique(loc, AST_NEG, std::move(one)); + expr = std::make_unique(loc, op, std::move(expr), std::move(minus_one)); } - SET_AST_NODE_LOC(expr.get(), begin, end); return expr; } // add a binary operator assignment statement, e.g., a += b - std::unique_ptr ParseState::addAsgnBinopStmt(dict> *attr, std::unique_ptr eq_lhs, AST::AstNodeType op, std::unique_ptr rhs, frontend_verilog_yy::location begin, frontend_verilog_yy::location end) + std::unique_ptr ParseState::addAsgnBinopStmt(dict> *attr, std::unique_ptr eq_lhs, AST::AstNodeType op, std::unique_ptr rhs) { - SET_AST_NODE_LOC(rhs.get(), end, end); + location loc = location_range(eq_lhs->location, rhs->location); if (op == AST_SHIFT_LEFT || op == AST_SHIFT_RIGHT || op == AST_SHIFT_SLEFT || op == AST_SHIFT_SRIGHT) { - rhs = std::make_unique(AST_TO_UNSIGNED, std::move(rhs)); - SET_AST_NODE_LOC(rhs.get(), end, end); + rhs = std::make_unique(rhs->location, AST_TO_UNSIGNED, std::move(rhs)); } auto binop_lhs = eq_lhs->clone(); - auto eq_rhs_owned = std::make_unique(op, std::move(binop_lhs), std::move(rhs)); - auto* eq_rhs = eq_rhs_owned.get(); + auto eq_rhs_owned = std::make_unique(loc, op, std::move(binop_lhs), std::move(rhs)); auto ret_lhs = eq_lhs->clone(); - auto stmt_owned = std::make_unique(AST_ASSIGN_EQ, std::move(eq_lhs), std::move(eq_rhs_owned)); + auto stmt_owned = std::make_unique(loc, AST_ASSIGN_EQ, std::move(eq_lhs), std::move(eq_rhs_owned)); auto* stmt = stmt_owned.get(); - SET_AST_NODE_LOC(eq_rhs, begin, end); - SET_AST_NODE_LOC(stmt, begin, end); ast_stack.back()->children.push_back(std::move(stmt_owned)); if (attr != nullptr) append_attr(stmt, attr); @@ -675,7 +669,7 @@ attr_list: attr_assign: hierarchical_id { - (*extra->attr_list)[*$1] = AstNode::mkconst_int(1, false); + (*extra->attr_list)[*$1] = AstNode::mkconst_int(@1, 1, false); } | hierarchical_id TOK_EQ expr { (*extra->attr_list)[*$1] = std::move($3); @@ -711,7 +705,7 @@ module: extra->enterTypeScope(); } TOK_ID { extra->do_not_require_port_stubs = false; - AstNode* mod = extra->pushChild(std::make_unique(AST_MODULE)); + AstNode* mod = extra->pushChild(std::make_unique(@$, AST_MODULE)); extra->current_ast_mod = mod; extra->port_stubs.clear(); extra->port_counter = 0; @@ -738,13 +732,13 @@ module_para_list: single_module_para: %empty | attr TOK_PARAMETER { - extra->astbuf1 = std::make_unique(AST_PARAMETER); - extra->astbuf1->children.push_back(AstNode::mkconst_int(0, true)); + extra->astbuf1 = std::make_unique(@$, AST_PARAMETER); + extra->astbuf1->children.push_back(AstNode::mkconst_int(@2, 0, true)); append_attr(extra->astbuf1.get(), $1); } param_type single_param_decl | attr TOK_LOCALPARAM { - extra->astbuf1 = std::make_unique(AST_LOCALPARAM); - extra->astbuf1->children.push_back(AstNode::mkconst_int(0, true)); + extra->astbuf1 = std::make_unique(@$, AST_LOCALPARAM); + extra->astbuf1->children.push_back(AstNode::mkconst_int(@2, 0, true)); append_attr(extra->astbuf1.get(), $1); } param_type single_param_decl | single_param_decl; @@ -765,12 +759,12 @@ module_arg_opt_assignment: auto& n = extra->ast_stack.back()->children.back(); n->attributes[ID::defaultvalue] = std::move($2); } else { - auto wire = std::make_unique(AST_IDENTIFIER); + auto wire = std::make_unique(@$, AST_IDENTIFIER); wire->str = extra->ast_stack.back()->children.back()->str; if (extra->ast_stack.back()->children.back()->is_reg || extra->ast_stack.back()->children.back()->is_logic) - extra->ast_stack.back()->children.push_back(std::make_unique(AST_INITIAL, std::make_unique(AST_BLOCK, std::make_unique(AST_ASSIGN_LE, std::move(wire), std::move($2))))); + extra->ast_stack.back()->children.push_back(std::make_unique(@$, AST_INITIAL, std::make_unique(@$, AST_BLOCK, std::make_unique(@$, AST_ASSIGN_LE, std::move(wire), std::move($2))))); else - extra->ast_stack.back()->children.push_back(std::make_unique(AST_ASSIGN, std::move(wire), std::move($2))); + extra->ast_stack.back()->children.push_back(std::make_unique(@$, AST_ASSIGN, std::move(wire), std::move($2))); } } else err_at_loc(@2, "SystemVerilog interface in module port list cannot have a default value."); @@ -792,8 +786,8 @@ module_arg: } } module_arg_opt_assignment | TOK_ID { - extra->astbuf1 = std::make_unique(AST_INTERFACEPORT); - extra->astbuf1->children.push_back(std::make_unique(AST_INTERFACEPORTTYPE)); + extra->astbuf1 = std::make_unique(@$, AST_INTERFACEPORT); + extra->astbuf1->children.push_back(std::make_unique(@$, AST_INTERFACEPORTTYPE)); extra->astbuf1->children[0]->str = *$1; } TOK_ID { /* SV interfaces */ if (!mode->sv) @@ -826,7 +820,7 @@ package: attr TOK_PACKAGE { extra->enterTypeScope(); } TOK_ID { - AstNode* mod = extra->pushChild(std::make_unique(AST_PACKAGE)); + AstNode* mod = extra->pushChild(std::make_unique(@$, AST_PACKAGE)); extra->current_ast_mod = mod; mod->str = *$4; append_attr(mod, $1); @@ -848,7 +842,7 @@ interface: extra->enterTypeScope(); } TOK_ID { extra->do_not_require_port_stubs = false; - AstNode* intf = extra->pushChild(std::make_unique(AST_INTERFACE)); + AstNode* intf = extra->pushChild(std::make_unique(@$, AST_INTERFACE)); extra->current_ast_mod = intf; extra->port_stubs.clear(); extra->port_counter = 0; @@ -872,7 +866,7 @@ interface_body_stmt: bind_directive: TOK_BIND { - (void)extra->pushChild(std::make_unique(AST_BIND)); + (void)extra->pushChild(std::make_unique(@$, AST_BIND)); } bind_target { // bind_target should have added at least one child @@ -881,8 +875,8 @@ bind_directive: TOK_ID { // The single_cell parser in cell_list_no_array uses extra->astbuf1 as // a sort of template for constructing cells. - extra->astbuf1 = std::make_unique(AST_CELL); - extra->astbuf1->children.push_back(std::make_unique(AST_CELLTYPE)); + extra->astbuf1 = std::make_unique(@$, AST_CELL); + extra->astbuf1->children.push_back(std::make_unique(@$, AST_CELLTYPE)); extra->astbuf1->children[0]->str = *$5; } cell_parameter_list_opt cell_list_no_array TOK_SEMICOL { @@ -921,7 +915,7 @@ bind_target_instance_list: // the bind node where we should add it. bind_target_instance: hierarchical_id { - auto node = std::make_unique(AST_IDENTIFIER); + auto node = std::make_unique(@$, AST_IDENTIFIER); node->str = *$1; extra->ast_stack.back()->children.push_back(std::move(node)); }; @@ -945,12 +939,12 @@ delay: non_opt_delay | %empty; io_wire_type: - { extra->astbuf3 = std::make_unique(AST_WIRE); extra->current_wire_rand = false; extra->current_wire_const = false; } + { extra->astbuf3 = std::make_unique(@$, AST_WIRE); extra->current_wire_rand = false; extra->current_wire_const = false; } wire_type_token_io wire_type_const_rand opt_wire_type_token wire_type_signedness { $$ = std::move(extra->astbuf3); SET_RULE_LOC(@$, @2, @$); }; non_io_wire_type: - { extra->astbuf3 = std::make_unique(AST_WIRE); extra->current_wire_rand = false; extra->current_wire_const = false; } + { extra->astbuf3 = std::make_unique(@$, AST_WIRE); extra->current_wire_rand = false; extra->current_wire_const = false; } wire_type_const_rand wire_type_token wire_type_signedness { $$ = std::move(extra->astbuf3); SET_RULE_LOC(@$, @2, @$); }; @@ -1056,30 +1050,30 @@ integer_vector_type: non_opt_range: TOK_LBRA expr TOK_COL expr TOK_RBRA { - $$ = std::make_unique(AST_RANGE); + $$ = std::make_unique(@$, AST_RANGE); $$->children.push_back(std::move($2)); $$->children.push_back(std::move($4)); } | TOK_LBRA expr TOK_POS_INDEXED expr TOK_RBRA { - $$ = std::make_unique(AST_RANGE); - auto expr = std::make_unique(AST_SELFSZ, std::move($2)); - $$->children.push_back(std::make_unique(AST_SUB, std::make_unique(AST_ADD, expr->clone(), std::move($4)), AstNode::mkconst_int(1, true))); - $$->children.push_back(std::make_unique(AST_ADD, std::move(expr), AstNode::mkconst_int(0, true))); + $$ = std::make_unique(@$, AST_RANGE); + auto expr = std::make_unique(@$, AST_SELFSZ, std::move($2)); + $$->children.push_back(std::make_unique(@$, AST_SUB, std::make_unique(@$, AST_ADD, expr->clone(), std::move($4)), AstNode::mkconst_int(@$, 1, true))); + $$->children.push_back(std::make_unique(@$, AST_ADD, std::move(expr), AstNode::mkconst_int(@$, 0, true))); } | TOK_LBRA expr TOK_NEG_INDEXED expr TOK_RBRA { - $$ = std::make_unique(AST_RANGE); - auto expr = std::make_unique(AST_SELFSZ, std::move($2)); - $$->children.push_back(std::make_unique(AST_ADD, expr->clone(), AstNode::mkconst_int(0, true))); - $$->children.push_back(std::make_unique(AST_SUB, std::make_unique(AST_ADD, std::move(expr), AstNode::mkconst_int(1, true)), std::move($4))); + $$ = std::make_unique(@$, AST_RANGE); + auto expr = std::make_unique(@$, AST_SELFSZ, std::move($2)); + $$->children.push_back(std::make_unique(@$, AST_ADD, expr->clone(), AstNode::mkconst_int(@$, 0, true))); + $$->children.push_back(std::make_unique(@$, AST_SUB, std::make_unique(@$, AST_ADD, std::move(expr), AstNode::mkconst_int(@$, 1, true)), std::move($4))); } | TOK_LBRA expr TOK_RBRA { - $$ = std::make_unique(AST_RANGE); + $$ = std::make_unique(@$, AST_RANGE); $$->children.push_back(std::move($2)); }; non_opt_multirange: non_opt_range non_opt_range { - $$ = std::make_unique(AST_MULTIRANGE, std::move($1), std::move($2)); + $$ = std::make_unique(@$, AST_MULTIRANGE, std::move($1), std::move($2)); } | non_opt_multirange non_opt_range { $$ = std::move($1); @@ -1113,7 +1107,7 @@ module_body_stmt: checker_decl: TOK_CHECKER TOK_ID TOK_SEMICOL { - AstNode* node = extra->pushChild(std::make_unique(AST_GENBLOCK)); + AstNode* node = extra->pushChild(std::make_unique(@$, AST_GENBLOCK)); node->str = *$2; } module_body TOK_ENDCHECKER { extra->ast_stack.pop_back(); @@ -1121,28 +1115,28 @@ checker_decl: task_func_decl: attr TOK_DPI_FUNCTION TOK_ID TOK_ID { - extra->current_function_or_task = extra->saveChild(std::make_unique(AST_DPI_FUNCTION, AstNode::mkconst_str(*$3), AstNode::mkconst_str(*$4))); + extra->current_function_or_task = extra->saveChild(std::make_unique(@$, AST_DPI_FUNCTION, AstNode::mkconst_str(@3, *$3), AstNode::mkconst_str(@4, *$4))); extra->current_function_or_task->str = *$4; append_attr(extra->current_function_or_task, $1); } opt_dpi_function_args TOK_SEMICOL { extra->current_function_or_task = nullptr; } | attr TOK_DPI_FUNCTION TOK_ID TOK_EQ TOK_ID TOK_ID { - extra->current_function_or_task = extra->saveChild(std::make_unique(AST_DPI_FUNCTION, AstNode::mkconst_str(*$5), AstNode::mkconst_str(*$3))); + extra->current_function_or_task = extra->saveChild(std::make_unique(@$, AST_DPI_FUNCTION, AstNode::mkconst_str(@5, *$5), AstNode::mkconst_str(@3, *$3))); extra->current_function_or_task->str = *$6; append_attr(extra->current_function_or_task, $1); } opt_dpi_function_args TOK_SEMICOL { extra->current_function_or_task = nullptr; } | attr TOK_DPI_FUNCTION TOK_ID TOK_COL TOK_ID TOK_EQ TOK_ID TOK_ID { - extra->current_function_or_task = extra->saveChild(std::make_unique(AST_DPI_FUNCTION, AstNode::mkconst_str(*$7), AstNode::mkconst_str(*$3 + ":" + RTLIL::unescape_id(*$5)))); + extra->current_function_or_task = extra->saveChild(std::make_unique(@$, AST_DPI_FUNCTION, AstNode::mkconst_str(@7, *$7), AstNode::mkconst_str(location_range(@3, @5), *$3 + ":" + RTLIL::unescape_id(*$5)))); extra->current_function_or_task->str = *$8; append_attr(extra->current_function_or_task, $1); } opt_dpi_function_args TOK_SEMICOL { extra->current_function_or_task = nullptr; } | attr TOK_TASK opt_automatic TOK_ID { - extra->current_function_or_task = extra->pushChild(std::make_unique(AST_TASK)); + extra->current_function_or_task = extra->pushChild(std::make_unique(@$, AST_TASK)); extra->current_function_or_task->str = *$4; append_attr(extra->current_function_or_task, $1); extra->current_function_or_task_port_id = 1; @@ -1156,7 +1150,7 @@ task_func_decl: // inlined, but ignores signals read only in tasks. This only matters // for event based simulation, and for synthesis we can treat a void // function like a task. - extra->current_function_or_task = extra->pushChild(std::make_unique(AST_TASK)); + extra->current_function_or_task = extra->pushChild(std::make_unique(@$, AST_TASK)); extra->current_function_or_task->str = *$5; append_attr(extra->current_function_or_task, $1); extra->current_function_or_task_port_id = 1; @@ -1165,10 +1159,10 @@ task_func_decl: extra->ast_stack.pop_back(); } | attr TOK_FUNCTION opt_automatic func_return_type TOK_ID { - extra->current_function_or_task = extra->pushChild(std::make_unique(AST_FUNCTION)); + extra->current_function_or_task = extra->pushChild(std::make_unique(@$, AST_FUNCTION)); extra->current_function_or_task->str = *$5; append_attr(extra->current_function_or_task, $1); - auto outreg = std::make_unique(AST_WIRE); + auto outreg = std::make_unique(@$, AST_WIRE); outreg->str = *$5; outreg->is_signed = false; outreg->is_reg = true; @@ -1187,18 +1181,18 @@ task_func_decl: func_return_type: hierarchical_type_id { - $$ = std::make_unique(AST_WIRETYPE); + $$ = std::make_unique(@$, AST_WIRETYPE); $$->str = *$1; } | opt_type_vec opt_signedness_default_unsigned { - $$ = makeRange(0, 0, $2); + $$ = makeRange(@$, 0, 0, $2); } | opt_type_vec opt_signedness_default_unsigned non_opt_range { $$ = std::move($3); $$->is_signed = $2; } | integer_atom_type opt_signedness_default_signed { - $$ = makeRange($1 - 1, 0, $2); + $$ = makeRange(@$, $1 - 1, 0, $2); }; opt_type_vec: @@ -1220,10 +1214,10 @@ opt_signedness_default_unsigned: dpi_function_arg: TOK_ID TOK_ID { - extra->current_function_or_task->children.push_back(AstNode::mkconst_str(*$1)); + extra->current_function_or_task->children.push_back(AstNode::mkconst_str(@1, *$1)); } | TOK_ID { - extra->current_function_or_task->children.push_back(AstNode::mkconst_str(*$1)); + extra->current_function_or_task->children.push_back(AstNode::mkconst_str(@1, *$1)); }; opt_dpi_function_args: @@ -1282,7 +1276,7 @@ task_func_port: if (!mode->sv) err_at_loc(@$, "task/function argument direction missing"); extra->albuf = new dict>; - extra->astbuf1 = std::make_unique(AST_WIRE); + extra->astbuf1 = std::make_unique(@$, AST_WIRE); extra->current_wire_rand = false; extra->current_wire_const = false; extra->astbuf1->is_input = true; @@ -1315,11 +1309,11 @@ specify_item: if (specify_edge != 0 && target->dat == nullptr) err_at_loc(@3, "Found specify edge but no data spec.\n"); - auto cell_owned = std::make_unique(AST_CELL); + auto cell_owned = std::make_unique(@$, AST_CELL); auto cell = cell_owned.get(); extra->ast_stack.back()->children.push_back(std::move(cell_owned)); cell->str = stringf("$specify$%d", autoidx++); - cell->children.push_back(std::make_unique(AST_CELLTYPE)); + cell->children.push_back(std::make_unique(@$, AST_CELLTYPE)); cell->children.back()->str = target->dat ? "$specify3" : "$specify2"; SET_AST_NODE_LOC(cell, en_expr.get() ? @1 : @2, @10); @@ -1331,57 +1325,57 @@ specify_item: oper_type = oper->at(1); } - cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_int(oper_type == '*', false, 1))); + cell->children.push_back(std::make_unique(@5, AST_PARASET, AstNode::mkconst_int(@5, oper_type == '*', false, 1))); cell->children.back()->str = "\\FULL"; - cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_int(oper_polarity != 0, false, 1))); + cell->children.push_back(std::make_unique(@5, AST_PARASET, AstNode::mkconst_int(@5, oper_polarity != 0, false, 1))); cell->children.back()->str = "\\SRC_DST_PEN"; - cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_int(oper_polarity == '+', false, 1))); + cell->children.push_back(std::make_unique(@5, AST_PARASET, AstNode::mkconst_int(@5, oper_polarity == '+', false, 1))); cell->children.back()->str = "\\SRC_DST_POL"; - cell->children.push_back(std::make_unique(AST_PARASET, std::move(timing->rise.t_min))); + cell->children.push_back(std::make_unique(@9, AST_PARASET, std::move(timing->rise.t_min))); cell->children.back()->str = "\\T_RISE_MIN"; - cell->children.push_back(std::make_unique(AST_PARASET, std::move(timing->rise.t_avg))); + cell->children.push_back(std::make_unique(@9, AST_PARASET, std::move(timing->rise.t_avg))); cell->children.back()->str = "\\T_RISE_TYP"; - cell->children.push_back(std::make_unique(AST_PARASET, std::move(timing->rise.t_max))); + cell->children.push_back(std::make_unique(@9, AST_PARASET, std::move(timing->rise.t_max))); cell->children.back()->str = "\\T_RISE_MAX"; - cell->children.push_back(std::make_unique(AST_PARASET, std::move(timing->fall.t_min))); + cell->children.push_back(std::make_unique(@9, AST_PARASET, std::move(timing->fall.t_min))); cell->children.back()->str = "\\T_FALL_MIN"; - cell->children.push_back(std::make_unique(AST_PARASET, std::move(timing->fall.t_avg))); + cell->children.push_back(std::make_unique(@9, AST_PARASET, std::move(timing->fall.t_avg))); cell->children.back()->str = "\\T_FALL_TYP"; - cell->children.push_back(std::make_unique(AST_PARASET, std::move(timing->fall.t_max))); + cell->children.push_back(std::make_unique(@9, AST_PARASET, std::move(timing->fall.t_max))); cell->children.back()->str = "\\T_FALL_MAX"; - cell->children.push_back(std::make_unique(AST_ARGUMENT, en_expr ? std::move(en_expr) : AstNode::mkconst_int(1, false, 1))); + cell->children.push_back(std::make_unique(@1, AST_ARGUMENT, en_expr ? std::move(en_expr) : AstNode::mkconst_int(@1, 1, false, 1))); cell->children.back()->str = "\\EN"; - cell->children.push_back(std::make_unique(AST_ARGUMENT, std::move(src_expr))); + cell->children.push_back(std::make_unique(@4, AST_ARGUMENT, std::move(src_expr))); cell->children.back()->str = "\\SRC"; - cell->children.push_back(std::make_unique(AST_ARGUMENT, std::move(target->dst))); + cell->children.push_back(std::make_unique(@6, AST_ARGUMENT, std::move(target->dst))); cell->children.back()->str = "\\DST"; if (target->dat) { - cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_int(specify_edge != 0, false, 1))); + cell->children.push_back(std::make_unique(@3, AST_PARASET, AstNode::mkconst_int(@3, specify_edge != 0, false, 1))); cell->children.back()->str = "\\EDGE_EN"; - cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_int(specify_edge == 'p', false, 1))); + cell->children.push_back(std::make_unique(@3, AST_PARASET, AstNode::mkconst_int(@3, specify_edge == 'p', false, 1))); cell->children.back()->str = "\\EDGE_POL"; - cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_int(target->polarity_op != 0, false, 1))); + cell->children.push_back(std::make_unique(@6, AST_PARASET, AstNode::mkconst_int(@6, target->polarity_op != 0, false, 1))); cell->children.back()->str = "\\DAT_DST_PEN"; - cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_int(target->polarity_op == '+', false, 1))); + cell->children.push_back(std::make_unique(@6, AST_PARASET, AstNode::mkconst_int(@6, target->polarity_op == '+', false, 1))); cell->children.back()->str = "\\DAT_DST_POL"; - cell->children.push_back(std::make_unique(AST_ARGUMENT, std::move(target->dat))); + cell->children.push_back(std::make_unique(@6, AST_ARGUMENT, std::move(target->dat))); cell->children.back()->str = "\\DAT"; } } | @@ -1390,68 +1384,68 @@ specify_item: *$1 != "$recrem" && *$1 != "$skew" && *$1 != "$timeskew" && *$1 != "$fullskew" && *$1 != "$nochange") err_at_loc(@1, "Unsupported specify rule type: %s\n", $1->c_str()); - auto src_pen = AstNode::mkconst_int($3 != 0, false, 1); - auto src_pol = AstNode::mkconst_int($3 == 'p', false, 1); - auto src_expr = std::move($4), src_en = $5 ? std::move($5) : AstNode::mkconst_int(1, false, 1); + auto src_pen = AstNode::mkconst_int(@3, $3 != 0, false, 1); + auto src_pol = AstNode::mkconst_int(@3, $3 == 'p', false, 1); + auto src_expr = std::move($4), src_en = $5 ? std::move($5) : AstNode::mkconst_int(@5, 1, false, 1); - auto dst_pen = AstNode::mkconst_int($7 != 0, false, 1); - auto dst_pol = AstNode::mkconst_int($7 == 'p', false, 1); - auto dst_expr = std::move($8), dst_en = $9 ? std::move($9) : AstNode::mkconst_int(1, false, 1); + auto dst_pen = AstNode::mkconst_int(@7, $7 != 0, false, 1); + auto dst_pol = AstNode::mkconst_int(@7, $7 == 'p', false, 1); + auto dst_expr = std::move($8), dst_en = $9 ? std::move($9) : AstNode::mkconst_int(@5, 1, false, 1); specify_triple_ptr_t limit = std::move($11); specify_triple_ptr_t limit2 = std::move($12); - auto cell_owned = std::make_unique(AST_CELL); + auto cell_owned = std::make_unique(@$, AST_CELL); auto cell = cell_owned.get(); extra->ast_stack.back()->children.push_back(std::move(cell_owned)); cell->str = stringf("$specify$%d", autoidx++); - cell->children.push_back(std::make_unique(AST_CELLTYPE)); + cell->children.push_back(std::make_unique(@$, AST_CELLTYPE)); cell->children.back()->str = "$specrule"; SET_AST_NODE_LOC(cell, @1, @14); - cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_str(*$1))); + cell->children.push_back(std::make_unique(@1, AST_PARASET, AstNode::mkconst_str(@1, *$1))); cell->children.back()->str = "\\TYPE"; - cell->children.push_back(std::make_unique(AST_PARASET, std::move(limit->t_min))); + cell->children.push_back(std::make_unique(@11, AST_PARASET, std::move(limit->t_min))); cell->children.back()->str = "\\T_LIMIT_MIN"; - cell->children.push_back(std::make_unique(AST_PARASET, std::move(limit->t_avg))); + cell->children.push_back(std::make_unique(@11, AST_PARASET, std::move(limit->t_avg))); cell->children.back()->str = "\\T_LIMIT_TYP"; - cell->children.push_back(std::make_unique(AST_PARASET, std::move(limit->t_max))); + cell->children.push_back(std::make_unique(@11, AST_PARASET, std::move(limit->t_max))); cell->children.back()->str = "\\T_LIMIT_MAX"; - cell->children.push_back(std::make_unique(AST_PARASET, limit2 ? std::move(limit2->t_min) : AstNode::mkconst_int(0, true))); + cell->children.push_back(std::make_unique(@12, AST_PARASET, limit2 ? std::move(limit2->t_min) : AstNode::mkconst_int(@12, 0, true))); cell->children.back()->str = "\\T_LIMIT2_MIN"; - cell->children.push_back(std::make_unique(AST_PARASET, limit2 ? std::move(limit2->t_avg) : AstNode::mkconst_int(0, true))); + cell->children.push_back(std::make_unique(@12, AST_PARASET, limit2 ? std::move(limit2->t_avg) : AstNode::mkconst_int(@12, 0, true))); cell->children.back()->str = "\\T_LIMIT2_TYP"; - cell->children.push_back(std::make_unique(AST_PARASET, limit2 ? std::move(limit2->t_max) : AstNode::mkconst_int(0, true))); + cell->children.push_back(std::make_unique(@12, AST_PARASET, limit2 ? std::move(limit2->t_max) : AstNode::mkconst_int(@12, 0, true))); cell->children.back()->str = "\\T_LIMIT2_MAX"; - cell->children.push_back(std::make_unique(AST_PARASET, std::move(src_pen))); + cell->children.push_back(std::make_unique(@3, AST_PARASET, std::move(src_pen))); cell->children.back()->str = "\\SRC_PEN"; - cell->children.push_back(std::make_unique(AST_PARASET, std::move(src_pol))); + cell->children.push_back(std::make_unique(@3, AST_PARASET, std::move(src_pol))); cell->children.back()->str = "\\SRC_POL"; - cell->children.push_back(std::make_unique(AST_PARASET, std::move(dst_pen))); + cell->children.push_back(std::make_unique(@3, AST_PARASET, std::move(dst_pen))); cell->children.back()->str = "\\DST_PEN"; - cell->children.push_back(std::make_unique(AST_PARASET, std::move(dst_pol))); + cell->children.push_back(std::make_unique(@7, AST_PARASET, std::move(dst_pol))); cell->children.back()->str = "\\DST_POL"; - cell->children.push_back(std::make_unique(AST_ARGUMENT, std::move(src_en))); + cell->children.push_back(std::make_unique(@5, AST_ARGUMENT, std::move(src_en))); cell->children.back()->str = "\\SRC_EN"; - cell->children.push_back(std::make_unique(AST_ARGUMENT, std::move(src_expr))); + cell->children.push_back(std::make_unique(@4, AST_ARGUMENT, std::move(src_expr))); cell->children.back()->str = "\\SRC"; - cell->children.push_back(std::make_unique(AST_ARGUMENT, std::move(dst_en))); + cell->children.push_back(std::make_unique(@9, AST_ARGUMENT, std::move(dst_en))); cell->children.back()->str = "\\DST_EN"; - cell->children.push_back(std::make_unique(AST_ARGUMENT, std::move(dst_expr))); + cell->children.push_back(std::make_unique(@8, AST_ARGUMENT, std::move(dst_expr))); cell->children.back()->str = "\\DST"; }; @@ -1527,19 +1521,19 @@ specify_rise_fall: $$ = std::make_unique(); $$->rise = std::move(*$2); $$->fall = std::move(*$4); - log_file_warning(current_filename, @$.begin.line, "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); + err_at_loc(@$, "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); } | TOK_LPAREN specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_RPAREN { $$ = std::make_unique(); $$->rise = std::move(*$2); $$->fall = std::move(*$4); - log_file_warning(current_filename, @$.begin.line, "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); + err_at_loc(@$, "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); } | TOK_LPAREN specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_RPAREN { $$ = std::make_unique(); $$->rise = std::move(*$2); $$->fall = std::move(*$4); - log_file_warning(current_filename, @$.begin.line, "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); + err_at_loc(@$, "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); } specify_triple: @@ -1697,7 +1691,7 @@ param_integer: param_real: TOK_REAL { - extra->astbuf1->children.push_back(std::make_unique(AST_REALVALUE)); + extra->astbuf1->children.push_back(std::make_unique(@$, AST_REALVALUE)); }; param_range: @@ -1725,8 +1719,8 @@ param_type: param_decl: attr TOK_PARAMETER { - extra->astbuf1 = std::make_unique(AST_PARAMETER); - extra->astbuf1->children.push_back(AstNode::mkconst_int(0, true)); + extra->astbuf1 = std::make_unique(@$, AST_PARAMETER); + extra->astbuf1->children.push_back(AstNode::mkconst_int(@$, 0, true)); append_attr(extra->astbuf1.get(), $1); } param_type param_decl_list TOK_SEMICOL { (void)extra->astbuf1.reset(); @@ -1734,8 +1728,8 @@ param_decl: localparam_decl: attr TOK_LOCALPARAM { - extra->astbuf1 = std::make_unique(AST_LOCALPARAM); - extra->astbuf1->children.push_back(AstNode::mkconst_int(0, true)); + extra->astbuf1 = std::make_unique(@$, AST_LOCALPARAM); + extra->astbuf1->children.push_back(AstNode::mkconst_int(@$, 0, true)); append_attr(extra->astbuf1.get(), $1); } param_type param_decl_list TOK_SEMICOL { (void)extra->astbuf1.reset(); @@ -1767,8 +1761,8 @@ single_param_decl_ident: if (extra->astbuf1 == nullptr) { if (!mode->sv) err_at_loc(@1, "In pure Verilog (not SystemVerilog), parameter/localparam with an initializer must use the parameter/localparam keyword"); - node_owned = std::make_unique(AST_PARAMETER); - node_owned->children.push_back(AstNode::mkconst_int(0, true)); + node_owned = std::make_unique(@$, AST_PARAMETER); + node_owned->children.push_back(AstNode::mkconst_int(@$, 0, true)); } else { node_owned = extra->astbuf1->clone(); } @@ -1786,7 +1780,7 @@ defparam_decl_list: single_defparam_decl: range rvalue TOK_EQ expr { - auto node = std::make_unique(AST_DEFPARAM); + auto node = std::make_unique(@$, AST_DEFPARAM); node->children.push_back(std::move($2)); node->children.push_back(std::move($4)); if ($1 != nullptr) @@ -1801,15 +1795,15 @@ single_defparam_decl: enum_type: TOK_ENUM { static int enum_count; // create parent node for the enum - extra->astbuf2 = std::make_unique(AST_ENUM); + extra->astbuf2 = std::make_unique(@$, AST_ENUM); extra->astbuf2->str = std::string("$enum"); extra->astbuf2->str += std::to_string(enum_count++); log_assert(!extra->cell_hack); extra->cell_hack = extra->astbuf2.get(); extra->ast_stack.back()->children.push_back(std::move(extra->astbuf2)); // create the template for the names - extra->astbuf1 = std::make_unique(AST_ENUM_ITEM); - extra->astbuf1->children.push_back(AstNode::mkconst_int(0, true)); + extra->astbuf1 = std::make_unique(@$, AST_ENUM_ITEM); + extra->astbuf1->children.push_back(AstNode::mkconst_int(@$, 0, true)); } enum_base_type TOK_LCURL enum_name_list optional_comma TOK_RCURL { // create template for the enum vars log_assert(extra->cell_hack); @@ -1817,7 +1811,7 @@ enum_type: TOK_ENUM { auto* tnode = tnode_owned.get(); extra->astbuf1 = std::move(tnode_owned); tnode->type = AST_WIRE; - tnode->attributes[ID::enum_type] = AstNode::mkconst_str(extra->cell_hack->str); + tnode->attributes[ID::enum_type] = AstNode::mkconst_str(@$, extra->cell_hack->str); extra->cell_hack = nullptr; // drop constant but keep any range tnode->children.erase(tnode->children.begin()); @@ -1858,7 +1852,7 @@ enum_name_decl: auto node = extra->astbuf1->clone(); node->str = *$1; SET_AST_NODE_LOC(node.get(), @1, @1); - node->children[0] = $2 ? std::move($2) : std::make_unique(AST_NONE); + node->children[0] = $2 ? std::move($2) : std::make_unique(@$, AST_NONE); extra->cell_hack->children.push_back(std::move(node)); } ; @@ -1908,8 +1902,8 @@ struct_type: ; struct_union: - TOK_STRUCT { $$ = std::make_unique(AST_STRUCT); } - | TOK_UNION { $$ = std::make_unique(AST_UNION); } + TOK_STRUCT { $$ = std::make_unique(@$, AST_STRUCT); } + | TOK_UNION { $$ = std::make_unique(@$, AST_UNION); } ; struct_body: opt_packed TOK_LCURL struct_member_list TOK_RCURL @@ -1951,7 +1945,7 @@ member_name: TOK_ID { } ; -struct_member_type: { extra->astbuf1 = std::make_unique(AST_STRUCT_ITEM); } member_type_token +struct_member_type: { extra->astbuf1 = std::make_unique(@$, AST_STRUCT_ITEM); } member_type_token ; member_type_token: @@ -2008,17 +2002,17 @@ wire_decl: free_attr(extra->albuf); } TOK_SEMICOL | attr TOK_SUPPLY0 TOK_ID { - extra->ast_stack.back()->children.push_back(std::make_unique(AST_WIRE)); + extra->ast_stack.back()->children.push_back(std::make_unique(@$, AST_WIRE)); extra->ast_stack.back()->children.back()->str = *$3; append_attr(extra->ast_stack.back()->children.back().get(), $1); - extra->ast_stack.back()->children.push_back(std::make_unique(AST_ASSIGN, std::make_unique(AST_IDENTIFIER), AstNode::mkconst_int(0, false, 1))); + extra->ast_stack.back()->children.push_back(std::make_unique(@$, AST_ASSIGN, std::make_unique(@$, AST_IDENTIFIER), AstNode::mkconst_int(@$, 0, false, 1))); extra->ast_stack.back()->children.back()->children[0]->str = *$3; } opt_supply_wires TOK_SEMICOL | attr TOK_SUPPLY1 TOK_ID { - extra->ast_stack.back()->children.push_back(std::make_unique(AST_WIRE)); + extra->ast_stack.back()->children.push_back(std::make_unique(@$, AST_WIRE)); extra->ast_stack.back()->children.back()->str = *$3; append_attr(extra->ast_stack.back()->children.back().get(), $1); - extra->ast_stack.back()->children.push_back(std::make_unique(AST_ASSIGN, std::make_unique(AST_IDENTIFIER), AstNode::mkconst_int(1, false, 1))); + extra->ast_stack.back()->children.push_back(std::make_unique(@$, AST_ASSIGN, std::make_unique(@$, AST_IDENTIFIER), AstNode::mkconst_int(@$, 1, false, 1))); extra->ast_stack.back()->children.back()->children[0]->str = *$3; } opt_supply_wires TOK_SEMICOL; @@ -2059,8 +2053,8 @@ wire_name_and_opt_assign: attr_allseq = true; } if (extra->current_wire_rand || attr_anyconst || attr_anyseq || attr_allconst || attr_allseq) { - auto wire = std::make_unique(AST_IDENTIFIER); - auto fcall = std::make_unique(AST_FCALL); + auto wire = std::make_unique(@$, AST_IDENTIFIER); + auto fcall = std::make_unique(@$, AST_FCALL); wire->str = extra->ast_stack.back()->children.back()->str; fcall->str = extra->current_wire_const ? "\\$anyconst" : "\\$anyseq"; if (attr_anyconst) @@ -2071,28 +2065,28 @@ wire_name_and_opt_assign: fcall->str = "\\$allconst"; if (attr_allseq) fcall->str = "\\$allseq"; - fcall->attributes[ID::reg] = AstNode::mkconst_str(RTLIL::unescape_id(wire->str)); - extra->ast_stack.back()->children.push_back(std::make_unique(AST_ASSIGN, std::move(wire), std::move(fcall))); + fcall->attributes[ID::reg] = AstNode::mkconst_str(@$, RTLIL::unescape_id(wire->str)); + extra->ast_stack.back()->children.push_back(std::make_unique(@$, AST_ASSIGN, std::move(wire), std::move(fcall))); } } | wire_name TOK_EQ expr { - auto wire = std::make_unique(AST_IDENTIFIER); + auto wire = std::make_unique(@$, AST_IDENTIFIER); wire->str = extra->ast_stack.back()->children.back()->str; if (extra->astbuf1->is_input) { extra->astbuf1->attributes[ID::defaultvalue] = std::move($3); } else if (extra->astbuf1->is_reg || extra->astbuf1->is_logic){ - auto assign = std::make_unique(AST_ASSIGN_LE, std::move(wire), std::move($3)); + auto assign = std::make_unique(@$, AST_ASSIGN_LE, std::move(wire), std::move($3)); SET_AST_NODE_LOC(assign.get(), @1, @3); - auto block = std::make_unique(AST_BLOCK, std::move(assign)); + auto block = std::make_unique(@$, AST_BLOCK, std::move(assign)); SET_AST_NODE_LOC(block.get(), @1, @3); - auto init = std::make_unique(AST_INITIAL, std::move(block)); + auto init = std::make_unique(@$, AST_INITIAL, std::move(block)); SET_AST_NODE_LOC(init.get(), @1, @3); extra->ast_stack.back()->children.push_back(std::move(init)); } else { - auto assign = std::make_unique(AST_ASSIGN, std::move(wire), std::move($3)); + auto assign = std::make_unique(@$, AST_ASSIGN, std::move(wire), std::move($3)); SET_AST_NODE_LOC(assign.get(), @1, @3); extra->ast_stack.back()->children.push_back(std::move(assign)); } @@ -2152,7 +2146,7 @@ assign_expr_list: assign_expr: lvalue TOK_EQ expr { - AstNode* node = extra->saveChild(std::make_unique(AST_ASSIGN, std::move($1), std::move($3))); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_ASSIGN, std::move($1), std::move($3))); SET_AST_NODE_LOC(node, @$, @$); }; @@ -2181,12 +2175,12 @@ typedef_decl: typedef_base_type: hierarchical_type_id { - $$ = std::make_unique(AST_WIRE); + $$ = std::make_unique(@$, AST_WIRE); $$->is_logic = true; extra->addWiretypeNode($1.get(), $$.get()); } | integer_vector_type opt_signedness_default_unsigned { - $$ = std::make_unique(AST_WIRE); + $$ = std::make_unique(@$, AST_WIRE); if ($1 == token::TOK_REG) { $$->is_reg = true; } else { @@ -2195,7 +2189,7 @@ typedef_base_type: $$->is_signed = $2; } | integer_atom_type opt_signedness_default_signed { - $$ = std::make_unique(AST_WIRE); + $$ = std::make_unique(@$, AST_WIRE); $$->is_logic = true; $$->is_signed = $2; $$->range_left = $1 - 1; @@ -2209,15 +2203,15 @@ enum_struct_type: cell_stmt: attr TOK_ID { - extra->astbuf1 = std::make_unique(AST_CELL); + extra->astbuf1 = std::make_unique(@$, AST_CELL); append_attr(extra->astbuf1.get(), $1); - extra->astbuf1->children.push_back(std::make_unique(AST_CELLTYPE)); + extra->astbuf1->children.push_back(std::make_unique(@$, AST_CELLTYPE)); extra->astbuf1->children[0]->str = *$2; } cell_parameter_list_opt cell_list TOK_SEMICOL { (void)extra->astbuf1.reset(); } | attr tok_prim_wrapper delay { - extra->astbuf1 = std::make_unique(AST_PRIMITIVE); + extra->astbuf1 = std::make_unique(@$, AST_PRIMITIVE); extra->astbuf1->str = *$2; append_attr(extra->astbuf1.get(), $1); } prim_list TOK_SEMICOL { @@ -2260,7 +2254,7 @@ single_cell_arraylist: extra->astbuf2->str = *$1; // TODO optimize again extra->cell_hack = extra->astbuf2.get(); - extra->ast_stack.back()->children.push_back(std::make_unique(AST_CELLARRAY, std::move($2), std::move(extra->astbuf2))); + extra->ast_stack.back()->children.push_back(std::make_unique(@$, AST_CELLARRAY, std::move($2), std::move(extra->astbuf2))); } TOK_LPAREN cell_port_list TOK_RPAREN{ log_assert(extra->cell_hack); SET_AST_NODE_LOC(extra->cell_hack, @1, @$); @@ -2298,7 +2292,7 @@ cell_parameter_list: cell_parameter: %empty | expr { - auto node = std::make_unique(AST_PARASET); + auto node = std::make_unique(@$, AST_PARASET); node->children.push_back(std::move($1)); extra->astbuf1->children.push_back(std::move(node)); } | @@ -2306,7 +2300,7 @@ cell_parameter: // just ignore empty parameters } | TOK_DOT TOK_ID TOK_LPAREN expr TOK_RPAREN { - auto node = std::make_unique(AST_PARASET); + auto node = std::make_unique(@$, AST_PARASET); node->str = *$2; node->children.push_back(std::move($4)); extra->astbuf1->children.push_back(std::move(node)); @@ -2343,33 +2337,33 @@ cell_port_list_rules: cell_port: attr { - auto node = std::make_unique(AST_ARGUMENT); + auto node = std::make_unique(@$, AST_ARGUMENT); extra->cell_hack->children.push_back(std::move(node)); free_attr($1); } | attr expr { - auto node = std::make_unique(AST_ARGUMENT); + auto node = std::make_unique(@$, AST_ARGUMENT); node->children.push_back(std::move($2)); extra->cell_hack->children.push_back(std::move(node)); free_attr($1); } | attr TOK_DOT TOK_ID TOK_LPAREN expr TOK_RPAREN { - auto node = std::make_unique(AST_ARGUMENT); + auto node = std::make_unique(@$, AST_ARGUMENT); node->str = *$3; node->children.push_back(std::move($5)); extra->cell_hack->children.push_back(std::move(node)); free_attr($1); } | attr TOK_DOT TOK_ID TOK_LPAREN TOK_RPAREN { - auto node = std::make_unique(AST_ARGUMENT); + auto node = std::make_unique(@$, AST_ARGUMENT); node->str = *$3; extra->cell_hack->children.push_back(std::move(node)); free_attr($1); } | attr TOK_DOT TOK_ID { - auto node = std::make_unique(AST_ARGUMENT); + auto node = std::make_unique(@$, AST_ARGUMENT); node->str = *$3; - node->children.push_back(std::make_unique(AST_IDENTIFIER)); + node->children.push_back(std::make_unique(@$, AST_IDENTIFIER)); node->children.back()->str = *$3; extra->cell_hack->children.push_back(std::move(node)); free_attr($1); @@ -2377,7 +2371,7 @@ cell_port: attr TOK_WILDCARD_CONNECT { if (!mode->sv) err_at_loc(@2, "Wildcard port connections are only supported in SystemVerilog mode."); - extra->cell_hack->attributes[ID::wildcard_port_conns] = AstNode::mkconst_int(1, false); + extra->cell_hack->attributes[ID::wildcard_port_conns] = AstNode::mkconst_int(@2, 1, false); free_attr($1); }; @@ -2399,12 +2393,12 @@ always_or_always_ff: always_stmt: attr always_or_always_ff { - AstNode* node = extra->pushChild(std::make_unique(AST_ALWAYS)); + AstNode* node = extra->pushChild(std::make_unique(@$, AST_ALWAYS)); append_attr(node, $1); if ($2) - node->attributes[ID::always_ff] = AstNode::mkconst_int(1, false); + node->attributes[ID::always_ff] = AstNode::mkconst_int(@2, 1, false); } always_cond { - (void)extra->pushChild(std::make_unique(AST_BLOCK)); + (void)extra->pushChild(std::make_unique(@$, AST_BLOCK)); } behavioral_stmt { SET_AST_NODE_LOC(extra->ast_stack.back(), @6, @6); extra->ast_stack.pop_back(); @@ -2415,21 +2409,21 @@ always_stmt: SET_RULE_LOC(@$, @2, @$); } | attr always_comb_or_latch { - AstNode* node = extra->pushChild(std::make_unique(AST_ALWAYS)); + AstNode* node = extra->pushChild(std::make_unique(@$, AST_ALWAYS)); append_attr(node, $1); if ($2) - node->attributes[ID::always_latch] = AstNode::mkconst_int(1, false); + node->attributes[ID::always_latch] = AstNode::mkconst_int(@2, 1, false); else - node->attributes[ID::always_comb] = AstNode::mkconst_int(1, false); - (void)extra->pushChild(std::make_unique(AST_BLOCK)); + node->attributes[ID::always_comb] = AstNode::mkconst_int(@2, 1, false); + (void)extra->pushChild(std::make_unique(@$, AST_BLOCK)); } behavioral_stmt { extra->ast_stack.pop_back(); extra->ast_stack.pop_back(); } | attr TOK_INITIAL { - AstNode* node = extra->pushChild(std::make_unique(AST_INITIAL)); + AstNode* node = extra->pushChild(std::make_unique(@$, AST_INITIAL)); append_attr(node, $1); - (void)extra->pushChild(std::make_unique(AST_BLOCK)); + (void)extra->pushChild(std::make_unique(@$, AST_BLOCK)); } behavioral_stmt { extra->ast_stack.pop_back(); extra->ast_stack.pop_back(); @@ -2450,19 +2444,19 @@ always_events: always_event: TOK_POSEDGE expr { - auto node = std::make_unique(AST_POSEDGE); + auto node = std::make_unique(@$, AST_POSEDGE); SET_AST_NODE_LOC(node.get(), @1, @1); node->children.push_back(std::move($2)); extra->ast_stack.back()->children.push_back(std::move(node)); } | TOK_NEGEDGE expr { - auto node = std::make_unique(AST_NEGEDGE); + auto node = std::make_unique(@$, AST_NEGEDGE); SET_AST_NODE_LOC(node.get(), @1, @1); node->children.push_back(std::move($2)); extra->ast_stack.back()->children.push_back(std::move(node)); } | expr { - auto node = std::make_unique(AST_EDGE); + auto node = std::make_unique(@$, AST_EDGE); node->children.push_back(std::move($1)); extra->ast_stack.back()->children.push_back(std::move(node)); }; @@ -2496,7 +2490,7 @@ opt_property: modport_stmt: TOK_MODPORT TOK_ID { - AstNode* modport = extra->pushChild(std::make_unique(AST_MODPORT)); + AstNode* modport = extra->pushChild(std::make_unique(@$, AST_MODPORT)); modport->str = *$2; } modport_args_opt { @@ -2516,7 +2510,7 @@ modport_arg: modport_member: TOK_ID { - AstNode* modport_member = extra->saveChild(std::make_unique(AST_MODPORTMEMBER)); + AstNode* modport_member = extra->saveChild(std::make_unique(@$, AST_MODPORTMEMBER)); modport_member->str = *$1; modport_member->is_input = extra->current_modport_input; modport_member->is_output = extra->current_modport_output; @@ -2531,7 +2525,7 @@ assert: if (mode->noassert) { } else { - AstNode* node = extra->saveChild(std::make_unique(mode->assume_asserts ? AST_ASSUME : AST_ASSERT, std::move($5))); + AstNode* node = extra->saveChild(std::make_unique(@$, mode->assume_asserts ? AST_ASSUME : AST_ASSERT, std::move($5))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @6); if ($1 != nullptr) node->str = *$1; @@ -2540,7 +2534,7 @@ assert: opt_sva_label TOK_ASSUME opt_property TOK_LPAREN expr TOK_RPAREN TOK_SEMICOL { if (mode->noassume) { } else { - AstNode* node = extra->saveChild(std::make_unique(mode->assert_assumes ? AST_ASSERT : AST_ASSUME, std::move($5))); + AstNode* node = extra->saveChild(std::make_unique(@$, mode->assert_assumes ? AST_ASSERT : AST_ASSUME, std::move($5))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @6); if ($1 != nullptr) node->str = *$1; @@ -2549,7 +2543,7 @@ assert: opt_sva_label TOK_ASSERT opt_property TOK_LPAREN TOK_EVENTUALLY expr TOK_RPAREN TOK_SEMICOL { if (mode->noassert) { } else { - AstNode* node = extra->saveChild(std::make_unique(mode->assume_asserts ? AST_FAIR : AST_LIVE, std::move($6))); + AstNode* node = extra->saveChild(std::make_unique(@$, mode->assume_asserts ? AST_FAIR : AST_LIVE, std::move($6))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @7); if ($1 != nullptr) node->str = *$1; @@ -2558,28 +2552,28 @@ assert: opt_sva_label TOK_ASSUME opt_property TOK_LPAREN TOK_EVENTUALLY expr TOK_RPAREN TOK_SEMICOL { if (mode->noassume) { } else { - AstNode* node = extra->saveChild(std::make_unique(mode->assert_assumes ? AST_LIVE : AST_FAIR, std::move($6))); + AstNode* node = extra->saveChild(std::make_unique(@$, mode->assert_assumes ? AST_LIVE : AST_FAIR, std::move($6))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @7); if ($1 != nullptr) node->str = *$1; } } | opt_sva_label TOK_COVER opt_property TOK_LPAREN expr TOK_RPAREN TOK_SEMICOL { - AstNode* node = extra->saveChild(std::make_unique(AST_COVER, std::move($5))); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_COVER, std::move($5))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @6); if ($1 != nullptr) { node->str = *$1; } } | opt_sva_label TOK_COVER opt_property TOK_LPAREN TOK_RPAREN TOK_SEMICOL { - AstNode* node = extra->saveChild(std::make_unique(AST_COVER, AstNode::mkconst_int(1, false))); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_COVER, AstNode::mkconst_int(@$, 1, false))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @5); if ($1 != nullptr) { node->str = *$1; } } | opt_sva_label TOK_COVER TOK_SEMICOL { - AstNode* node = extra->saveChild(std::make_unique(AST_COVER, AstNode::mkconst_int(1, false))); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_COVER, AstNode::mkconst_int(@$, 1, false))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @2); if ($1 != nullptr) { node->str = *$1; @@ -2588,57 +2582,57 @@ assert: opt_sva_label TOK_RESTRICT opt_property TOK_LPAREN expr TOK_RPAREN TOK_SEMICOL { if (mode->norestrict) { } else { - AstNode* node = extra->saveChild(std::make_unique(AST_ASSUME, std::move($5))); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_ASSUME, std::move($5))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @6); if ($1 != nullptr) node->str = *$1; } if (!$3) - log_file_warning(current_filename, @$.begin.line, "SystemVerilog does not allow \"restrict\" without \"property\".\n"); + err_at_loc(@$, "SystemVerilog does not allow \"restrict\" without \"property\".\n"); } | opt_sva_label TOK_RESTRICT opt_property TOK_LPAREN TOK_EVENTUALLY expr TOK_RPAREN TOK_SEMICOL { if (mode->norestrict) { } else { - AstNode* node = extra->saveChild(std::make_unique(AST_FAIR, std::move($6))); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_FAIR, std::move($6))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @7); if ($1 != nullptr) node->str = *$1; } if (!$3) - log_file_warning(current_filename, @$.begin.line, "SystemVerilog does not allow \"restrict\" without \"property\".\n"); + err_at_loc(@$, "SystemVerilog does not allow \"restrict\" without \"property\".\n"); }; assert_property: opt_sva_label TOK_ASSERT TOK_PROPERTY TOK_LPAREN expr TOK_RPAREN TOK_SEMICOL { - AstNode* node = extra->saveChild(std::make_unique(mode->assume_asserts ? AST_ASSUME : AST_ASSERT, std::move($5))); + AstNode* node = extra->saveChild(std::make_unique(@$, mode->assume_asserts ? AST_ASSUME : AST_ASSERT, std::move($5))); SET_AST_NODE_LOC(node, @1, @6); if ($1 != nullptr) { extra->ast_stack.back()->children.back()->str = *$1; } } | opt_sva_label TOK_ASSUME TOK_PROPERTY TOK_LPAREN expr TOK_RPAREN TOK_SEMICOL { - AstNode* node = extra->saveChild(std::make_unique(AST_ASSUME, std::move($5))); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_ASSUME, std::move($5))); SET_AST_NODE_LOC(node, @1, @6); if ($1 != nullptr) { extra->ast_stack.back()->children.back()->str = *$1; } } | opt_sva_label TOK_ASSERT TOK_PROPERTY TOK_LPAREN TOK_EVENTUALLY expr TOK_RPAREN TOK_SEMICOL { - AstNode* node = extra->saveChild(std::make_unique(mode->assume_asserts ? AST_FAIR : AST_LIVE, std::move($6))); + AstNode* node = extra->saveChild(std::make_unique(@$, mode->assume_asserts ? AST_FAIR : AST_LIVE, std::move($6))); SET_AST_NODE_LOC(node, @1, @7); if ($1 != nullptr) { extra->ast_stack.back()->children.back()->str = *$1; } } | opt_sva_label TOK_ASSUME TOK_PROPERTY TOK_LPAREN TOK_EVENTUALLY expr TOK_RPAREN TOK_SEMICOL { - AstNode* node = extra->saveChild(std::make_unique(AST_FAIR, std::move($6))); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_FAIR, std::move($6))); SET_AST_NODE_LOC(node, @1, @7); if ($1 != nullptr) { extra->ast_stack.back()->children.back()->str = *$1; } } | opt_sva_label TOK_COVER TOK_PROPERTY TOK_LPAREN expr TOK_RPAREN TOK_SEMICOL { - AstNode* node = extra->saveChild(std::make_unique(AST_COVER, std::move($5))); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_COVER, std::move($5))); SET_AST_NODE_LOC(node, @1, @6); if ($1 != nullptr) { extra->ast_stack.back()->children.back()->str = *$1; @@ -2647,7 +2641,7 @@ assert_property: opt_sva_label TOK_RESTRICT TOK_PROPERTY TOK_LPAREN expr TOK_RPAREN TOK_SEMICOL { if (mode->norestrict) { } else { - AstNode* node = extra->saveChild(std::make_unique(AST_ASSUME, std::move($5))); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_ASSUME, std::move($5))); SET_AST_NODE_LOC(node, @1, @6); if ($1 != nullptr) { extra->ast_stack.back()->children.back()->str = *$1; @@ -2657,7 +2651,7 @@ assert_property: opt_sva_label TOK_RESTRICT TOK_PROPERTY TOK_LPAREN TOK_EVENTUALLY expr TOK_RPAREN TOK_SEMICOL { if (mode->norestrict) { } else { - AstNode* node = extra->saveChild(std::make_unique(AST_FAIR, std::move($6))); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_FAIR, std::move($6))); SET_AST_NODE_LOC(node, @1, @7); if ($1 != nullptr) { extra->ast_stack.back()->children.back()->str = *$1; @@ -2667,23 +2661,23 @@ assert_property: simple_behavioral_stmt: attr lvalue TOK_EQ delay expr { - AstNode* node = extra->saveChild(std::make_unique(AST_ASSIGN_EQ, std::move($2), std::move($5))); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_ASSIGN_EQ, std::move($2), std::move($5))); SET_AST_NODE_LOC(node, @2, @5); append_attr(node, $1); } | attr lvalue attr inc_or_dec_op { - extra->addIncOrDecStmt($1, std::move($2), $3, $4, @1, @4); + extra->addIncOrDecStmt($1, std::move($2), $3, $4, location_range(@1, @4)); } | attr inc_or_dec_op attr lvalue { - extra->addIncOrDecStmt($1, std::move($4), $3, $2, @1, @4); + extra->addIncOrDecStmt($1, std::move($4), $3, $2, location_range(@1, @4)); } | attr lvalue OP_LE delay expr { - AstNode* node = extra->saveChild(std::make_unique(AST_ASSIGN_LE, std::move($2), std::move($5))); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_ASSIGN_LE, std::move($2), std::move($5))); SET_AST_NODE_LOC(node, @2, @5); append_attr(node, $1); } | attr lvalue asgn_binop delay expr { - (void)extra->addAsgnBinopStmt($1, std::move($2), $3, std::move($5), @2, @5); + (void)extra->addAsgnBinopStmt($1, std::move($2), $3, std::move($5)); }; asgn_binop: @@ -2708,9 +2702,9 @@ inc_or_dec_op: for_initialization: TOK_ID TOK_EQ expr { - auto ident = std::make_unique(AST_IDENTIFIER); + auto ident = std::make_unique(@$, AST_IDENTIFIER); ident->str = *$1; - auto node = std::make_unique(AST_ASSIGN_EQ, std::move(ident), std::move($3)); + auto node = std::make_unique(@$, AST_ASSIGN_EQ, std::move(ident), std::move($3)); SET_AST_NODE_LOC(node.get(), @1, @3); extra->ast_stack.back()->children.push_back(std::move(node)); } | @@ -2729,7 +2723,7 @@ for_initialization: if (range != nullptr) wire->children.push_back(std::move(range)); - auto ident = std::make_unique(AST_IDENTIFIER); + auto ident = std::make_unique(@$, AST_IDENTIFIER); ident->str = *$3; wire->str = *$3; @@ -2739,13 +2733,13 @@ for_initialization: // loop variable initialization SET_AST_NODE_LOC(ident.get(), @3, @3); - auto asgn = std::make_unique(AST_ASSIGN_EQ, std::move(ident), std::move($5)); + auto asgn = std::make_unique(@$, AST_ASSIGN_EQ, std::move(ident), std::move($5)); SET_AST_NODE_LOC(asgn.get(), @3, @5); loop->children.push_back(std::move(asgn)); // inject a wrapping block to declare the loop variable and // contain the current loop - auto wrapper = std::make_unique(AST_BLOCK); + auto wrapper = std::make_unique(@$, AST_BLOCK); wrapper->str = "$fordecl_block$" + std::to_string(autoidx++); wrapper->children.push_back(std::move(wire)); wrapper->children.push_back(std::move(loop)); @@ -2761,7 +2755,7 @@ behavioral_stmt: free_attr($1); } | attr hierarchical_id { - AstNode* node = extra->pushChild(std::make_unique(AST_TCALL)); + AstNode* node = extra->pushChild(std::make_unique(@$, AST_TCALL)); node->str = *$2; append_attr(node, $1); } opt_arg_list TOK_SEMICOL{ @@ -2769,7 +2763,7 @@ behavioral_stmt: extra->ast_stack.pop_back(); } | attr TOK_MSG_TASKS { - AstNode* node = extra->pushChild(std::make_unique(AST_TCALL)); + AstNode* node = extra->pushChild(std::make_unique(@$, AST_TCALL)); node->str = *$2; append_attr(node, $1); } opt_arg_list TOK_SEMICOL{ @@ -2779,7 +2773,7 @@ behavioral_stmt: attr TOK_BEGIN { extra->enterTypeScope(); } opt_label { - AstNode* node = extra->pushChild(std::make_unique(AST_BLOCK)); + AstNode* node = extra->pushChild(std::make_unique(@$, AST_BLOCK)); append_attr(node, $1); if ($4 != nullptr) node->str = *$4; @@ -2800,12 +2794,12 @@ behavioral_stmt: extra->ast_stack.pop_back(); } | attr TOK_FOR TOK_LPAREN { - AstNode* node = extra->pushChild(std::make_unique(AST_FOR)); + AstNode* node = extra->pushChild(std::make_unique(@$, AST_FOR)); append_attr(node, $1); } for_initialization TOK_SEMICOL expr { extra->ast_stack.back()->children.push_back(std::move($7)); } TOK_SEMICOL simple_behavioral_stmt TOK_RPAREN { - AstNode* block = extra->pushChild(std::make_unique(AST_BLOCK)); + AstNode* block = extra->pushChild(std::make_unique(@$, AST_BLOCK)); block->str = "$for_loop$" + std::to_string(autoidx++); } behavioral_stmt { SET_AST_NODE_LOC(extra->ast_stack.back(), @13, @13); @@ -2814,9 +2808,9 @@ behavioral_stmt: extra->ast_stack.pop_back(); } | attr TOK_WHILE TOK_LPAREN expr TOK_RPAREN { - AstNode* node = extra->pushChild(std::make_unique(AST_WHILE)); + AstNode* node = extra->pushChild(std::make_unique(@$, AST_WHILE)); append_attr(node, $1); - auto block_owned = std::make_unique(AST_BLOCK); + auto block_owned = std::make_unique(@$, AST_BLOCK); auto* block = block_owned.get(); extra->ast_stack.back()->children.push_back(std::move($4)); extra->ast_stack.back()->children.push_back(std::move(block_owned)); @@ -2827,9 +2821,9 @@ behavioral_stmt: extra->ast_stack.pop_back(); } | attr TOK_REPEAT TOK_LPAREN expr TOK_RPAREN { - AstNode* node = extra->pushChild(std::make_unique(AST_REPEAT)); + AstNode* node = extra->pushChild(std::make_unique(@$, AST_REPEAT)); append_attr(node, $1); - auto block_owned = std::make_unique(AST_BLOCK); + auto block_owned = std::make_unique(@$, AST_BLOCK); auto* block = block_owned.get(); extra->ast_stack.back()->children.push_back(std::move($4)); extra->ast_stack.back()->children.push_back(std::move(block_owned)); @@ -2856,22 +2850,22 @@ behavioral_stmt: // we have to undangle it from the stack patch_block_on_stack = true; } else if (outer->get_bool_attribute(ID::full_case)) - (*$1)[ID::full_case] = AstNode::mkconst_int(1, false); + (*$1)[ID::full_case] = AstNode::mkconst_int(@$, 1, false); } - auto expr = std::make_unique(AST_REDUCE_BOOL, std::move($4)); + auto expr = std::make_unique(@$, AST_REDUCE_BOOL, std::move($4)); if (!node) { // not parallel "else if": begin new construction - node_owned = std::make_unique(AST_CASE); + node_owned = std::make_unique(@$, AST_CASE); node = node_owned.get(); append_attr(node, $1); - node->children.push_back(node->get_bool_attribute(ID::parallel_case) ? AstNode::mkconst_int(1, false, 1) : expr->clone()); + node->children.push_back(node->get_bool_attribute(ID::parallel_case) ? AstNode::mkconst_int(@$, 1, false, 1) : expr->clone()); extra->ast_stack.back()->children.push_back(std::move(node_owned)); } else { free_attr($1); } - auto block_owned = std::make_unique(AST_BLOCK); + auto block_owned = std::make_unique(@$, AST_BLOCK); auto* block = block_owned.get(); - auto cond_owned = std::make_unique(AST_COND, node->get_bool_attribute(ID::parallel_case) ? std::move(expr) : AstNode::mkconst_int(1, false, 1), std::move(block_owned)); + auto cond_owned = std::make_unique(@$, AST_COND, node->get_bool_attribute(ID::parallel_case) ? std::move(expr) : AstNode::mkconst_int(@$, 1, false, 1), std::move(block_owned)); SET_AST_NODE_LOC(cond_owned.get(), @4, @4); node->children.push_back(std::move(cond_owned)); // Double it and give it to the next person @@ -2887,7 +2881,7 @@ behavioral_stmt: extra->ast_stack.pop_back(); } | case_attr case_type TOK_LPAREN expr TOK_RPAREN { - AstNode* node = extra->pushChild(std::make_unique(AST_CASE, std::move($4))); + AstNode* node = extra->pushChild(std::make_unique(@$, AST_CASE, std::move($4))); append_attr(node, $1); SET_AST_NODE_LOC(extra->ast_stack.back(), @4, @4); } opt_synopsys_attr case_body TOK_ENDCASE { @@ -2904,22 +2898,22 @@ if_attr: AstNode *context = extra->ast_stack.back(); if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if)) err_at_loc(@2, "unique0 keyword cannot be used for 'else if' branch."); - (*$1)[ID::parallel_case] = AstNode::mkconst_int(1, false); + (*$1)[ID::parallel_case] = AstNode::mkconst_int(@$, 1, false); $$ = $1; } | attr TOK_PRIORITY { AstNode *context = extra->ast_stack.back(); if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if)) err_at_loc(@2, "priority keyword cannot be used for 'else if' branch."); - (*$1)[ID::full_case] = AstNode::mkconst_int(1, false); + (*$1)[ID::full_case] = AstNode::mkconst_int(@$, 1, false); $$ = $1; } | attr TOK_UNIQUE { AstNode *context = extra->ast_stack.back(); if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if)) err_at_loc(@2, "unique keyword cannot be used for 'else if' branch."); - (*$1)[ID::full_case] = AstNode::mkconst_int(1, false); - (*$1)[ID::parallel_case] = AstNode::mkconst_int(1, false); + (*$1)[ID::full_case] = AstNode::mkconst_int(@$, 1, false); + (*$1)[ID::parallel_case] = AstNode::mkconst_int(@$, 1, false); $$ = $1; }; @@ -2928,16 +2922,16 @@ case_attr: $$ = $1; } | attr TOK_UNIQUE0 { - (*$1)[ID::parallel_case] = AstNode::mkconst_int(1, false); + (*$1)[ID::parallel_case] = AstNode::mkconst_int(@$, 1, false); $$ = $1; } | attr TOK_PRIORITY { - (*$1)[ID::full_case] = AstNode::mkconst_int(1, false); + (*$1)[ID::full_case] = AstNode::mkconst_int(@$, 1, false); $$ = $1; } | attr TOK_UNIQUE { - (*$1)[ID::full_case] = AstNode::mkconst_int(1, false); - (*$1)[ID::parallel_case] = AstNode::mkconst_int(1, false); + (*$1)[ID::full_case] = AstNode::mkconst_int(@$, 1, false); + (*$1)[ID::parallel_case] = AstNode::mkconst_int(@$, 1, false); $$ = $1; }; @@ -2955,11 +2949,11 @@ case_type: opt_synopsys_attr: opt_synopsys_attr TOK_SYNOPSYS_FULL_CASE { if (extra->ast_stack.back()->attributes.count(ID::full_case) == 0) - extra->ast_stack.back()->attributes[ID::full_case] = AstNode::mkconst_int(1, false); + extra->ast_stack.back()->attributes[ID::full_case] = AstNode::mkconst_int(@$, 1, false); } | opt_synopsys_attr TOK_SYNOPSYS_PARALLEL_CASE { if (extra->ast_stack.back()->attributes.count(ID::parallel_case) == 0) - extra->ast_stack.back()->attributes[ID::parallel_case] = AstNode::mkconst_int(1, false); + extra->ast_stack.back()->attributes[ID::parallel_case] = AstNode::mkconst_int(@$, 1, false); } | %empty; @@ -2970,12 +2964,12 @@ behavioral_stmt_list: optional_else: TOK_ELSE { extra->ast_stack.pop_back(); - auto block_owned = std::make_unique(AST_BLOCK); + auto block_owned = std::make_unique(@$, AST_BLOCK); auto* block = block_owned.get(); - block->attributes[ID::promoted_if] = AstNode::mkconst_int(1, false); + block->attributes[ID::promoted_if] = AstNode::mkconst_int(@$, 1, false); AstNode* cond = extra->saveChild( - std::make_unique(AST_COND, - std::make_unique(AST_DEFAULT), + std::make_unique(@$, AST_COND, + std::make_unique(@$, AST_DEFAULT), std::move(block_owned))); extra->ast_stack.push_back(block); SET_AST_NODE_LOC(cond, @1, @1); @@ -2991,10 +2985,11 @@ case_body: case_item: { (void)extra->pushChild(std::make_unique( + @$, extra->case_type_stack.size() && extra->case_type_stack.back() == 'x' ? AST_CONDX : extra->case_type_stack.size() && extra->case_type_stack.back() == 'z' ? AST_CONDZ : AST_COND)); } case_select { - (void)extra->pushChild(std::make_unique(AST_BLOCK)); + (void)extra->pushChild(std::make_unique(@$, AST_BLOCK)); extra->case_type_stack.push_back(0); } behavioral_stmt { extra->case_type_stack.pop_back(); @@ -3010,6 +3005,7 @@ gen_case_body: gen_case_item: { (void)extra->pushChild(std::make_unique( + @$, extra->case_type_stack.size() && extra->case_type_stack.back() == 'x' ? AST_CONDX : extra->case_type_stack.size() && extra->case_type_stack.back() == 'z' ? AST_CONDZ : AST_COND)); } case_select { @@ -3026,11 +3022,11 @@ case_select: case_expr_list: TOK_DEFAULT { - AstNode* node = extra->saveChild(std::make_unique(AST_DEFAULT)); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_DEFAULT)); SET_AST_NODE_LOC(node, @1, @1); } | TOK_SVA_LABEL { - AstNode* node = extra->pushChild(std::make_unique(AST_IDENTIFIER)); + AstNode* node = extra->pushChild(std::make_unique(@$, AST_IDENTIFIER)); SET_AST_NODE_LOC(node, @1, @1); } | expr { @@ -3042,12 +3038,12 @@ case_expr_list: rvalue: hierarchical_id TOK_LBRA expr TOK_RBRA TOK_DOT rvalue { - $$ = std::make_unique(AST_PREFIX, std::move($3), std::move($6)); + $$ = std::make_unique(@$, AST_PREFIX, std::move($3), std::move($6)); $$->str = *$1; SET_AST_NODE_LOC($$.get(), @1, @6); } | hierarchical_id range { - $$ = std::make_unique(AST_IDENTIFIER, std::move($2)); + $$ = std::make_unique(@$, AST_IDENTIFIER, std::move($2)); $$->str = *$1; SET_AST_NODE_LOC($$.get(), @1, @1); if ($2 == nullptr && ($$->str == "\\$initstate" || @@ -3056,7 +3052,7 @@ rvalue: $$->type = AST_FCALL; } | hierarchical_id non_opt_multirange { - $$ = std::make_unique(AST_IDENTIFIER, std::move($2)); + $$ = std::make_unique(@$, AST_IDENTIFIER, std::move($2)); $$->str = *$1; SET_AST_NODE_LOC($$.get(), @1, @1); }; @@ -3071,7 +3067,7 @@ lvalue: lvalue_concat_list: expr { - $$ = std::make_unique(AST_CONCAT); + $$ = std::make_unique(@$, AST_CONCAT); $$->children.push_back(std::move($1)); } | expr TOK_COMMA lvalue_concat_list { @@ -3109,7 +3105,7 @@ gen_stmt_or_module_body_stmt: genvar_identifier: TOK_ID { - $$ = std::make_unique(AST_IDENTIFIER); + $$ = std::make_unique(@$, AST_IDENTIFIER); $$->str = *$1; }; @@ -3120,7 +3116,7 @@ genvar_initialization: TOK_GENVAR genvar_identifier TOK_EQ expr { if (!mode->sv) err_at_loc(@3, "Generate for loop inline variable declaration is only supported in SystemVerilog mode!"); - AstNode* node = extra->saveChild(std::make_unique(AST_GENVAR)); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_GENVAR)); node->is_reg = true; node->is_signed = true; node->range_left = 31; @@ -3128,18 +3124,18 @@ genvar_initialization: node->str = $2->str; node->children.push_back(checkRange(node, nullptr)); SET_AST_NODE_LOC(node, @1, @4); - node = extra->saveChild(std::make_unique(AST_ASSIGN_EQ, std::move($2), std::move($4))); + node = extra->saveChild(std::make_unique(@$, AST_ASSIGN_EQ, std::move($2), std::move($4))); SET_AST_NODE_LOC(node, @1, @4); } | genvar_identifier TOK_EQ expr { - AstNode* node = extra->saveChild(std::make_unique(AST_ASSIGN_EQ, std::move($1), std::move($3))); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_ASSIGN_EQ, std::move($1), std::move($3))); SET_AST_NODE_LOC(node, @1, @3); }; // this production creates the obligatory if-else shift/reduce conflict gen_stmt: TOK_FOR TOK_LPAREN { - (void)extra->pushChild(std::make_unique(AST_GENFOR)); + (void)extra->pushChild(std::make_unique(@$, AST_GENFOR)); } genvar_initialization TOK_SEMICOL expr { extra->ast_stack.back()->children.push_back(std::move($6)); } TOK_SEMICOL simple_behavioral_stmt TOK_RPAREN gen_stmt_block { @@ -3148,21 +3144,21 @@ gen_stmt: extra->ast_stack.pop_back(); } | TOK_IF TOK_LPAREN expr TOK_RPAREN { - (void)extra->pushChild(std::make_unique(AST_GENIF)); + (void)extra->pushChild(std::make_unique(@$, AST_GENIF)); extra->ast_stack.back()->children.push_back(std::move($3)); } gen_stmt_block opt_gen_else { SET_AST_NODE_LOC(extra->ast_stack.back(), @1, @7); extra->ast_stack.pop_back(); } | case_type TOK_LPAREN expr TOK_RPAREN { - (void)extra->pushChild(std::make_unique(AST_GENCASE, std::move($3))); + (void)extra->pushChild(std::make_unique(@$, AST_GENCASE, std::move($3))); } gen_case_body TOK_ENDCASE { extra->case_type_stack.pop_back(); SET_AST_NODE_LOC(extra->ast_stack.back(), @1, @7); extra->ast_stack.pop_back(); } | TOK_MSG_TASKS { - AstNode* node = extra->pushChild(std::make_unique(AST_TECALL)); + AstNode* node = extra->pushChild(std::make_unique(@$, AST_TECALL)); node->str = *$1; } opt_arg_list TOK_SEMICOL{ SET_AST_NODE_LOC(extra->ast_stack.back(), @1, @3); @@ -3173,7 +3169,7 @@ gen_block: TOK_BEGIN { extra->enterTypeScope(); } opt_label { - AstNode* node = extra->pushChild(std::make_unique(AST_GENBLOCK)); + AstNode* node = extra->pushChild(std::make_unique(@$, AST_GENBLOCK)); node->str = $3 ? *$3 : std::string(); } module_gen_body TOK_END opt_label { extra->exitTypeScope(); @@ -3185,7 +3181,7 @@ gen_block: // result is wrapped in a genblock only if necessary gen_stmt_block: { - (void)extra->pushChild(std::make_unique(AST_GENBLOCK)); + (void)extra->pushChild(std::make_unique(@$, AST_GENBLOCK)); } gen_stmt_or_module_body_stmt { SET_AST_NODE_LOC(extra->ast_stack.back(), @2, @2); extra->ast_stack.pop_back(); @@ -3199,7 +3195,7 @@ expr: $$ = std::move($1); } | basic_expr TOK_QUE attr expr TOK_COL expr { - $$ = std::make_unique(AST_TERNARY); + $$ = std::make_unique(@$, AST_TERNARY); $$->children.push_back(std::move($1)); $$->children.push_back(std::move($4)); $$->children.push_back(std::move($6)); @@ -3207,12 +3203,12 @@ expr: append_attr($$.get(), $3); } | inc_or_dec_op attr rvalue { - $$ = extra->addIncOrDecExpr(std::move($3), $2, $1, @1, @3, false, mode->sv); + $$ = extra->addIncOrDecExpr(std::move($3), $2, $1, location_range(@1, @3), false, mode->sv); } | // TODO: Attributes are allowed in the middle here, but they create some // non-trivial conflicts that don't seem worth solving for now. rvalue inc_or_dec_op { - $$ = extra->addIncOrDecExpr(std::move($1), nullptr, $2, @1, @2, true, mode->sv); + $$ = extra->addIncOrDecExpr(std::move($1), nullptr, $2, location_range(@1, @2), true, mode->sv); }; basic_expr: @@ -3226,12 +3222,12 @@ basic_expr: auto val = p.const2ast(*$4, extra->case_type_stack.size() == 0 ? 0 : extra->case_type_stack.back(), !mode->lib); if (val == nullptr) log_error("Value conversion failed: `%s'\n", $4->c_str()); - $$ = std::make_unique(AST_TO_BITS, std::move($2), std::move(val)); + $$ = std::make_unique(@$, AST_TO_BITS, std::move($2), std::move(val)); } | hierarchical_id integral_number { if ($2->compare(0, 1, "'") != 0) err_at_loc(@2, "Cast operation must be applied on sized constants, e.g. \'d0, while %s is not a sized constant.", $2->c_str()); - auto bits = std::make_unique(AST_IDENTIFIER); + auto bits = std::make_unique(@$, AST_IDENTIFIER); bits->str = *$1; SET_AST_NODE_LOC(bits.get(), @1, @1); auto p = make_ConstParser_here(@2); @@ -3239,7 +3235,7 @@ basic_expr: SET_AST_NODE_LOC(val.get(), @2, @2); if (val == nullptr) log_error("Value conversion failed: `%s'\n", $2->c_str()); - $$ = std::make_unique(AST_TO_BITS, std::move(bits), std::move(val)); + $$ = std::make_unique(@$, AST_TO_BITS, std::move(bits), std::move(val)); } | integral_number { auto p = make_ConstParser_here(@1); @@ -3249,7 +3245,7 @@ basic_expr: log_error("Value conversion failed: `%s'\n", $1->c_str()); } | TOK_REALVAL { - $$ = std::make_unique(AST_REALVALUE); + $$ = std::make_unique(@$, AST_REALVALUE); char *p = (char*)malloc(GetSize(*$1) + 1), *q; for (int i = 0, j = 0; j < GetSize(*$1); j++) if ((*$1)[j] != '_') @@ -3260,12 +3256,12 @@ basic_expr: free(p); } | TOK_STRING { - $$ = AstNode::mkconst_str(*$1); + $$ = AstNode::mkconst_str(@1, *$1); SET_AST_NODE_LOC($$.get(), @1, @1); } | hierarchical_id attr { // super sketchy! Orphaned pointer in non-owning extra->ast_stack - AstNode *node = new AstNode(AST_FCALL); + AstNode *node = new AstNode(@1, AST_FCALL); node->str = *$1; extra->ast_stack.push_back(node); SET_AST_NODE_LOC(node, @1, @1); @@ -3275,11 +3271,11 @@ basic_expr: extra->ast_stack.pop_back(); } | TOK_TO_SIGNED attr TOK_LPAREN expr TOK_RPAREN { - $$ = std::make_unique(AST_TO_SIGNED, std::move($4)); + $$ = std::make_unique(@$, AST_TO_SIGNED, std::move($4)); append_attr($$.get(), $2); } | TOK_TO_UNSIGNED attr TOK_LPAREN expr TOK_RPAREN { - $$ = std::make_unique(AST_TO_UNSIGNED, std::move($4)); + $$ = std::make_unique(@$, AST_TO_UNSIGNED, std::move($4)); append_attr($$.get(), $2); } | TOK_LPAREN expr TOK_RPAREN { @@ -3292,230 +3288,230 @@ basic_expr: $$ = std::move($2); } | TOK_LCURL expr TOK_LCURL concat_list TOK_RCURL TOK_RCURL { - $$ = std::make_unique(AST_REPLICATE, std::move($2), std::move($4)); + $$ = std::make_unique(@$, AST_REPLICATE, std::move($2), std::move($4)); } | TOK_TILDE attr basic_expr %prec UNARY_OPS { - $$ = std::make_unique(AST_BIT_NOT, std::move($3)); + $$ = std::make_unique(@$, AST_BIT_NOT, std::move($3)); SET_AST_NODE_LOC($$.get(), @1, @3); append_attr($$.get(), $2); } | basic_expr TOK_AMP attr basic_expr { - $$ = std::make_unique(AST_BIT_AND, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_BIT_AND, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr OP_NAND attr basic_expr { - $$ = std::make_unique(AST_BIT_NOT, std::make_unique(AST_BIT_AND, std::move($1), std::move($4))); + $$ = std::make_unique(@$, AST_BIT_NOT, std::make_unique(@$, AST_BIT_AND, std::move($1), std::move($4))); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr TOK_PIPE attr basic_expr { - $$ = std::make_unique(AST_BIT_OR, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_BIT_OR, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr OP_NOR attr basic_expr { - $$ = std::make_unique(AST_BIT_NOT, std::make_unique(AST_BIT_OR, std::move($1), std::move($4))); + $$ = std::make_unique(@$, AST_BIT_NOT, std::make_unique(@$, AST_BIT_OR, std::move($1), std::move($4))); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr TOK_CARET attr basic_expr { - $$ = std::make_unique(AST_BIT_XOR, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_BIT_XOR, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr OP_XNOR attr basic_expr { - $$ = std::make_unique(AST_BIT_XNOR, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_BIT_XNOR, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | TOK_AMP attr basic_expr %prec UNARY_OPS { - $$ = std::make_unique(AST_REDUCE_AND, std::move($3)); + $$ = std::make_unique(@$, AST_REDUCE_AND, std::move($3)); SET_AST_NODE_LOC($$.get(), @1, @3); append_attr($$.get(), $2); } | OP_NAND attr basic_expr %prec UNARY_OPS { - $$ = std::make_unique(AST_REDUCE_AND, std::move($3)); + $$ = std::make_unique(@$, AST_REDUCE_AND, std::move($3)); SET_AST_NODE_LOC($$.get(), @1, @3); append_attr($$.get(), $2); - $$ = std::make_unique(AST_LOGIC_NOT, std::move($$)); + $$ = std::make_unique(@$, AST_LOGIC_NOT, std::move($$)); } | TOK_PIPE attr basic_expr %prec UNARY_OPS { - $$ = std::make_unique(AST_REDUCE_OR, std::move($3)); + $$ = std::make_unique(@$, AST_REDUCE_OR, std::move($3)); SET_AST_NODE_LOC($$.get(), @1, @3); append_attr($$.get(), std::move($2)); } | OP_NOR attr basic_expr %prec UNARY_OPS { - $$ = std::make_unique(AST_REDUCE_OR, std::move($3)); + $$ = std::make_unique(@$, AST_REDUCE_OR, std::move($3)); SET_AST_NODE_LOC($$.get(), @1, @3); append_attr($$.get(), $2); - $$ = std::make_unique(AST_LOGIC_NOT, std::move($$)); + $$ = std::make_unique(@$, AST_LOGIC_NOT, std::move($$)); SET_AST_NODE_LOC($$.get(), @1, @3); } | TOK_CARET attr basic_expr %prec UNARY_OPS { - $$ = std::make_unique(AST_REDUCE_XOR, std::move($3)); + $$ = std::make_unique(@$, AST_REDUCE_XOR, std::move($3)); SET_AST_NODE_LOC($$.get(), @1, @3); append_attr($$.get(), $2); } | OP_XNOR attr basic_expr %prec UNARY_OPS { - $$ = std::make_unique(AST_REDUCE_XNOR, std::move($3)); + $$ = std::make_unique(@$, AST_REDUCE_XNOR, std::move($3)); SET_AST_NODE_LOC($$.get(), @1, @3); append_attr($$.get(), $2); } | basic_expr OP_SHL attr basic_expr { - $$ = std::make_unique(AST_SHIFT_LEFT, std::move($1), std::make_unique(AST_TO_UNSIGNED, std::move($4))); + $$ = std::make_unique(@$, AST_SHIFT_LEFT, std::move($1), std::make_unique(@$, AST_TO_UNSIGNED, std::move($4))); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr OP_SHR attr basic_expr { - $$ = std::make_unique(AST_SHIFT_RIGHT, std::move($1), std::make_unique(AST_TO_UNSIGNED, std::move($4))); + $$ = std::make_unique(@$, AST_SHIFT_RIGHT, std::move($1), std::make_unique(@$, AST_TO_UNSIGNED, std::move($4))); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr OP_SSHL attr basic_expr { - $$ = std::make_unique(AST_SHIFT_SLEFT, std::move($1), std::make_unique(AST_TO_UNSIGNED, std::move($4))); + $$ = std::make_unique(@$, AST_SHIFT_SLEFT, std::move($1), std::make_unique(@$, AST_TO_UNSIGNED, std::move($4))); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr OP_SSHR attr basic_expr { - $$ = std::make_unique(AST_SHIFT_SRIGHT, std::move($1), std::make_unique(AST_TO_UNSIGNED, std::move($4))); + $$ = std::make_unique(@$, AST_SHIFT_SRIGHT, std::move($1), std::make_unique(@$, AST_TO_UNSIGNED, std::move($4))); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr TOK_LT attr basic_expr { - $$ = std::make_unique(AST_LT, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_LT, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr OP_LE attr basic_expr { - $$ = std::make_unique(AST_LE, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_LE, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr OP_EQ attr basic_expr { - $$ = std::make_unique(AST_EQ, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_EQ, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr OP_NE attr basic_expr { - $$ = std::make_unique(AST_NE, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_NE, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr OP_EQX attr basic_expr { - $$ = std::make_unique(AST_EQX, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_EQX, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr OP_NEX attr basic_expr { - $$ = std::make_unique(AST_NEX, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_NEX, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr OP_GE attr basic_expr { - $$ = std::make_unique(AST_GE, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_GE, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr TOK_GT attr basic_expr { - $$ = std::make_unique(AST_GT, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_GT, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr TOK_PLUS attr basic_expr { - $$ = std::make_unique(AST_ADD, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_ADD, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr TOK_MINUS attr basic_expr { - $$ = std::make_unique(AST_SUB, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_SUB, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr TOK_ASTER attr basic_expr { - $$ = std::make_unique(AST_MUL, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_MUL, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr TOK_SLASH attr basic_expr { - $$ = std::make_unique(AST_DIV, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_DIV, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr TOK_PERC attr basic_expr { - $$ = std::make_unique(AST_MOD, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_MOD, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr OP_POW attr basic_expr { - $$ = std::make_unique(AST_POW, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_POW, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | TOK_PLUS attr basic_expr %prec UNARY_OPS { - $$ = std::make_unique(AST_POS, std::move($3)); + $$ = std::make_unique(@$, AST_POS, std::move($3)); SET_AST_NODE_LOC($$.get(), @1, @3); append_attr($$.get(), $2); } | TOK_MINUS attr basic_expr %prec UNARY_OPS { - $$ = std::make_unique(AST_NEG, std::move($3)); + $$ = std::make_unique(@$, AST_NEG, std::move($3)); SET_AST_NODE_LOC($$.get(), @1, @3); append_attr($$.get(), $2); } | basic_expr OP_LAND attr basic_expr { - $$ = std::make_unique(AST_LOGIC_AND, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_LOGIC_AND, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr OP_LOR attr basic_expr { - $$ = std::make_unique(AST_LOGIC_OR, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_LOGIC_OR, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | TOK_EXCL attr basic_expr %prec UNARY_OPS { - $$ = std::make_unique(AST_LOGIC_NOT, std::move($3)); + $$ = std::make_unique(@$, AST_LOGIC_NOT, std::move($3)); SET_AST_NODE_LOC($$.get(), @1, @3); append_attr($$.get(), $2); } | TOK_SIGNED OP_CAST TOK_LPAREN expr TOK_RPAREN { if (!mode->sv) err_at_loc(@2, "Static cast is only supported in SystemVerilog mode."); - $$ = std::make_unique(AST_TO_SIGNED, std::move($4)); + $$ = std::make_unique(@$, AST_TO_SIGNED, std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); } | TOK_UNSIGNED OP_CAST TOK_LPAREN expr TOK_RPAREN { if (!mode->sv) err_at_loc(@2, "Static cast is only supported in SystemVerilog mode."); - $$ = std::make_unique(AST_TO_UNSIGNED, std::move($4)); + $$ = std::make_unique(@$, AST_TO_UNSIGNED, std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); } | basic_expr OP_CAST TOK_LPAREN expr TOK_RPAREN { if (!mode->sv) err_at_loc(@2, "Static cast is only supported in SystemVerilog mode."); - $$ = std::make_unique(AST_CAST_SIZE, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_CAST_SIZE, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); } | typedef_base_type OP_CAST TOK_LPAREN expr TOK_RPAREN { if (!mode->sv) err_at_loc(@2, "Static cast is only supported in SystemVerilog mode."); - $$ = std::make_unique(AST_CAST_SIZE, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_CAST_SIZE, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); } | TOK_LPAREN expr TOK_EQ expr TOK_RPAREN { extra->ensureAsgnExprAllowed(@3, mode->sv); $$ = $2->clone(); - auto node = std::make_unique(AST_ASSIGN_EQ, std::move($2), std::move($4)); + auto node = std::make_unique(@$, AST_ASSIGN_EQ, std::move($2), std::move($4)); SET_AST_NODE_LOC(node.get(), @2, @4); extra->ast_stack.back()->children.push_back(std::move(node)); } | TOK_LPAREN expr asgn_binop expr TOK_RPAREN { extra->ensureAsgnExprAllowed(@3, mode->sv); - $$ = extra->addAsgnBinopStmt(nullptr, std::move($2), $3, std::move($4), @2, @4)-> clone(); + $$ = extra->addAsgnBinopStmt(nullptr, std::move($2), $3, std::move($4))-> clone(); }; concat_list: expr { - $$ = std::make_unique(AST_CONCAT, std::move($1)); + $$ = std::make_unique(@$, AST_CONCAT, std::move($1)); } | expr TOK_COMMA concat_list { $$ = std::move($3); diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index d9e437ac5..d0355311d 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5704,7 +5704,7 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri { cover("kernel.rtlil.sigspec.parse"); - AST::current_filename = "input"; + // AST::current_filename = "input"; std::vector tokens; sigspec_parse_split(tokens, str, ','); @@ -5720,7 +5720,7 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri if (('0' <= netname[0] && netname[0] <= '9') || netname[0] == '\'') { cover("kernel.rtlil.sigspec.parse.const"); - VERILOG_FRONTEND::ConstParser p; + VERILOG_FRONTEND::ConstParser p{location()}; auto ast = p.const2ast(netname); if (ast == nullptr) return false; From ed0582c9f2c19693e7489ecb395b1857988cd155 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 24 Jun 2025 22:14:30 +0200 Subject: [PATCH 10/38] fixup! ast, read_verilog: unify location types, reduce filename copying --- frontends/verilog/verilog_error.cc | 54 ++++++++++++++++ frontends/verilog/verilog_error.h | 25 ++++++++ frontends/verilog/verilog_location.h | 96 ++++++++++++++++++++++++++++ 3 files changed, 175 insertions(+) create mode 100644 frontends/verilog/verilog_error.cc create mode 100644 frontends/verilog/verilog_error.h create mode 100644 frontends/verilog/verilog_location.h diff --git a/frontends/verilog/verilog_error.cc b/frontends/verilog/verilog_error.cc new file mode 100644 index 000000000..410a13580 --- /dev/null +++ b/frontends/verilog/verilog_error.cc @@ -0,0 +1,54 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Claire Xenia Wolf + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * --- + * + */ + +#include "kernel/yosys_common.h" +#include "frontends/verilog/verilog_error.h" +#include "frontends/verilog/verilog_location.h" + +USING_YOSYS_NAMESPACE + +[[noreturn]] +static void verr_at(std::string filename, int begin_line, char const *fmt, va_list ap) +{ + char buffer[1024]; + char *p = buffer; + p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap); + p += snprintf(p, buffer + sizeof(buffer) - p, "\n"); + YOSYS_NAMESPACE_PREFIX log_file_error(filename, begin_line, "%s", buffer); + exit(1); +} + +void VERILOG_FRONTEND::err_at_ast(AST::AstSrcLocType loc, char const *fmt, ...) +{ + va_list args; + va_start(args, fmt); + verr_at(*loc.begin.filename, loc.begin.line, fmt, args); + va_end(args); +} + +[[noreturn]] +void VERILOG_FRONTEND::err_at_loc(location loc, char const *fmt, ...) +{ + va_list args; + va_start(args, fmt); + verr_at(loc.begin.filename ? *(loc.begin.filename) : "UNKNOWN", loc.begin.line, fmt, args); +} + diff --git a/frontends/verilog/verilog_error.h b/frontends/verilog/verilog_error.h new file mode 100644 index 000000000..4cb65164b --- /dev/null +++ b/frontends/verilog/verilog_error.h @@ -0,0 +1,25 @@ +#ifndef VERILOG_ERROR_H +#define VERILOG_ERROR_H + +#include "kernel/yosys_common.h" +#include "frontends/ast/ast.h" +#include "frontends/verilog/verilog_location.h" + +#if ! defined(yyFlexLexerOnce) +#define yyFlexLexer frontend_verilog_yyFlexLexer +#include +#endif + +YOSYS_NAMESPACE_BEGIN + +namespace VERILOG_FRONTEND +{ + [[noreturn]] + void err_at_ast(AST::AstSrcLocType loc, char const *fmt, ...); + [[noreturn]] + void err_at_loc(location loc, char const *fmt, ...); +}; + +YOSYS_NAMESPACE_END + +#endif diff --git a/frontends/verilog/verilog_location.h b/frontends/verilog/verilog_location.h new file mode 100644 index 000000000..d2ef8e94c --- /dev/null +++ b/frontends/verilog/verilog_location.h @@ -0,0 +1,96 @@ +#ifndef VERILOG_LOCATION_H +#define VERILOG_LOCATION_H + +#include +#include +#include +#include + +/** + * Provide frontend-wide location tracking like what bison generates + * but using shared_ptr for filename + */ + +struct position { + std::shared_ptr filename; + int line; + int column; + + position(std::shared_ptr filename, int line = 1, int column = 1) + : filename(filename), line(line), column(column) {} + position() = default; + position(const position& other) = default; + position& operator=(const position& other) = default; + + void advance() { ++column; } + void columns(int count = 1) { + column += count; + } + + void lines(int count = 1) { + line += count; + column = 1; + } + std::string to_string() const { + std::ostringstream oss; + if (filename && !filename->empty()) { + oss << *filename << ":"; + } + oss << line << ":" << column; + return oss.str(); + } +}; + +struct location { + position begin; + position end; + + location() = default; + location(const position& b, const position& e) + : begin(b), end(e) {} + location(const location& other) = default; + location& operator=(const location& other) = default; + + void step() { begin = end; } + + void columns(int count = 1) { + end.columns(count); + } + + void lines(int count = 1) { + end.lines(count); + } + std::string to_string() const { + std::ostringstream oss; + bool same_file = (!begin.filename && !end.filename) || + (begin.filename && end.filename && + *begin.filename == *end.filename); + + if (same_file) { + if (begin.filename && !begin.filename->empty()) + oss << *begin.filename << ":"; + + if (begin.line == end.line) { + if (begin.column == end.column) { + oss << begin.line << ":" << begin.column; + } else { + oss << begin.line << ":" << begin.column + << "-" << end.column; + } + } else { + oss << begin.line << ":" << begin.column + << "-" << end.line << ":" << end.column; + } + } else { + oss << begin.to_string() << "-" << end.to_string(); + } + + return oss.str(); + } +}; + +static inline std::ostream& operator<<(std::ostream& os, const location& loc) { + return os << loc.to_string(); +} + +#endif From 040d717ad7150dab295ee64c730bb900de1a0c5d Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 24 Jun 2025 22:45:59 +0200 Subject: [PATCH 11/38] fixup! fixup! ast, read_verilog: unify location types, reduce filename copying --- frontends/verilog/verilog_frontend.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h index e97cee4fc..eabc0d46b 100644 --- a/frontends/verilog/verilog_frontend.h +++ b/frontends/verilog/verilog_frontend.h @@ -32,11 +32,6 @@ #include "kernel/yosys.h" #include "frontends/ast/ast.h" -#if ! defined(yyFlexLexerOnce) -#define yyFlexLexer frontend_verilog_yyFlexLexer -#include -#endif - #include #include From c70224a68a620370fdc401b4e44fcc489478035d Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 25 Jun 2025 10:23:44 +1200 Subject: [PATCH 12/38] Add libfl-dev Should fix the missing `` error. --- .github/actions/setup-build-env/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/setup-build-env/action.yml b/.github/actions/setup-build-env/action.yml index dfdcd88c0..059287a63 100644 --- a/.github/actions/setup-build-env/action.yml +++ b/.github/actions/setup-build-env/action.yml @@ -8,7 +8,7 @@ runs: shell: bash run: | sudo apt-get update - sudo apt-get install gperf build-essential bison flex libreadline-dev gawk tcl-dev libffi-dev git graphviz xdot pkg-config python3 libboost-system-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev libbz2-dev + sudo apt-get install gperf build-essential bison flex libfl-dev libreadline-dev gawk tcl-dev libffi-dev git graphviz xdot pkg-config python3 libboost-system-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev libbz2-dev - name: Install macOS Dependencies if: runner.os == 'macOS' From 7b5035e0c4ba38391cff50f657e9e690c756c120 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 25 Jun 2025 10:38:07 +1200 Subject: [PATCH 13/38] preproc depends on parser --- frontends/verilog/Makefile.inc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc index a563c899c..838ee8c58 100644 --- a/frontends/verilog/Makefile.inc +++ b/frontends/verilog/Makefile.inc @@ -13,6 +13,8 @@ frontends/verilog/verilog_parser.tab.hh: frontends/verilog/verilog_parser.tab.cc frontends/verilog/verilog_frontend.h: frontends/verilog/verilog_parser.tab.hh frontends/verilog/verilog_error.h: frontends/verilog/verilog_parser.tab.hh +frontends/verilog/preproc.o: frontends/verilog/verilog_parser.tab.hh + frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l frontends/verilog/verilog_parser.tab.cc $(Q) mkdir -p $(dir $@) $(P) flex -o frontends/verilog/verilog_lexer.cc $< From b90622b7edb13048d7f0427fb288f382d535a588 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 25 Jun 2025 10:39:50 +1200 Subject: [PATCH 14/38] docs/verilog_frontend.rst: Fix indentation --- .../source/yosys_internals/flow/verilog_frontend.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/source/yosys_internals/flow/verilog_frontend.rst b/docs/source/yosys_internals/flow/verilog_frontend.rst index d6bdf6b6d..2a26daec3 100644 --- a/docs/source/yosys_internals/flow/verilog_frontend.rst +++ b/docs/source/yosys_internals/flow/verilog_frontend.rst @@ -187,13 +187,13 @@ simplifies the creation of AST nodes for simple expressions a bit. For example the bison code for parsing multiplications: .. code:: none - :number-lines: + :number-lines: - basic_expr TOK_ASTER attr basic_expr { - $$ = std::make_unique(AST_MUL, std::move($1), std::move($4)); - SET_AST_NODE_LOC($$.get(), @1, @4); - append_attr($$.get(), $3); - } | + basic_expr TOK_ASTER attr basic_expr { + $$ = std::make_unique(AST_MUL, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); + } | The generated AST data structure is then passed directly to the AST frontend that performs the actual conversion to RTLIL. From a2b2188a7fd62045b85c88edac06ff56ee204d0f Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 25 Jun 2025 11:25:39 +1200 Subject: [PATCH 15/38] preproc.cc: Use full path for generated file Fixes out-of-tree builds. --- frontends/verilog/preproc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc index d07e39189..b83fad7c3 100644 --- a/frontends/verilog/preproc.cc +++ b/frontends/verilog/preproc.cc @@ -34,7 +34,7 @@ #include "preproc.h" #include "verilog_frontend.h" -#include "verilog_parser.tab.hh" +#include "frontends/verilog/verilog_parser.tab.hh" #include "kernel/log.h" #include #include From cf0f72dbd7f8edd4f77034f262f7dca4dadde27b Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 25 Jun 2025 11:32:46 +1200 Subject: [PATCH 16/38] Makefile: Add flex lib/include for brew --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 3fbd8762a..19c7650e2 100644 --- a/Makefile +++ b/Makefile @@ -133,8 +133,8 @@ ifeq ($(ENABLE_PYOSYS),1) CXXFLAGS += -I$(BREW_PREFIX)/boost/include LINKFLAGS += -L$(BREW_PREFIX)/boost/lib -L$(BREW_PREFIX)/boost-python3/lib endif -CXXFLAGS += -I$(BREW_PREFIX)/readline/include -LINKFLAGS += -L$(BREW_PREFIX)/readline/lib +CXXFLAGS += -I$(BREW_PREFIX)/readline/include -I$(BREW_PREFIX)/flex/include +LINKFLAGS += -L$(BREW_PREFIX)/readline/lib -L$(BREW_PREFIX)/flex/lib PKG_CONFIG_PATH := $(BREW_PREFIX)/libffi/lib/pkgconfig:$(PKG_CONFIG_PATH) PKG_CONFIG_PATH := $(BREW_PREFIX)/tcl-tk/lib/pkgconfig:$(PKG_CONFIG_PATH) export PATH := $(BREW_PREFIX)/bison/bin:$(BREW_PREFIX)/gettext/bin:$(BREW_PREFIX)/flex/bin:$(PATH) From 7e026d824a061225296b9ac53a21821e33aa9b5a Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 25 Jun 2025 11:37:40 +1200 Subject: [PATCH 17/38] dpicall.cc: Fix sans-plugin function call --- frontends/ast/dpicall.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/ast/dpicall.cc b/frontends/ast/dpicall.cc index 07314e3d7..d76318739 100644 --- a/frontends/ast/dpicall.cc +++ b/frontends/ast/dpicall.cc @@ -153,7 +153,7 @@ YOSYS_NAMESPACE_END YOSYS_NAMESPACE_BEGIN -AST::AstNode *AST::dpi_call(AstSrcLocType loc, const std::string&, const std::string &fname, const std::vector&, const std::vector&) +std::unique_ptr AST::dpi_call(AstSrcLocType, const std::string&, const std::string &fname, const std::vector&, const std::vector>&) { log_error("Can't call DPI function `%s': this version of yosys is built without plugin support\n", fname.c_str()); } From 41d9a1b88e11d5ccede076fb972154a66db555b7 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 9 Jul 2025 14:34:03 +0200 Subject: [PATCH 18/38] readme, verilog_parser: bison 3.8 and ubuntu 22.04 example --- README.md | 2 +- frontends/verilog/verilog_parser.y | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 71d47d76c..63408d4aa 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ recommended) and some standard tools such as GNU Flex, GNU Bison, and GNU Make. TCL, readline and libffi are optional (see ``ENABLE_*`` settings in Makefile). Xdot (graphviz) is used by the ``show`` command in yosys to display schematics. -For example on Ubuntu Linux 16.04 LTS the following commands will install all +For example on Ubuntu Linux 22.04 LTS the following commands will install all prerequisites for building yosys: $ sudo apt-get install build-essential clang lld bison flex \ diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 7ccf404f7..728c7f6d5 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -33,7 +33,7 @@ * */ -%require "3.0" +%require "3.8" %language "c++" %define api.value.type variant %define api.prefix {frontend_verilog_yy} From 56058b3ed4b1fd6e4d32ec0586dbd1879a06366e Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 9 Jul 2025 15:24:34 +0200 Subject: [PATCH 19/38] read_verilog, ast: use unified locations in errors and simplify dependencies --- frontends/verilog/.gitignore | 1 - frontends/verilog/Makefile.inc | 6 ++---- frontends/verilog/verilog_error.cc | 14 ++++++-------- frontends/verilog/verilog_error.h | 7 ------- frontends/verilog/verilog_frontend.cc | 2 +- frontends/verilog/verilog_lexer.h | 5 +++++ frontends/verilog/verilog_parser.y | 4 ++-- 7 files changed, 16 insertions(+), 23 deletions(-) diff --git a/frontends/verilog/.gitignore b/frontends/verilog/.gitignore index cb6775cbc..aadbcdcdd 100644 --- a/frontends/verilog/.gitignore +++ b/frontends/verilog/.gitignore @@ -2,4 +2,3 @@ verilog_lexer.cc verilog_parser.output verilog_parser.tab.cc verilog_parser.tab.hh -stack.hh diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc index 838ee8c58..67e8074bf 100644 --- a/frontends/verilog/Makefile.inc +++ b/frontends/verilog/Makefile.inc @@ -3,18 +3,16 @@ GENFILES += frontends/verilog/verilog_parser.tab.cc GENFILES += frontends/verilog/verilog_parser.tab.hh GENFILES += frontends/verilog/verilog_parser.output GENFILES += frontends/verilog/verilog_lexer.cc -GENFILES += frontends/verilog/stack.hh -frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y frontends/verilog/verilog_location.h +frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y $(Q) mkdir -p $(dir $@) $(P) $(BISON) -Wall -Werror -o $@ -d -r all -b frontends/verilog/verilog_parser $< frontends/verilog/verilog_parser.tab.hh: frontends/verilog/verilog_parser.tab.cc -frontends/verilog/verilog_frontend.h: frontends/verilog/verilog_parser.tab.hh -frontends/verilog/verilog_error.h: frontends/verilog/verilog_parser.tab.hh frontends/verilog/preproc.o: frontends/verilog/verilog_parser.tab.hh +frontends/verilog/verilog_lexer.h: frontends/verilog/verilog_parser.tab.hh frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l frontends/verilog/verilog_parser.tab.cc $(Q) mkdir -p $(dir $@) $(P) flex -o frontends/verilog/verilog_lexer.cc $< diff --git a/frontends/verilog/verilog_error.cc b/frontends/verilog/verilog_error.cc index 410a13580..4adfaafa6 100644 --- a/frontends/verilog/verilog_error.cc +++ b/frontends/verilog/verilog_error.cc @@ -25,6 +25,12 @@ USING_YOSYS_NAMESPACE +/** + * Legacy behavior is to only track lines. Now we have columns too, but we don't + * report them in errors. + * TODO: report columns, too + */ + [[noreturn]] static void verr_at(std::string filename, int begin_line, char const *fmt, va_list ap) { @@ -36,14 +42,6 @@ static void verr_at(std::string filename, int begin_line, char const *fmt, va_li exit(1); } -void VERILOG_FRONTEND::err_at_ast(AST::AstSrcLocType loc, char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - verr_at(*loc.begin.filename, loc.begin.line, fmt, args); - va_end(args); -} - [[noreturn]] void VERILOG_FRONTEND::err_at_loc(location loc, char const *fmt, ...) { diff --git a/frontends/verilog/verilog_error.h b/frontends/verilog/verilog_error.h index 4cb65164b..2eeb4538e 100644 --- a/frontends/verilog/verilog_error.h +++ b/frontends/verilog/verilog_error.h @@ -5,17 +5,10 @@ #include "frontends/ast/ast.h" #include "frontends/verilog/verilog_location.h" -#if ! defined(yyFlexLexerOnce) -#define yyFlexLexer frontend_verilog_yyFlexLexer -#include -#endif - YOSYS_NAMESPACE_BEGIN namespace VERILOG_FRONTEND { - [[noreturn]] - void err_at_ast(AST::AstSrcLocType loc, char const *fmt, ...); [[noreturn]] void err_at_loc(location loc, char const *fmt, ...); }; diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index 733ec8ba7..e7d34dac5 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -51,7 +51,7 @@ static std::list> verilog_defaults_stack; static void error_on_dpi_function(AST::AstNode *node) { if (node->type == AST::AST_DPI_FUNCTION) - err_at_ast(node->location, "Found DPI function %s.\n", node->str.c_str()); + err_at_loc(node->location, "Found DPI function %s.\n", node->str.c_str()); for (auto& child : node->children) error_on_dpi_function(child.get()); } diff --git a/frontends/verilog/verilog_lexer.h b/frontends/verilog/verilog_lexer.h index b7885181c..fe56b27d2 100644 --- a/frontends/verilog/verilog_lexer.h +++ b/frontends/verilog/verilog_lexer.h @@ -7,6 +7,11 @@ #include #include +#if ! defined(yyFlexLexerOnce) +#define yyFlexLexer frontend_verilog_yyFlexLexer +#include +#endif + YOSYS_NAMESPACE_BEGIN namespace VERILOG_FRONTEND { diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 728c7f6d5..0d068d2ed 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -200,7 +200,7 @@ if (type_node->range_left >= 0 && type_node->range_right >= 0) { // type already restricts the range if (range_node) { - err_at_ast(type_node->location, "integer/genvar types cannot have packed dimensions."); + err_at_loc(type_node->location, "integer/genvar types cannot have packed dimensions."); } else { range_node = makeRange(type_node->location, type_node->range_left, type_node->range_right, false); @@ -217,7 +217,7 @@ } } if (!valid) - err_at_ast(type_node->location, "wire/reg/logic packed dimension must be of the form [:]"); + err_at_loc(type_node->location, "wire/reg/logic packed dimension must be of the form [:]"); } return range_node; From e690fb59f16fc533dafee20f131fa1047d1ce1f7 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 9 Jul 2025 16:11:10 +0200 Subject: [PATCH 20/38] docs: fix verilog frontend internals --- .../yosys_internals/flow/verilog_frontend.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/source/yosys_internals/flow/verilog_frontend.rst b/docs/source/yosys_internals/flow/verilog_frontend.rst index 2a26daec3..8381641b3 100644 --- a/docs/source/yosys_internals/flow/verilog_frontend.rst +++ b/docs/source/yosys_internals/flow/verilog_frontend.rst @@ -47,9 +47,9 @@ be found in :file:`frontends/verilog/verilog_lexer.l` in the Yosys source tree. The lexer does little more than identifying all keywords and literals recognised by the Yosys Verilog frontend. -The lexer keeps track of the current location in the Verilog source code using -some VerilogLexer member variables. These variables are used by the constructor of AST nodes -to annotate each node with the source code location it originated from. +The lexer keeps track of the current location in the Verilog source code with +a ``VerilogLexer::out_loc`` and uses it to construct parser-defined +symbol objects. Finally the lexer identifies and handles special comments such as "``// synopsys translate_off``" and "``// synopsys full_case``". (It is recommended to use @@ -178,11 +178,11 @@ properties: - | Source code location | Each ``AST::AstNode`` is automatically annotated with the current source - code location by the ``AST::AstNode`` constructor. It is stored in the - ``std::string filename`` and ``int linenum`` member variables. + code location by the ``AST::AstNode`` constructor. The ``location`` type + is a manual reimplementation of the bison-provided location type. This + type is defined at ``frontends/verilog/verilog_location.h``. -The ``AST::AstNode`` constructor can be called with up to two child nodes that -are automatically added to the list of child nodes for the new object. This +The ``AST::AstNode`` constructor can be called with up to 4 child nodes. This simplifies the creation of AST nodes for simple expressions a bit. For example the bison code for parsing multiplications: @@ -205,7 +205,7 @@ tree respectively. Transforming AST to RTLIL ------------------------- -The AST Frontend converts a set of modules in AST representation to modules in +The AST frontend converts a set of modules in AST representation to modules in RTLIL representation and adds them to the current design. This is done in two steps: simplification and RTLIL generation. From a519390fc41ff07c3eba54386528b85c6be5a4f6 Mon Sep 17 00:00:00 2001 From: garytwong Date: Thu, 19 Jun 2025 16:41:18 +0000 Subject: [PATCH 21/38] verilog: fix string literal regular expression (#5187) * verilog: fix string literal regular expression. A backslash was improperly quoted, causing string literal matching to fail when the final token before a closing quote was an escaped backslash. * verilog: add regression test for string literal regex bug. Test for bug triggered by escaped backslash immediately before closing quote (introduced in ca7d94af and fixed by 40aa7eaf). --- frontends/verilog/verilog_lexer.l | 2 +- tests/verilog/bug5160.v | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 tests/verilog/bug5160.v diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 8e6e022b1..be9a439b0 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -371,7 +371,7 @@ TIME_SCALE_SUFFIX [munpf]?s } \" { BEGIN(STRING); } -([^\"]|\\.)+ { yymore(); } +([^\\"]|\\.)+ { yymore(); } \" { BEGIN(0); char *yystr = strdup(YYText()); diff --git a/tests/verilog/bug5160.v b/tests/verilog/bug5160.v new file mode 100644 index 000000000..5b141a360 --- /dev/null +++ b/tests/verilog/bug5160.v @@ -0,0 +1,5 @@ +// Regression test for bug mentioned in #5160: +// https://github.com/YosysHQ/yosys/pull/5160#issuecomment-2983643084 +module top; + initial $display( "\\" ); +endmodule From e17ed5df884a8cd00da1f28454da88c2c58256f8 Mon Sep 17 00:00:00 2001 From: Gary Wong Date: Thu, 3 Jul 2025 20:51:12 -0600 Subject: [PATCH 22/38] verilog: add support for SystemVerilog string literals. Differences are new escape sequences (including escaped newline continuations and hex escapes) and triple-quoted literals. --- docs/source/yosys_internals/verilog.rst | 3 + frontends/verilog/verilog_lexer.l | 167 +++++++++++---- tests/verilog/bug5160.v | 5 - tests/verilog/string-literals.ys | 257 ++++++++++++++++++++++++ 4 files changed, 385 insertions(+), 47 deletions(-) delete mode 100644 tests/verilog/bug5160.v create mode 100644 tests/verilog/string-literals.ys diff --git a/docs/source/yosys_internals/verilog.rst b/docs/source/yosys_internals/verilog.rst index 0039aaab7..d67553aa9 100644 --- a/docs/source/yosys_internals/verilog.rst +++ b/docs/source/yosys_internals/verilog.rst @@ -381,3 +381,6 @@ from SystemVerilog: will process conditionals using these keywords by annotating their representation with the appropriate ``full_case`` and/or ``parallel_case`` attributes, which are described above.) + +- SystemVerilog string literals are supported (triple-quoted strings and + escape sequences such as line continuations and hex escapes). diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index be9a439b0..ea6a554dc 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -154,11 +154,132 @@ parser::symbol_type char_tok(char c, parser::location_type loc) { return parser::make_ch_t(c, loc); } } +static bool is_hex_dig(char c, int *val, parser::location_type loc) +{ + if ('0' <= c && c <= '9') { + *val = c - '0'; + return true; + } else if ('a' <= c && c <= 'f') { + *val = c - 'a' + 0xA; + return true; + } else if ('A' <= c && c <= 'F') { + *val = c - 'A' + 0xA; + return true; + } else if (c == 'x' || c == 'X' || c == 'z' || c == 'Z' || c == '?') { + log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "'%c' not a valid digit in hex escape sequence.\n", c); + *val = 0; // not semantically valid in hex escape... + return true; // ...but still processed as part of hex token + } + + return false; +} + +static bool is_oct_dig(char c, int *val, parser::location_type loc) +{ + if ('0' <= c && c <= '7') { + *val = c - '0'; + return true; + } else if (c == 'x' || c == 'X' || c == 'z' || c == 'Z' || c == '?') { + log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "'%c' not a valid digit in octal escape sequence.\n", c); + *val = 0; // not semantically valid in octal escape... + return true; // ...but still processed as part of octal token + } + + return false; +} + +static parser::symbol_type process_str(char *str, int len, bool triple, parser::location_type loc) +{ + char *in, *out; // Overwrite input buffer: flex manual states "Actions + // are free to modify 'yytext' except for lengthening it". + + for (in = str, out = str; in < str + len; in++) + switch (*in) { + case '\n': + case '\r': + if (in + 1 < str + len && (in[1] ^ *in) == ('\n' ^ '\r')) + in++; + if (!triple) + log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "Multi-line string literals should be triple-quoted or escaped.\n"); + *out++ = '\n'; + break; + case '\\': + in++; + log_assert(in < str + len); + switch (*in) { + case 'a': + *out++ = '\a'; + break; + case 'f': + *out++ = '\f'; + break; + case 'n': + *out++ = '\n'; + break; + case 'r': /* not part of IEEE-1800 2023, but seems + like a good idea to support it anyway */ + *out++ = '\r'; + break; + case 't': + *out++ = '\t'; + break; + case 'v': + *out++ = '\v'; + break; + case 'x': + int val; + if (in + 1 < str + len && is_hex_dig(in[1], &val, loc)) { + *out = val; + in++; + if (in + 1 < str + len && is_hex_dig(in[1], &val, loc)) { + *out = *out * 0x10 + val; + in++; + } + out++; + } else + log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "ignoring invalid hex escape.\n"); + break; + case '\\': + *out++ = '\\'; + break; + case '"': + *out++ = '"'; + break; + case '\n': + case '\r': + if (in + 1 < str + len && (in[1] ^ *in) == ('\n' ^ '\r')) + in++; + break; + default: + if ('0' <= *in && *in <= '7') { + int val; + + *out = *in - '0'; + if (in + 1 < str + len && is_oct_dig(in[1], &val, loc)) { + *out = *out * 010 + val; + in++; + if (in + 1 < str + len && is_oct_dig(in[1], &val, loc)) { + if (*out >= 040) + log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "octal escape exceeds \\377\n"); + *out = *out * 010 + val; + in++; + } + } + out++; + } else + *out++ = *in; + } + break; + default: + *out++ = *in; + } + + return parser::make_TOK_STRING(std::make_unique(str, out - str), loc); +} %} %x COMMENT -%x STRING %x SYNOPSYS_TRANSLATE_OFF %x SYNOPSYS_FLAGS %x IMPORT_DPI @@ -370,47 +491,9 @@ TIME_SCALE_SUFFIX [munpf]?s return parser::make_TOK_REALVAL(std::move(val), out_loc); } -\" { BEGIN(STRING); } -([^\\"]|\\.)+ { yymore(); } -\" { - BEGIN(0); - char *yystr = strdup(YYText()); - yystr[strlen(YYText()) - 1] = 0; - int i = 0, j = 0; - while (yystr[i]) { - if (yystr[i] == '\\' && yystr[i + 1]) { - i++; - if (yystr[i] == 'a') - yystr[i] = '\a'; - else if (yystr[i] == 'f') - yystr[i] = '\f'; - else if (yystr[i] == 'n') - yystr[i] = '\n'; - else if (yystr[i] == 'r') - yystr[i] = '\r'; - else if (yystr[i] == 't') - yystr[i] = '\t'; - else if (yystr[i] == 'v') - yystr[i] = '\v'; - else if ('0' <= yystr[i] && yystr[i] <= '7') { - yystr[i] = yystr[i] - '0'; - if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') { - yystr[i + 1] = yystr[i] * 8 + yystr[i + 1] - '0'; - i++; - } - if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') { - yystr[i + 1] = yystr[i] * 8 + yystr[i + 1] - '0'; - i++; - } - } - } - yystr[j++] = yystr[i++]; - } - yystr[j] = 0; - string_t val = std::make_unique(yystr, j); - free(yystr); - return parser::make_TOK_STRING(std::move(val), out_loc); -} +\"([^\\"]|\\.|\\\n)*\" { return process_str(yytext + 1, yyleng - 2, false, out_loc); } + +\"{3}(\"{0,2}([^\\"]|\\.|\\\n))*\"{3} { return process_str(yytext + 3, yyleng - 6, true, out_loc); } and|nand|or|nor|xor|xnor|not|buf|bufif0|bufif1|notif0|notif1 { auto val = std::make_unique(YYText()); diff --git a/tests/verilog/bug5160.v b/tests/verilog/bug5160.v deleted file mode 100644 index 5b141a360..000000000 --- a/tests/verilog/bug5160.v +++ /dev/null @@ -1,5 +0,0 @@ -// Regression test for bug mentioned in #5160: -// https://github.com/YosysHQ/yosys/pull/5160#issuecomment-2983643084 -module top; - initial $display( "\\" ); -endmodule diff --git a/tests/verilog/string-literals.ys b/tests/verilog/string-literals.ys new file mode 100644 index 000000000..a0f0f0460 --- /dev/null +++ b/tests/verilog/string-literals.ys @@ -0,0 +1,257 @@ +# Test valid escape sequences yield correct results: +logger -expect-no-warnings +read_verilog << EOF +module top; + wire[7:0] sp = "\ "; + wire[7:0] spval = 32; + wire[7:0] ex = "\!"; + wire[7:0] exval = 33; + wire[7:0] dq = "\""; + wire[7:0] dqval = 34; + wire[7:0] ha = "\#"; + wire[7:0] haval = 35; + wire[7:0] do = "\$"; + wire[7:0] doval = 36; + wire[7:0] pc = "\%"; + wire[7:0] pcval = 37; + wire[7:0] am = "\&"; + wire[7:0] amval = 38; + wire[7:0] sq = "\'"; + wire[7:0] sqval = 39; + wire[7:0] op = "\("; + wire[7:0] opval = 40; + wire[7:0] cp = "\)"; + wire[7:0] cpval = 41; + wire[7:0] as = "\*"; + wire[7:0] asval = 42; + wire[7:0] pl = "\+"; + wire[7:0] plval = 43; + wire[7:0] co = "\,"; + wire[7:0] coval = 44; + wire[7:0] mi = "\-"; + wire[7:0] mival = 45; + wire[7:0] do = "\."; + wire[7:0] doval = 46; + wire[7:0] sl = "\/"; + wire[7:0] slval = 47; + + wire[7:0] dig0 = "\012"; + wire[7:0] dig0val = 10; + wire[7:0] dig8 = "\8"; // not octal, a literal '8' + wire[7:0] dig8val = 56; + wire[7:0] dig9 = "\9"; // not octal, a literal '9' + wire[7:0] dig9val = 57; + + wire[7:0] cl = "\:"; + wire[7:0] clval = 58; + wire[7:0] sc = "\;"; + wire[7:0] scval = 59; + wire[7:0] lt = "\<"; + wire[7:0] ltval = 60; + wire[7:0] eq = "\="; + wire[7:0] eqval = 61; + wire[7:0] gt = "\>"; + wire[7:0] gtval = 62; + wire[7:0] qu = "\?"; + wire[7:0] quval = 63; + wire[7:0] at = "\@"; + wire[7:0] atval = 64; + + wire[7:0] A = "\A"; + wire[7:0] Aval = 65; // etc. etc. + + wire[7:0] os = "\["; + wire[7:0] osval = 91; + wire[7:0] bs = "\\"; + wire[7:0] bsval = 92; + wire[7:0] cs = "\]"; + wire[7:0] csval = 93; + wire[7:0] ca = "\^"; + wire[7:0] caval = 94; + wire[7:0] us = "\_"; + wire[7:0] usval = 95; + wire[7:0] bq = "\`"; + wire[7:0] bqval = 96; + + wire[7:0] a = "\a"; // alert, ASCII BEL=7 + wire[7:0] aval = 7; + wire[7:0] b = "\b"; + wire[7:0] bval = 98; + wire[7:0] c = "\c"; + wire[7:0] cval = 99; + wire[7:0] d = "\d"; + wire[7:0] dval = 100; + wire[7:0] e = "\e"; + wire[7:0] eval = 101; + wire[7:0] f = "\f"; // form feed, ASCII FF=12 + wire[7:0] fval = 12; + wire[7:0] g = "\g"; + wire[7:0] gval = 103; + wire[7:0] h = "\h"; + wire[7:0] hval = 104; + wire[7:0] i = "\i"; + wire[7:0] ival = 105; + wire[7:0] j = "\j"; + wire[7:0] jval = 106; + wire[7:0] k = "\k"; + wire[7:0] kval = 107; + wire[7:0] l = "\l"; + wire[7:0] lval = 108; + wire[7:0] m = "\m"; + wire[7:0] mval = 109; + wire[7:0] n = "\n"; // new line, ASCII LF=10 + wire[7:0] nval = 10; + wire[7:0] o = "\o"; + wire[7:0] oval = 111; + wire[7:0] p = "\p"; + wire[7:0] pval = 112; + wire[7:0] q = "\q"; + wire[7:0] qval = 113; + wire[7:0] r = "\r"; // carriage return, ASCII CR=13, not IEEE 1800-2023 + wire[7:0] rval = 13; + wire[7:0] s = "\s"; + wire[7:0] sval = 115; + wire[7:0] t = "\t"; // tab, ASCII HT=9 + wire[7:0] tval = 9; + wire[7:0] u = "\u"; + wire[7:0] uval = 117; + wire[7:0] v = "\v"; // vertical tab, ASCII VT=11 + wire[7:0] vval = 11; + wire[7:0] w = "\w"; + wire[7:0] wval = 119; + wire[7:0] x = "\x2A"; // hex escape + wire[7:0] xval = 42; + wire[7:0] y = "\y"; + wire[7:0] yval = 121; + wire[7:0] z = "\z"; + wire[7:0] zval = 122; + + wire[7:0] ob = "\{"; + wire[7:0] obval = 123; + wire[7:0] vb = "\|"; + wire[7:0] vbval = 124; + wire[7:0] cb = "\}"; + wire[7:0] cbval = 125; + wire[7:0] ti = "\~"; + wire[7:0] tival = 126; +endmodule +EOF +sat -prove sp spval -prove ex exval -prove dq dqval -prove ha haval -prove do doval -prove pc pcval -prove am amval -prove sq sqval -prove op opval -prove cp cpval -prove as asval -prove pl plval -prove co coval -prove mi mival -prove do doval -prove sl slval -verify +sat -prove dig0 dig0val -prove dig8 dig8val -prove dig9 dig9val -verify +sat -prove cl clval -prove sc scval -prove lt ltval -prove eq eqval -prove gt gtval -prove qu quval -prove at atval -prove A Aval -verify +sat -prove os osval -prove bs bsval -prove cs csval -prove ca caval -prove us usval -prove bq bqval -verify +sat -prove a aval -prove b bval -prove c cval -prove d dval -prove e eval -prove f fval -prove g gval -prove h hval -prove i ival -prove j jval -prove k kval -prove l lval -prove m mval -prove n nval -prove o oval -prove p pval -prove q qval -prove r rval -prove s sval -prove t tval -prove u uval -prove v vval -prove w wval -prove x xval -prove y yval -prove z zval -verify +sat -prove ob obval -prove vb vbval -prove cb cbval -prove ti tival -verify +logger -check-expected +design -reset + +# Test octal escape out of range. +logger -expect warning "octal escape exceeds \\377" 1 +read_verilog << EOF +module top; + wire[7:0] x = "\400"; +endmodule +EOF +logger -check-expected +design -reset + +# Test invalid octal digit. +logger -expect warning "'\?' not a valid digit in octal escape sequence" 1 +read_verilog << EOF +module top; + wire[7:0] x = "\0?"; +endmodule +EOF +logger -check-expected +design -reset + +# Test invalid hex digit. +logger -expect warning "'X' not a valid digit in hex escape sequence" 1 +read_verilog << EOF +module top; + wire[7:0] x = "\x0X"; +endmodule +EOF +logger -check-expected +design -reset + +# Test hex escape with no hex digits at all. +logger -expect warning "ignoring invalid hex escape" 1 +read_verilog << EOF +module top; + wire[7:0] x = "\xy"; +endmodule +EOF +logger -check-expected +design -reset + +# Test hex escape interrupted by end of string. +logger -expect warning "ignoring invalid hex escape" 1 +read_verilog << EOF +module top; + wire[7:0] x = "\x"; +endmodule +EOF +logger -check-expected +design -reset + +# Test multi-line string. +logger -expect warning "Multi-line string literals should be triple-quoted or escaped" 1 +read_verilog << EOF +module top; + wire[31:0] x = "A +BC"; + wire[31:0] xval = 32'h410A4243; +endmodule +EOF +logger -check-expected +design -reset + +# Test multi-line triple-quoted string. +logger -expect-no-warnings +read_verilog << EOF +module top; + wire[31:0] x = """A +BC"""; + wire[31:0] xval = 32'h410A4243; +endmodule +EOF +logger -check-expected +sat -prove x xval -verify +design -reset + +# Test escaped multi-line string. +logger -expect-no-warnings +read_verilog << EOF +module top; + wire[31:0] x = "AB\ +CD"; + wire[31:0] xval = 32'h41424344; +endmodule +EOF +logger -check-expected +sat -prove x xval -verify +design -reset + +# Test octal escape with surrounding data. +logger -expect-no-warnings +read_verilog << EOF +module top; + wire[31:0] x = "AB\234C"; + wire[31:0] xval = 32'h41429C43; +endmodule +EOF +logger -check-expected +sat -prove x xval -verify +design -reset + +# Test hex escape with surrounding data. +logger -expect-no-warnings +read_verilog << EOF +module top; + wire[31:0] x = "A\xBCDE"; + wire[31:0] xval = 32'h41BC4445; +endmodule +EOF +logger -check-expected +sat -prove x xval -verify From ca241696593dfd865ef0e4a82fba069d393ec559 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 10 Jul 2025 23:59:54 +0200 Subject: [PATCH 23/38] verilog: fix build dependency graph --- frontends/verilog/Makefile.inc | 1 + 1 file changed, 1 insertion(+) diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc index 67e8074bf..3f937f3c2 100644 --- a/frontends/verilog/Makefile.inc +++ b/frontends/verilog/Makefile.inc @@ -10,6 +10,7 @@ frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y frontends/verilog/verilog_parser.tab.hh: frontends/verilog/verilog_parser.tab.cc +frontends/verilog/verilog_frontend.o: frontends/verilog/verilog_parser.tab.hh frontends/verilog/preproc.o: frontends/verilog/verilog_parser.tab.hh frontends/verilog/verilog_lexer.h: frontends/verilog/verilog_parser.tab.hh From 26e592e798604b68955b74df7d119c47ce9bdee7 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 14 Jul 2025 21:45:41 +0200 Subject: [PATCH 24/38] CI: sneak FlexLexer.h into the WASI sysroot --- .github/workflows/extra-builds.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/extra-builds.yml b/.github/workflows/extra-builds.yml index d7ceb3fe3..521f8c61d 100644 --- a/.github/workflows/extra-builds.yml +++ b/.github/workflows/extra-builds.yml @@ -72,6 +72,7 @@ jobs: cat > build/Makefile.conf < Date: Mon, 14 Jul 2025 22:14:11 +0200 Subject: [PATCH 25/38] CI: bump flex and bison on Windows --- .github/workflows/wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index b01ce6b3a..e2b3c2349 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -79,7 +79,7 @@ jobs: - if: ${{ matrix.os.family == 'windows' }} name: "[Windows] Flex/Bison" run: | - choco install winflexbison3 + choco install winflexbison3 --source https://github.com/lexxmark/winflexbison/releases/download/v2.5.25/win_flex_bison-2.5.25.zip - if: ${{ matrix.os.family == 'macos' && matrix.os.archs == 'arm64' }} name: "[macOS/arm64] Install Python 3.8 (see: https://cibuildwheel.pypa.io/en/stable/faq/#macos-building-cpython-38-wheels-on-arm64)" uses: actions/setup-python@v5 From b5be4b92091eb843662d748e8ba381a216157fab Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 14 Jul 2025 22:16:46 +0200 Subject: [PATCH 26/38] fixup! CI: sneak FlexLexer.h into the WASI sysroot --- .github/workflows/extra-builds.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/extra-builds.yml b/.github/workflows/extra-builds.yml index 521f8c61d..0767b1721 100644 --- a/.github/workflows/extra-builds.yml +++ b/.github/workflows/extra-builds.yml @@ -67,12 +67,12 @@ jobs: WASI_SDK=wasi-sdk-19.0 WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz if ! [ -d ${WASI_SDK} ]; then curl -L ${WASI_SDK_URL} | tar xzf -; fi + ln -s /usr/include/FlexLexer.h ${WASI_SDK}/share/wasi-sysroot/include/ mkdir -p build cat > build/Makefile.conf < Date: Thu, 17 Jul 2025 12:03:39 +0000 Subject: [PATCH 27/38] CI: install flex for WASI builds. --- .github/workflows/extra-builds.yml | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/.github/workflows/extra-builds.yml b/.github/workflows/extra-builds.yml index 0767b1721..c4f6cc51f 100644 --- a/.github/workflows/extra-builds.yml +++ b/.github/workflows/extra-builds.yml @@ -33,13 +33,13 @@ jobs: with: name: vcxsrc path: yosys-win32-vcxsrc-latest.zip - + vs-build: name: Visual Studio build runs-on: windows-latest needs: [vs-prep, pre_job] if: needs.pre_job.outputs.should_skip != 'true' - steps: + steps: - uses: actions/download-artifact@v4 with: name: vcxsrc @@ -67,11 +67,21 @@ jobs: WASI_SDK=wasi-sdk-19.0 WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz if ! [ -d ${WASI_SDK} ]; then curl -L ${WASI_SDK_URL} | tar xzf -; fi - ln -s /usr/include/FlexLexer.h ${WASI_SDK}/share/wasi-sysroot/include/ + + FLEX_VER=2.6.4 + FLEX=flex-${FLEX_VER} + FLEX_URL=https://github.com/westes/flex/releases/download/v${FLEX_VER}/${FLEX}.tar.gz + if ! [ -d ${FLEX} ]; then curl -L ${FLEX_URL} | tar xzf -; fi + + mkdir -p flex-build + (cd flex-build && + ../${FLEX}/configure --prefix=$(pwd)/../flex-prefix && + make && + make install) mkdir -p build cat > build/Makefile.conf < Date: Thu, 17 Jul 2025 12:15:47 +0000 Subject: [PATCH 28/38] CI: fix typo --- .github/workflows/extra-builds.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/extra-builds.yml b/.github/workflows/extra-builds.yml index c4f6cc51f..a1ff62604 100644 --- a/.github/workflows/extra-builds.yml +++ b/.github/workflows/extra-builds.yml @@ -81,7 +81,7 @@ jobs: mkdir -p build cat > build/Makefile.conf < Date: Wed, 16 Jul 2025 11:52:46 +1200 Subject: [PATCH 29/38] Sneak FlexLexer.h into VS build --- .github/workflows/extra-builds.yml | 1 + misc/create_vcxsrc.sh | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/.github/workflows/extra-builds.yml b/.github/workflows/extra-builds.yml index a1ff62604..3bbb55110 100644 --- a/.github/workflows/extra-builds.yml +++ b/.github/workflows/extra-builds.yml @@ -27,6 +27,7 @@ jobs: with: submodules: true persist-credentials: false + - run: sudo apt-get install libfl-dev - name: Build run: make vcxsrc YOSYS_VER=latest - uses: actions/upload-artifact@v4 diff --git a/misc/create_vcxsrc.sh b/misc/create_vcxsrc.sh index d7b516fd6..31bea8a36 100644 --- a/misc/create_vcxsrc.sh +++ b/misc/create_vcxsrc.sh @@ -20,6 +20,13 @@ mv zlib-1.2.11/* "$vcxsrc"/yosys/libs/zlib/. rm -rf zlib-1.2.11 pushd "$vcxsrc"/yosys ls libs/zlib/*.c | sed 's,.*:,,; s,//*,/,g; s,/[^/]*/\.\./,/,g; y, \\,\n\n,;' | grep '^[^/]' >> ../../srcfiles.txt + +if [ -f "/usr/include/FlexLexer.h" ] ; then + mkdir -p libs/flex + cp /usr/include/FlexLexer.h libs/flex/FlexLexer.h + ls libs/flex/*.h >> ../../srcfiles.txt +fi + popd { n=$(grep -B999 '' "$vcxsrc"/YosysVS/YosysVS.vcxproj | wc -l) From 8044b558e6fb35d9d5c28a0d70003f2cf124a4ef Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 16 Jul 2025 13:48:31 +1200 Subject: [PATCH 30/38] Add flex lib to vcxsrc include dirs --- misc/create_vcxsrc.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/misc/create_vcxsrc.sh b/misc/create_vcxsrc.sh index 31bea8a36..d6800d15e 100644 --- a/misc/create_vcxsrc.sh +++ b/misc/create_vcxsrc.sh @@ -38,6 +38,9 @@ popd } > "$vcxsrc"/YosysVS/YosysVS.vcxproj.new sed -i 's,,\n stdcpp17\n /Zc:__cplusplus %(AdditionalOptions),g' "$vcxsrc"/YosysVS/YosysVS.vcxproj.new +if [ -f "/usr/include/FlexLexer.h" ] ; then + sed -i 's,,;..\\yosys\\libs\\flex,g' "$vcxsrc"/YosysVS/YosysVS.vcxproj.new +fi mv "$vcxsrc"/YosysVS/YosysVS.vcxproj.new "$vcxsrc"/YosysVS/YosysVS.vcxproj mkdir -p "$vcxsrc"/yosys From 112b22728d79025cc0bf2d35b8d7aa67ff17acf2 Mon Sep 17 00:00:00 2001 From: Emil J Date: Sat, 19 Jul 2025 22:21:17 +0200 Subject: [PATCH 31/38] rtlil: remove comment Co-authored-by: KrystalDelusion <93062060+KrystalDelusion@users.noreply.github.com> --- kernel/rtlil.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index d0355311d..2cdcc8bb2 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5704,7 +5704,6 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri { cover("kernel.rtlil.sigspec.parse"); - // AST::current_filename = "input"; std::vector tokens; sigspec_parse_split(tokens, str, ','); From 540623a5135a7c696c04f58bbeeac88304169261 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Sat, 19 Jul 2025 22:39:55 +0200 Subject: [PATCH 32/38] Revert "CI: bump flex and bison on Windows" This reverts commit efbc138ced04e2fc9cff67b8ca7a862cdd7b4278. --- .github/workflows/wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index e2b3c2349..b01ce6b3a 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -79,7 +79,7 @@ jobs: - if: ${{ matrix.os.family == 'windows' }} name: "[Windows] Flex/Bison" run: | - choco install winflexbison3 --source https://github.com/lexxmark/winflexbison/releases/download/v2.5.25/win_flex_bison-2.5.25.zip + choco install winflexbison3 - if: ${{ matrix.os.family == 'macos' && matrix.os.archs == 'arm64' }} name: "[macOS/arm64] Install Python 3.8 (see: https://cibuildwheel.pypa.io/en/stable/faq/#macos-building-cpython-38-wheels-on-arm64)" uses: actions/setup-python@v5 From 6e011d19485e318e080cc228d08b99807f4c0e17 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Sat, 19 Jul 2025 22:40:45 +0200 Subject: [PATCH 33/38] fixup! readme, verilog_parser: bison 3.8 and ubuntu 22.04 example --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 63408d4aa..229087b3d 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ Xdot (graphviz) is used by the ``show`` command in yosys to display schematics. For example on Ubuntu Linux 22.04 LTS the following commands will install all prerequisites for building yosys: - $ sudo apt-get install build-essential clang lld bison flex \ + $ sudo apt-get install build-essential clang lld bison flex libfl-dev \ libreadline-dev gawk tcl-dev libffi-dev git \ graphviz xdot pkg-config python3 libboost-system-dev \ libboost-python-dev libboost-filesystem-dev zlib1g-dev From 66a9fc9fe095fb77fae828fd08be3d3d9770119e Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Sat, 19 Jul 2025 22:45:19 +0200 Subject: [PATCH 34/38] preproc: formatting --- frontends/verilog/preproc.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/frontends/verilog/preproc.h b/frontends/verilog/preproc.h index 51562787a..fd2e99f3d 100644 --- a/frontends/verilog/preproc.h +++ b/frontends/verilog/preproc.h @@ -73,12 +73,12 @@ struct define_map_t; std::string frontend_verilog_preproc(std::istream &f, - std::string filename, - const define_map_t &pre_defines, - define_map_t &global_defines_cache, - const std::list &include_dirs, - VERILOG_FRONTEND::ParseState &parse_state, - VERILOG_FRONTEND::ParseMode &parse_mode); + std::string filename, + const define_map_t &pre_defines, + define_map_t &global_defines_cache, + const std::list &include_dirs, + VERILOG_FRONTEND::ParseState &parse_state, + VERILOG_FRONTEND::ParseMode &parse_mode); YOSYS_NAMESPACE_END From 588c5d5a576c4cfdad47fbbe7dad9c958aae1269 Mon Sep 17 00:00:00 2001 From: Emil J Date: Sat, 19 Jul 2025 22:46:17 +0200 Subject: [PATCH 35/38] verilog_lexer: remove comment Co-authored-by: KrystalDelusion <93062060+KrystalDelusion@users.noreply.github.com> --- frontends/verilog/verilog_lexer.l | 2 -- 1 file changed, 2 deletions(-) diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index ea6a554dc..9f276b763 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -83,8 +83,6 @@ YOSYS_NAMESPACE_END string_t val = std::make_unique(std::string("\\") + YYText()); \ return parser::make_TOK_ID(std::move(val), out_loc); -// #define YY_INPUT(buf,result,max_size) \ -// result = readsome(*extra->lexin, buf, max_size) #define YY_USER_ACTION \ out_loc.step(); \ From 6b59d052823a65bac33be13e754ae0f3c27f59a5 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Sat, 19 Jul 2025 22:53:02 +0200 Subject: [PATCH 36/38] verilog_lexer: fix fallthrough warning --- frontends/verilog/verilog_lexer.l | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 9f276b763..a1e846991 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -67,7 +67,7 @@ YOSYS_NAMESPACE_BEGIN #define YY_DECL parser::symbol_type VerilogLexer::nextToken() #undef yyterminate -#define yyterminate() terminate() +#define yyterminate() return terminate() YOSYS_NAMESPACE_END From e77252ce8d657f7eea3eb0aa60d66acab652df46 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Sat, 19 Jul 2025 22:56:48 +0200 Subject: [PATCH 37/38] verilog_lexer, verilog_parser: remove comment --- frontends/verilog/verilog_lexer.l | 2 -- frontends/verilog/verilog_parser.y | 9 --------- 2 files changed, 11 deletions(-) diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index a1e846991..bd1316e23 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -59,8 +59,6 @@ USING_YOSYS_NAMESPACE using namespace AST; using namespace VERILOG_FRONTEND; using parser = frontend_verilog_yy::parser; -//#define YYSTYPE FRONTEND_VERILOG_YYSTYPE -//#define YYLTYPE FRONTEND_VERILOG_YYLTYPE YOSYS_NAMESPACE_BEGIN #undef YY_DECL diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 0d068d2ed..085c7ce74 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -49,7 +49,6 @@ #include "kernel/yosys_common.h" #include "frontends/verilog/verilog_error.h" #include "frontends/verilog/verilog_location.h" - // start requires YOSYS_NAMESPACE_BEGIN namespace VERILOG_FRONTEND { struct ParseState; @@ -57,11 +56,9 @@ class VerilogLexer; }; YOSYS_NAMESPACE_END - // end requires } %code provides { - // start provides USING_YOSYS_NAMESPACE; using namespace AST; using namespace VERILOG_FRONTEND; @@ -70,7 +67,6 @@ namespace VERILOG_FRONTEND { typedef std::map UserTypeMap; struct ParseState { - // TODO initialization? int port_counter; dict port_stubs; dict> *attr_list, default_attr_list; @@ -122,11 +118,9 @@ }; }; YOSYS_NAMESPACE_END - // end provides } %code { - // start unqual #include #include #include @@ -430,11 +424,9 @@ { err_at_loc(loc, "%s", msg.c_str()); } - // end unqual } %code requires { - // start requires #include #include #include @@ -480,7 +472,6 @@ using ch_t = char; using integer_t = int; using ast_node_type_t = YOSYS_NAMESPACE_PREFIX AST::AstNodeType; - // end requires } %token string_t "string" From 7047bc26b30aeedfb333be47fc8a3d36ce43ba8e Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Sat, 19 Jul 2025 22:57:53 +0200 Subject: [PATCH 38/38] preproc: formatting --- frontends/verilog/preproc.cc | 4 ++-- frontends/verilog/preproc.h | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc index b83fad7c3..6dff1b6fc 100644 --- a/frontends/verilog/preproc.cc +++ b/frontends/verilog/preproc.cc @@ -751,8 +751,8 @@ frontend_verilog_preproc(std::istream &f, const define_map_t &pre_defines, define_map_t &global_defines_cache, const std::list &include_dirs, - ParseState &parse_state, - ParseMode &parse_mode) + ParseState &parse_state, + ParseMode &parse_mode) { define_map_t defines; defines.merge(pre_defines); diff --git a/frontends/verilog/preproc.h b/frontends/verilog/preproc.h index fd2e99f3d..8333f7661 100644 --- a/frontends/verilog/preproc.h +++ b/frontends/verilog/preproc.h @@ -73,12 +73,12 @@ struct define_map_t; std::string frontend_verilog_preproc(std::istream &f, - std::string filename, - const define_map_t &pre_defines, - define_map_t &global_defines_cache, - const std::list &include_dirs, - VERILOG_FRONTEND::ParseState &parse_state, - VERILOG_FRONTEND::ParseMode &parse_mode); + std::string filename, + const define_map_t &pre_defines, + define_map_t &global_defines_cache, + const std::list &include_dirs, + VERILOG_FRONTEND::ParseState &parse_state, + VERILOG_FRONTEND::ParseMode &parse_mode); YOSYS_NAMESPACE_END