functional backend: rename "type" to either "kind" or "sort" to make the terminology consistent

This commit is contained in:
Emily Schmidt 2024-08-28 12:39:41 +01:00
parent 27efed27c2
commit 4eeb8d326a
6 changed files with 63 additions and 63 deletions

View File

@ -151,8 +151,8 @@ template<class NodePrinter> struct CxxPrintVisitor : public Functional::Abstract
void arithmetic_shift_right(Node, Node a, Node b) override { print("{}.arithmetic_shift_right({})", a, b); } void arithmetic_shift_right(Node, Node a, Node b) override { print("{}.arithmetic_shift_right({})", a, b); }
void mux(Node, Node a, Node b, Node s) override { print("{2}.any() ? {1} : {0}", a, b, s); } void mux(Node, Node a, Node b, Node s) override { print("{2}.any() ? {1} : {0}", a, b, s); }
void constant(Node, RTLIL::Const const & value) override { print("{}", cxx_const(value)); } void constant(Node, RTLIL::Const const & value) override { print("{}", cxx_const(value)); }
void input(Node, IdString name, IdString type) override { log_assert(type == ID($input)); print("input.{}", input_struct[name]); } void input(Node, IdString name, IdString kind) override { log_assert(kind == ID($input)); print("input.{}", input_struct[name]); }
void state(Node, IdString name, IdString type) override { log_assert(type == ID($state)); print("current_state.{}", state_struct[name]); } void state(Node, IdString name, IdString kind) override { log_assert(kind == ID($state)); print("current_state.{}", state_struct[name]); }
void memory_read(Node, Node mem, Node addr) override { print("{}.read({})", mem, addr); } void memory_read(Node, Node mem, Node addr) override { print("{}.read({})", mem, addr); }
void memory_write(Node, Node mem, Node addr, Node data) override { print("{}.write({}, {})", mem, addr, data); } void memory_write(Node, Node mem, Node addr, Node data) override { print("{}.write({}, {})", mem, addr, data); }
}; };

View File

@ -179,8 +179,8 @@ struct SmtPrintVisitor : public Functional::AbstractVisitor<SExpr> {
SExpr memory_read(Node, Node mem, Node addr) override { return list("select", n(mem), n(addr)); } SExpr memory_read(Node, Node mem, Node addr) override { return list("select", n(mem), n(addr)); }
SExpr memory_write(Node, Node mem, Node addr, Node data) override { return list("store", n(mem), n(addr), n(data)); } SExpr memory_write(Node, Node mem, Node addr, Node data) override { return list("store", n(mem), n(addr), n(data)); }
SExpr input(Node, IdString name, IdString type) override { log_assert(type == ID($input)); return input_struct.access("inputs", name); } SExpr input(Node, IdString name, IdString kind) override { log_assert(kind == ID($input)); return input_struct.access("inputs", name); }
SExpr state(Node, IdString name, IdString type) override { log_assert(type == ID($state)); return state_struct.access("state", name); } SExpr state(Node, IdString name, IdString kind) override { log_assert(kind == ID($state)); return state_struct.access("state", name); }
}; };
struct SmtModule { struct SmtModule {

View File

@ -144,9 +144,9 @@ struct FunctionalTestGeneric : public Pass
for(auto node : fir) for(auto node : fir)
std::cout << RTLIL::unescape_id(node.name()) << " = " << node.to_string([](auto n) { return RTLIL::unescape_id(n.name()); }) << "\n"; std::cout << RTLIL::unescape_id(node.name()) << " = " << node.to_string([](auto n) { return RTLIL::unescape_id(n.name()); }) << "\n";
for(auto output : fir.all_outputs()) for(auto output : fir.all_outputs())
std::cout << RTLIL::unescape_id(output->type) << " " << RTLIL::unescape_id(output->name) << " = " << RTLIL::unescape_id(output->value().name()) << "\n"; std::cout << RTLIL::unescape_id(output->kind) << " " << RTLIL::unescape_id(output->name) << " = " << RTLIL::unescape_id(output->value().name()) << "\n";
for(auto state : fir.all_states()) for(auto state : fir.all_states())
std::cout << RTLIL::unescape_id(state->type) << " " << RTLIL::unescape_id(state->name) << " = " << RTLIL::unescape_id(state->next_value().name()) << "\n"; std::cout << RTLIL::unescape_id(state->kind) << " " << RTLIL::unescape_id(state->name) << " = " << RTLIL::unescape_id(state->next_value().name()) << "\n";
} }
} }
} FunctionalCxxBackend; } FunctionalCxxBackend;

View File

@ -26,11 +26,11 @@ The `Functional::IR` class supports the syntax `for(auto node : ir)` to iterate
`Functional::IR` also keeps track of inputs, outputs and states. `Functional::IR` also keeps track of inputs, outputs and states.
By a "state" we mean a pair of a "current state" input and a "next state" output. By a "state" we mean a pair of a "current state" input and a "next state" output.
One such pair is created for every register and for every memory. One such pair is created for every register and for every memory.
Every input, output and state has a name (equal to their name in RTLIL), a sort and a "type". Every input, output and state has a name (equal to their name in RTLIL), a sort and a kind.
The "type" field usually remains as the default value `$input`, `$output` or `$state`, however some RTLIL cells such as `$assert` or `$anyseq` generate auxiliary inputs/outputs/states that are given a different type to distinguish them from ordinary RTLIL inputs/outputs/states. The kind field usually remains as the default value `$input`, `$output` or `$state`, however some RTLIL cells such as `$assert` or `$anyseq` generate auxiliary inputs/outputs/states that are given a different kind to distinguish them from ordinary RTLIL inputs/outputs/states.
- To access an individual input/output/state, use `ir.input(name, type)`, `ir.output(name, type)` or `ir.state(name, type)`. `type` defaults to the default type. - To access an individual input/output/state, use `ir.input(name, kind)`, `ir.output(name, kind)` or `ir.state(name, kind)`. `kind` defaults to the default kind.
- To iterate over all inputs/outputs/states of a certain "type", methods `ir.inputs`, `ir.outputs`, `ir.states` are provided. Their argument defaults to the default types mentioned. - To iterate over all inputs/outputs/states of a certain kind, methods `ir.inputs`, `ir.outputs`, `ir.states` are provided. Their argument defaults to the default kinds mentioned.
- To iterate over inputs/outputs/states of any "type", use `ir.all_inputs`, `ir.all_outputs` and `ir.all_states`. - To iterate over inputs/outputs/states of any kind, use `ir.all_inputs`, `ir.all_outputs` and `ir.all_states`.
- Outputs have a node that indicate the value of the output, this can be retrieved via `output.value()`. - Outputs have a node that indicate the value of the output, this can be retrieved via `output.value()`.
- States have a node that indicate the next value of the state, this can be retrieved via `state.next_value()`. - States have a node that indicate the next value of the state, this can be retrieved via `state.next_value()`.
They also have an initial value that is accessed as either `state.initial_value_signal()` or `state.initial_value_memory()`, depending on their sort. They also have an initial value that is accessed as either `state.initial_value_signal()` or `state.initial_value_memory()`, depending on their sort.

View File

@ -67,26 +67,26 @@ const char *fn_to_string(Fn fn) {
log_error("fn_to_string: unknown Functional::Fn value %d", (int)fn); log_error("fn_to_string: unknown Functional::Fn value %d", (int)fn);
} }
vector<IRInput const*> IR::inputs(IdString type) const { vector<IRInput const*> IR::inputs(IdString kind) const {
vector<IRInput const*> ret; vector<IRInput const*> ret;
for (const auto &[name, input] : _inputs) for (const auto &[name, input] : _inputs)
if(input.type == type) if(input.kind == kind)
ret.push_back(&input); ret.push_back(&input);
return ret; return ret;
} }
vector<IROutput const*> IR::outputs(IdString type) const { vector<IROutput const*> IR::outputs(IdString kind) const {
vector<IROutput const*> ret; vector<IROutput const*> ret;
for (const auto &[name, output] : _outputs) for (const auto &[name, output] : _outputs)
if(output.type == type) if(output.kind == kind)
ret.push_back(&output); ret.push_back(&output);
return ret; return ret;
} }
vector<IRState const*> IR::states(IdString type) const { vector<IRState const*> IR::states(IdString kind) const {
vector<IRState const*> ret; vector<IRState const*> ret;
for (const auto &[name, state] : _states) for (const auto &[name, state] : _states)
if(state.type == type) if(state.kind == kind)
ret.push_back(&state); ret.push_back(&state);
return ret; return ret;
} }
@ -120,8 +120,8 @@ struct PrintVisitor : DefaultVisitor<std::string> {
std::string zero_extend(Node, Node a, int out_width) override { return "zero_extend(" + np(a) + ", " + std::to_string(out_width) + ")"; } std::string zero_extend(Node, Node a, int out_width) override { return "zero_extend(" + np(a) + ", " + std::to_string(out_width) + ")"; }
std::string sign_extend(Node, Node a, int out_width) override { return "sign_extend(" + np(a) + ", " + std::to_string(out_width) + ")"; } std::string sign_extend(Node, Node a, int out_width) override { return "sign_extend(" + np(a) + ", " + std::to_string(out_width) + ")"; }
std::string constant(Node, RTLIL::Const const& value) override { return "constant(" + value.as_string() + ")"; } std::string constant(Node, RTLIL::Const const& value) override { return "constant(" + value.as_string() + ")"; }
std::string input(Node, IdString name, IdString type) override { return "input(" + name.str() + ", " + type.str() + ")"; } std::string input(Node, IdString name, IdString kind) override { return "input(" + name.str() + ", " + kind.str() + ")"; }
std::string state(Node, IdString name, IdString type) override { return "state(" + name.str() + ", " + type.str() + ")"; } std::string state(Node, IdString name, IdString kind) override { return "state(" + name.str() + ", " + kind.str() + ")"; }
std::string default_handler(Node self) override { std::string default_handler(Node self) override {
std::string ret = fn_to_string(self.fn()); std::string ret = fn_to_string(self.fn());
ret += "("; ret += "(";

View File

@ -34,7 +34,7 @@ namespace Functional {
// each function is documented with a short pseudocode declaration or definition // each function is documented with a short pseudocode declaration or definition
// standard C/Verilog operators are used to describe the result // standard C/Verilog operators are used to describe the result
// //
// the types used in this are: // the sorts used in this are:
// - bit[N]: a bitvector of N bits // - bit[N]: a bitvector of N bits
// bit[N] can be indicated as signed or unsigned. this is not tracked by the functional backend // bit[N] can be indicated as signed or unsigned. this is not tracked by the functional backend
// but is meant to indicate how the value is interpreted // but is meant to indicate how the value is interpreted
@ -43,12 +43,12 @@ namespace Functional {
// - int: C++ int // - int: C++ int
// - Const[N]: yosys RTLIL::Const (with size() == N) // - Const[N]: yosys RTLIL::Const (with size() == N)
// - IdString: yosys IdString // - IdString: yosys IdString
// - any: used in documentation to indicate that the type is unconstrained // - any: used in documentation to indicate that the sort is unconstrained
// //
// nodes in the functional backend are either of type bit[N] or memory[N,M] (for some N, M: int) // nodes in the functional backend are either of sort bit[N] or memory[N,M] (for some N, M: int)
// additionally, they can carry a constant of type int, Const[N] or IdString // additionally, they can carry a constant of sort int, Const[N] or IdString
// each node has a 'sort' field that stores the type of the node // each node has a 'sort' field that stores the sort of the node
// slice, zero_extend, sign_extend use the type field to store out_width // slice, zero_extend, sign_extend use the sort field to store out_width
enum class Fn { enum class Fn {
// invalid() = known-invalid/shouldn't happen value // invalid() = known-invalid/shouldn't happen value
// TODO: maybe remove this and use e.g. std::optional instead? // TODO: maybe remove this and use e.g. std::optional instead?
@ -136,7 +136,7 @@ namespace Functional {
// returns the name of a Fn value, as a string literal // returns the name of a Fn value, as a string literal
const char *fn_to_string(Fn); const char *fn_to_string(Fn);
// Sort represents the sort or type of a node // Sort represents the sort or type of a node
// currently the only two types are signal/bit and memory // currently the only two sorts are signal/bit and memory
class Sort { class Sort {
std::variant<int, std::pair<int, int>> _v; std::variant<int, std::pair<int, int>> _v;
public: public:
@ -144,11 +144,11 @@ namespace Functional {
Sort(int addr_width, int data_width) : _v(std::make_pair(addr_width, data_width)) { } Sort(int addr_width, int data_width) : _v(std::make_pair(addr_width, data_width)) { }
bool is_signal() const { return _v.index() == 0; } bool is_signal() const { return _v.index() == 0; }
bool is_memory() const { return _v.index() == 1; } bool is_memory() const { return _v.index() == 1; }
// returns the width of a bitvector type, errors out for other types // returns the width of a bitvector sort, errors out for other sorts
int width() const { return std::get<0>(_v); } int width() const { return std::get<0>(_v); }
// returns the address width of a bitvector type, errors out for other types // returns the address width of a bitvector sort, errors out for other sorts
int addr_width() const { return std::get<1>(_v).first; } int addr_width() const { return std::get<1>(_v).first; }
// returns the data width of a bitvector type, errors out for other types // returns the data width of a bitvector sort, errors out for other sorts
int data_width() const { return std::get<1>(_v).second; } int data_width() const { return std::get<1>(_v).second; }
bool operator==(Sort const& other) const { return _v == other._v; } bool operator==(Sort const& other) const { return _v == other._v; }
unsigned int hash() const { return mkhash(_v); } unsigned int hash() const { return mkhash(_v); }
@ -160,22 +160,22 @@ namespace Functional {
friend class Factory; friend class Factory;
public: public:
IdString name; IdString name;
IdString type; IdString kind;
Sort sort; Sort sort;
private: private:
IRInput(IR &, IdString name, IdString type, Sort sort) IRInput(IR &, IdString name, IdString kind, Sort sort)
: name(name), type(type), sort(std::move(sort)) {} : name(name), kind(kind), sort(std::move(sort)) {}
}; };
class IROutput { class IROutput {
friend class Factory; friend class Factory;
IR &_ir; IR &_ir;
public: public:
IdString name; IdString name;
IdString type; IdString kind;
Sort sort; Sort sort;
private: private:
IROutput(IR &ir, IdString name, IdString type, Sort sort) IROutput(IR &ir, IdString name, IdString kind, Sort sort)
: _ir(ir), name(name), type(type), sort(std::move(sort)) {} : _ir(ir), name(name), kind(kind), sort(std::move(sort)) {}
public: public:
Node value() const; Node value() const;
bool has_value() const; bool has_value() const;
@ -186,12 +186,12 @@ namespace Functional {
IR &_ir; IR &_ir;
public: public:
IdString name; IdString name;
IdString type; IdString kind;
Sort sort; Sort sort;
private: private:
std::variant<RTLIL::Const, MemContents> _initial; std::variant<RTLIL::Const, MemContents> _initial;
IRState(IR &ir, IdString name, IdString type, Sort sort) IRState(IR &ir, IdString name, IdString kind, Sort sort)
: _ir(ir), name(name), type(type), sort(std::move(sort)) {} : _ir(ir), name(name), kind(kind), sort(std::move(sort)) {}
public: public:
Node next_value() const; Node next_value() const;
bool has_next_value() const; bool has_next_value() const;
@ -253,20 +253,20 @@ namespace Functional {
Node operator[](int i); Node operator[](int i);
void topological_sort(); void topological_sort();
void forward_buf(); void forward_buf();
IRInput const& input(IdString name, IdString type) const { return _inputs.at({name, type}); } IRInput const& input(IdString name, IdString kind) const { return _inputs.at({name, kind}); }
IRInput const& input(IdString name) const { return input(name, ID($input)); } IRInput const& input(IdString name) const { return input(name, ID($input)); }
IROutput const& output(IdString name, IdString type) const { return _outputs.at({name, type}); } IROutput const& output(IdString name, IdString kind) const { return _outputs.at({name, kind}); }
IROutput const& output(IdString name) const { return output(name, ID($output)); } IROutput const& output(IdString name) const { return output(name, ID($output)); }
IRState const& state(IdString name, IdString type) const { return _states.at({name, type}); } IRState const& state(IdString name, IdString kind) const { return _states.at({name, kind}); }
IRState const& state(IdString name) const { return state(name, ID($state)); } IRState const& state(IdString name) const { return state(name, ID($state)); }
bool has_input(IdString name, IdString type) const { return _inputs.count({name, type}); } bool has_input(IdString name, IdString kind) const { return _inputs.count({name, kind}); }
bool has_output(IdString name, IdString type) const { return _outputs.count({name, type}); } bool has_output(IdString name, IdString kind) const { return _outputs.count({name, kind}); }
bool has_state(IdString name, IdString type) const { return _states.count({name, type}); } bool has_state(IdString name, IdString kind) const { return _states.count({name, kind}); }
vector<IRInput const*> inputs(IdString type) const; vector<IRInput const*> inputs(IdString kind) const;
vector<IRInput const*> inputs() const { return inputs(ID($input)); } vector<IRInput const*> inputs() const { return inputs(ID($input)); }
vector<IROutput const*> outputs(IdString type) const; vector<IROutput const*> outputs(IdString kind) const;
vector<IROutput const*> outputs() const { return outputs(ID($output)); } vector<IROutput const*> outputs() const { return outputs(ID($output)); }
vector<IRState const*> states(IdString type) const; vector<IRState const*> states(IdString kind) const;
vector<IRState const*> states() const { return states(ID($state)); } vector<IRState const*> states() const { return states(ID($state)); }
vector<IRInput const*> all_inputs() const; vector<IRInput const*> all_inputs() const;
vector<IROutput const*> all_outputs() const; vector<IROutput const*> all_outputs() const;
@ -364,12 +364,12 @@ namespace Functional {
}; };
inline IR::Graph::Ref IR::mutate(Node n) { return _graph[n._ref.index()]; } inline IR::Graph::Ref IR::mutate(Node n) { return _graph[n._ref.index()]; }
inline Node IR::operator[](int i) { return Node(_graph[i]); } inline Node IR::operator[](int i) { return Node(_graph[i]); }
inline Node IROutput::value() const { return Node(_ir._graph({name, type, false})); } inline Node IROutput::value() const { return Node(_ir._graph({name, kind, false})); }
inline bool IROutput::has_value() const { return _ir._graph.has_key({name, type, false}); } inline bool IROutput::has_value() const { return _ir._graph.has_key({name, kind, false}); }
inline void IROutput::set_value(Node value) { log_assert(sort == value.sort()); _ir.mutate(value).assign_key({name, type, false}); } inline void IROutput::set_value(Node value) { log_assert(sort == value.sort()); _ir.mutate(value).assign_key({name, kind, false}); }
inline Node IRState::next_value() const { return Node(_ir._graph({name, type, true})); } inline Node IRState::next_value() const { return Node(_ir._graph({name, kind, true})); }
inline bool IRState::has_next_value() const { return _ir._graph.has_key({name, type, true}); } inline bool IRState::has_next_value() const { return _ir._graph.has_key({name, kind, true}); }
inline void IRState::set_next_value(Node value) { log_assert(sort == value.sort()); _ir.mutate(value).assign_key({name, type, true}); } inline void IRState::set_next_value(Node value) { log_assert(sort == value.sort()); _ir.mutate(value).assign_key({name, kind, true}); }
inline Node IR::iterator::operator*() { return Node(_ir->_graph[_index]); } inline Node IR::iterator::operator*() { return Node(_ir->_graph[_index]); }
inline arrow_proxy<Node> IR::iterator::operator->() { return arrow_proxy<Node>(**this); } inline arrow_proxy<Node> IR::iterator::operator->() { return arrow_proxy<Node>(**this); }
// AbstractVisitor provides an abstract base class for visitors // AbstractVisitor provides an abstract base class for visitors
@ -403,8 +403,8 @@ namespace Functional {
virtual T arithmetic_shift_right(Node self, Node a, Node b) = 0; virtual T arithmetic_shift_right(Node self, Node a, Node b) = 0;
virtual T mux(Node self, Node a, Node b, Node s) = 0; virtual T mux(Node self, Node a, Node b, Node s) = 0;
virtual T constant(Node self, RTLIL::Const const & value) = 0; virtual T constant(Node self, RTLIL::Const const & value) = 0;
virtual T input(Node self, IdString name, IdString type) = 0; virtual T input(Node self, IdString name, IdString kind) = 0;
virtual T state(Node self, IdString name, IdString type) = 0; virtual T state(Node self, IdString name, IdString kind) = 0;
virtual T memory_read(Node self, Node mem, Node addr) = 0; virtual T memory_read(Node self, Node mem, Node addr) = 0;
virtual T memory_write(Node self, Node mem, Node addr, Node data) = 0; virtual T memory_write(Node self, Node mem, Node addr, Node data) = 0;
}; };
@ -547,26 +547,26 @@ namespace Functional {
log_assert(node.sort() == value.sort()); log_assert(node.sort() == value.sort());
_ir.mutate(node).append_arg(value._ref); _ir.mutate(node).append_arg(value._ref);
} }
IRInput &add_input(IdString name, IdString type, Sort sort) { IRInput &add_input(IdString name, IdString kind, Sort sort) {
auto [it, inserted] = _ir._inputs.emplace({name, type}, IRInput(_ir, name, type, std::move(sort))); auto [it, inserted] = _ir._inputs.emplace({name, kind}, IRInput(_ir, name, kind, std::move(sort)));
if (!inserted) log_error("input `%s` was re-defined", name.c_str()); if (!inserted) log_error("input `%s` was re-defined", name.c_str());
return it->second; return it->second;
} }
IROutput &add_output(IdString name, IdString type, Sort sort) { IROutput &add_output(IdString name, IdString kind, Sort sort) {
auto [it, inserted] = _ir._outputs.emplace({name, type}, IROutput(_ir, name, type, std::move(sort))); auto [it, inserted] = _ir._outputs.emplace({name, kind}, IROutput(_ir, name, kind, std::move(sort)));
if (!inserted) log_error("output `%s` was re-defined", name.c_str()); if (!inserted) log_error("output `%s` was re-defined", name.c_str());
return it->second; return it->second;
} }
IRState &add_state(IdString name, IdString type, Sort sort) { IRState &add_state(IdString name, IdString kind, Sort sort) {
auto [it, inserted] = _ir._states.emplace({name, type}, IRState(_ir, name, type, std::move(sort))); auto [it, inserted] = _ir._states.emplace({name, kind}, IRState(_ir, name, kind, std::move(sort)));
if (!inserted) log_error("state `%s` was re-defined", name.c_str()); if (!inserted) log_error("state `%s` was re-defined", name.c_str());
return it->second; return it->second;
} }
Node value(IRInput const& input) { Node value(IRInput const& input) {
return add(IR::NodeData(Fn::input, std::pair(input.name, input.type)), input.sort, {}); return add(IR::NodeData(Fn::input, std::pair(input.name, input.kind)), input.sort, {});
} }
Node value(IRState const& state) { Node value(IRState const& state) {
return add(IR::NodeData(Fn::state, std::pair(state.name, state.type)), state.sort, {}); return add(IR::NodeData(Fn::state, std::pair(state.name, state.kind)), state.sort, {});
} }
void suggest_name(Node node, IdString name) { void suggest_name(Node node, IdString name) {
_ir.mutate(node).sparse_attr() = name; _ir.mutate(node).sparse_attr() = name;