systemverilog-plugin: Adjusting simplify.cc, removing unneded code

Signed-off-by: Magdalena Andrys <mandrys@antmicro.com>
diff --git a/systemverilog-plugin/third_party/yosys/simplify.cc b/systemverilog-plugin/third_party/yosys/simplify.cc
index 78e5768..71d15a4 100644
--- a/systemverilog-plugin/third_party/yosys/simplify.cc
+++ b/systemverilog-plugin/third_party/yosys/simplify.cc
@@ -28,8 +28,8 @@
 
 #include "kernel/log.h"
 #include "libs/sha1/sha1.h"
-#include "frontends/verilog/verilog_frontend.h"
-#include "ast.h"
+
+#include "const2ast.h"
 
 #include <sstream>
 #include <stdarg.h>
@@ -37,149 +37,22 @@
 #include <math.h>
 
 YOSYS_NAMESPACE_BEGIN
-
-using namespace AST;
-using namespace AST_INTERNAL;
-
-// Process a format string and arguments for $display, $write, $sprintf, etc
-
-std::string AstNode::process_format_str(const std::string &sformat, int next_arg, int stage, int width_hint, bool sign_hint) {
-	// Other arguments are placeholders. Process the string as we go through it
-	std::string sout;
-	for (size_t i = 0; i < sformat.length(); i++)
-	{
-		// format specifier
-		if (sformat[i] == '%')
-		{
-			// If there's no next character, that's a problem
-			if (i+1 >= sformat.length())
-				log_file_error(filename, location.first_line, "System task `%s' called with `%%' at end of string.\n", str.c_str());
-
-			char cformat = sformat[++i];
-
-			// %% is special, does not need a matching argument
-			if (cformat == '%')
-			{
-				sout += '%';
-				continue;
-			}
-
-			bool got_len = false;
-			bool got_zlen = false;
-			int len_value = 0;
-
-			while ('0' <= cformat && cformat <= '9')
-			{
-				if (!got_len && cformat == '0')
-					got_zlen = true;
-
-				got_len = true;
-				len_value = 10*len_value + (cformat - '0');
-
-				cformat = sformat[++i];
-			}
-
-			// Simplify the argument
-			AstNode *node_arg = nullptr;
-
-			// Everything from here on depends on the format specifier
-			switch (cformat)
-			{
-				case 's':
-				case 'S':
-				case 'd':
-				case 'D':
-					if (got_len && len_value != 0)
-						goto unsupported_format;
-					YS_FALLTHROUGH
-				case 'x':
-				case 'X':
-					if (next_arg >= GetSize(children))
-						log_file_error(filename, location.first_line, "Missing argument for %%%c format specifier in system task `%s'.\n",
-								cformat, str.c_str());
-
-					node_arg = children[next_arg++];
-					while (node_arg->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
-					if (node_arg->type != AST_CONSTANT)
-						log_file_error(filename, location.first_line, "Failed to evaluate system task `%s' with non-constant argument.\n", str.c_str());
-					break;
-
-				case 'm':
-				case 'M':
-					if (got_len)
-						goto unsupported_format;
-					break;
-
-				case 'l':
-				case 'L':
-					if (got_len)
-						goto unsupported_format;
-					break;
-
-				default:
-				unsupported_format:
-					log_file_error(filename, location.first_line, "System task `%s' called with invalid/unsupported format specifier.\n", str.c_str());
-					break;
-			}
-
-			switch (cformat)
-			{
-				case 's':
-				case 'S':
-					sout += node_arg->bitsAsConst().decode_string();
-					break;
-
-				case 'd':
-				case 'D':
-					sout += stringf("%d", node_arg->bitsAsConst().as_int());
-					break;
-
-				case 'x':
-				case 'X':
-					{
-						Const val = node_arg->bitsAsConst();
-
-						while (GetSize(val) % 4 != 0)
-							val.bits.push_back(State::S0);
-
-						int len = GetSize(val) / 4;
-						for (int i = len; i < len_value; i++)
-							sout += got_zlen ? '0' : ' ';
-
-						for (int i = len-1; i >= 0; i--) {
-							Const digit = val.extract(4*i, 4);
-							if (digit.is_fully_def())
-								sout += stringf(cformat == 'x' ? "%x" : "%X", digit.as_int());
-							else
-								sout += cformat == 'x' ? "x" : "X";
-						}
-					}
-					break;
-
-				case 'm':
-				case 'M':
-					sout += log_id(current_module->name);
-					break;
-
-				case 'l':
-				case 'L':
-					sout += log_id(current_module->name);
-					break;
-
-				default:
-					log_abort();
-			}
-		}
-
-		// not a format specifier
-		else
-			sout += sformat[i];
-	}
-	return sout;
+namespace VERILOG_FRONTEND
+{
+extern bool sv_mode;
 }
+YOSYS_NAMESPACE_END
 
+namespace systemverilog_plugin
+{
 
-void AstNode::annotateTypedEnums(AstNode *template_node)
+using namespace ::Yosys;
+using namespace ::Yosys::AST;
+using namespace ::Yosys::AST_INTERNAL;
+
+bool simplify(AstNode *ast_node, bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param);
+
+void annotateTypedEnums(AstNode *ast_node, AstNode *template_node)
 {
 	//check if enum
 	if (template_node->attributes.count(ID::enum_type)) {
@@ -192,7 +65,7 @@
 		log_assert(current_scope.count(enum_type) == 1);
 		AstNode *enum_node = current_scope.at(enum_type);
 		log_assert(enum_node->type == AST_ENUM);
-		while (enum_node->simplify(true, false, false, 1, -1, false, true)) { }
+		while (simplify(enum_node, true, false, false, 1, -1, false, true)) { }
 		//get width from 1st enum item:
 		log_assert(enum_node->children.size() >= 1);
 		AstNode *enum_item0 = enum_node->children[0];
@@ -233,7 +106,7 @@
 			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
-			attributes[enum_item_str.c_str()] = mkconst_str(enum_item->str);
+			ast_node->attributes[enum_item_str.c_str()] = AstNode::mkconst_str(enum_item->str);
 		}
 	}
 }
@@ -407,120 +280,7 @@
 	return (is_union ? packed_width : offset);
 }
 
-[[noreturn]] static void struct_op_error(AstNode *node)
-{
-	log_file_error(node->filename, node->location.first_line, "Unsupported operation for struct/union member %s\n", node->str.c_str()+1);
-}
-
-static AstNode *node_int(int ival)
-{
-	return AstNode::mkconst_int(ival, true);
-}
-
-static AstNode *multiply_by_const(AstNode *expr_node, int stride)
-{
-	return new AstNode(AST_MUL, expr_node, node_int(stride));
-}
-
-static AstNode *normalize_struct_index(AstNode *expr, AstNode *member_node, int dimension)
-{
-	expr = expr->clone();
-
-	int offset = get_struct_range_offset(member_node, dimension);
-	if (offset) {
-		expr = new AstNode(AST_SUB, expr, node_int(offset));
-	}
-
-	if (member_node->multirange_swapped[dimension]) {
-		// The dimension has swapped range; swap index into the struct accordingly.
-		int msb = get_struct_range_width(member_node, dimension) - 1;
-		expr = new AstNode(AST_SUB, node_int(msb), expr);
-	}
-
-	return expr;
-}
-
-static AstNode *struct_index_lsb_offset(AstNode *lsb_offset, AstNode *rnode, AstNode *member_node, int dimension, int &stride)
-{
-	stride /= get_struct_range_width(member_node, dimension);
-	auto right = normalize_struct_index(rnode->children.back(), member_node, dimension);
-	auto offset = stride > 1 ? multiply_by_const(right, stride) : right;
-	return lsb_offset ? new AstNode(AST_ADD, lsb_offset, offset) : offset;
-}
-
-static AstNode *struct_index_msb_offset(AstNode *lsb_offset, AstNode *rnode, AstNode *member_node, int dimension, int stride)
-{
-	log_assert(rnode->children.size() <= 2);
-
-	// Offset to add to LSB
-	AstNode *offset;
-	if (rnode->children.size() == 1) {
-		// Index, e.g. s.a[i]
-		offset = node_int(stride - 1);
-	}
-	else {
-		// rnode->children.size() == 2
-		// Slice, e.g. s.a[i:j]
-		auto left = normalize_struct_index(rnode->children[0], member_node, dimension);
-		auto right = normalize_struct_index(rnode->children[1], member_node, dimension);
-		offset = new AstNode(AST_SUB, left, right);
-		if (stride > 1) {
-			// offset = (msb - lsb + 1)*stride - 1
-			auto slice_width = new AstNode(AST_ADD, offset, node_int(1));
-			offset = new AstNode(AST_SUB, multiply_by_const(slice_width, stride), node_int(1));
-		}
-	}
-
-	return new AstNode(AST_ADD, lsb_offset, offset);
-}
-
-
-AstNode *AST::make_struct_member_range(AstNode *node, AstNode *member_node)
-{
-	// 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
-	// such as array indexing or slicing
-	int range_left = member_node->range_left;
-	int range_right = member_node->range_right;
-	if (node->children.empty()) {
-		// no range operations apply, return the whole width
-		return make_range(range_left - range_right, 0);
-	}
-
-	if (node->children.size() != 1) {
-		struct_op_error(node);
-	}
-
-	// Range operations
-	auto rnode = node->children[0];
-	AstNode *lsb_offset = NULL;
-	int stride = range_left - range_right + 1;
-	size_t i = 0;
-
-	// Calculate LSB offset for the final index / slice
-	if (rnode->type == AST_RANGE) {
-		lsb_offset = struct_index_lsb_offset(lsb_offset, rnode, member_node, i, stride);
-	}
-	else if (rnode->type == AST_MULTIRANGE) {
-		// Add offset for each dimension
-		auto mrnode = rnode;
-		for (i = 0; i < mrnode->children.size(); i++) {
-			rnode = mrnode->children[i];
-			lsb_offset = struct_index_lsb_offset(lsb_offset, rnode, member_node, i, stride);
-		}
-		i--;  // Step back to the final index / slice
-	}
-	else {
-		struct_op_error(node);
-	}
-
-	// Calculate MSB offset for the final index / slice
-	auto msb_offset = struct_index_msb_offset(lsb_offset->clone(), rnode, member_node, i, stride);
-
-	return new AstNode(AST_RANGE, msb_offset, lsb_offset);
-}
-
-AstNode *AST::get_struct_member(const AstNode *node)
+AstNode get_struct_member(const AstNode *node)
 {
 	AST::AstNode *member_node;
 	if (node->attributes.count(ID::wiretype) && (member_node = node->attributes.at(ID::wiretype)) &&
@@ -606,84 +366,6 @@
 	return prefix + str;
 }
 
-// direct access to this global should be limited to the following two functions
-static const RTLIL::Design *simplify_design_context = nullptr;
-
-void AST::set_simplify_design_context(const RTLIL::Design *design)
-{
-	log_assert(!simplify_design_context || !design);
-	simplify_design_context = design;
-}
-
-// lookup the module with the given name in the current design context
-static const RTLIL::Module* lookup_module(const std::string &name)
-{
-	return simplify_design_context->module(name);
-}
-
-const RTLIL::Module* AstNode::lookup_cell_module()
-{
-	log_assert(type == AST_CELL);
-
-	auto reprocess_after = [this] (const std::string &modname) {
-		if (!attributes.count(ID::reprocess_after))
-			attributes[ID::reprocess_after] = AstNode::mkconst_str(modname);
-	};
-
-	const AstNode *celltype = nullptr;
-	for (const AstNode *child : children)
-		if (child->type == AST_CELLTYPE) {
-			celltype = child;
-			break;
-		}
-	log_assert(celltype != nullptr);
-
-	const RTLIL::Module *module = lookup_module(celltype->str);
-	if (!module)
-		module = lookup_module("$abstract" + celltype->str);
-	if (!module) {
-		if (celltype->str.at(0) != '$')
-			reprocess_after(celltype->str);
-		return nullptr;
-	}
-
-	// build a mapping from true param name to param value
-	size_t para_counter = 0;
-	dict<RTLIL::IdString, RTLIL::Const> cell_params_map;
-	for (AstNode *child : children) {
-		if (child->type != AST_PARASET)
-			continue;
-
-		if (child->str.empty() && para_counter >= module->avail_parameters.size())
-			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];
-		if (value->type != AST_REALVALUE && value->type != AST_CONSTANT)
-			return nullptr; // let genrtlil handle this error
-		cell_params_map[paraname] = value->asParaConst();
-	}
-
-	// put the parameters in order and generate the derived module name
-	std::vector<std::pair<RTLIL::IdString, RTLIL::Const>> named_parameters;
-	for (RTLIL::IdString param : module->avail_parameters) {
-		auto it = cell_params_map.find(param);
-		if (it != cell_params_map.end())
-			named_parameters.emplace_back(it->first, it->second);
-	}
-	std::string modname = celltype->str;
-	if (cell_params_map.size()) // not named_parameters to cover hierarchical defparams
-		modname = derived_module_name(celltype->str, named_parameters);
-
-	// try to find the resolved module
-	module = lookup_module(modname);
-	if (!module) {
-		reprocess_after(modname);
-		return nullptr;
-	}
-	return module;
-}
-
 // returns whether an expression contains an unbased unsized literal; does not
 // check the literal exists in a self-determined context
 static bool contains_unbased_unsized(const AstNode *node)
@@ -837,6 +519,21 @@
 		check_auto_nosync(child);
 }
 
+static inline std::string encode_filename(const std::string &filename)
+{    
+    std::stringstream val; 
+    if (!std::any_of(filename.begin(), filename.end(), [](char c) { 
+        return static_cast<unsigned char>(c) < 33 || static_cast<unsigned char>(c) > 126; 
+    })) return filename;
+    for (unsigned char const c : filename) {
+        if (c < 33 || c > 126) 
+            val << stringf("$%02x", c);
+        else 
+            val << c;
+    }    
+    return val.str();
+}
+
 // convert the AST into a simpler AST that has all parameters substituted by their
 // values, unrolled for-loops, expanded generate blocks, etc. when this function
 // is done with an AST it can be converted into RTLIL using genRTLIL().
@@ -1280,7 +977,7 @@
 
 				// 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() << "$" << encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++);
 				std::string tmp_str = sstr.str();
 				add_wire_for_ref(ref, tmp_str);
 
@@ -1825,7 +1522,7 @@
 			attributes[ID::wiretype] = mkconst_str(resolved_type_node->str);
 
 			// if an enum then add attributes to support simulator tracing
-			annotateTypedEnums(template_node);
+			annotateTypedEnums(ast_node, template_node);
 
 			// Insert clones children from template at beginning
 			for (int i  = 0; i < GetSize(template_node->children); i++)
@@ -2181,7 +1878,7 @@
 			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 << "$" << 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)));
@@ -2777,14 +2474,14 @@
 			// mask and shift operations, disabled for now
 
 			AstNode *wire_mask = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(source_width-1, true), mkconst_int(0, true)));
-			wire_mask->str = stringf("$bitselwrite$mask$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++);
+			wire_mask->str = stringf("$bitselwrite$mask$%s:%d$%d", encode_filename(filename).c_str(), location.first_line, autoidx++);
 			wire_mask->attributes[ID::nosync] = AstNode::mkconst_int(1, false);
 			wire_mask->is_logic = true;
 			while (wire_mask->simplify(true, false, false, 1, -1, false, false)) { }
 			current_ast_mod->children.push_back(wire_mask);
 
 			AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(source_width-1, true), mkconst_int(0, true)));
-			wire_data->str = stringf("$bitselwrite$data$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++);
+			wire_data->str = stringf("$bitselwrite$data$%s:%d$%d", encode_filename(filename).c_str(), location.first_line, autoidx++);
 			wire_data->attributes[ID::nosync] = AstNode::mkconst_int(1, false);
 			wire_data->is_logic = true;
 			while (wire_data->simplify(true, false, false, 1, -1, false, false)) { }
@@ -2795,7 +2492,7 @@
 			shift_expr->detectSignWidth(shamt_width_hint, shamt_sign_hint);
 
 			AstNode *wire_sel = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(shamt_width_hint-1, true), mkconst_int(0, true)));
-			wire_sel->str = stringf("$bitselwrite$sel$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++);
+			wire_sel->str = stringf("$bitselwrite$sel$%s:%d$%d", encode_filename(filename).c_str(), location.first_line, autoidx++);
 			wire_sel->attributes[ID::nosync] = AstNode::mkconst_int(1, false);
 			wire_sel->is_logic = true;
 			wire_sel->is_signed = shamt_sign_hint;
@@ -2874,7 +2571,7 @@
 	if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME || type == AST_LIVE || type == AST_FAIR || type == AST_COVER) && current_block != NULL)
 	{
 		std::stringstream sstr;
-		sstr << "$formal$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++);
+		sstr << "$formal$" << encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++);
 		std::string id_check = sstr.str() + "_CHECK", id_en = sstr.str() + "_EN";
 
 		AstNode *wire_check = new AstNode(AST_WIRE);
@@ -2983,7 +2680,7 @@
 			newNode = new AstNode(AST_BLOCK);
 
 			AstNode *wire_tmp = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(width_hint-1, true), mkconst_int(0, true)));
-			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", encode_filename(filename).c_str(), location.first_line, autoidx++);
 			current_ast_mod->children.push_back(wire_tmp);
 			current_scope[wire_tmp->str] = wire_tmp;
 			wire_tmp->attributes[ID::nosync] = AstNode::mkconst_int(1, false);
@@ -3021,7 +2718,7 @@
 			(children[0]->children.size() == 1 || children[0]->children.size() == 2) && children[0]->children[0]->type == AST_RANGE)
 	{
 		std::stringstream sstr;
-		sstr << "$memwr$" << children[0]->str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++);
+		sstr << "$memwr$" << children[0]->str << "$" << encode_filename(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;
@@ -3293,7 +2990,7 @@
 					AstNode *reg = new AstNode(AST_WIRE, new AstNode(AST_RANGE,
 							mkconst_int(width_hint-1, true), mkconst_int(0, true)));
 
-					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", encode_filename(filename).c_str(), location.first_line, myidx, i);
 					reg->is_reg = true;
 					reg->is_signed = sign_hint;
 
@@ -3828,7 +3525,7 @@
 
 
 		std::stringstream sstr;
-		sstr << str << "$func$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++) << '.';
+		sstr << str << "$func$" << encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++) << '.';
 		std::string prefix = sstr.str();
 
 		AstNode *decl = current_scope[str];
@@ -4375,1300 +4072,4 @@
 	return did_something;
 }
 
-void AstNode::replace_result_wire_name_in_function(const std::string &from, const std::string &to)
-{
-	for (AstNode *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)
-{
-	int mem_width, mem_size, addr_bits;
-	memory->meminfo(mem_width, mem_size, addr_bits);
-
-	AstNode *block = new AstNode(AST_BLOCK);
-
-	AstNode *meminit = nullptr;
-	int next_meminit_cursor=0;
-	vector<State> meminit_bits;
-	vector<State> en_bits;
-	int meminit_size=0;
-
-	for (int i = 0; i < mem_width; i++)
-		en_bits.push_back(State::S1);
-
-	std::ifstream f;
-	f.open(mem_filename.c_str());
-	if (f.fail()) {
-#ifdef _WIN32
-		char slash = '\\';
-#else
-		char slash = '/';
-#endif
-		std::string path = filename.substr(0, filename.find_last_of(slash)+1);
-		f.open(path + mem_filename.c_str());
-		yosys_input_files.insert(path + mem_filename);
-	} else {
-		yosys_input_files.insert(mem_filename);
-	}
-	if (f.fail() || GetSize(mem_filename) == 0)
-		log_file_error(filename, location.first_line, "Can not open file `%s` for %s.\n", mem_filename.c_str(), str.c_str());
-
-	log_assert(GetSize(memory->children) == 2 && memory->children[1]->type == AST_RANGE && memory->children[1]->range_valid);
-	int range_left =  memory->children[1]->range_left, range_right =  memory->children[1]->range_right;
-	int range_min = min(range_left, range_right), range_max = max(range_left, range_right);
-
-	if (start_addr < 0)
-		start_addr = range_min;
-
-	if (finish_addr < 0)
-		finish_addr = range_max + 1;
-
-	bool in_comment = false;
-	int increment = start_addr <= finish_addr ? +1 : -1;
-	int cursor = start_addr;
-
-	while (!f.eof())
-	{
-		std::string line, token;
-		std::getline(f, line);
-
-		for (int i = 0; i < GetSize(line); i++) {
-			if (in_comment && line.compare(i, 2, "*/") == 0) {
-				line[i] = ' ';
-				line[i+1] = ' ';
-				in_comment = false;
-				continue;
-			}
-			if (!in_comment && line.compare(i, 2, "/*") == 0)
-				in_comment = true;
-			if (in_comment)
-				line[i] = ' ';
-		}
-
-		while (1)
-		{
-			token = next_token(line, " \t\r\n");
-			if (token.empty() || token.compare(0, 2, "//") == 0)
-				break;
-
-			if (token[0] == '@') {
-				token = token.substr(1);
-				const char *nptr = token.c_str();
-				char *endptr;
-				cursor = strtol(nptr, &endptr, 16);
-				if (!*nptr || *endptr)
-					log_file_error(filename, location.first_line, "Can not parse address `%s` for %s.\n", nptr, str.c_str());
-				continue;
-			}
-
-			AstNode *value = VERILOG_FRONTEND::const2ast(stringf("%d'%c", mem_width, is_readmemh ? 'h' : 'b') + token);
-
-			if (unconditional_init)
-			{
-				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 = new AstNode(AST_MEMINIT);
-					meminit->children.push_back(AstNode::mkconst_int(cursor, false));
-					meminit->children.push_back(nullptr);
-					meminit->children.push_back(AstNode::mkconst_bits(en_bits, false));
-					meminit->children.push_back(nullptr);
-					meminit->str = memory->str;
-					meminit->id2ast = memory;
-					meminit_bits.clear();
-					meminit_size = 0;
-
-					current_ast_mod->children.push_back(meminit);
-					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.back()->children[0]->str = memory->str;
-				block->children.back()->children[0]->id2ast = memory;
-				block->children.back()->children[0]->was_checked = true;
-			}
-
-			cursor += increment;
-			if ((cursor == finish_addr+increment) || (increment > 0 && cursor > range_max) || (increment < 0 && cursor < range_min))
-				break;
-		}
-
-		if ((cursor == finish_addr+increment) || (increment > 0 && cursor > range_max) || (increment < 0 && cursor < range_min))
-			break;
-	}
-
-	if (meminit != nullptr) {
-		meminit->children[1] = AstNode::mkconst_bits(meminit_bits, false);
-		meminit->children[3] = AstNode::mkconst_int(meminit_size, false);
-	}
-
-	return block;
-}
-
-// annotate the names of all wires and other named objects in a named generate
-// or procedural block; nested blocks are themselves annotated such that the
-// prefix is carried forward, but resolution of their children is deferred
-void AstNode::expand_genblock(const std::string &prefix)
-{
-	if (type == AST_IDENTIFIER || type == AST_FCALL || type == AST_TCALL || type == AST_WIRETYPE || type == AST_PREFIX) {
-		log_assert(!str.empty());
-
-		// search starting in the innermost scope and then stepping outward
-		for (size_t ppos = prefix.size() - 1; ppos; --ppos) {
-			if (prefix.at(ppos) != '.') continue;
-
-			std::string new_prefix = prefix.substr(0, ppos + 1);
-			auto attempt_resolve = [&new_prefix](const std::string &ident) -> std::string {
-				std::string new_name = prefix_id(new_prefix, ident);
-				if (current_scope.count(new_name))
-					return new_name;
-				return {};
-			};
-
-			// attempt to resolve the full identifier
-			std::string resolved = attempt_resolve(str);
-			if (!resolved.empty()) {
-				str = resolved;
-				break;
-			}
-
-			// attempt to resolve hierarchical prefixes within the identifier,
-			// as the prefix could refer to a local scope which exists but
-			// hasn't yet been elaborated
-			for (size_t spos = str.size() - 1; spos; --spos) {
-				if (str.at(spos) != '.') continue;
-				resolved = attempt_resolve(str.substr(0, spos));
-				if (!resolved.empty()) {
-					str = resolved + str.substr(spos);
-					ppos = 1; // break outer loop
-					break;
-				}
-			}
-
-		}
-	}
-
-	auto prefix_node = [&prefix](AstNode* child) {
-		if (child->str.empty()) return;
-		std::string new_name = prefix_id(prefix, child->str);
-		if (child->type == AST_FUNCTION)
-			child->replace_result_wire_name_in_function(child->str, new_name);
-		else
-			child->str = new_name;
-		current_scope[new_name] = child;
-	};
-
-	for (size_t i = 0; i < children.size(); i++) {
-		AstNode *child = children[i];
-
-		switch (child->type) {
-		case AST_WIRE:
-		case AST_MEMORY:
-		case AST_PARAMETER:
-		case AST_LOCALPARAM:
-		case AST_FUNCTION:
-		case AST_TASK:
-		case AST_CELL:
-		case AST_TYPEDEF:
-		case AST_ENUM_ITEM:
-		case AST_GENVAR:
-			prefix_node(child);
-			break;
-
-		case AST_BLOCK:
-		case AST_GENBLOCK:
-			if (!child->str.empty())
-				prefix_node(child);
-			break;
-
-		case AST_ENUM:
-			current_scope[child->str] = child;
-			for (auto enode : child->children){
-				log_assert(enode->type == AST_ENUM_ITEM);
-				prefix_node(enode);
-			}
-			break;
-
-		default:
-			break;
-		}
-	}
-
-	for (size_t i = 0; i < children.size(); i++) {
-		AstNode *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
-		if (type == AST_PREFIX && i == 1) {
-			std::string backup_scope_name = child->str;
-			child->expand_genblock(prefix);
-			child->str = backup_scope_name;
-			continue;
-		}
-		// functions/tasks may reference wires, constants, etc. in this scope
-		if (child->type == AST_FUNCTION || child->type == AST_TASK)
-			continue;
-		// named blocks pick up the current prefix and will expanded later
-		if ((child->type == AST_GENBLOCK || child->type == AST_BLOCK) && !child->str.empty())
-			continue;
-
-		child->expand_genblock(prefix);
-	}
-}
-
-// add implicit AST_GENBLOCK names according to IEEE 1364-2005 Section 12.4.3 or
-// IEEE 1800-2017 Section 27.6
-void AstNode::label_genblks(std::set<std::string>& existing, int &counter)
-{
-	switch (type) {
-	case AST_GENIF:
-	case AST_GENFOR:
-	case AST_GENCASE:
-		// seeing a proper generate control flow construct increments the
-		// counter once
-		++counter;
-		for (AstNode *child : children)
-			child->label_genblks(existing, counter);
-		break;
-
-	case AST_GENBLOCK: {
-		// if this block is unlabeled, generate its corresponding unique name
-		for (int padding = 0; str.empty(); ++padding) {
-			std::string candidate = "\\genblk";
-			for (int i = 0; i < padding; ++i)
-				candidate += '0';
-			candidate += std::to_string(counter);
-			if (!existing.count(candidate))
-				str = candidate;
-		}
-		// within a genblk, the counter starts fresh
-		std::set<std::string> existing_local = existing;
-		int counter_local = 0;
-		for (AstNode *child : children)
-			child->label_genblks(existing_local, counter_local);
-		break;
-	}
-
-	default:
-		// track names which could conflict with implicit genblk names
-		if (str.rfind("\\genblk", 0) == 0)
-			existing.insert(str);
-		for (AstNode *child : children)
-			child->label_genblks(existing, counter);
-		break;
-	}
-}
-
-// helper function for mem2reg_as_needed_pass1
-static void mark_memories_assign_lhs_complex(dict<AstNode*, pool<std::string>> &mem2reg_places,
-		dict<AstNode*, uint32_t> &mem2reg_candidates, AstNode *that)
-{
-	for (auto &child : that->children)
-		mark_memories_assign_lhs_complex(mem2reg_places, mem2reg_candidates, child);
-
-	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_candidates[mem] |= AstNode::MEM2REG_FL_CMPLX_LHS;
-	}
-}
-
-// find memories that should be replaced by registers
-void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg_places,
-		dict<AstNode*, uint32_t> &mem2reg_candidates, dict<AstNode*, uint32_t> &proc_flags, uint32_t &flags)
-{
-	uint32_t children_flags = 0;
-	int lhs_children_counter = 0;
-
-	if (type == AST_TYPEDEF)
-		return; // don't touch content of typedefs
-
-	if (type == AST_ASSIGN || type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ)
-	{
-		// 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);
-
-		if (children[0]->type == AST_IDENTIFIER && children[0]->id2ast && children[0]->id2ast->type == AST_MEMORY)
-		{
-			AstNode *mem = children[0]->id2ast;
-
-			// 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_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));
-				proc_flags[mem] |= AstNode::MEM2REG_FL_EQ1;
-			}
-
-			// for proper (non-init) writes: remember if this is a constant index or not
-			if ((flags & MEM2REG_FL_INIT) == 0) {
-				if (children[0]->children.size() && children[0]->children[0]->type == AST_RANGE && children[0]->children[0]->children.size()) {
-					if (children[0]->children[0]->children[0]->type == AST_CONSTANT)
-						mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_CONST_LHS;
-					else
-						mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_VAR_LHS;
-				}
-			}
-
-			// 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_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_candidates[mem] |= AstNode::MEM2REG_FL_SET_ELSE;
-			}
-		}
-
-		lhs_children_counter = 1;
-	}
-
-	if (type == AST_IDENTIFIER && id2ast && id2ast->type == AST_MEMORY)
-	{
-		AstNode *mem = id2ast;
-
-		// 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_candidates[mem] |= AstNode::MEM2REG_FL_EQ2;
-		}
-	}
-
-	// also activate if requested, either by using mem2reg attribute or by declaring array as 'wire' instead of 'reg' or 'logic'
-	if (type == AST_MEMORY && (get_bool_attribute(ID::mem2reg) || (flags & AstNode::MEM2REG_FL_ALL) || !(is_reg || is_logic)))
-		mem2reg_candidates[this] |= AstNode::MEM2REG_FL_FORCED;
-
-	if ((type == AST_MODULE || type == AST_INTERFACE) && get_bool_attribute(ID::mem2reg))
-		children_flags |= AstNode::MEM2REG_FL_ALL;
-
-	dict<AstNode*, uint32_t> *proc_flags_p = NULL;
-
-	if (type == AST_ALWAYS) {
-		int count_edge_events = 0;
-		for (auto child : children)
-			if (child->type == AST_POSEDGE || child->type == AST_NEGEDGE)
-				count_edge_events++;
-		if (count_edge_events != 1)
-			children_flags |= AstNode::MEM2REG_FL_ASYNC;
-		proc_flags_p = new dict<AstNode*, uint32_t>;
-	}
-	else if (type == AST_INITIAL) {
-		children_flags |= AstNode::MEM2REG_FL_INIT;
-		proc_flags_p = new dict<AstNode*, uint32_t>;
-	}
-
-	uint32_t backup_flags = flags;
-	flags |= children_flags;
-	log_assert((flags & ~0x000000ff) == 0);
-
-	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) {
-					if (proc_flags_p)
-						c->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, *proc_flags_p, flags);
-					else
-						c->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, proc_flags, flags);
-				}
-			}
-		} else
-		if (proc_flags_p)
-			child->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, *proc_flags_p, flags);
-		else
-			child->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, proc_flags, flags);
-	}
-
-	flags &= ~children_flags | backup_flags;
-
-	if (proc_flags_p) {
-#ifndef NDEBUG
-		for (auto it : *proc_flags_p)
-			log_assert((it.second & ~0xff000000) == 0);
-#endif
-		delete proc_flags_p;
-	}
-}
-
-bool AstNode::mem2reg_check(pool<AstNode*> &mem2reg_set)
-{
-	if (type != AST_IDENTIFIER || !id2ast || !mem2reg_set.count(id2ast))
-		return false;
-
-	if (children.empty() || children[0]->type != AST_RANGE || GetSize(children[0]->children) != 1)
-		log_file_error(filename, location.first_line, "Invalid array access.\n");
-
-	return true;
-}
-
-void AstNode::mem2reg_remove(pool<AstNode*> &mem2reg_set, vector<AstNode*> &delnodes)
-{
-	log_assert(mem2reg_set.count(this) == 0);
-
-	if (mem2reg_set.count(id2ast))
-		id2ast = nullptr;
-
-	for (size_t i = 0; i < children.size(); i++) {
-		if (mem2reg_set.count(children[i]) > 0) {
-			delnodes.push_back(children[i]);
-			children.erase(children.begin() + (i--));
-		} else {
-			children[i]->mem2reg_remove(mem2reg_set, delnodes);
-		}
-	}
-}
-
-// actually replace memories with registers
-bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block, AstNode *&async_block)
-{
-	bool did_something = false;
-
-	if (type == AST_BLOCK)
-		block = this;
-
-	if (type == AST_FUNCTION || type == AST_TASK)
-		return false;
-
-	if (type == AST_TYPEDEF)
-		return false;
-
-	if (type == AST_MEMINIT && id2ast && mem2reg_set.count(id2ast))
-	{
-		log_assert(children[0]->type == AST_CONSTANT);
-		log_assert(children[1]->type == AST_CONSTANT);
-		log_assert(children[2]->type == AST_CONSTANT);
-		log_assert(children[3]->type == AST_CONSTANT);
-
-		int cursor = children[0]->asInt(false);
-		Const data = children[1]->bitsAsConst();
-		Const en = children[2]->bitsAsConst();
-		int length = children[3]->asInt(false);
-
-		if (length != 0)
-		{
-			AstNode *block = new AstNode(AST_INITIAL, new AstNode(AST_BLOCK));
-			mod->children.push_back(block);
-			block = block->children[0];
-
-			int wordsz = GetSize(data) / length;
-
-			for (int i = 0; i < length; i++) {
-				int pos = 0;
-				while (pos < wordsz) {
-					if (en[pos] != State::S1) {
-						pos++;
-					} else {
-						int epos = pos + 1;
-						while (epos < wordsz && en[epos] == State::S1)
-							epos++;
-						int clen = epos - pos;
-						AstNode *range = new AstNode(AST_RANGE, AstNode::mkconst_int(cursor+i, false));
-						if (pos != 0 || epos != wordsz) {
-							int left;
-							int right;
-							AstNode *mrange = id2ast->children[0];
-							if (mrange->range_left < mrange->range_right) {
-								right = mrange->range_right - pos;
-								left = mrange->range_right - epos + 1;
-							} else {
-								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)));
-						}
-						AstNode *target = new AstNode(AST_IDENTIFIER, 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).bits, false)));
-						pos = epos;
-					}
-				}
-			}
-		}
-
-		AstNode *newNode = new AstNode(AST_NONE);
-		newNode->cloneInto(this);
-		delete newNode;
-
-		did_something = true;
-	}
-
-	if (type == AST_ASSIGN && block == NULL && 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);
-		}
-
-		AstNode *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;
-
-		did_something = true;
-	}
-
-	if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && children[0]->mem2reg_check(mem2reg_set) &&
-			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++);
-		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);
-
-		AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(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->attributes[ID::nosync] = AstNode::mkconst_int(1, false);
-		mod->children.push_back(wire_addr);
-		while (wire_addr->simplify(true, false, false, 1, -1, false, false)) { }
-
-		AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(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->attributes[ID::nosync] = AstNode::mkconst_int(1, false);
-		mod->children.push_back(wire_data);
-		while (wire_data->simplify(true, false, false, 1, -1, false, false)) { }
-
-		log_assert(block != NULL);
-		size_t assign_idx = 0;
-		while (assign_idx < block->children.size() && block->children[assign_idx] != 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());
-		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);
-
-		AstNode *case_node = new AstNode(AST_CASE, new AstNode(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));
-			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);
-		}
-		block->children.insert(block->children.begin()+assign_idx+2, case_node);
-
-		children[0]->delete_children();
-		children[0]->range_valid = false;
-		children[0]->id2ast = NULL;
-		children[0]->str = id_data;
-		type = AST_ASSIGN_EQ;
-		children[0]->was_checked = true;
-
-		did_something = true;
-	}
-
-	if (mem2reg_check(mem2reg_set))
-	{
-		AstNode *bit_part_sel = NULL;
-		if (children.size() == 2)
-			bit_part_sel = children[1]->clone();
-
-		if (children[0]->children[0]->type == AST_CONSTANT)
-		{
-			int id = children[0]->children[0]->integer;
-			int left = id2ast->children[1]->children[0]->integer;
-			int right = id2ast->children[1]->children[1]->integer;
-			bool valid_const_access =
-				(left <= id && id <= right) ||
-				(right <= id && id <= left);
-			if (valid_const_access)
-			{
-				str = stringf("%s[%d]", str.c_str(), id);
-				delete_children();
-				range_valid = false;
-				id2ast = NULL;
-			}
-			else
-			{
-				int width;
-				if (bit_part_sel)
-				{
-					bit_part_sel->dumpAst(nullptr, "? ");
-					if (bit_part_sel->children.size() == 1)
-						width = 0;
-					else
-						width = bit_part_sel->children[0]->integer -
-							bit_part_sel->children[1]->integer;
-					delete bit_part_sel;
-					bit_part_sel = nullptr;
-				}
-				else
-				{
-					width = id2ast->children[0]->children[0]->integer -
-						id2ast->children[0]->children[1]->integer;
-				}
-				width = abs(width) + 1;
-
-				delete_children();
-
-				std::vector<RTLIL::State> 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;
-			}
-		}
-		else
-		{
-			std::stringstream sstr;
-			sstr << "$mem2reg_rd$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_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);
-
-			AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(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->attributes[ID::nosync] = AstNode::mkconst_int(1, false);
-			mod->children.push_back(wire_addr);
-			while (wire_addr->simplify(true, false, false, 1, -1, false, false)) { }
-
-			AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(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->attributes[ID::nosync] = AstNode::mkconst_int(1, false);
-			mod->children.push_back(wire_data);
-			while (wire_data->simplify(true, false, false, 1, -1, false, false)) { }
-
-			AstNode *assign_addr = new AstNode(block ? AST_ASSIGN_EQ : AST_ASSIGN, new AstNode(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));
-			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));
-				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);
-			}
-
-			std::vector<RTLIL::State> 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));
-			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);
-
-			if (block)
-			{
-				size_t assign_idx = 0;
-				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);
-			}
-			else
-			{
-				AstNode *proc = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK));
-				proc->children[0]->children.push_back(case_node);
-				mod->children.push_back(proc);
-				mod->children.push_back(assign_addr);
-			}
-
-			delete_children();
-			range_valid = false;
-			id2ast = NULL;
-			str = id_data;
-		}
-
-		if (bit_part_sel)
-			children.push_back(bit_part_sel);
-
-		did_something = true;
-	}
-
-	log_assert(id2ast == NULL || mem2reg_set.count(id2ast) == 0);
-
-	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;
-
-	return did_something;
-}
-
-// calculate memory dimensions
-void AstNode::meminfo(int &mem_width, int &mem_size, int &addr_bits)
-{
-	log_assert(type == AST_MEMORY);
-
-	mem_width = children[0]->range_left - children[0]->range_right + 1;
-	mem_size = children[1]->range_left - children[1]->range_right;
-
-	if (mem_size < 0)
-		mem_size *= -1;
-	mem_size += min(children[1]->range_left, children[1]->range_right) + 1;
-
-	addr_bits = 1;
-	while ((1 << addr_bits) < mem_size)
-		addr_bits++;
-}
-
-bool AstNode::detect_latch(const std::string &var)
-{
-	switch (type)
-	{
-	case AST_ALWAYS:
-		for (auto &c : children)
-		{
-			switch (c->type)
-			{
-			case AST_POSEDGE:
-			case AST_NEGEDGE:
-				return false;
-			case AST_EDGE:
-				break;
-			case AST_BLOCK:
-				if (!c->detect_latch(var))
-					return false;
-				break;
-			default:
-				log_abort();
-			}
-		}
-		return true;
-	case AST_BLOCK:
-		for (auto &c : children)
-			if (!c->detect_latch(var))
-				return false;
-		return true;
-	case AST_CASE:
-		{
-			bool r = true;
-			for (auto &c : children) {
-				if (c->type == AST_COND) {
-					if (c->children.at(1)->detect_latch(var))
-						return true;
-					r = false;
-				}
-				if (c->type == AST_DEFAULT) {
-					if (c->children.at(0)->detect_latch(var))
-						return true;
-					r = false;
-				}
-			}
-			return r;
-		}
-	case AST_ASSIGN_EQ:
-	case AST_ASSIGN_LE:
-		if (children.at(0)->type == AST_IDENTIFIER &&
-				children.at(0)->children.empty() && children.at(0)->str == var)
-			return false;
-		return true;
-	default:
-		return true;
-	}
-}
-
-bool AstNode::has_const_only_constructs()
-{
-	if (type == AST_WHILE || type == AST_REPEAT)
-		return true;
-	for (auto child : children)
-		if (child->has_const_only_constructs())
-			return true;
-	return false;
-}
-
-bool AstNode::is_simple_const_expr()
-{
-	if (type == AST_IDENTIFIER)
-		return false;
-	for (auto child : children)
-		if (!child->is_simple_const_expr())
-			return false;
-	return true;
-}
-
-// helper function for AstNode::eval_const_function()
-bool AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &variables, AstNode *fcall, bool must_succeed)
-{
-	if (type == AST_IDENTIFIER && variables.count(str)) {
-		int offset = variables.at(str).offset, width = variables.at(str).val.bits.size();
-		if (!children.empty()) {
-			if (children.size() != 1 || children.at(0)->type != AST_RANGE) {
-				if (!must_succeed)
-					return false;
-				log_file_error(filename, location.first_line, "Memory access in constant function is not supported\n%s: ...called from here.\n",
-						fcall->loc_string().c_str());
-			}
-			if (!children.at(0)->replace_variables(variables, fcall, must_succeed))
-				return false;
-			while (simplify(true, false, false, 1, -1, false, true)) { }
-			if (!children.at(0)->range_valid) {
-				if (!must_succeed)
-					return false;
-				log_file_error(filename, location.first_line, "Non-constant range\n%s: ... called from here.\n",
-						fcall->loc_string().c_str());
-			}
-			offset = min(children.at(0)->range_left, children.at(0)->range_right);
-			width = min(std::abs(children.at(0)->range_left - children.at(0)->range_right) + 1, width);
-		}
-		offset -= variables.at(str).offset;
-		if (variables.at(str).range_swapped)
-			offset = -offset;
-		std::vector<RTLIL::State> &var_bits = variables.at(str).val.bits;
-		std::vector<RTLIL::State> 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;
-		return true;
-	}
-
-	for (auto &child : children)
-		if (!child->replace_variables(variables, fcall, must_succeed))
-			return false;
-	return true;
-}
-
-// attempt to statically evaluate a functions with all-const arguments
-AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed)
-{
-	std::map<std::string, AstNode*> backup_scope = current_scope;
-	std::map<std::string, AstNode::varinfo_t> variables;
-	std::vector<AstNode*> to_delete;
-	AstNode *block = new AstNode(AST_BLOCK);
-	AstNode *result = nullptr;
-
-	size_t argidx = 0;
-	for (auto child : children)
-	{
-		block->children.push_back(child->clone());
-	}
-
-	while (!block->children.empty())
-	{
-		AstNode *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> ");
-#endif
-
-		if (stmt->type == AST_WIRE)
-		{
-			while (stmt->simplify(true, false, false, 1, -1, false, true)) { }
-			if (!stmt->range_valid) {
-				if (!must_succeed)
-					goto finished;
-				log_file_error(stmt->filename, stmt->location.first_line, "Can't determine size of variable %s\n%s: ... called from here.\n",
-						stmt->str.c_str(), fcall->loc_string().c_str());
-			}
-			AstNode::varinfo_t &variable = variables[stmt->str];
-			int width = abs(stmt->range_left - stmt->range_right) + 1;
-			// if this variable has already been declared as an input, check the
-			// sizes match if it already had an explicit size
-			if (variable.arg && variable.explicitly_sized && variable.val.size() != width) {
-				log_file_error(filename, location.first_line, "Incompatible re-declaration of constant function wire %s.\n", stmt->str.c_str());
-			}
-			variable.val = RTLIL::Const(RTLIL::State::Sx, width);
-			variable.offset = stmt->range_swapped ? stmt->range_left : stmt->range_right;
-			variable.range_swapped = stmt->range_swapped;
-			variable.is_signed = stmt->is_signed;
-			variable.explicitly_sized = stmt->children.size() &&
-				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++);
-			}
-			// load the constant arg's value into this variable
-			if (variable.arg) {
-				if (variable.arg->type == AST_CONSTANT) {
-					variable.val = variable.arg->bitsAsConst(width);
-				} else {
-					log_assert(variable.arg->type == AST_REALVALUE);
-					variable.val = variable.arg->realAsConst(width);
-				}
-			}
-			current_scope[stmt->str] = stmt;
-
-			block->children.erase(block->children.begin());
-			to_delete.push_back(stmt);
-			continue;
-		}
-
-		log_assert(variables.count(str) != 0);
-
-		if (stmt->type == AST_LOCALPARAM)
-		{
-			while (stmt->simplify(true, false, false, 1, -1, false, true)) { }
-
-			current_scope[stmt->str] = stmt;
-
-			block->children.erase(block->children.begin());
-			to_delete.push_back(stmt);
-			continue;
-		}
-
-		if (stmt->type == AST_ASSIGN_EQ)
-		{
-			if (stmt->children.at(0)->type == AST_IDENTIFIER && stmt->children.at(0)->children.size() != 0 &&
-					stmt->children.at(0)->children.at(0)->type == AST_RANGE)
-				if (!stmt->children.at(0)->children.at(0)->replace_variables(variables, fcall, must_succeed))
-					goto finished;
-			if (!stmt->children.at(1)->replace_variables(variables, fcall, must_succeed))
-				goto finished;
-			while (stmt->simplify(true, false, false, 1, -1, false, true)) { }
-
-			if (stmt->type != AST_ASSIGN_EQ)
-				continue;
-
-			if (stmt->children.at(1)->type != AST_CONSTANT) {
-				if (!must_succeed)
-					goto finished;
-				log_file_error(stmt->filename, stmt->location.first_line, "Non-constant expression in constant function\n%s: ... called from here. X\n",
-						fcall->loc_string().c_str());
-			}
-
-			if (stmt->children.at(0)->type != AST_IDENTIFIER) {
-				if (!must_succeed)
-					goto finished;
-				log_file_error(stmt->filename, stmt->location.first_line, "Unsupported composite left hand side in constant function\n%s: ... called from here.\n",
-						fcall->loc_string().c_str());
-			}
-
-			if (!variables.count(stmt->children.at(0)->str)) {
-				if (!must_succeed)
-					goto finished;
-				log_file_error(stmt->filename, stmt->location.first_line, "Assignment to non-local variable in constant function\n%s: ... called from here.\n",
-						fcall->loc_string().c_str());
-			}
-
-			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.bits.size());
-			} else {
-				AstNode *range = stmt->children.at(0)->children.at(0);
-				if (!range->range_valid) {
-					if (!must_succeed)
-						goto finished;
-					log_file_error(range->filename, range->location.first_line, "Non-constant range\n%s: ... called from here.\n",
-							fcall->loc_string().c_str());
-				}
-				int offset = min(range->range_left, range->range_right);
-				int width = std::abs(range->range_left - range->range_right) + 1;
-				varinfo_t &v = variables[stmt->children.at(0)->str];
-				RTLIL::Const r = stmt->children.at(1)->bitsAsConst(v.val.bits.size());
-				for (int i = 0; i < width; i++) {
-					int index = i + offset - v.offset;
-					if (v.range_swapped)
-						index = -index;
-					v.val.bits.at(index) = r.bits.at(i);
-				}
-			}
-
-			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->children.erase(stmt->children.begin() + 2);
-			stmt->children.erase(stmt->children.begin());
-			stmt->type = AST_WHILE;
-			continue;
-		}
-
-		if (stmt->type == AST_WHILE)
-		{
-			AstNode *cond = stmt->children.at(0)->clone();
-			if (!cond->replace_variables(variables, fcall, must_succeed))
-				goto finished;
-			while (cond->simplify(true, false, false, 1, -1, false, true)) { }
-
-			if (cond->type != AST_CONSTANT) {
-				if (!must_succeed)
-					goto finished;
-				log_file_error(stmt->filename, stmt->location.first_line, "Non-constant expression in constant function\n%s: ... called from here.\n",
-						fcall->loc_string().c_str());
-			}
-
-			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();
-			if (!num->replace_variables(variables, fcall, must_succeed))
-				goto finished;
-			while (num->simplify(true, false, false, 1, -1, false, true)) { }
-
-			if (num->type != AST_CONSTANT) {
-				if (!must_succeed)
-					goto finished;
-				log_file_error(stmt->filename, stmt->location.first_line, "Non-constant expression in constant function\n%s: ... called from here.\n",
-						fcall->loc_string().c_str());
-			}
-
-			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());
-
-			delete stmt;
-			delete num;
-			continue;
-		}
-
-		if (stmt->type == AST_CASE)
-		{
-			AstNode *expr = stmt->children.at(0)->clone();
-			if (!expr->replace_variables(variables, fcall, must_succeed))
-				goto finished;
-			while (expr->simplify(true, false, false, 1, -1, false, true)) { }
-
-			AstNode *sel_case = NULL;
-			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();
-					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();
-					if (!cond->replace_variables(variables, fcall, must_succeed))
-						goto finished;
-
-					cond = new AstNode(AST_EQ, expr->clone(), cond);
-					while (cond->simplify(true, false, false, 1, -1, false, true)) { }
-
-					if (cond->type != AST_CONSTANT) {
-						if (!must_succeed)
-							goto finished;
-						log_file_error(stmt->filename, stmt->location.first_line, "Non-constant expression in constant function\n%s: ... called from here.\n",
-								fcall->loc_string().c_str());
-					}
-
-					found_match = cond->asBool();
-					delete cond;
-				}
-
-				if (found_match) {
-					sel_case = stmt->children.at(i)->children.back();
-					break;
-				}
-			}
-
-			block->children.erase(block->children.begin());
-			if (sel_case)
-				block->children.insert(block->children.begin(), sel_case->clone());
-			delete stmt;
-			delete expr;
-			continue;
-		}
-
-		if (stmt->type == AST_BLOCK)
-		{
-			if (!stmt->str.empty())
-				stmt->expand_genblock(stmt->str + ".");
-
-			block->children.erase(block->children.begin());
-			block->children.insert(block->children.begin(), stmt->children.begin(), stmt->children.end());
-			stmt->children.clear();
-			delete stmt;
-			continue;
-		}
-
-		if (!must_succeed)
-			goto finished;
-		log_file_error(stmt->filename, stmt->location.first_line, "Unsupported language construct in constant function\n%s: ... called from here.\n",
-				fcall->loc_string().c_str());
-		log_abort();
-	}
-
-	result = AstNode::mkconst_bits(variables.at(str).val.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;
-}
-
-void AstNode::allocateDefaultEnumValues()
-{
-	log_assert(type==AST_ENUM);
-	log_assert(children.size() > 0);
-	if (children.front()->attributes.count(ID::enum_base_type))
-		return; // already elaborated
-	int last_enum_int = -1;
-	for (auto node : children) {
-		log_assert(node->type==AST_ENUM_ITEM);
-		node->attributes[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:
-				// explicit constant (or folded expression)
-				// TODO: can't extend 'x or 'z item
-				last_enum_int = node->children[i]->integer;
-				break;
-			default:
-				// ignore ranges
-				break;
-			}
-			// TODO: range check
-		}
-	}
-}
-
-bool AstNode::is_recursive_function() const
-{
-	std::set<const AstNode *> visited;
-	std::function<bool(const AstNode *node)> visit = [&](const AstNode *node) {
-		if (visited.count(node))
-			return node == this;
-		visited.insert(node);
-		if (node->type == AST_FCALL) {
-			auto it = current_scope.find(node->str);
-			if (it != current_scope.end() && visit(it->second))
-				return true;
-		}
-		for (const AstNode *child : node->children) {
-			if (visit(child))
-				return true;
-		}
-		return false;
-	};
-
-	log_assert(type == AST_FUNCTION);
-	return visit(this);
-}
-
-std::pair<AstNode*, AstNode*> AstNode::get_tern_choice()
-{
-	if (!children[0]->isConst())
-		return {};
-
-	bool found_sure_true = false;
-	bool found_maybe_true = false;
-
-	if (children[0]->type == AST_CONSTANT)
-		for (auto &bit : children[0]->bits) {
-			if (bit == RTLIL::State::S1)
-				found_sure_true = true;
-			if (bit > RTLIL::State::S1)
-				found_maybe_true = true;
-		}
-	else
-		found_sure_true = children[0]->asReal(true) != 0;
-
-	AstNode *choice = nullptr, *not_choice = nullptr;
-	if (found_sure_true)
-		choice = children[1], not_choice = children[2];
-	else if (!found_maybe_true)
-		choice = children[2], not_choice = children[1];
-
-	return {choice, not_choice};
-}
-
-std::string AstNode::try_pop_module_prefix() const
-{
-	AstNode *current_scope_ast = (current_ast_mod == nullptr) ? current_ast : current_ast_mod;
-	size_t pos = str.find('.', 1);
-	if (str[0] == '\\' && pos != std::string::npos) {
-		std::string new_str = "\\" + str.substr(pos + 1);
-		if (current_scope.count(new_str)) {
-			std::string prefix = str.substr(0, pos);
-			auto it = current_scope_ast->attributes.find(ID::hdlname);
-			if ((it != current_scope_ast->attributes.end() && it->second->str == prefix)
-					|| prefix == current_scope_ast->str)
-				return new_str;
-		}
-	}
-	return str;
-}
-
-YOSYS_NAMESPACE_END
+} // namespace systemverilog_plugin