mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-04 05:19:11 +00:00 
			
		
		
		
	ast/simplify: Use clone_at_zero() for "at_zero" evaluations
The correct way of using the 'at_zero' regime of simplify is to perform the simplification on a cloned AST subtree, otherwise the "at_zero" evaluation seeps into the main tree. Move the effect of the 'at_zero' flag to the cloning itself, so that the simplify flag can be retired. We assume we can rely on id2ast in the new clone method.
This commit is contained in:
		
							parent
							
								
									77d4b5230e
								
							
						
					
					
						commit
						4fceeb3b32
					
				
					 3 changed files with 56 additions and 22 deletions
				
			
		| 
						 | 
				
			
			@ -336,6 +336,10 @@ namespace AST
 | 
			
		|||
		// Helper for looking up identifiers which are prefixed with the current module name
 | 
			
		||||
		std::string try_pop_module_prefix() const;
 | 
			
		||||
 | 
			
		||||
		// 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();
 | 
			
		||||
 | 
			
		||||
		// helper to print errors from simplify/genrtlil code
 | 
			
		||||
		[[noreturn]] void input_error(const char *format, ...) const YS_ATTRIBUTE(format(printf, 2, 3));
 | 
			
		||||
	};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -887,10 +887,10 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
 | 
			
		|||
			if (range->children.size() == 1)
 | 
			
		||||
				this_width = 1;
 | 
			
		||||
			else if (!range->range_valid) {
 | 
			
		||||
				AstNode *left_at_zero_ast = children[0]->children[0]->clone();
 | 
			
		||||
				AstNode *right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone() : left_at_zero_ast->clone();
 | 
			
		||||
				while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
 | 
			
		||||
				while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
 | 
			
		||||
				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();
 | 
			
		||||
				while (left_at_zero_ast->simplify(true, false, false, 1, -1, false, false)) { }
 | 
			
		||||
				while (right_at_zero_ast->simplify(true, false, false, 1, -1, false, 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;
 | 
			
		||||
| 
						 | 
				
			
			@ -1460,10 +1460,10 @@ 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();
 | 
			
		||||
					AstNode *right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone() : left_at_zero_ast->clone();
 | 
			
		||||
					while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
 | 
			
		||||
					while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
 | 
			
		||||
					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();
 | 
			
		||||
					while (left_at_zero_ast->simplify(true, false, false, 1, -1, false, false)) { }
 | 
			
		||||
					while (right_at_zero_ast->simplify(true, false, false, 1, -1, false, 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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -773,6 +773,44 @@ static IdentUsage always_asgn_before_use(const AstNode *node, const std::string
 | 
			
		|||
	return IdentUsage::NotReferenced;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AstNode *AstNode::clone_at_zero()
 | 
			
		||||
{
 | 
			
		||||
	int width_hint;
 | 
			
		||||
	bool sign_hint;
 | 
			
		||||
	AstNode *pointee;
 | 
			
		||||
 | 
			
		||||
	switch (type) {
 | 
			
		||||
	case AST_IDENTIFIER:
 | 
			
		||||
		if (id2ast)
 | 
			
		||||
			pointee = id2ast;
 | 
			
		||||
		else if (current_scope.count(str))
 | 
			
		||||
			pointee = current_scope[str];
 | 
			
		||||
		else
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		if (pointee->type != AST_WIRE &&
 | 
			
		||||
				pointee->type != AST_AUTOWIRE &&
 | 
			
		||||
				pointee->type != AST_MEMORY)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		YS_FALLTHROUGH;
 | 
			
		||||
	case AST_MEMRD:
 | 
			
		||||
		detectSignWidth(width_hint, sign_hint);
 | 
			
		||||
		return mkconst_int(0, sign_hint, width_hint);
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	AstNode *that = new AstNode;
 | 
			
		||||
	*that = *this;
 | 
			
		||||
	for (auto &it : that->children)
 | 
			
		||||
		it = it->clone_at_zero();
 | 
			
		||||
	for (auto &it : that->attributes)
 | 
			
		||||
		it.second = it.second->clone();
 | 
			
		||||
	return that;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool try_determine_range_width(AstNode *range, int &result_width)
 | 
			
		||||
{
 | 
			
		||||
	log_assert(range->type == AST_RANGE);
 | 
			
		||||
| 
						 | 
				
			
			@ -782,11 +820,11 @@ static bool try_determine_range_width(AstNode *range, int &result_width)
 | 
			
		|||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	AstNode *left_at_zero_ast = range->children[0]->clone();
 | 
			
		||||
	AstNode *right_at_zero_ast = range->children[1]->clone();
 | 
			
		||||
	AstNode *left_at_zero_ast = range->children[0]->clone_at_zero();
 | 
			
		||||
	AstNode *right_at_zero_ast = range->children[1]->clone_at_zero();
 | 
			
		||||
 | 
			
		||||
	while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) {}
 | 
			
		||||
	while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) {}
 | 
			
		||||
	while (left_at_zero_ast->simplify(true, false, false, 1, -1, false, false)) {}
 | 
			
		||||
	while (right_at_zero_ast->simplify(true, false, false, 1, -1, false, false)) {}
 | 
			
		||||
 | 
			
		||||
	bool ok = false;
 | 
			
		||||
	if (left_at_zero_ast->type == AST_CONSTANT
 | 
			
		||||
| 
						 | 
				
			
			@ -873,6 +911,8 @@ 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, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param)
 | 
			
		||||
{
 | 
			
		||||
	log_assert(!at_zero);
 | 
			
		||||
 | 
			
		||||
	static int recursion_counter = 0;
 | 
			
		||||
	static bool deep_recursion_warning = false;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4202,16 +4242,6 @@ replace_fcall_later:;
 | 
			
		|||
				if (current_scope[str]->children[0]->isConst())
 | 
			
		||||
					newNode = current_scope[str]->children[0]->clone();
 | 
			
		||||
			}
 | 
			
		||||
			else if (at_zero && current_scope.count(str) > 0) {
 | 
			
		||||
				AstNode *node = current_scope[str];
 | 
			
		||||
				if (node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_MEMORY)
 | 
			
		||||
					newNode = mkconst_int(0, sign_hint, width_hint);
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		case AST_MEMRD:
 | 
			
		||||
			if (at_zero) {
 | 
			
		||||
				newNode = mkconst_int(0, sign_hint, width_hint);
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		case AST_BIT_NOT:
 | 
			
		||||
			if (children[0]->type == AST_CONSTANT) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue