mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-30 19:22:31 +00:00 
			
		
		
		
	tidy up generic functional backend, add generic scope class, tidy up c++ functional backend
This commit is contained in:
		
							parent
							
								
									39bf4f04f7
								
							
						
					
					
						commit
						eb2bb8c45b
					
				
					 3 changed files with 156 additions and 162 deletions
				
			
		|  | @ -23,6 +23,7 @@ | |||
| USING_YOSYS_NAMESPACE | ||||
| PRIVATE_NAMESPACE_BEGIN | ||||
| 
 | ||||
| const char illegal_characters[] = "!\"#%&'()*+,-./:;<=>?@[]\\^`{|}~ "; | ||||
| const char *reserved_keywords[] = { | ||||
| 	"alignas","alignof","and","and_eq","asm","atomic_cancel","atomic_commit", | ||||
| 	"atomic_noexcept","auto","bitand","bitor","bool","break","case", | ||||
|  | @ -41,45 +42,6 @@ const char *reserved_keywords[] = { | |||
| 	nullptr | ||||
| }; | ||||
| 
 | ||||
| struct CxxScope { | ||||
| 	pool<std::string> used_names; | ||||
| 	dict<IdString, std::string> name_map; | ||||
| 
 | ||||
| 	CxxScope() { | ||||
| 		for(const char **p = reserved_keywords; *p != nullptr; p++) | ||||
| 			reserve(*p); | ||||
| 	} | ||||
| 	void reserve(std::string name) { | ||||
| 		used_names.insert(name); | ||||
| 	} | ||||
| 	std::string insert(IdString id) { | ||||
| 		std::string str = RTLIL::unescape_id(id); | ||||
| 		for(size_t i = 0; i < str.size(); i++) | ||||
| 			if(strchr("!\"#%&'()*+,-./:;<=>?@[]\\^`{|}~ ", str[i])) | ||||
| 				str[i] = '_'; | ||||
| 		if(used_names.count(str) == 0){ | ||||
| 			used_names.insert(str); | ||||
| 			name_map.insert({id, str}); | ||||
| 			return str; | ||||
| 		} | ||||
| 		for (int idx = 0 ; ; idx++){ | ||||
| 			std::string suffixed = str + "_" + std::to_string(idx); | ||||
| 			if (used_names.count(suffixed) == 0) { | ||||
| 				used_names.insert(suffixed); | ||||
| 				if(name_map.count(id) == 0) | ||||
| 					name_map.insert({id, suffixed}); | ||||
| 				return suffixed; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	std::string operator[](IdString id) { | ||||
| 		if(name_map.count(id) > 0) | ||||
| 			return name_map[id]; | ||||
| 		else | ||||
| 			return insert(id); | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| struct CxxType { | ||||
| 	FunctionalIR::Sort sort; | ||||
| 	CxxType(FunctionalIR::Sort sort) : sort(sort) {} | ||||
|  | @ -109,66 +71,30 @@ struct CxxWriter { | |||
| struct CxxStruct { | ||||
|   std::string name; | ||||
|   dict<IdString, CxxType> types; | ||||
|   CxxScope scope; | ||||
|   bool generate_methods; | ||||
|   CxxStruct(std::string name, bool generate_methods = false) | ||||
|     : name(name), generate_methods(generate_methods) { | ||||
|   FunctionalTools::Scope scope; | ||||
|   CxxStruct(std::string name) | ||||
|     : name(name), scope(illegal_characters, reserved_keywords) { | ||||
|     scope.reserve("out"); | ||||
|     scope.reserve("dump"); | ||||
|   } | ||||
|   void insert(IdString name, CxxType type) { | ||||
|     scope.insert(name); | ||||
|     scope(name); | ||||
|     types.insert({name, type}); | ||||
|   } | ||||
|   void print(CxxWriter &f) { | ||||
|     f.printf("struct %s {\n", name.c_str()); | ||||
|     f.printf("\tstruct %s {\n", name.c_str()); | ||||
|     for (auto p : types) { | ||||
|       f.printf("\t%s %s;\n", p.second.to_string().c_str(), scope[p.first].c_str()); | ||||
|       f.printf("\t\t%s %s;\n", p.second.to_string().c_str(), scope(p.first).c_str()); | ||||
|     } | ||||
|     f.printf("\n\ttemplate <typename T> void dump(T &out) const {\n"); | ||||
|     f.printf("\n\t\ttemplate <typename T> void visit(T &fn) {\n"); | ||||
|     for (auto p : types) { | ||||
|       f.printf("\t\tout(\"%s\", %s);\n", RTLIL::unescape_id(p.first).c_str(), scope[p.first].c_str()); | ||||
|       f.printf("\t\t\tfn(\"%s\", %s);\n", RTLIL::unescape_id(p.first).c_str(), scope(p.first).c_str()); | ||||
|     } | ||||
|     f.printf("\t}\n\n"); | ||||
| 
 | ||||
|     if (generate_methods) { | ||||
|       // Add size method
 | ||||
|       f.printf("\tint size() const {\n"); | ||||
|       f.printf("\t\treturn %d;\n", types.size()); | ||||
|       f.printf("\t}\n\n"); | ||||
| 
 | ||||
|       // Add get_input method
 | ||||
|       f.printf("\tstd::variant<%s> get_input(const int index) {\n", generate_variant_types().c_str()); | ||||
|       f.printf("\t\tswitch (index) {\n"); | ||||
|       int idx = 0; | ||||
|       for (auto p : types) { | ||||
| 	f.printf("\t\t\tcase %d: return std::ref(%s);\n", idx, scope[p.first].c_str()); | ||||
| 	idx++; | ||||
|       } | ||||
|       f.printf("\t\t\tdefault: throw std::out_of_range(\"Invalid input index\");\n"); | ||||
|       f.printf("\t\t}\n"); | ||||
|       f.printf("\t}\n"); | ||||
|     } | ||||
|      | ||||
|     f.printf("};\n\n"); | ||||
|     f.printf("\t\t}\n"); | ||||
|     f.printf("\t};\n\n"); | ||||
|   }; | ||||
|   std::string operator[](IdString field) { | ||||
|     return scope[field]; | ||||
|   } | ||||
|   private: | ||||
|   std::string generate_variant_types() const { | ||||
|         std::set<std::string> unique_types; | ||||
|         for (const auto& p : types) { | ||||
|             unique_types.insert("std::reference_wrapper<" + p.second.to_string() + ">"); | ||||
|         } | ||||
|         std::ostringstream oss; | ||||
|         for (auto it = unique_types.begin(); it != unique_types.end(); ++it) { | ||||
|             if (it != unique_types.begin()) { | ||||
|                 oss << ", "; | ||||
|             } | ||||
|             oss << *it; | ||||
|         } | ||||
|         return oss.str(); | ||||
|     return scope(field); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
|  | @ -255,6 +181,54 @@ template<class NodeNames> struct CxxPrintVisitor { | |||
| 	std::string undriven(Node, int width) { return format("$const<%0>(0)", width); } | ||||
| }; | ||||
| 
 | ||||
| struct CxxModule { | ||||
| 	FunctionalIR ir; | ||||
| 	CxxStruct input_struct, output_struct, state_struct; | ||||
| 	std::string module_name; | ||||
| 
 | ||||
| 	explicit CxxModule(Module *module) : | ||||
| 		ir(FunctionalIR::from_module(module)), | ||||
| 		input_struct("Inputs"), | ||||
| 		output_struct("Outputs"), | ||||
| 		state_struct("State") | ||||
| 	{ | ||||
| 		for (auto [name, sort] : ir.inputs()) | ||||
| 			input_struct.insert(name, sort); | ||||
| 		for (auto [name, sort] : ir.outputs()) | ||||
| 			output_struct.insert(name, sort); | ||||
| 		for (auto [name, sort] : ir.state()) | ||||
| 			state_struct.insert(name, sort); | ||||
| 		module_name = FunctionalTools::Scope(illegal_characters, reserved_keywords)(module->name); | ||||
| 	} | ||||
| 	void write_header(CxxWriter &f) { | ||||
| 		f.printf("#include \"sim.h\"\n\n"); | ||||
| 	} | ||||
| 	void write_struct_def(CxxWriter &f) { | ||||
| 		f.printf("struct %s {\n", module_name.c_str()); | ||||
| 		input_struct.print(f); | ||||
| 		output_struct.print(f); | ||||
| 		state_struct.print(f); | ||||
| 		f.printf("\tstatic void eval(Inputs const &, Outputs &, State const &, State &);\n"); | ||||
| 		f.printf("};\n\n"); | ||||
| 	} | ||||
| 	void write_eval_def(CxxWriter &f) { | ||||
| 		f.printf("void %s::eval(%s::Inputs const &input, %s::Outputs &output, %s::State const ¤t_state, %s::State &next_state)\n{\n", module_name.c_str(), module_name.c_str(), module_name.c_str(), module_name.c_str(), module_name.c_str()); | ||||
| 		FunctionalTools::Scope locals(illegal_characters, reserved_keywords); | ||||
| 		locals.reserve("input"); | ||||
| 		locals.reserve("output"); | ||||
| 		locals.reserve("current_state"); | ||||
| 		locals.reserve("next_state"); | ||||
| 		auto node_name = [&](FunctionalIR::Node n) { return locals(n.id(), n.name()); }; | ||||
| 		for (auto node : ir) | ||||
| 			f.printf("\t%s %s = %s;\n", CxxType(node.sort()).to_string().c_str(), node_name(node).c_str(), node.visit(CxxPrintVisitor(node_name, input_struct, state_struct)).c_str()); | ||||
| 		for (auto [name, sort] : ir.state()) | ||||
| 			f.printf("\tnext_state.%s = %s;\n", state_struct[name].c_str(), node_name(ir.get_state_next_node(name)).c_str()); | ||||
| 		for (auto [name, sort] : ir.outputs()) | ||||
| 			f.printf("\toutput.%s = %s;\n", output_struct[name].c_str(), node_name(ir.get_output_node(name)).c_str()); | ||||
| 		f.printf("}\n"); | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| struct FunctionalCxxBackend : public Backend | ||||
| { | ||||
| 	FunctionalCxxBackend() : Backend("functional_cxx", "convert design to C++ using the functional backend") {} | ||||
|  | @ -265,47 +239,13 @@ struct FunctionalCxxBackend : public Backend | |||
| 		log("\n"); | ||||
|     } | ||||
| 
 | ||||
| 	void printCxx(std::ostream &stream, std::string, std::string const & name, Module *module) | ||||
| 	void printCxx(std::ostream &stream, std::string, Module *module) | ||||
| 	{ | ||||
| 		auto ir = FunctionalIR::from_module(module); | ||||
| 		CxxWriter f(stream); | ||||
| 
 | ||||
| 		f.printf("#include \"sim.h\"\n"); | ||||
| 		f.printf("#include <variant>\n"); | ||||
| 		CxxStruct input_struct(name + "_Inputs", true); | ||||
| 		for (auto [name, sort] : ir.inputs()) | ||||
| 			input_struct.insert(name, sort); | ||||
| 		CxxStruct output_struct(name + "_Outputs"); | ||||
| 		for (auto [name, sort] : ir.outputs()) | ||||
| 			output_struct.insert(name, sort); | ||||
| 		CxxStruct state_struct(name + "_State"); | ||||
| 		for (auto [name, sort] : ir.state()) | ||||
| 			state_struct.insert(name, sort); | ||||
| 
 | ||||
| 		dict<int, std::string> node_names; | ||||
| 		CxxScope locals; | ||||
| 
 | ||||
| 		input_struct.print(f); | ||||
| 		output_struct.print(f); | ||||
| 		state_struct.print(f); | ||||
| 
 | ||||
| 		f.printf("void %s(%s_Inputs const &input, %s_Outputs &output, %s_State const ¤t_state, %s_State &next_state)\n{\n", name.c_str(), name.c_str(), name.c_str(), name.c_str(), name.c_str()); | ||||
| 		locals.reserve("input"); | ||||
| 		locals.reserve("output"); | ||||
| 		locals.reserve("current_state"); | ||||
| 		locals.reserve("next_state"); | ||||
| 		auto node_to_string = [&](FunctionalIR::Node n) { return node_names.at(n.id()); }; | ||||
| 		for (auto node : ir) | ||||
| 		{ | ||||
| 			std::string name = locals.insert(node.name()); | ||||
| 			node_names.emplace(node.id(), name); | ||||
| 			f.printf("\t%s %s = %s;\n", CxxType(node.sort()).to_string().c_str(), name.c_str(), node.visit(CxxPrintVisitor(node_to_string, input_struct, state_struct)).c_str()); | ||||
| 		} | ||||
| 		for (auto [name, sort] : ir.state()) | ||||
| 			f.printf("\tnext_state.%s = %s;\n", state_struct[name].c_str(), node_to_string(ir.get_state_next_node(name)).c_str()); | ||||
| 		for (auto [name, sort] : ir.outputs()) | ||||
| 			f.printf("\toutput.%s = %s;\n", output_struct[name].c_str(), node_to_string(ir.get_output_node(name)).c_str()); | ||||
| 		f.printf("}\n"); | ||||
| 		CxxModule mod(module); | ||||
| 		mod.write_header(f); | ||||
| 		mod.write_struct_def(f); | ||||
| 		mod.write_eval_def(f); | ||||
| 	} | ||||
| 
 | ||||
| 	void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override | ||||
|  | @ -317,7 +257,7 @@ struct FunctionalCxxBackend : public Backend | |||
| 
 | ||||
| 		for (auto module : design->selected_modules()) { | ||||
|             log("Dumping module `%s'.\n", module->name.c_str()); | ||||
| 			printCxx(*f, filename, RTLIL::unescape_id(module->name), module); | ||||
| 			printCxx(*f, filename, module); | ||||
| 		} | ||||
| 	} | ||||
| } FunctionalCxxBackend; | ||||
|  |  | |||
|  | @ -33,7 +33,7 @@ class CellSimplifier { | |||
| 		} else { | ||||
| 			reduced_b_width = new_width; | ||||
| 			T lower_b = factory.slice(b, b_width, 0, new_width); | ||||
| 			T overflow = factory.ugt(b, factory.constant(RTLIL::Const(y_width, b_width)), b_width); | ||||
| 			T overflow = factory.unsigned_greater_than(b, factory.constant(RTLIL::Const(y_width, b_width)), b_width); | ||||
| 			return factory.mux(lower_b, factory.constant(RTLIL::Const(y_width, new_width)), overflow, new_width); | ||||
| 		} | ||||
| 	} | ||||
|  | @ -102,17 +102,17 @@ public: | |||
| 			T a = extend(inputs.at(ID(A)), a_width, width, is_signed); | ||||
| 			T b = extend(inputs.at(ID(B)), b_width, width, is_signed); | ||||
| 			if(cellType.in({ID($eq), ID($eqx)})) | ||||
| 				return extend(factory.eq(a, b, width), 1, y_width, false); | ||||
| 				return extend(factory.equal(a, b, width), 1, y_width, false); | ||||
| 			else if(cellType.in({ID($ne), ID($nex)})) | ||||
| 				return extend(factory.ne(a, b, width), 1, y_width, false); | ||||
| 				return extend(factory.not_equal(a, b, width), 1, y_width, false); | ||||
| 			else if(cellType == ID($lt)) | ||||
| 				return extend(is_signed ? factory.gt(b, a, width) : factory.ugt(b, a, width), 1, y_width, false); | ||||
| 				return extend(is_signed ? factory.signed_greater_than(b, a, width) : factory.unsigned_greater_than(b, a, width), 1, y_width, false); | ||||
| 			else if(cellType == ID($le)) | ||||
| 				return extend(is_signed ? factory.ge(b, a, width) : factory.uge(b, a, width), 1, y_width, false); | ||||
| 				return extend(is_signed ? factory.signed_greater_equal(b, a, width) : factory.unsigned_greater_equal(b, a, width), 1, y_width, false); | ||||
| 			else if(cellType == ID($gt)) | ||||
| 				return extend(is_signed ? factory.gt(a, b, width) : factory.ugt(a, b, width), 1, y_width, false); | ||||
| 				return extend(is_signed ? factory.signed_greater_than(a, b, width) : factory.unsigned_greater_than(a, b, width), 1, y_width, false); | ||||
| 			else if(cellType == ID($ge)) | ||||
| 				return extend(is_signed ? factory.ge(a, b, width) : factory.uge(a, b, width), 1, y_width, false); | ||||
| 				return extend(is_signed ? factory.signed_greater_equal(a, b, width) : factory.unsigned_greater_equal(a, b, width), 1, y_width, false); | ||||
| 			else | ||||
| 				log_abort(); | ||||
| 		}else if(cellType.in({ID($logic_or), ID($logic_and)})){ | ||||
|  | @ -127,7 +127,7 @@ public: | |||
| 			return extend(inputs.at(ID(A)), a_width, y_width, a_signed); | ||||
| 		}else if(cellType == ID($neg)){ | ||||
| 			T a = extend(inputs.at(ID(A)), a_width, y_width, a_signed); | ||||
| 			return factory.neg(a, y_width); | ||||
| 			return factory.unary_minus(a, y_width); | ||||
| 		}else if(cellType == ID($logic_not)){ | ||||
| 			T a = reduce_or(inputs.at(ID(A)), a_width); | ||||
| 			T y = factory.bitwise_not(a, 1); | ||||
|  | @ -161,7 +161,7 @@ public: | |||
| 			T shr = logical_shift_right(a, b, width, b_width); | ||||
| 			if(b_signed) { | ||||
| 				T sign_b = factory.slice(b, b_width, b_width - 1, 1); | ||||
| 				T shl = logical_shift_left(a, factory.neg(b, b_width), width, b_width); | ||||
| 				T shl = logical_shift_left(a, factory.unary_minus(b, b_width), width, b_width); | ||||
| 				T y = factory.mux(shr, shl, sign_b, width); | ||||
| 				return extend(y, width, y_width, false); | ||||
| 			} else { | ||||
|  | @ -237,10 +237,10 @@ public: | |||
| 		if(results.size() == 0) | ||||
| 			return factory.undriven(0); | ||||
| 		T node = results[0]; | ||||
| 		int size = results[0].size(); | ||||
| 		int size = results[0].width(); | ||||
| 		for(size_t i = 1; i < results.size(); i++) { | ||||
| 			node = factory.concat(node, size, results[i], results[i].size()); | ||||
| 			size += results[i].size(); | ||||
| 			node = factory.concat(node, size, results[i], results[i].width()); | ||||
| 			size += results[i].width(); | ||||
| 		} | ||||
| 		return node; | ||||
| 	} | ||||
|  | @ -405,6 +405,13 @@ void FunctionalIR::topological_sort() { | |||
|     if(scc) log_error("combinational loops, aborting\n"); | ||||
| } | ||||
| 
 | ||||
| IdString merge_name(IdString a, IdString b) { | ||||
| 	if(a[0] == '$' && b[0] == '\\') | ||||
| 		return b; | ||||
| 	else | ||||
| 		return a; | ||||
| } | ||||
| 
 | ||||
| void FunctionalIR::forward_buf() { | ||||
|     std::vector<int> perm, alias; | ||||
|     perm.clear(); | ||||
|  | @ -416,10 +423,15 @@ void FunctionalIR::forward_buf() { | |||
|         { | ||||
|             int target_index = alias[node.arg(0).index()]; | ||||
|             auto target_node = _graph[perm[target_index]]; | ||||
|             if(!target_node.has_sparse_attr() && node.has_sparse_attr()){ | ||||
|                 IdString id = node.sparse_attr(); | ||||
|                 target_node.sparse_attr() = id; | ||||
|             } | ||||
| 			if(node.has_sparse_attr()) { | ||||
| 				if(target_node.has_sparse_attr()) { | ||||
| 					IdString id = merge_name(node.sparse_attr(), target_node.sparse_attr()); | ||||
| 					target_node.sparse_attr() = id; | ||||
| 				} else { | ||||
| 					IdString id = node.sparse_attr(); | ||||
| 					target_node.sparse_attr() = id; | ||||
| 				} | ||||
| 			} | ||||
|             alias.push_back(target_index); | ||||
|         } | ||||
|         else | ||||
|  |  | |||
|  | @ -29,6 +29,58 @@ | |||
| USING_YOSYS_NAMESPACE | ||||
| YOSYS_NAMESPACE_BEGIN | ||||
| 
 | ||||
| namespace FunctionalTools { | ||||
| 	class Scope { | ||||
| 		const char *_illegal_characters; | ||||
| 		pool<std::string> _used_names; | ||||
| 		dict<int, std::string> _by_id; | ||||
| 		dict<IdString, std::string> _by_name; | ||||
| 		std::string allocate_name(IdString suggestion) { | ||||
| 			std::string str = RTLIL::unescape_id(suggestion); | ||||
| 			for(size_t i = 0; i < str.size(); i++) | ||||
| 				if(strchr(_illegal_characters, str[i])) | ||||
| 					str[i] = '_'; | ||||
| 			if(_used_names.count(str) == 0) { | ||||
| 				_used_names.insert(str); | ||||
| 				return str; | ||||
| 			} | ||||
| 			for (int idx = 0 ; ; idx++){ | ||||
| 				std::string suffixed = str + "_" + std::to_string(idx); | ||||
| 				if(_used_names.count(suffixed) == 0) { | ||||
| 					_used_names.insert(suffixed); | ||||
| 					return suffixed; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	public: | ||||
| 		Scope(const char *illegal_characters = "", const char **keywords = nullptr) { | ||||
| 			_illegal_characters = illegal_characters; | ||||
| 			if(keywords != nullptr) | ||||
| 				for(const char **p = keywords; *p != nullptr; p++) | ||||
| 					reserve(*p); | ||||
| 		} | ||||
| 		void reserve(std::string name) { | ||||
| 			_used_names.insert(std::move(name)); | ||||
| 		} | ||||
| 		std::string operator()(int id, IdString suggestion) { | ||||
| 			auto it = _by_id.find(id); | ||||
| 			if(it != _by_id.end()) | ||||
| 				return it->second; | ||||
| 			std::string str = allocate_name(suggestion); | ||||
| 			_by_id.insert({id, str}); | ||||
| 			return str; | ||||
| 		} | ||||
| 		std::string operator()(IdString idstring) { | ||||
| 			auto it = _by_name.find(idstring); | ||||
| 			if(it != _by_name.end()) | ||||
| 				return it->second; | ||||
| 			std::string str = allocate_name(idstring); | ||||
| 			_by_name.insert({idstring, str}); | ||||
| 			return str; | ||||
| 		} | ||||
| 	}; | ||||
| } | ||||
| 
 | ||||
| class FunctionalIR { | ||||
| 	enum class Fn { | ||||
| 		invalid, | ||||
|  | @ -133,7 +185,7 @@ public: | |||
| 		friend class Factory; | ||||
| 		friend class FunctionalIR; | ||||
| 		Graph::Ref _ref; | ||||
| 		Node(Graph::Ref ref) : _ref(ref) { } | ||||
| 		explicit Node(Graph::Ref ref) : _ref(ref) { } | ||||
| 		operator Graph::Ref() { return _ref; } | ||||
| 		template<class NodePrinter> struct PrintVisitor { | ||||
| 			NodePrinter np; | ||||
|  | @ -225,7 +277,6 @@ public: | |||
| 		{ | ||||
| 			return visit(PrintVisitor(np)); | ||||
| 		} | ||||
| 		/* TODO: delete */ int size() const { return sort().width(); } | ||||
| 	}; | ||||
| 	class Factory { | ||||
| 		FunctionalIR &_ir; | ||||
|  | @ -235,7 +286,7 @@ public: | |||
| 			Graph::Ref ref = _ir._graph.add(std::move(fn), {std::move(sort)}); | ||||
| 			for (auto arg : args) | ||||
| 				ref.append_arg(Graph::Ref(arg)); | ||||
| 			return ref; | ||||
| 			return Node(ref); | ||||
| 		} | ||||
| 		void check_basic_binary(Node const &a, Node const &b) { log_assert(a.sort().is_signal() && a.sort() == b.sort()); } | ||||
| 		void check_shift(Node const &a, Node const &b) { log_assert(a.sort().is_signal() && b.sort().is_signal()); } | ||||
|  | @ -341,39 +392,30 @@ public: | |||
| 		void suggest_name(Node node, IdString name) { | ||||
| 			node._ref.sparse_attr() = name; | ||||
| 		} | ||||
| 
 | ||||
| 		/* TODO delete this later*/ | ||||
| 		Node eq(Node a, Node b, int) { return equal(a, b, 0); } | ||||
| 		Node ne(Node a, Node b, int) { return not_equal(a, b, 0); } | ||||
| 		Node gt(Node a, Node b, int) { return signed_greater_than(a, b, 0); } | ||||
| 		Node ge(Node a, Node b, int) { return signed_greater_equal(a, b, 0); } | ||||
| 		Node ugt(Node a, Node b, int) { return unsigned_greater_than(a, b, 0); } | ||||
| 		Node uge(Node a, Node b, int) { return unsigned_greater_equal(a, b, 0); } | ||||
| 		Node neg(Node a, int) { return unary_minus(a, 0); } | ||||
| 	}; | ||||
| 	static FunctionalIR from_module(Module *module); | ||||
| 	Factory factory() { return Factory(*this); } | ||||
| 	int size() const { return _graph.size(); } | ||||
| 	Node operator[](int i) { return _graph[i]; } | ||||
| 	Node operator[](int i) { return Node(_graph[i]); } | ||||
| 	void topological_sort(); | ||||
| 	void forward_buf(); | ||||
| 	dict<IdString, Sort> inputs() const { return _inputs; } | ||||
| 	dict<IdString, Sort> outputs() const { return _outputs; } | ||||
| 	dict<IdString, Sort> state() const { return _state; } | ||||
| 	Node get_output_node(IdString name) { return _graph({name, false}); } | ||||
| 	Node get_state_next_node(IdString name) { return _graph({name, true}); } | ||||
| 	Node get_output_node(IdString name) { return Node(_graph({name, false})); } | ||||
| 	Node get_state_next_node(IdString name) { return Node(_graph({name, true})); } | ||||
| 	class Iterator { | ||||
| 		friend class FunctionalIR; | ||||
| 		FunctionalIR &_ir; | ||||
| 		FunctionalIR *_ir; | ||||
| 		int _index; | ||||
| 		Iterator(FunctionalIR &ir, int index) : _ir(ir), _index(index) {} | ||||
| 		Iterator(FunctionalIR *ir, int index) : _ir(ir), _index(index) {} | ||||
| 	public: | ||||
| 		Node operator*() { return _ir._graph[_index]; } | ||||
| 		Node operator*() { return Node(_ir->_graph[_index]); } | ||||
| 		Iterator &operator++() { _index++; return *this; } | ||||
| 		bool operator!=(Iterator const &other) const { return _index != other._index; } | ||||
| 	}; | ||||
| 	Iterator begin() { return Iterator(*this, 0); } | ||||
| 	Iterator end() { return Iterator(*this, _graph.size()); } | ||||
| 	Iterator begin() { return Iterator(this, 0); } | ||||
| 	Iterator end() { return Iterator(this, _graph.size()); } | ||||
| }; | ||||
| 
 | ||||
| YOSYS_NAMESPACE_END | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue