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
 | ||||
| 		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