Skip to content

Commit 59a57e1

Browse files
EthanBerko32niko89082bcarlet
authored
Add DFG crate and data structure (#1)
* Code for DFG * Move to crate * Format + fix build * updated dfg * fixed formatting * Fix warnings * Made changes based on PR comments --------- Co-authored-by: niko89082 <154576789+niko89082@users.noreply.github.com> Co-authored-by: bcarlet <8906114+bcarlet@users.noreply.github.com>
1 parent 52d0155 commit 59a57e1

5 files changed

Lines changed: 342 additions & 0 deletions

File tree

Cargo.lock

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
name = "calyx-libm"
33
version.workspace = true
44
edition.workspace = true
5+
rust-version.workspace = true
56

67
[dependencies]
78
argh.workspace = true
@@ -10,6 +11,7 @@ calyx-libm-approx.workspace = true
1011
calyx-libm-ast.workspace = true
1112
calyx-libm-ast-lowering.workspace = true
1213
calyx-libm-backend.workspace = true
14+
calyx-libm-dfg.workspace = true
1315
calyx-libm-hir.workspace = true
1416
calyx-libm-hir-passes.workspace = true
1517
calyx-libm-utils.workspace = true
@@ -44,6 +46,7 @@ calyx-libm-approx = { path = "crates/approx" }
4446
calyx-libm-ast = { path = "crates/ast" }
4547
calyx-libm-ast-lowering = { path = "crates/ast_lowering" }
4648
calyx-libm-backend = { path = "crates/backend" }
49+
calyx-libm-dfg = { path = "crates/dfg" }
4750
calyx-libm-hir = { path = "crates/hir" }
4851
calyx-libm-hir-passes = { path = "crates/hir_passes" }
4952
calyx-libm-macros = { path = "crates/macros" }

crates/dfg/Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[package]
2+
name = "calyx-libm-dfg"
3+
version.workspace = true
4+
edition.workspace = true
5+
6+
[dependencies]
7+
cranelift-entity.workspace = true

crates/dfg/src/dfg.rs

Lines changed: 321 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,321 @@
1+
use cranelift_entity::{EntityList, ListPool, PrimaryMap, entity_impl};
2+
use std::ops::{Index, IndexMut};
3+
4+
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
5+
pub struct NodeId(u32);
6+
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
7+
pub struct EdgeId(u32);
8+
entity_impl!(NodeId, "n");
9+
entity_impl!(EdgeId, "e");
10+
11+
#[derive(Debug)]
12+
pub struct Dfg {
13+
pub nodes: PrimaryMap<NodeId, Node>,
14+
pub edges: PrimaryMap<EdgeId, Edge>,
15+
pub edge_pool: ListPool<EdgeId>,
16+
}
17+
18+
impl Dfg {
19+
pub fn new() -> Self {
20+
Dfg {
21+
nodes: PrimaryMap::new(),
22+
edges: PrimaryMap::new(),
23+
edge_pool: ListPool::new(),
24+
}
25+
}
26+
27+
pub fn with_nodes(nodes: PrimaryMap<NodeId, Node>) -> Self {
28+
Dfg {
29+
nodes,
30+
edges: PrimaryMap::new(),
31+
edge_pool: ListPool::new(),
32+
}
33+
}
34+
35+
///Adds an edge to the Dfg. Updates connected nodes to contain this edge
36+
///as an neighbor
37+
pub fn add_edge(&mut self, edge: Edge) -> EdgeId {
38+
let e_id = self.edges.push(edge);
39+
self.nodes[self.edges[e_id].output]
40+
.inputs
41+
.push(e_id, &mut self.edge_pool);
42+
self.nodes[self.edges[e_id].input]
43+
.outputs
44+
.push(e_id, &mut self.edge_pool);
45+
e_id
46+
}
47+
48+
pub fn add_node(&mut self, node: Node) -> NodeId {
49+
self.nodes.push(node)
50+
}
51+
52+
pub fn add_const(&mut self, value: f64) -> NodeId {
53+
self.nodes.push(Node {
54+
node_type: NodeKind::Const(value),
55+
inputs: EntityList::new(),
56+
outputs: EntityList::new(),
57+
props: Vec::new(),
58+
})
59+
}
60+
61+
pub fn inputs(&self, node: NodeId) -> &[EdgeId] {
62+
self[node].inputs.as_slice(&self.edge_pool)
63+
}
64+
65+
pub fn node_ids(&self) -> impl Iterator<Item = NodeId> {
66+
self.nodes.keys()
67+
}
68+
69+
pub fn input_nodes(&self) -> Vec<NodeId> {
70+
self.nodes
71+
.keys()
72+
.filter(|&id| matches!(self.nodes[id].node_type, NodeKind::Input))
73+
.collect()
74+
}
75+
76+
pub fn output_nodes(&self) -> Vec<NodeId> {
77+
self.nodes
78+
.keys()
79+
.filter(|&id| matches!(self.nodes[id].node_type, NodeKind::Output))
80+
.collect()
81+
}
82+
83+
pub fn len(&self) -> usize {
84+
self.nodes.len()
85+
}
86+
87+
pub fn is_empty(&self) -> bool {
88+
self.nodes.is_empty()
89+
}
90+
91+
pub fn to_dot(&self, name: &str) -> String {
92+
let mut dot: String = String::new();
93+
94+
dot.push_str(&format!(
95+
"subgraph {name} {{\n\
96+
\trankdir=BT;\n\
97+
\tordering=out;\n\
98+
\tnode [fontname=\"Helvetica\"];\n\
99+
\tedge [fontname=\"Helvetica\"];\n\n",
100+
));
101+
102+
for (n_id, node) in self.nodes.iter() {
103+
dot.push_str(&format!(
104+
"\t{} [label=\"{}\", shape={}];\n",
105+
n_id,
106+
node,
107+
if node.node_type == NodeKind::Input
108+
|| node.node_type == NodeKind::Output
109+
{
110+
"box"
111+
} else {
112+
"circle"
113+
}
114+
));
115+
}
116+
117+
for edge in self.edges.values() {
118+
dot.push_str(&format!("\t{} -> {};\n", edge.input, edge.output));
119+
}
120+
121+
dot.push_str("}\n");
122+
123+
dot
124+
}
125+
}
126+
127+
macro_rules! dfg_index_impl {
128+
($field:ident, $idx:ty, $out:ty) => {
129+
impl Index<$idx> for Dfg {
130+
type Output = $out;
131+
132+
#[inline]
133+
fn index(&self, index: $idx) -> &Self::Output {
134+
&self.$field[index]
135+
}
136+
}
137+
138+
impl IndexMut<$idx> for Dfg {
139+
#[inline]
140+
fn index_mut(&mut self, index: $idx) -> &mut Self::Output {
141+
&mut self.$field[index]
142+
}
143+
}
144+
};
145+
}
146+
147+
dfg_index_impl!(edges, EdgeId, Edge);
148+
dfg_index_impl!(nodes, NodeId, Node);
149+
150+
impl Default for Dfg {
151+
fn default() -> Self {
152+
Self::new()
153+
}
154+
}
155+
156+
#[derive(Debug)]
157+
pub struct Node {
158+
pub inputs: EntityList<EdgeId>,
159+
pub outputs: EntityList<EdgeId>,
160+
pub props: Vec<String>,
161+
pub node_type: NodeKind,
162+
}
163+
164+
#[derive(Debug)]
165+
pub struct Edge {
166+
pub input: NodeId,
167+
pub output: NodeId,
168+
pub props: Vec<String>,
169+
pub edge_type: Type,
170+
}
171+
172+
#[derive(Clone, Debug, PartialEq)]
173+
pub enum ArithOp {
174+
Add,
175+
Sub,
176+
Mul,
177+
Div,
178+
Neg,
179+
Sin,
180+
Cos,
181+
Asin,
182+
Acos,
183+
Asinh,
184+
Acosh,
185+
Abs,
186+
Pow,
187+
Min,
188+
Max,
189+
Floor,
190+
Exp,
191+
Gain { gain: f64 },
192+
Block { name: String },
193+
Other { name: String },
194+
}
195+
196+
#[derive(Clone, Debug, PartialEq)]
197+
pub enum NodeKind {
198+
Input,
199+
Output,
200+
Const(f64),
201+
Op(ArithOp),
202+
}
203+
204+
#[derive(Clone, Debug)]
205+
pub enum Type {
206+
Int {
207+
signed: bool,
208+
bits: usize,
209+
},
210+
Fixed {
211+
signed: bool,
212+
bits: usize,
213+
exp: isize,
214+
},
215+
F64,
216+
F32,
217+
F16,
218+
}
219+
220+
impl std::fmt::Display for ArithOp {
221+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
222+
match self {
223+
ArithOp::Add => write!(f, "+"),
224+
ArithOp::Sub => write!(f, "-"),
225+
ArithOp::Mul => write!(f, "*"),
226+
ArithOp::Div => write!(f, "/"),
227+
ArithOp::Neg => write!(f, "neg"),
228+
ArithOp::Abs => write!(f, "abs"),
229+
ArithOp::Pow => write!(f, "pow"),
230+
ArithOp::Min => write!(f, "min"),
231+
ArithOp::Max => write!(f, "max"),
232+
ArithOp::Floor => write!(f, "floor"),
233+
ArithOp::Exp => write!(f, "exp"),
234+
ArithOp::Sin => write!(f, "sin"),
235+
ArithOp::Cos => write!(f, "cos"),
236+
ArithOp::Asin => write!(f, "asin"),
237+
ArithOp::Acos => write!(f, "acos"),
238+
ArithOp::Asinh => write!(f, "asinh"),
239+
ArithOp::Acosh => write!(f, "acosh"),
240+
ArithOp::Gain { gain: g } => write!(f, "gain({})", g),
241+
ArithOp::Block { name: n } => write!(f, "{}", n),
242+
ArithOp::Other { name: n } => write!(f, "{}", n),
243+
}
244+
}
245+
}
246+
247+
impl std::fmt::Display for Type {
248+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
249+
match self {
250+
Type::Int { signed: s, bits: b } => {
251+
write!(f, "{}{}", if *s { "int" } else { "uint" }, b)
252+
}
253+
Type::Fixed {
254+
signed: s,
255+
bits: b,
256+
exp: e,
257+
} => write!(f, "{}fix<{},{}>", if *s { "s" } else { "u" }, b, e),
258+
Type::F64 => write!(f, "double"),
259+
Type::F32 => write!(f, "float"),
260+
Type::F16 => write!(f, "f16"),
261+
}
262+
}
263+
}
264+
265+
impl std::fmt::Display for Node {
266+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
267+
match &self.node_type {
268+
NodeKind::Input => write!(f, "Input"),
269+
NodeKind::Output => write!(f, "Output"),
270+
NodeKind::Op(o) => write!(f, "{o}"),
271+
NodeKind::Const(c) => write!(f, "{c}"),
272+
}
273+
}
274+
}
275+
276+
impl std::fmt::Display for Dfg {
277+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
278+
writeln!(f, "Nodes:")?;
279+
280+
for id in self.nodes.keys() {
281+
let node = &self.nodes[id];
282+
283+
write!(f, " {id}: {:?} ", node.node_type)?;
284+
285+
let inputs = node.inputs.as_slice(&self.edge_pool);
286+
let outputs = node.outputs.as_slice(&self.edge_pool);
287+
288+
write!(f, "in=[")?;
289+
for (i, e) in inputs.iter().enumerate() {
290+
if i > 0 {
291+
write!(f, ", ")?;
292+
}
293+
write!(f, "{e}")?;
294+
}
295+
296+
write!(f, "] out=[")?;
297+
for (i, e) in outputs.iter().enumerate() {
298+
if i > 0 {
299+
write!(f, ", ")?;
300+
}
301+
write!(f, "{e}")?;
302+
}
303+
304+
writeln!(f, "]")?;
305+
}
306+
307+
writeln!(f, "\nEdges:")?;
308+
309+
for id in self.edges.keys() {
310+
let edge = &self.edges[id];
311+
312+
writeln!(
313+
f,
314+
" {id}: {:?} {:?} -> {:?}",
315+
edge.edge_type, edge.input, edge.output
316+
)?;
317+
}
318+
319+
Ok(())
320+
}
321+
}

crates/dfg/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
mod dfg;
2+
3+
pub use dfg::*;

0 commit comments

Comments
 (0)