diff options
Diffstat (limited to 'frontends/ast/simplify.cc')
| -rw-r--r-- | frontends/ast/simplify.cc | 134 | 
1 files changed, 103 insertions, 31 deletions
| diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 46013544b..1c9932ee0 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -50,7 +50,6 @@ using namespace AST_INTERNAL;  bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param)  {  	static int recursion_counter = 0; -	static pair<string, int> last_blocking_assignment_warn;  	static bool deep_recursion_warning = false;  	if (recursion_counter++ == 1000 && deep_recursion_warning) { @@ -72,7 +71,6 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  	if (stage == 0)  	{  		log_assert(type == AST_MODULE || type == AST_INTERFACE); -		last_blocking_assignment_warn = pair<string, int>();  		deep_recursion_warning = true;  		while (simplify(const_fold, at_zero, in_lvalue, 1, width_hint, sign_hint, in_param)) { } @@ -113,6 +111,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  				if (memflags & AstNode::MEM2REG_FL_CMPLX_LHS)  					goto verbose_activate; +				if ((memflags & AstNode::MEM2REG_FL_CONST_LHS) && !(memflags & AstNode::MEM2REG_FL_VAR_LHS)) +					goto verbose_activate; +  				// log("Note: Not replacing memory %s with list of registers (flags=0x%08lx).\n", mem->str.c_str(), long(memflags));  				continue; @@ -325,6 +326,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  		for (size_t i = 0; i < children.size(); i++) {  			AstNode *node = children[i];  			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("\\dynports")) +								delete attributes.at("\\dynports"); +							attributes["\\dynports"] = AstNode::mkconst_int(1, true); +						} +					} +				}  				if (this_wire_scope.count(node->str) > 0) {  					AstNode *first_node = this_wire_scope[node->str];  					if (first_node->is_input && node->is_reg) @@ -938,7 +948,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  			}  		}  		if (current_scope.count(str) == 0) { -			if (flag_autowire) { +			if (flag_autowire || str == "\\$global_clock") {  				AstNode *auto_wire = new AstNode(AST_AUTOWIRE);  				auto_wire->str = str;  				current_ast_mod->children.push_back(auto_wire); @@ -1499,6 +1509,7 @@ skip_dynamic_range_lvalue_expansion:;  		newNode->children.push_back(assign_en);  		AstNode *assertnode = new AstNode(type); +		assertnode->str = str;  		assertnode->children.push_back(new AstNode(AST_IDENTIFIER));  		assertnode->children.push_back(new AstNode(AST_IDENTIFIER));  		assertnode->children[0]->str = id_check; @@ -1579,14 +1590,6 @@ skip_dynamic_range_lvalue_expansion:;  		sstr << "$memwr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++);  		std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA", id_en = sstr.str() + "_EN"; -		if (type == AST_ASSIGN_EQ) { -			pair<string, int> this_blocking_assignment_warn(filename, linenum); -			if (this_blocking_assignment_warn != last_blocking_assignment_warn) -				log_warning("Blocking assignment to memory in line %s:%d is handled like a non-blocking assignment.\n", -						filename.c_str(), linenum); -			last_blocking_assignment_warn = this_blocking_assignment_warn; -		} -  		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); @@ -2169,6 +2172,8 @@ skip_dynamic_range_lvalue_expansion:;  				}  				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;  			} @@ -2210,6 +2215,8 @@ skip_dynamic_range_lvalue_expansion:;  		std::map<std::string, std::string> replace_rules;  		vector<AstNode*> added_mod_children;  		dict<std::string, AstNode*> wire_cache; +		vector<AstNode*> new_stmts; +		vector<AstNode*> output_assignments;  		if (current_block == NULL)  		{ @@ -2334,8 +2341,8 @@ skip_dynamic_range_lvalue_expansion:;  					wire->port_id = 0;  					wire->is_input = false;  					wire->is_output = false; -					if (!child->is_output) -						wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false); +					wire->is_reg = true; +					wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false);  					wire_cache[child->str] = wire;  					current_ast_mod->children.push_back(wire); @@ -2357,13 +2364,10 @@ skip_dynamic_range_lvalue_expansion:;  							new AstNode(AST_ASSIGN_EQ, wire_id, arg) :  							new AstNode(AST_ASSIGN_EQ, arg, wire_id);  					assign->children[0]->was_checked = true; - -					for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) { -						if (*it != current_block_child) -							continue; -						current_block->children.insert(it, assign); -						break; -					} +					if (child->is_input) +						new_stmts.push_back(assign); +					else +						output_assignments.push_back(assign);  				}  			} @@ -2377,14 +2381,18 @@ skip_dynamic_range_lvalue_expansion:;  			{  				AstNode *stmt = child->clone();  				stmt->replace_ids(prefix, replace_rules); +				new_stmts.push_back(stmt); +			} -				for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) { -					if (*it != current_block_child) -						continue; -					current_block->children.insert(it, stmt); -					break; -				} +		new_stmts.insert(new_stmts.end(), output_assignments.begin(), output_assignments.end()); + +		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()); +				break;  			} +		}  	replace_fcall_with_id:  		if (type == AST_FCALL) { @@ -2910,7 +2918,7 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg  		dict<AstNode*, uint32_t> &mem2reg_candidates, dict<AstNode*, uint32_t> &proc_flags, uint32_t &flags)  {  	uint32_t children_flags = 0; -	int ignore_children_counter = 0; +	int lhs_children_counter = 0;  	if (type == AST_ASSIGN || type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ)  	{ @@ -2936,6 +2944,16 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg  				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)) @@ -2948,7 +2966,7 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg  			}  		} -		ignore_children_counter = 1; +		lhs_children_counter = 1;  	}  	if (type == AST_IDENTIFIER && id2ast && id2ast->type == AST_MEMORY) @@ -2991,12 +3009,23 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg  	log_assert((flags & ~0x000000ff) == 0);  	for (auto child : children) -		if (ignore_children_counter > 0) -			ignore_children_counter--; -		else if (proc_flags_p) +	{ +		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; @@ -3048,6 +3077,39 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,  	if (type == AST_FUNCTION || type == AST_TASK)  		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); + +		int cursor = children[0]->asInt(false); +		Const data = children[1]->bitsAsConst(); +		int length = children[2]->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++) { +				block->children.push_back(new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER, new AstNode(AST_RANGE, AstNode::mkconst_int(cursor+i, false))), mkconst_bits(data.extract(i*wordsz, wordsz).bits, false))); +				block->children.back()->children[0]->str = str; +				block->children.back()->children[0]->id2ast = id2ast; +				block->children.back()->children[0]->was_checked = true; +			} +		} + +		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) { @@ -3277,6 +3339,16 @@ bool AstNode::has_const_only_constructs(bool &recommend_const_eval)  	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()  void AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &variables, AstNode *fcall)  { | 
