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 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 input(Node, IdString name, IdString type) override { log_assert(type == 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 input(Node, IdString name, IdString kind) override { log_assert(kind == ID($input)); print("input.{}", input_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_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_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 state(Node, IdString name, IdString type) override { log_assert(type == ID($state)); return state_struct.access("state", 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 kind) override { log_assert(kind == ID($state)); return state_struct.access("state", name); }
};
struct SmtModule {

View File

@ -144,9 +144,9 @@ struct FunctionalTestGeneric : public Pass
for(auto node : fir)
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())
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())
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;

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.
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.
Every input, output and state has a name (equal to their name in RTLIL), a sort and a "type".
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.
- 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 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 inputs/outputs/states of any "type", use `ir.all_inputs`, `ir.all_outputs` and `ir.all_states`.
Every input, output and state has a name (equal to their name in RTLIL), a sort and a kind.
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, 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 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 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()`.
- 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.

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);
}
vector<IRInput const*> IR::inputs(IdString type) const {
vector<IRInput const*> IR::inputs(IdString kind) const {
vector<IRInput const*> ret;
for (const auto &[name, input] : _inputs)
if(input.type == type)
if(input.kind == kind)
ret.push_back(&input);
return ret;
}
vector<IROutput const*> IR::outputs(IdString type) const {
vector<IROutput const*> IR::outputs(IdString kind) const {
vector<IROutput const*> ret;
for (const auto &[name, output] : _outputs)
if(output.type == type)
if(output.kind == kind)
ret.push_back(&output);
return ret;
}
vector<IRState const*> IR::states(IdString type) const {
vector<IRState const*> IR::states(IdString kind) const {
vector<IRState const*> ret;
for (const auto &[name, state] : _states)
if(state.type == type)
if(state.kind == kind)
ret.push_back(&state);
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 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 input(Node, IdString name, IdString type) override { return "input(" + name.str() + ", " + type.str() + ")"; }
std::string state(Node, IdString name, IdString type) override { return "state(" + 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 kind) override { return "state(" + name.str() + ", " + kind.str() + ")"; }
std::string default_handler(Node self) override {
std::string ret = fn_to_string(self.fn());
ret += "(";

View File

@ -34,7 +34,7 @@ namespace Functional {
// each function is documented with a short pseudocode declaration or definition
// 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] 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
@ -43,12 +43,12 @@ namespace Functional {
// - int: C++ int
// - Const[N]: yosys RTLIL::Const (with size() == N)
// - 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)
// additionally, they can carry a constant of type int, Const[N] or IdString
// each node has a 'sort' field that stores the type of the node
// slice, zero_extend, sign_extend use the type field to store out_width
// 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 sort int, Const[N] or IdString
// each node has a 'sort' field that stores the sort of the node
// slice, zero_extend, sign_extend use the sort field to store out_width
enum class Fn {
// invalid() = known-invalid/shouldn't happen value
// 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
const char *fn_to_string(Fn);
// 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 {
std::variant<int, std::pair<int, int>> _v;
public:
@ -144,11 +144,11 @@ namespace Functional {
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_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); }
// 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; }
// 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; }
bool operator==(Sort const& other) const { return _v == other._v; }
unsigned int hash() const { return mkhash(_v); }
@ -160,22 +160,22 @@ namespace Functional {
friend class Factory;
public:
IdString name;
IdString type;
IdString kind;
Sort sort;
private:
IRInput(IR &, IdString name, IdString type, Sort sort)
: name(name), type(type), sort(std::move(sort)) {}
IRInput(IR &, IdString name, IdString kind, Sort sort)
: name(name), kind(kind), sort(std::move(sort)) {}
};
class IROutput {
friend class Factory;
IR &_ir;
public:
IdString name;
IdString type;
IdString kind;
Sort sort;
private:
IROutput(IR &ir, IdString name, IdString type, Sort sort)
: _ir(ir), name(name), type(type), sort(std::move(sort)) {}
IROutput(IR &ir, IdString name, IdString kind, Sort sort)
: _ir(ir), name(name), kind(kind), sort(std::move(sort)) {}
public:
Node value() const;
bool has_value() const;
@ -186,12 +186,12 @@ namespace Functional {
IR &_ir;
public:
IdString name;
IdString type;
IdString kind;
Sort sort;
private:
std::variant<RTLIL::Const, MemContents> _initial;
IRState(IR &ir, IdString name, IdString type, Sort sort)
: _ir(ir), name(name), type(type), sort(std::move(sort)) {}
IRState(IR &ir, IdString name, IdString kind, Sort sort)
: _ir(ir), name(name), kind(kind), sort(std::move(sort)) {}
public:
Node next_value() const;
bool has_next_value() const;
@ -253,20 +253,20 @@ namespace Functional {
Node operator[](int i);
void topological_sort();
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)); }
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)); }
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)); }
bool has_input(IdString name, IdString type) const { return _inputs.count({name, type}); }
bool has_output(IdString name, IdString type) const { return _outputs.count({name, type}); }
bool has_state(IdString name, IdString type) const { return _states.count({name, type}); }
vector<IRInput const*> inputs(IdString type) const;
bool has_input(IdString name, IdString kind) const { return _inputs.count({name, kind}); }
bool has_output(IdString name, IdString kind) const { return _outputs.count({name, kind}); }
bool has_state(IdString name, IdString kind) const { return _states.count({name, kind}); }
vector<IRInput const*> inputs(IdString kind) const;
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<IRState const*> states(IdString type) const;
vector<IRState const*> states(IdString kind) const;
vector<IRState const*> states() const { return states(ID($state)); }
vector<IRInput const*> all_inputs() 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 Node IR::operator[](int i) { return Node(_graph[i]); }
inline Node IROutput::value() const { return Node(_ir._graph({name, type, false})); }
inline bool IROutput::has_value() const { return _ir._graph.has_key({name, type, false}); }
inline void IROutput::set_value(Node value) { log_assert(sort == value.sort()); _ir.mutate(value).assign_key({name, type, false}); }
inline Node IRState::next_value() const { return Node(_ir._graph({name, type, true})); }
inline bool IRState::has_next_value() const { return _ir._graph.has_key({name, type, true}); }
inline void IRState::set_next_value(Node value) { log_assert(sort == value.sort()); _ir.mutate(value).assign_key({name, type, true}); }
inline Node IROutput::value() const { return Node(_ir._graph({name, kind, 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, kind, false}); }
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, kind, 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 arrow_proxy<Node> IR::iterator::operator->() { return arrow_proxy<Node>(**this); }
// 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 mux(Node self, Node a, Node b, Node s) = 0;
virtual T constant(Node self, RTLIL::Const const & value) = 0;
virtual T input(Node self, IdString name, IdString type) = 0;
virtual T state(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 kind) = 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;
};
@ -547,26 +547,26 @@ namespace Functional {
log_assert(node.sort() == value.sort());
_ir.mutate(node).append_arg(value._ref);
}
IRInput &add_input(IdString name, IdString type, Sort sort) {
auto [it, inserted] = _ir._inputs.emplace({name, type}, IRInput(_ir, name, type, std::move(sort)));
IRInput &add_input(IdString name, IdString kind, Sort 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());
return it->second;
}
IROutput &add_output(IdString name, IdString type, Sort sort) {
auto [it, inserted] = _ir._outputs.emplace({name, type}, IROutput(_ir, name, type, std::move(sort)));
IROutput &add_output(IdString name, IdString kind, Sort 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());
return it->second;
}
IRState &add_state(IdString name, IdString type, Sort sort) {
auto [it, inserted] = _ir._states.emplace({name, type}, IRState(_ir, name, type, std::move(sort)));
IRState &add_state(IdString name, IdString kind, Sort 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());
return it->second;
}
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) {
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) {
_ir.mutate(node).sparse_attr() = name;