libs/EXTERNAL/libyosys/frontends/ast/simplify.cc
// find memories that should be replaced by registers
find memories that should be replaced by registers
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; 
	if (type == AST_ASSIGN || type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ)
	{
		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;
			if (flags & AstNode::MEM2REG_FL_ASYNC) {
				if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_ASYNC))
					mem2reg_places[mem].insert(stringf("%s:%d", filename.c_str(), location.first_line));
				mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_SET_ASYNC;
			}
			if (type == AST_ASSIGN_EQ) {
				if (!(proc_flags[mem] & AstNode::MEM2REG_FL_EQ1))
					mem2reg_places[mem].insert(stringf("%s:%d", filename.c_str(), location.first_line));
				proc_flags[mem] |= AstNode::MEM2REG_FL_EQ1;
			}
			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;
				}
			}
			if (flags & MEM2REG_FL_INIT) {
				if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_INIT))
					mem2reg_places[mem].insert(stringf("%s:%d", 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", 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;
		if ((proc_flags[mem] & AstNode::MEM2REG_FL_EQ1) && !(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_EQ2)) {
			mem2reg_places[mem].insert(stringf("%s:%d", filename.c_str(), location.first_line));
			mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_EQ2;
		}
	}
	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 && 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>;
	}
	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;
	}
}
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 ; if ( type == AST_ASSIGN || type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ ) { 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 ; if ( flags & AstNode :: MEM2REG_FL_ASYNC ) { if ( ! ( mem2reg_candidates [ mem ] & AstNode :: MEM2REG_FL_SET_ASYNC ) ) mem2reg_places [ mem ] . insert ( stringf ( " " , filename . c_str ( ) , location . first_line ) ) ; mem2reg_candidates [ mem ] |= AstNode :: MEM2REG_FL_SET_ASYNC ; } if ( type == AST_ASSIGN_EQ ) { if ( ! ( proc_flags [ mem ] & AstNode :: MEM2REG_FL_EQ1 ) ) mem2reg_places [ mem ] . insert ( stringf ( " " , filename . c_str ( ) , location . first_line ) ) ; proc_flags [ mem ] |= AstNode :: MEM2REG_FL_EQ1 ; } 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 ; } } if ( flags & MEM2REG_FL_INIT ) { if ( ! ( mem2reg_candidates [ mem ] & AstNode :: MEM2REG_FL_SET_INIT ) ) mem2reg_places [ mem ] . insert ( stringf ( " " , 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 ( " " , 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 ; if ( ( proc_flags [ mem ] & AstNode :: MEM2REG_FL_EQ1 ) && ! ( mem2reg_candidates [ mem ] & AstNode :: MEM2REG_FL_EQ2 ) ) { mem2reg_places [ mem ] . insert ( stringf ( " " , filename . c_str ( ) , location . first_line ) ) ; mem2reg_candidates [ mem ] |= AstNode :: MEM2REG_FL_EQ2 ; } } 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 && 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 > ; } 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 ; } }
find memories that should be replaced by registers
find memories that should be replaced by registers
// don't touch content of typedefs // mark all memories that are used in a complex expression on the left side of an assignment // activate mem2reg if this is assigned in an async proc // remember if this is assigned blocking (=) // for proper (non-init) writes: remember if this is a constant index or not // remember where this is // flag if used after blocking assignment (in same proc) // also activate if requested, either by using mem2reg attribute or by declaring array as 'wire' instead of 'reg' or 'logic'