From 1f674166222d12efda8608de1ace72d0e1f2d06f Mon Sep 17 00:00:00 2001 From: Michael Maloney Date: Wed, 27 Dec 2023 20:44:13 +0000 Subject: [PATCH 1/2] Small expr.rs cleanups. --- bitsy/src/expr.rs | 88 +++++++++++++++++++++++------------------------ 1 file changed, 43 insertions(+), 45 deletions(-) diff --git a/bitsy/src/expr.rs b/bitsy/src/expr.rs index 5d9119f..a3d7c9d 100644 --- a/bitsy/src/expr.rs +++ b/bitsy/src/expr.rs @@ -45,6 +45,7 @@ pub enum Expr { ToWord(Loc, OnceCell, Arc), /// A vector constructor expression. Eg, `[0w2, 1w2, 2w2]`. Vec(Loc, OnceCell, Vec>), + /// An index into a struct type. Eg, `foo->bar`. IdxField(Loc, OnceCell, Arc, String), /// A static index. Eg, `foo[0]`. Idx(Loc, OnceCell, Arc, u64), @@ -292,23 +293,6 @@ impl Expr { } } - pub fn paths(&self) -> Vec { - let paths = std::cell::RefCell::new(vec![]); - let mut func = |e: &Expr| { - if let Expr::Reference(_loc, _typ, path) = e { - paths.borrow_mut().push(path.clone()); - } else if let Expr::Net(_loc, _typ, _netid) = e { - panic!("paths() only works on symbolic expressions."); - } - }; - self.with_subexprs(&mut func); - - let mut results = paths.into_inner(); - results.sort(); - results.dedup(); - results - } - pub fn is_constant(&self) -> bool { self.free_vars().is_empty() } @@ -401,35 +385,49 @@ impl Expr { self.paths().contains(&path) } - pub fn type_of(&self) -> Type { - self.type_of_cell().unwrap().get().unwrap().clone() + fn paths(&self) -> Vec { + let paths = std::cell::RefCell::new(vec![]); + let mut func = |e: &Expr| { + if let Expr::Reference(_loc, _typ, path) = e { + paths.borrow_mut().push(path.clone()); + } else if let Expr::Net(_loc, _typ, _netid) = e { + panic!("paths() only works on symbolic expressions."); + } + }; + self.with_subexprs(&mut func); + + let mut results = paths.into_inner(); + results.sort(); + results.dedup(); + results } - fn type_of_cell(&self) -> Option<&OnceCell> { - match self { - Expr::Net(_loc, typ, _netid) => Some(typ), - Expr::Reference(_loc, typ, _path) => Some(typ), - Expr::Word(_loc, typ, _width, _val) => Some(typ), - Expr::Enum(_loc, typ, _typedef, _name) => Some(typ), - Expr::Ctor(_loc, typ, _name, _e) => Some(typ), - Expr::Struct(_loc, typ, _fields) => Some(typ), - Expr::Let(_loc, typ, _name, _e, _b) => Some(typ), - Expr::UnOp(_loc, typ, _op, _e) => Some(typ), - Expr::BinOp(_loc, typ, _op, _e1, _e2) => Some(typ), - Expr::If(_loc, typ, _cond, _e1, _e2) => Some(typ), - Expr::Match(_loc, typ, _e, _arms) => Some(typ), - Expr::Mux(_loc, typ, _cond, _e1, _e2) => Some(typ), - Expr::Cat(_loc, typ, _es) => Some(typ), - Expr::Sext(_loc, typ, _e) => Some(typ), - Expr::Zext(_loc, typ, _e) => Some(typ), - Expr::TryCast(_loc, typ, _e) => Some(typ), - Expr::ToWord(_loc, typ, _e) => Some(typ), - Expr::Vec(_loc, typ, _es) => Some(typ), - Expr::Idx(_loc, typ, _e, _i) => Some(typ), - Expr::IdxField(_loc, typ, _e, _field) => Some(typ), - Expr::IdxRange(_loc, typ, _e, _j, _i) => Some(typ), - Expr::Call(_loc, typ, _fndef, _es) => Some(typ), - Expr::Hole(_loc, typ, _opt_name) => Some(typ), - } + pub fn type_of(&self) -> Type { + let cell = match self { + Expr::Net(_loc, typ, _netid) => typ, + Expr::Reference(_loc, typ, _path) => typ, + Expr::Word(_loc, typ, _width, _val) => typ, + Expr::Enum(_loc, typ, _typedef, _name) => typ, + Expr::Ctor(_loc, typ, _name, _e) => typ, + Expr::Struct(_loc, typ, _fields) => typ, + Expr::Let(_loc, typ, _name, _e, _b) => typ, + Expr::UnOp(_loc, typ, _op, _e) => typ, + Expr::BinOp(_loc, typ, _op, _e1, _e2) => typ, + Expr::If(_loc, typ, _cond, _e1, _e2) => typ, + Expr::Match(_loc, typ, _e, _arms) => typ, + Expr::Mux(_loc, typ, _cond, _e1, _e2) => typ, + Expr::Cat(_loc, typ, _es) => typ, + Expr::Sext(_loc, typ, _e) => typ, + Expr::Zext(_loc, typ, _e) => typ, + Expr::TryCast(_loc, typ, _e) => typ, + Expr::ToWord(_loc, typ, _e) => typ, + Expr::Vec(_loc, typ, _es) => typ, + Expr::Idx(_loc, typ, _e, _i) => typ, + Expr::IdxField(_loc, typ, _e, _field) => typ, + Expr::IdxRange(_loc, typ, _e, _j, _i) => typ, + Expr::Call(_loc, typ, _fndef, _es) => typ, + Expr::Hole(_loc, typ, _opt_name) => typ, + }; + cell.get().unwrap().clone() } } From a3c6570febe83eef32bea130ebd74edb98ad3e5f Mon Sep 17 00:00:00 2001 From: Michael Maloney Date: Thu, 28 Dec 2023 00:03:42 +0000 Subject: [PATCH 2/2] Hack in vec dynindex and updatedynindex. --- bitsy/examples/vecs.bitsy | 9 ++++++++ bitsy/src/expr.rs | 42 +++++++++++++++++++++++++++++++++--- bitsy/src/expr/typecheck.rs | 35 ++++++++++++++++++++++++------ bitsy/src/package/resolve.rs | 4 ++++ bitsy/src/sim.rs | 18 ++++++++++++++++ bitsy/src/sim/eval.rs | 22 +++++++++++++++++++ bitsy/src/sim/value.rs | 7 ++++++ 7 files changed, 127 insertions(+), 10 deletions(-) create mode 100644 bitsy/examples/vecs.bitsy diff --git a/bitsy/examples/vecs.bitsy b/bitsy/examples/vecs.bitsy new file mode 100644 index 0000000..c9d4dc0 --- /dev/null +++ b/bitsy/examples/vecs.bitsy @@ -0,0 +1,9 @@ +pub mod Top { + outgoing out of Word<8>; + reg i of Word<3> reset 0; + i <= i + 1; + + node vecs of Vec, 8>; + vecs := [0, 1, 2, 3, 4, 5, 6, 7]; + out := dynindex(updatedynindex(vecs, 3w3, 100w8), i); +} diff --git a/bitsy/src/expr.rs b/bitsy/src/expr.rs index a3d7c9d..4f05694 100644 --- a/bitsy/src/expr.rs +++ b/bitsy/src/expr.rs @@ -51,6 +51,10 @@ pub enum Expr { Idx(Loc, OnceCell, Arc, u64), /// A static index range. Eg, `foo[8..4]`. IdxRange(Loc, OnceCell, Arc, u64, u64), + + VecDynIdx(Loc, OnceCell, Arc, Arc), + + VecUpdateDynIdx(Loc, OnceCell, Arc, Arc, Arc), /// A function call. Eg, `foo(x, y)`. Call(Loc, OnceCell, Arc, Vec>), /// A hole. Eg, `?foo`. @@ -144,6 +148,8 @@ impl HasLoc for Expr { Expr::TryCast(loc, _typ, _e) => loc.clone(), Expr::ToWord(loc, _typ, _e) => loc.clone(), Expr::Vec(loc, _typ, _es) => loc.clone(), + Expr::VecDynIdx(loc, _typ, _e, _i) => loc.clone(), + Expr::VecUpdateDynIdx(loc, _typ, _e, _i, _ei) => loc.clone(), Expr::IdxField(loc, _typ, _e, _field) => loc.clone(), Expr::Idx(loc, _typ, _e, _i) => loc.clone(), Expr::IdxRange(loc, _typ, _e, _j, _i) => loc.clone(), @@ -269,6 +275,17 @@ impl Expr { e.with_subexprs(callback); } }, + Expr::VecDynIdx(_loc, _typ, e, i) => { + callback(self); + e.with_subexprs(callback); + i.with_subexprs(callback); + }, + Expr::VecUpdateDynIdx(_loc, _typ, e, i, ei) => { + callback(self); + e.with_subexprs(callback); + i.with_subexprs(callback); + ei.with_subexprs(callback); + }, Expr::IdxField(_loc, _typ, e, _field) => { callback(self); e.with_subexprs(callback); @@ -367,6 +384,20 @@ impl Expr { }, Expr::Sext(_loc, _typ, e) => e.free_vars(), Expr::Zext(_loc, _typ, e) => e.free_vars(), + Expr::VecDynIdx(_loc, _typ, e, i) => { + let mut result = BTreeSet::new(); + for ex in &[e, i] { + result.extend(ex.free_vars()) + } + result + }, + Expr::VecUpdateDynIdx(_loc, _typ, e, i, ei) => { + let mut result = BTreeSet::new(); + for ex in &[e, i, ei] { + result.extend(ex.free_vars()) + } + result + }, Expr::IdxField(_loc, _typ, e, _field) => e.free_vars(), Expr::Idx(_loc, _typ, e, _i) => e.free_vars(), Expr::IdxRange(_loc, _typ, e, _j, _i) => e.free_vars(), @@ -403,7 +434,11 @@ impl Expr { } pub fn type_of(&self) -> Type { - let cell = match self { + let cell = self.type_of_cell(); + cell.get().unwrap().clone() + } + pub fn type_of_cell(&self) -> &OnceCell { + match self { Expr::Net(_loc, typ, _netid) => typ, Expr::Reference(_loc, typ, _path) => typ, Expr::Word(_loc, typ, _width, _val) => typ, @@ -422,12 +457,13 @@ impl Expr { Expr::TryCast(_loc, typ, _e) => typ, Expr::ToWord(_loc, typ, _e) => typ, Expr::Vec(_loc, typ, _es) => typ, + Expr::VecDynIdx(_loc, typ, _e, _i) => typ, + Expr::VecUpdateDynIdx(_loc, typ, _e, _i, _ei) => typ, Expr::Idx(_loc, typ, _e, _i) => typ, Expr::IdxField(_loc, typ, _e, _field) => typ, Expr::IdxRange(_loc, typ, _e, _j, _i) => typ, Expr::Call(_loc, typ, _fndef, _es) => typ, Expr::Hole(_loc, typ, _opt_name) => typ, - }; - cell.get().unwrap().clone() + } } } diff --git a/bitsy/src/expr/typecheck.rs b/bitsy/src/expr/typecheck.rs index 4b03bd7..e808c4c 100644 --- a/bitsy/src/expr/typecheck.rs +++ b/bitsy/src/expr/typecheck.rs @@ -257,10 +257,9 @@ impl Expr { _ => Err(TypeError::Other(self.clone(), format!("{self:?} is not the expected type {type_expected:?}"))), }; - if let Some(typ) = self.type_of_cell() { - if let Ok(()) = &result { - let _ = typ.set(type_expected); - } + if let Ok(()) = &result { + let typ = self.type_of_cell(); + let _ = typ.set(type_expected); } result } @@ -301,6 +300,29 @@ impl Expr { } }, Expr::Vec(_loc, _typ, _es) => None, + Expr::VecDynIdx(_loc, _typ, e, i) => { + // TODO + i.typeinfer(ctx.clone()); + match e.typeinfer(ctx.clone()) { + Some(Type::Vec(inner_type, _len)) => { + Some(*inner_type) + }, + _ => None, + } + + }, + Expr::VecUpdateDynIdx(_loc, _typ, e, i, ei) => { + // TODO + i.typeinfer(ctx.clone()); + ei.typeinfer(ctx.clone()); + match e.typeinfer(ctx.clone()) { + Some(Type::Vec(inner_type, len)) => { + Some(Type::Vec(inner_type, len)) + }, + _ => None, + } + + }, Expr::Idx(_loc, _typ, e, i) => { match e.typeinfer(ctx.clone()) { Some(Type::Word(n)) if *i < n => Some(Type::word(1)), @@ -320,9 +342,8 @@ impl Expr { }; if let Some(type_actual) = &result { - if let Some(typ) = self.type_of_cell() { - let _ = typ.set(type_actual.clone()); - } + let typ = self.type_of_cell(); + typ.set(type_actual.clone()).unwrap(); } result } diff --git a/bitsy/src/package/resolve.rs b/bitsy/src/package/resolve.rs index cf79054..852eec6 100644 --- a/bitsy/src/package/resolve.rs +++ b/bitsy/src/package/resolve.rs @@ -224,6 +224,8 @@ fn expr_dependencies(expr: &ast::Expr) -> BTreeSet { "zext", "trycast", "word", + "dynindex", + "updatedynindex", "@Valid", "@Invalid", ]; @@ -505,6 +507,8 @@ fn resolve_expr( "zext" => Expr::Zext(loc.clone(), OnceCell::new(), package_es[0].clone()), "trycast" => Expr::TryCast(loc.clone(), OnceCell::new(), package_es[0].clone()), "word" => Expr::ToWord(loc.clone(), OnceCell::new(), package_es[0].clone()), + "dynindex" => Expr::VecDynIdx(loc.clone(), OnceCell::new(), package_es[0].clone(), package_es[1].clone()), + "updatedynindex" => Expr::VecUpdateDynIdx(loc.clone(), OnceCell::new(), package_es[0].clone(), package_es[1].clone(), package_es[2].clone()), "@Valid" => { Expr::Ctor(loc.clone(), OnceCell::new(), "Valid".to_string(), package_es) }, diff --git a/bitsy/src/sim.rs b/bitsy/src/sim.rs index 44ba8e7..c8a8b73 100644 --- a/bitsy/src/sim.rs +++ b/bitsy/src/sim.rs @@ -644,6 +644,14 @@ impl Expr { Expr::TryCast(loc, typ, e) => Expr::TryCast(loc.clone(), typ.clone(), e.rebase_rec(current_path, shadowed)), Expr::ToWord(loc, typ, e) => Expr::ToWord(loc.clone(), typ.clone(), e.rebase_rec(current_path, shadowed)), Expr::Vec(loc, typ, es) => Expr::Vec(loc.clone(), typ.clone(), es.iter().map(|e| e.rebase_rec(current_path.clone(), shadowed)).collect()), + Expr::VecDynIdx(loc, typ, e, i) => Expr::VecDynIdx(loc.clone(), typ.clone(), e.rebase_rec(current_path.clone(), shadowed), i.rebase_rec(current_path.clone(), shadowed)), + Expr::VecUpdateDynIdx(loc, typ, e, i, ei) => Expr::VecUpdateDynIdx( + loc.clone(), + typ.clone(), + e.rebase_rec(current_path.clone(), shadowed), + i.rebase_rec(current_path.clone(), shadowed), + ei.rebase_rec(current_path.clone(), shadowed), + ), Expr::IdxField(loc, typ, e, field) => Expr::IdxField(loc.clone(), typ.clone(), e.rebase_rec(current_path, shadowed), field.clone()), Expr::Idx(loc, typ, e, i) => Expr::Idx(loc.clone(), typ.clone(), e.rebase_rec(current_path, shadowed), *i), Expr::IdxRange(loc, typ, e, j, i) => Expr::IdxRange(loc.clone(), typ.clone(), e.rebase_rec(current_path, shadowed), *j, *i), @@ -754,6 +762,14 @@ impl Expr { Expr::TryCast(loc, typ, e) => Expr::TryCast(loc.clone(), typ.clone(), e.references_to_nets_rec(net_id_by_path, shadowed)), Expr::ToWord(loc, typ, e) => Expr::ToWord(loc.clone(), typ.clone(), e.references_to_nets_rec(net_id_by_path, shadowed)), Expr::Vec(loc, typ, es) => Expr::Vec(loc.clone(), typ.clone(), es.iter().map(|e| e.references_to_nets_rec(net_id_by_path, shadowed)).collect()), + Expr::VecDynIdx(loc, typ, e, i) => Expr::VecDynIdx(loc.clone(), typ.clone(), e.references_to_nets_rec(net_id_by_path, shadowed), i.references_to_nets_rec(net_id_by_path, shadowed)), + Expr::VecUpdateDynIdx(loc, typ, e, i, ei) => Expr::VecUpdateDynIdx( + loc.clone(), + typ.clone(), + e.references_to_nets_rec(net_id_by_path, shadowed), + i.references_to_nets_rec(net_id_by_path, shadowed), + ei.references_to_nets_rec(net_id_by_path, shadowed), + ), Expr::IdxField(loc, typ, e, field) => Expr::IdxField(loc.clone(), typ.clone(), e.references_to_nets_rec(net_id_by_path, shadowed), field.clone()), Expr::Idx(loc, typ, e, i) => Expr::Idx(loc.clone(), typ.clone(), e.references_to_nets_rec(net_id_by_path, shadowed), *i), Expr::IdxRange(loc, typ, e, j, i) => Expr::IdxRange(loc.clone(), typ.clone(), e.references_to_nets_rec(net_id_by_path, shadowed), *j, *i), @@ -789,6 +805,8 @@ impl Expr { Expr::TryCast(_loc, _typ, e) => e.depends_on_net(net_id), Expr::ToWord(_loc, _typ, e) => e.depends_on_net(net_id), Expr::Vec(_loc, _typ, es) => es.iter().any(|e| e.depends_on_net(net_id)), + Expr::VecDynIdx(_loc, _typ, e, i) => e.depends_on_net(net_id) || i.depends_on_net(net_id), + Expr::VecUpdateDynIdx(_loc, _typ, e, i, ei) => e.depends_on_net(net_id) || i.depends_on_net(net_id) || ei.depends_on_net(net_id), Expr::IdxField(_loc, _typ, e, _field) => e.depends_on_net(net_id), Expr::Idx(_loc, _typ, e, _i) => e.depends_on_net(net_id), Expr::IdxRange(_loc, _typ, e, _j, _i) => e.depends_on_net(net_id), diff --git a/bitsy/src/sim/eval.rs b/bitsy/src/sim/eval.rs index 6da37fd..42d0a17 100644 --- a/bitsy/src/sim/eval.rs +++ b/bitsy/src/sim/eval.rs @@ -225,6 +225,28 @@ impl Expr { } Value::Vec(vs) }, + Expr::VecDynIdx(_loc, _typ, e, i) => { + let e_value = e.eval_with_ctx(bitsy, ctx.clone()); + let i_value = i.eval_with_ctx(bitsy, ctx.clone()); + if e_value.is_x() || i_value.is_x() { + return Value::X; + } + let vs = e_value.to_vec().unwrap(); + let idx: usize = i_value.to_u64().unwrap().try_into().unwrap(); + vs[idx].clone() + }, + Expr::VecUpdateDynIdx(_loc, _typ, e, i, ei) => { + let e_value = e.eval_with_ctx(bitsy, ctx.clone()); + let i_value = i.eval_with_ctx(bitsy, ctx.clone()); + let ei_value = ei.eval_with_ctx(bitsy, ctx.clone()); + if e_value.is_x() || i_value.is_x() || ei_value.is_x() { + return Value::X; + } + let mut vs = e_value.to_vec().unwrap(); + let idx: usize = i_value.to_u64().unwrap().try_into().unwrap(); + vs[idx] = ei_value; + Value::Vec(vs) + }, Expr::IdxField(_loc, _typ, e, field) => { let value = e.eval_with_ctx(bitsy, ctx.clone()); if let Value::X = value { diff --git a/bitsy/src/sim/value.rs b/bitsy/src/sim/value.rs index 2905b45..db78766 100644 --- a/bitsy/src/sim/value.rs +++ b/bitsy/src/sim/value.rs @@ -44,6 +44,13 @@ impl Value { _ => None, } } + + pub fn to_vec(&self) -> Option> { + match self { + Value::Vec(vs) => Some(vs.clone()), + _ => None, + } + } } #[test]