mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 19:52:31 +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
 | 		// Helper for looking up identifiers which are prefixed with the current module name
 | ||||||
| 		std::string try_pop_module_prefix() const; | 		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
 | 		// helper to print errors from simplify/genrtlil code
 | ||||||
| 		[[noreturn]] void input_error(const char *format, ...) const YS_ATTRIBUTE(format(printf, 2, 3)); | 		[[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) | 			if (range->children.size() == 1) | ||||||
| 				this_width = 1; | 				this_width = 1; | ||||||
| 			else if (!range->range_valid) { | 			else if (!range->range_valid) { | ||||||
| 				AstNode *left_at_zero_ast = children[0]->children[0]->clone(); | 				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() : left_at_zero_ast->clone(); | 				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, 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, true, 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) | 				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()); | 					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; | 				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) { | 				if (!children[0]->range_valid) { | ||||||
| 					AstNode *left_at_zero_ast = children[0]->children[0]->clone(); | 					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() : left_at_zero_ast->clone(); | 					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, 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, true, 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) | 					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()); | 						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; | 					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; | 	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) | static bool try_determine_range_width(AstNode *range, int &result_width) | ||||||
| { | { | ||||||
| 	log_assert(range->type == AST_RANGE); | 	log_assert(range->type == AST_RANGE); | ||||||
|  | @ -782,11 +820,11 @@ static bool try_determine_range_width(AstNode *range, int &result_width) | ||||||
| 		return true; | 		return true; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	AstNode *left_at_zero_ast = range->children[0]->clone(); | 	AstNode *left_at_zero_ast = range->children[0]->clone_at_zero(); | ||||||
| 	AstNode *right_at_zero_ast = range->children[1]->clone(); | 	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 (left_at_zero_ast->simplify(true, false, false, 1, -1, false, false)) {} | ||||||
| 	while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) {} | 	while (right_at_zero_ast->simplify(true, false, false, 1, -1, false, false)) {} | ||||||
| 
 | 
 | ||||||
| 	bool ok = false; | 	bool ok = false; | ||||||
| 	if (left_at_zero_ast->type == AST_CONSTANT | 	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.
 | // 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) | 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 int recursion_counter = 0; | ||||||
| 	static bool deep_recursion_warning = false; | 	static bool deep_recursion_warning = false; | ||||||
| 
 | 
 | ||||||
|  | @ -4202,16 +4242,6 @@ replace_fcall_later:; | ||||||
| 				if (current_scope[str]->children[0]->isConst()) | 				if (current_scope[str]->children[0]->isConst()) | ||||||
| 					newNode = current_scope[str]->children[0]->clone(); | 					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; | 			break; | ||||||
| 		case AST_BIT_NOT: | 		case AST_BIT_NOT: | ||||||
| 			if (children[0]->type == AST_CONSTANT) { | 			if (children[0]->type == AST_CONSTANT) { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue