Skip to content

Commit

Permalink
ComputeGraph datatype for the upcoming functional backend
Browse files Browse the repository at this point in the history
  • Loading branch information
jix committed Apr 11, 2024
1 parent 99164ec commit ad15301
Show file tree
Hide file tree
Showing 2 changed files with 515 additions and 32 deletions.
369 changes: 369 additions & 0 deletions kernel/functional.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,369 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2024 Jannis Harder <[email protected]> <[email protected]>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/

#ifndef FUNCTIONAL_H
#define FUNCTIONAL_H

#include <tuple>
#include "kernel/yosys.h"

YOSYS_NAMESPACE_BEGIN

template<
typename Fn, // Function type (deduplicated across whole graph)
typename Attr = std::tuple<>, // Call attributes (present in every node)
typename SparseAttr = std::tuple<>, // Sparse call attributes (optional per node)
typename Key = std::tuple<> // Stable keys to refer to nodes
>
struct ComputeGraph
{
struct Ref;
private:

// Functions are deduplicated by assigning unique ids
idict<Fn> functions;

struct Node {
int fn_index;
int arg_offset;
int arg_count;
Attr attr;

Node(int fn_index, Attr &&attr, int arg_offset, int arg_count = 0)
: fn_index(fn_index), arg_offset(arg_offset), arg_count(arg_count), attr(std::move(attr)) {}

Node(int fn_index, Attr const &attr, int arg_offset, int arg_count = 0)
: fn_index(fn_index), arg_offset(arg_offset), arg_count(arg_count), attr(attr) {}
};


std::vector<Node> nodes;
std::vector<int> args;
dict<Key, int> keys_;
dict<int, SparseAttr> sparse_attrs;

public:
template<typename Graph>
struct BaseRef
{
protected:
friend struct ComputeGraph;
Graph *graph_;
int index_;
BaseRef(Graph *graph, int index) : graph_(graph), index_(index) {
log_assert(index_ >= 0);
check();
}

void check() const { log_assert(index_ < graph_->size()); }

Node const &deref() const { check(); return graph_->nodes[index_]; }

public:
ComputeGraph const &graph() const { return graph_; }
int index() const { return index_; }

int size() const { return deref().arg_count; }

BaseRef arg(int n) const
{
Node const &node = deref();
log_assert(n >= 0 && n < node.arg_count);
return BaseRef(graph_, graph_->args[node.arg_offset + n]);
}

std::vector<int>::const_iterator arg_indices_cbegin() const
{
Node const &node = deref();
return graph_->args.cbegin() + node.arg_offset;
}

std::vector<int>::const_iterator arg_indices_cend() const
{
Node const &node = deref();
return graph_->args.cbegin() + node.arg_offset + node.arg_count;
}

Fn const &function() const { return graph_->functions[deref().fn_index]; }
Attr const &attr() const { return deref().attr; }

bool has_sparse_attr() const { return graph_->sparse_attrs.count(index_); }

SparseAttr const &sparse_attr() const
{
auto found = graph_->sparse_attrs.find(index_);
log_assert(found != graph_->sparse_attrs.end());
return *found;
}
};

using ConstRef = BaseRef<ComputeGraph const>;

struct Ref : public BaseRef<ComputeGraph>
{
private:
friend struct ComputeGraph;
Ref(ComputeGraph *graph, int index) : BaseRef<ComputeGraph>(graph, index) {}
Node &deref() const { this->check(); return this->graph_->nodes[this->index_]; }

public:
void set_function(Fn const &function) const
{
deref().fn_index = this->graph_->functions(function);
}

Attr &attr() const { return deref().attr; }

void append_arg(ConstRef arg) const
{
log_assert(arg.graph_ == this->graph_);
append_arg(arg.index());
}

void append_arg(int arg) const
{
log_assert(arg >= 0 && arg < this->graph_->size());
Node &node = deref();
if (node.arg_offset + node.arg_count != GetSize(this->graph_->args))
move_args(node);
this->graph_->args.push_back(arg);
node.arg_count++;
}

operator ConstRef() const
{
return ConstRef(this->graph_, this->index_);
}

SparseAttr &sparse_attr() const
{
return this->graph_->sparse_attrs[this->index_];
}

void clear_sparse_attr() const
{
this->graph_->sparse_attrs.erase(this->index_);
}

void assign_key(Key const &key) const
{
this->graph_->keys_.emplace(key, this->index_);
}

private:
void move_args(Node &node) const
{
auto &args = this->graph_->args;
int old_offset = node.arg_offset;
node.arg_offset = GetSize(args);
for (int i = 0; i != node.arg_count; ++i)
args.push_back(args[old_offset + i]);
}

};

bool has_key(Key const &key) const
{
return keys_.count(key);
}

dict<Key, int> const &keys() const
{
return keys_;
}

ConstRef operator()(Key const &key) const
{
auto it = keys_.find(key);
log_assert(it != keys_.end());
return (*this)[it->second];
}

Ref operator()(Key const &key)
{
auto it = keys_.find(key);
log_assert(it != keys_.end());
return (*this)[it->second];
}

int size() const { return GetSize(nodes); }

ConstRef operator[](int index) const { return ConstRef(this, index); }
Ref operator[](int index) { return Ref(this, index); }

Ref add(Fn const &function, Attr &&attr)
{
int index = GetSize(nodes);
int fn_index = functions(function);
nodes.emplace_back(fn_index, std::move(attr), GetSize(args));
return Ref(this, index);
}

Ref add(Fn const &function, Attr const &attr)
{
int index = GetSize(nodes);
int fn_index = functions(function);
nodes.emplace_back(fn_index, attr, GetSize(args));
return Ref(this, index);
}

template<typename T>
Ref add(Fn const &function, Attr const &attr, T const &args)
{
Ref added = add(function, attr);
for (auto arg : args)
added.append_arg(arg);
return added;
}

template<typename T>
Ref add(Fn const &function, Attr &&attr, T const &args)
{
Ref added = add(function, std::move(attr));
for (auto arg : args)
added.append_arg(arg);
return added;
}

template<typename T>
Ref add(Fn const &function, Attr const &attr, T begin, T end)
{
Ref added = add(function, attr);
for (; begin != end; ++begin)
added.append_arg(*begin);
return added;
}

void permute(std::vector<int> const &perm)
{
log_assert(perm.size() <= nodes.size());
std::vector<int> inv_perm;
inv_perm.resize(nodes.size(), -1);
for (int i = 0; i < GetSize(perm); ++i)
{
int j = perm[i];
log_assert(j >= 0 && j < GetSize(perm));
log_assert(inv_perm[j] == -1);
inv_perm[j] = i;
}
permute(perm, inv_perm);
}

void permute(std::vector<int> const &perm, std::vector<int> const &inv_perm)
{
log_assert(inv_perm.size() == nodes.size());
std::vector<Node> new_nodes;
new_nodes.reserve(perm.size());
dict<int, SparseAttr> new_sparse_attrs;
for (int i : perm)
{
int j = GetSize(new_nodes);
new_nodes.emplace_back(std::move(nodes[i]));
auto found = sparse_attrs.find(i);
if (found != sparse_attrs.end())
new_sparse_attrs.emplace(j, std::move(found->second));
}

std::swap(nodes, new_nodes);
std::swap(sparse_attrs, new_sparse_attrs);

for (int &arg : args)
{
log_assert(arg < GetSize(inv_perm));
arg = inv_perm[arg];
}

for (auto &key : keys_)
{
log_assert(key.second < GetSize(inv_perm));
key.second = inv_perm[key.second];
}
}

struct SccAdaptor
{
private:
ComputeGraph const &graph_;
std::vector<int> indices_;
public:
SccAdaptor(ComputeGraph const &graph) : graph_(graph)
{
indices_.resize(graph.size(), -1);
}


typedef int node_type;

struct node_enumerator {
private:
friend struct SccAdaptor;
int current, end;
node_enumerator(int current, int end) : current(current), end(end) {}

public:

bool finished() const { return current == end; }
node_type next() {
log_assert(!finished());
node_type result = current;
++current;
return result;
}
};

node_enumerator enumerate_nodes() {
return node_enumerator(0, GetSize(indices_));
}


struct successor_enumerator {
private:
friend struct SccAdaptor;
std::vector<int>::const_iterator current, end;
successor_enumerator(std::vector<int>::const_iterator current, std::vector<int>::const_iterator end) :
current(current), end(end) {}

public:
bool finished() const { return current == end; }
node_type next() {
log_assert(!finished());
node_type result = *current;
++current;
return result;
}
};

successor_enumerator enumerate_successors(int index) const {
auto const &ref = graph_[index];
return successor_enumerator(ref.arg_indices_cbegin(), ref.arg_indices_cend());
}

int &dfs_index(node_type const &node) { return indices_[node]; }

std::vector<int> const &dfs_indices() { return indices_; }
};

};



YOSYS_NAMESPACE_END


#endif
Loading

0 comments on commit ad15301

Please sign in to comment.