From 68e09ac921e8d66aa2a6e11ec972a54d64e04811 Mon Sep 17 00:00:00 2001 From: tjjfvi Date: Tue, 5 Mar 2024 14:56:03 -0500 Subject: [PATCH 01/16] ... --- src/host/readback.rs | 1 + src/main.rs | 2 +- src/run.rs | 2 + src/run/addr.rs | 20 +++-- src/run/allocator.rs | 121 +++++++++++++++++++------------ src/run/def.rs | 2 +- src/run/instruction.rs | 24 +++--- src/run/interact.rs | 93 +++++++++++++++--------- src/run/net.rs | 25 ++++--- src/run/node.rs | 23 +++--- src/run/parallel.rs | 2 +- src/run/port.rs | 161 ++++++++++++++++++----------------------- src/run/tag.rs | 123 +++++++++++++++++++++++++++++++ src/run/wire.rs | 35 +++++---- src/trace.rs | 22 +++--- 15 files changed, 410 insertions(+), 246 deletions(-) create mode 100644 src/run/tag.rs diff --git a/src/host/readback.rs b/src/host/readback.rs index 72126391..9d755b4b 100644 --- a/src/host/readback.rs +++ b/src/host/readback.rs @@ -26,6 +26,7 @@ impl Host { net } } + /// See [`Host::readback`]. struct ReadbackState<'a> { host: &'a Host, diff --git a/src/main.rs b/src/main.rs index fb15a03f..2191e804 100644 --- a/src/main.rs +++ b/src/main.rs @@ -348,7 +348,7 @@ fn reduce_exprs(host: &Host, exprs: &[Net], opts: &RuntimeOpts) { for expr in exprs { let mut net = DynNet::new(&heap, opts.lazy_mode); dispatch_dyn_net!(&mut net => { - host.encode_net(net, Trg::port(run::Port::new_var(net.root.addr())), expr); + host.encode_net(net, Trg::port(net.root.as_var()), expr); let start_time = Instant::now(); if opts.single_core { net.normal(); diff --git a/src/run.rs b/src/run.rs index ae0790cd..ad0a1f4c 100644 --- a/src/run.rs +++ b/src/run.rs @@ -62,6 +62,7 @@ mod net; mod node; mod parallel; mod port; +mod tag; mod wire; pub use addr::*; @@ -72,6 +73,7 @@ pub use linker::*; pub use net::*; pub use node::*; pub use port::*; +pub use tag::*; pub use wire::*; pub type Lab = u16; diff --git a/src/run/addr.rs b/src/run/addr.rs index c27eac8d..f19515f2 100644 --- a/src/run/addr.rs +++ b/src/run/addr.rs @@ -37,17 +37,21 @@ impl Addr { const HALF_MASK: usize = 0b1000; - /// Given an address to one word of a two-word allocation, returns the address - /// of the first word of that allocation. + /// TODO #[inline(always)] - pub(super) fn left_half(&self) -> Self { - Addr(self.0 & !Addr::HALF_MASK) + pub(super) fn floor(&self, align: Align) -> Self { + Addr(self.0 & (usize::MAX << align.tag_bits())) } - /// Given an address to one word of a two-word allocation, returns the address - /// of the other word of that allocation. + /// TODO #[inline(always)] - pub fn other_half(&self) -> Self { - Addr(self.0 ^ Addr::HALF_MASK) + pub(super) fn other(&self, align: Align) -> Self { + Addr(self.0 ^ (1 << align.tag_bits())) + } + + /// TODO + #[inline(always)] + pub(super) fn offset(&self, words: usize) -> Self { + Addr(self.0 + (words << 3)) } } diff --git a/src/run/allocator.rs b/src/run/allocator.rs index 308207a2..95139a53 100644 --- a/src/run/allocator.rs +++ b/src/run/allocator.rs @@ -1,27 +1,17 @@ use super::*; -/// The memory behind a two-word allocation. -/// -/// This must be aligned to 16 bytes so that the left word's address always ends -/// with `0b0000` and the right word's address always ends with `0b1000`. -#[repr(C)] -#[repr(align(16))] -#[derive(Default)] -pub(super) struct Node(pub AtomicU64, pub AtomicU64); - /// The memory buffer backing a [`Net`]. -#[repr(align(16))] -pub struct Heap(pub(super) [Node]); +#[repr(align(64))] +pub struct Heap(pub(super) [AtomicU64]); impl Heap { #[inline] /// Allocate a new heap with a given size in words. pub fn new_words(words: usize) -> Box { - let nodes = words / 2; unsafe { Box::from_raw(core::ptr::slice_from_raw_parts_mut( - alloc::alloc(Layout::array::(nodes).unwrap()) as *mut _, - nodes, + alloc::alloc(Layout::array::(words).unwrap().align_to(64).unwrap()) as *mut _, + words, ) as *mut _) } } @@ -37,66 +27,101 @@ pub struct Allocator<'h> { pub(super) tracer: Tracer, pub(super) heap: &'h Heap, pub(super) next: usize, - pub(super) head: Addr, + pub(super) heads: [Addr; 4], } deref!({<'h>} Allocator<'h> => self.tracer: Tracer); +impl Align { + #[inline(always)] + const fn free(self) -> u64 { + (1 << self as u64) << 60 + } +} + +/// Sentinel values used to indicate free memory. +impl Port { + pub(super) const FREE_1: Port = Port(Align1.free()); + pub(super) const FREE_2: Port = Port(Align2.free()); + pub(super) const FREE_4: Port = Port(Align4.free()); + pub(super) const FREE_8: Port = Port(Align8.free()); +} + impl<'h> Allocator<'h> { pub fn new(heap: &'h Heap) -> Self { - Allocator { tracer: Tracer::default(), heap, next: 0, head: Addr::NULL } + Allocator { tracer: Tracer::default(), heap, next: 0, heads: [Addr::NULL; 4] } + } + + fn head(&mut self, align: Align) -> &mut Addr { + unsafe { self.heads.get_unchecked_mut(align as usize) } } - /// Frees one word of a two-word allocation. + fn push_addr(head: &mut Addr, addr: Addr) { + addr.val().store(head.0 as u64, Relaxed); + *head = addr; + } + + /// Frees one word of an allocation of size `alloc_align`. #[inline(always)] - pub fn half_free(&mut self, addr: Addr) { - trace!(self.tracer, addr); - const FREE: u64 = Port::FREE.0; + pub fn free_word(&mut self, mut addr: Addr, alloc_align: Align) { if cfg!(feature = "_fuzz") { if cfg!(not(feature = "_fuzz_no_free")) { - assert_ne!(addr.val().swap(FREE, Relaxed), FREE, "double free"); + let free = Port::FREE_1.0; + assert_ne!(addr.val().swap(free, Relaxed), free, "double free"); } - } else { - addr.val().store(FREE, Relaxed); - if addr.other_half().val().load(Relaxed) == FREE { - trace!(self.tracer, "other free"); - let addr = addr.left_half(); - if addr.val().compare_exchange(FREE, self.head.0 as u64, Relaxed, Relaxed).is_ok() { - let old_head = &self.head; - let new_head = addr; - trace!(self.tracer, "appended", old_head, new_head); - self.head = new_head; - } else { - trace!(self.tracer, "too slow"); - }; + return; + } + let mut align = Align1; + if align == alloc_align { + return Self::push_addr(self.head(align), addr); + } + addr.val().store(align.free(), Relaxed); + while align != alloc_align { + if addr.other(align).val().load(Relaxed) != align.free() { + return; + } + trace!(self.tracer, "other free"); + let next_align = unsafe { align.next().unwrap_unchecked() }; + addr = addr.floor(next_align); + let next_value = if next_align == alloc_align { self.head(alloc_align).0 as u64 } else { next_align.free() }; + if addr.val().compare_exchange(align.free(), next_value, Relaxed, Relaxed).is_err() { + return trace!(self.tracer, "too slow"); } + trace!(self.tracer, "success"); + if next_align == alloc_align { + let old_head = next_value; + let new_head = addr; + trace!(self.tracer, "appended", old_head, new_head); + return *self.head(align) = addr; + } + align = next_align; } } - /// Allocates a two-word node. + /// Allocates a node, with a size specified by `align`. #[inline(never)] - pub fn alloc(&mut self) -> Addr { - trace!(self.tracer, self.head); - let addr = if self.head != Addr::NULL { - let addr = self.head.clone(); - let next = Addr(self.head.val().load(Relaxed) as usize); - trace!(self.tracer, next); - self.head = next; + pub fn alloc(&mut self, align: Align) -> Addr { + let head = self.head(align); + let addr = if *head != Addr::NULL { + let addr = *head; + let next = Addr(head.val().load(Relaxed) as usize); + *head = next; addr } else { let index = self.next; - self.next += 1; - Addr(&self.heap.0.get(index).expect("OOM").0 as *const _ as _) + self.next += 8; + Addr(&self.heap.0.get(index).expect("OOM") as *const _ as _) }; - trace!(self.tracer, addr, self.head); - addr.val().store(Port::LOCK.0, Relaxed); - addr.other_half().val().store(Port::LOCK.0, Relaxed); + trace!(self, addr); + for i in 0 .. align.width() { + addr.offset(i as usize).val().store(Port::LOCK.0, Relaxed); + } addr } #[inline(always)] pub(crate) fn free_wire(&mut self, wire: Wire) { - self.half_free(wire.addr()); + self.free_word(wire.addr(), wire.alloc_align()); } /// If `trg` is a wire, frees the backing memory. diff --git a/src/run/def.rs b/src/run/def.rs index 0c947def..cf9d8473 100644 --- a/src/run/def.rs +++ b/src/run/def.rs @@ -186,7 +186,7 @@ impl<'a, M: Mode> Net<'a, M> { let def = port.addr().def(); - if trg.tag() == Ctr && !def.labs.has(trg.lab()) { + if trg.is_ctr_ish() && !def.labs.has(trg.lab()) { return self.comm02(port, trg); } diff --git a/src/run/instruction.rs b/src/run/instruction.rs index 7aaf3787..feacbf33 100644 --- a/src/run/instruction.rs +++ b/src/run/instruction.rs @@ -112,14 +112,14 @@ impl<'a, M: Mode> Net<'a, M> { #[inline(always)] pub(crate) fn do_ctr(&mut self, lab: Lab, trg: Trg) -> (Trg, Trg) { let port = trg.target(); - if !M::LAZY && port.tag() == Ctr && port.lab() == lab { - trace!(self.tracer, "fast"); + if !M::LAZY && port.is(Tag::Ctr) && port.lab() == lab { + trace!(self, "fast"); self.free_trg(trg); let node = port.consume_node(); self.rwts.anni += 1; (Trg::wire(node.p1), Trg::wire(node.p2)) // TODO: fast copy? - } else if false && !M::LAZY && port.tag() == Num || port.tag() == Ref && lab >= port.lab() { + } else if false && !M::LAZY && port.is(Tag::Num) || port.is(Tag::Ref) && lab >= port.lab() { self.rwts.comm += 1; (Trg::port(port.clone()), Trg::port(port)) } else { @@ -170,7 +170,7 @@ impl<'a, M: Mode> Net<'a, M> { #[inline(always)] pub(crate) fn do_mat(&mut self, trg: Trg) -> (Trg, Trg) { let port = trg.target(); - if !M::LAZY && port.tag() == Num { + if !M::LAZY && port.is(Tag::Num) { self.rwts.oper += 1; self.free_trg(trg); let num = port.num(); @@ -198,13 +198,13 @@ impl<'a, M: Mode> Net<'a, M> { #[inline(always)] pub(crate) fn do_wires(&mut self) -> (Trg, Trg, Trg, Trg) { - let a = self.alloc(); - let b = a.other_half(); + let a = self.alloc(Align2); + let b = a.offset(1); ( - Trg::port(Port::new_var(a.clone())), - Trg::wire(Wire::new(a)), - Trg::port(Port::new_var(b.clone())), - Trg::wire(Wire::new(b)), + Trg::port(Port::new_var(Align2, a.clone())), + Trg::wire(Wire::new(Align2, a)), + Trg::port(Port::new_var(Align2, b.clone())), + Trg::wire(Wire::new(Align2, b)), ) } @@ -213,7 +213,7 @@ impl<'a, M: Mode> Net<'a, M> { #[allow(unused)] // TODO: emit this instruction pub(crate) fn do_mat_con_con(&mut self, trg: Trg, out: Trg) -> (Trg, Trg, Trg) { let port = trg.target(); - if !M::LAZY && trg.target().tag() == Num { + if !M::LAZY && trg.target().is(Tag::Num) { self.rwts.oper += 1; self.free_trg(trg); let num = port.num(); @@ -241,7 +241,7 @@ impl<'a, M: Mode> Net<'a, M> { #[allow(unused)] // TODO: emit this instruction pub(crate) fn do_mat_con(&mut self, trg: Trg, out: Trg) -> (Trg, Trg) { let port = trg.target(); - if trg.target().tag() == Num { + if trg.target().is(Tag::Num) { self.rwts.oper += 1; self.free_trg(trg); let num = port.num(); diff --git a/src/run/interact.rs b/src/run/interact.rs index 80c5e3bb..1590bddd 100644 --- a/src/run/interact.rs +++ b/src/run/interact.rs @@ -4,42 +4,47 @@ impl<'a, M: Mode> Net<'a, M> { /// Performs an interaction between two connected principal ports. #[inline(always)] pub fn interact(&mut self, a: Port, b: Port) { - self.tracer.sync(); - trace!(self.tracer, a, b); + self.sync(); + trace!(self, a, b); + use Tag::*; match (a.tag(), b.tag()) { // not actually an active pair (Var | Red, _) | (_, Var | Red) => unreachable!(), // nil-nil (Ref, Ref | Num) if !a.is_skippable() => self.call(a, b), (Ref | Num, Ref) if !b.is_skippable() => self.call(b, a), - (Num | Ref, Num | Ref) => self.rwts.eras += 1, + (Num | Ref | AdtZ, Num | Ref | AdtZ) => self.rwts.eras += 1, // comm 2/2 - (Ctr, Mat) if a.lab() != 0 => self.comm22(a, b), - (Mat, Ctr) if b.lab() != 0 => self.comm22(a, b), - (Ctr, Op) | (Op, Ctr) => self.comm22(a, b), - (Ctr, Ctr) if a.lab() != b.lab() => self.comm22(a, b), + (Mat | Op, CtrN!() | AdtN!()) => self.comm2N(a, b), + (CtrN!() | AdtN!(), Mat | Op) => self.comm2N(b, a), // anni - (Mat, Mat) | (Op, Op) | (Ctr, Ctr) => self.anni2(a, b), + (CtrN!(), CtrN!()) => self.anniNM(a, b), + (Mat, Mat) | (Op, Op) => self.anni2(a, b), // comm 2/0 - (Ref, Ctr) if b.lab() >= a.lab() => self.comm02(a, b), - (Ctr, Ref) if a.lab() >= b.lab() => self.comm02(b, a), - (Num, Ctr) => self.comm02(a, b), - (Ctr, Num) => self.comm02(b, a), - (Ref, _) if a == Port::ERA => self.comm02(a, b), - (_, Ref) if b == Port::ERA => self.comm02(b, a), + (Ref, CtrN!() | AdtN!()) if b.lab() >= a.lab() => self.comm0N(a, b), + (CtrN!() | AdtN!(), Ref) if a.lab() >= b.lab() => self.comm0N(b, a), + (Num, CtrN!() | AdtN!()) => self.comm0N(a, b), + (CtrN!() | AdtN!(), Num) => self.comm0N(b, a), + (AdtZ, Op | Mat) => self.comm02(a, b), + (Op | Mat, AdtZ) => self.comm02(a, b), + // TODO + (AdtN!() | AdtZ, CtrN!()) => self.adt_ctr(a, b), + (CtrN!(), AdtN!() | AdtZ) => self.adt_ctr(b, a), + (AdtN!() | AdtZ, AdtN!() | AdtZ) => todo!(), // deref - (Ref, _) => self.call(a, b), - (_, Ref) => self.call(b, a), + (Ref, Mat | Op) if a == Port::ERA => self.comm02(a, b), + (Mat | Op, Ref) if b == Port::ERA => self.comm02(b, a), + (Ref, CtrN!() | AdtN!()) if a == Port::ERA => self.comm0N(a, b), + (CtrN!() | AdtN!(), Ref) if b == Port::ERA => self.comm0N(b, a), + (Ref, CtrN!() | AdtN!() | Mat | Op) => self.call(a, b), + (CtrN!() | AdtN!() | Mat | Op, Ref) => self.call(b, a), // native ops - (Op, Num) => self.op_num(a, b), - (Num, Op) => self.op_num(b, a), + (Op, Num) => self.opr_num(a, b), + (Num, Op) => self.opr_num(b, a), (Mat, Num) => self.mat_num(a, b), (Num, Mat) => self.mat_num(b, a), // todo: what should the semantics of these be? - (Mat, Ctr) // b.lab() == 0 - | (Ctr, Mat) // a.lab() == 0 - | (Op, Mat) - | (Mat, Op) => unimplemented!("{:?}-{:?}", a.tag(), b.tag()), + (Op, Mat) | (Mat, Op) => unimplemented!("{:?}-{:?}", a.tag(), b.tag()), } } @@ -72,7 +77,7 @@ impl<'a, M: Mode> Net<'a, M> { /// ``` #[inline(never)] pub fn anni2(&mut self, a: Port, b: Port) { - trace!(self.tracer, a, b); + trace!(self, a, b); self.rwts.anni += 1; let a = a.consume_node(); let b = b.consume_node(); @@ -119,7 +124,7 @@ impl<'a, M: Mode> Net<'a, M> { /// ``` #[inline(never)] pub fn comm22(&mut self, a: Port, b: Port) { - trace!(self.tracer, a, b); + trace!(self, a, b); self.rwts.comm += 1; let a = a.consume_node(); @@ -130,13 +135,13 @@ impl<'a, M: Mode> Net<'a, M> { let B1 = self.create_node(b.tag, b.lab); let B2 = self.create_node(b.tag, b.lab); - trace!(self.tracer, A1.p0, A2.p0, B1.p0, B2.p0); + trace!(self, A1.p0, A2.p0, B1.p0, B2.p0); self.link_port_port(A1.p1, B1.p1); self.link_port_port(A1.p2, B2.p1); self.link_port_port(A2.p1, B1.p2); self.link_port_port(A2.p2, B2.p2); - trace!(self.tracer); + trace!(self); self.link_wire_port(a.p1, B1.p0); self.link_wire_port(a.p2, B2.p0); self.link_wire_port(b.p1, A1.p0); @@ -165,7 +170,7 @@ impl<'a, M: Mode> Net<'a, M> { /// ``` #[inline(never)] pub fn comm02(&mut self, a: Port, b: Port) { - trace!(self.tracer, a, b); + trace!(self, a, b); self.rwts.comm += 1; let b = b.consume_node(); self.link_wire_port(b.p1, a.clone()); @@ -204,20 +209,20 @@ impl<'a, M: Mode> Net<'a, M> { /// ``` #[inline(never)] pub fn mat_num(&mut self, a: Port, b: Port) { - trace!(self.tracer, a, b); + trace!(self, a, b); self.rwts.oper += 1; let a = a.consume_node(); let b = b.num(); if b == 0 { let x = self.create_node(Ctr, 0); - trace!(self.tracer, x.p0); + trace!(self, x.p0); self.link_port_port(x.p2, Port::ERA); self.link_wire_port(a.p2, x.p1); self.link_wire_port(a.p1, x.p0); } else { - let x = self.create_node(Ctr, 0); - let y = self.create_node(Ctr, 0); - trace!(self.tracer, x.p0, y.p0); + let x = self.create_node(Tag::Ctr, 0); + let y = self.create_node(Tag::Ctr, 0); + trace!(self, x.p0, y.p0); self.link_port_port(x.p1, Port::ERA); self.link_port_port(x.p2, y.p0); self.link_port_port(y.p1, Port::new_num(b - 1)); @@ -253,21 +258,37 @@ impl<'a, M: Mode> Net<'a, M> { /// ``` #[inline(never)] pub fn op_num(&mut self, a: Port, b: Port) { - trace!(self.tracer, a, b); + trace!(self, a, b); let a = a.consume_node(); let op = unsafe { Op::from_unchecked(a.lab) }; let a1 = a.p1.load_target(); - if a1.tag() == Num { + if a1.is(Tag::Num) { self.rwts.oper += 1; let out = op.op(b.num(), a1.num()); self.link_wire_port(a.p2, Port::new_num(out)); } else { let op = op.swap(); - let x = self.create_node(Op, op as u16); - trace!(self.tracer, x.p0); + let x = self.create_node(Tag::Op, op as u16); + trace!(self, x.p0); self.link_port_port(x.p1, b); self.link_wire_port(a.p2, x.p2); self.link_wire_port(a.p1, x.p0); } } + + fn comm2N(&mut self, a: Port, b: Port) { + todo!() + } + + fn anniNM(&mut self, a: Port, b: Port) { + todo!() + } + + fn comm0N(&mut self, a: Port, b: Port) { + todo!() + } + + fn adt_ctr(&mut self, b: Port, a: Port) { + todo!() + } } diff --git a/src/run/net.rs b/src/run/net.rs index 5ecbed83..da04bb76 100644 --- a/src/run/net.rs +++ b/src/run/net.rs @@ -16,8 +16,8 @@ deref!({<'a, M: Mode>} Net<'a, M> => self.linker: Linker<'a, M>); impl<'h, M: Mode> Net<'h, M> { /// Creates an empty net with a given heap. pub fn new(heap: &'h Heap) -> Self { - let mut net = Net::new_with_root(heap, Wire(std::ptr::null())); - net.root = Wire::new(net.alloc()); + let mut net = Net::new_with_root(heap, Wire(0)); + net.root = Wire::new(Align2, net.alloc(Align2)); net } @@ -55,13 +55,13 @@ impl<'a, M: Mode> Net<'a, M> { let mut path: Vec = vec![]; loop { - trace!(self.tracer, prev); + trace!(self, prev); // Load ptrs let next = self.get_target_full(prev.clone()); - trace!(self.tracer, next); + trace!(self, next); // If next is root, stop. - if next == Port::new_var(root.addr()) || next == Port::new_var(self.root.addr()) { + if next == root.as_var() || next == self.root.as_var() { break; } @@ -73,7 +73,7 @@ impl<'a, M: Mode> Net<'a, M> { prev = path.pop().unwrap(); continue; // Otherwise, if it is a ref, expand it. - } else if next.tag() == Ref && next != Port::ERA { + } else if next.is(Tag::Ref) && next != Port::ERA { self.call(next, prev.clone()); continue; // Otherwise, we're done. @@ -83,7 +83,7 @@ impl<'a, M: Mode> Net<'a, M> { } // If next is an aux port, pass through. - let main = self.get_header(next.addr().left_half()); + let main = self.get_header(next.addr().floor(next.alloc_align())); path.push(prev); prev = main.this.clone(); } @@ -93,15 +93,16 @@ impl<'a, M: Mode> Net<'a, M> { pub fn normal_from(&mut self, root: Wire) { assert!(M::LAZY); - let mut visit = vec![Port::new_var(root.addr())]; + let mut visit = vec![root.as_var()]; while let Some(prev) = visit.pop() { - trace!(self.tracer, "visit", prev); + trace!(self, "visit", prev); //println!("normal {} | {}", prev.view(), self.rewrites()); let next = self.weak_normal(prev, root.clone()); - trace!(self.tracer, "got", next); + trace!(self, "got", next); if next.is_full_node() { - visit.push(Port::new_var(next.addr())); - visit.push(Port::new_var(next.addr().other_half())); + todo!(); + // visit.push(Port::new_var( next.addr())); + // visit.push(Port::new_var( next.addr().other_half())); } } } diff --git a/src/run/node.rs b/src/run/node.rs index 60b27e2e..822b96d6 100644 --- a/src/run/node.rs +++ b/src/run/node.rs @@ -19,8 +19,8 @@ impl Port { TraverseNode { tag: self.tag(), lab: self.lab(), - p1: Wire::new(self.addr()), - p2: Wire::new(self.addr().other_half()), + p1: Wire::new(self.align(), self.addr()), + p2: Wire::new(self.align(), self.addr().other(Align1)), } } } @@ -34,30 +34,29 @@ pub struct CreatedNode { impl<'a, M: Mode> Net<'a, M> { #[inline(always)] pub fn create_node(&mut self, tag: Tag, lab: Lab) -> CreatedNode { - let addr = self.alloc(); + assert_eq!(tag.width(), 2); + let addr = self.alloc(tag.align()); CreatedNode { p0: Port::new(tag, lab, addr.clone()), - p1: Port::new_var(addr.clone()), - p2: Port::new_var(addr.other_half()), + p1: Port::new_var(Align2, addr), + p2: Port::new_var(Align2, addr.other(Align1)), } } /// Creates a wire an aux port pair. #[inline(always)] pub fn create_wire(&mut self) -> (Wire, Port) { - let addr = self.alloc(); - self.half_free(addr.other_half()); - (Wire::new(addr.clone()), Port::new_var(addr)) + let addr = self.alloc(Align2); + (Wire::new(Align1, addr), Port::new_var(Align1, addr)) } /// Creates a wire pointing to a given port; sometimes necessary to avoid /// deadlock. #[inline(always)] pub fn create_wire_to(&mut self, port: Port) -> Wire { - let addr = self.alloc(); - self.half_free(addr.other_half()); - let wire = Wire::new(addr); - self.link_port_port(port, Port::new_var(wire.addr())); + let addr = self.alloc(Align1); + let wire = Wire::new(Align1, addr); + self.link_port_port(port, wire.as_var()); wire } } diff --git a/src/run/parallel.rs b/src/run/parallel.rs index 1fc97fde..2695c786 100644 --- a/src/run/parallel.rs +++ b/src/run/parallel.rs @@ -10,7 +10,7 @@ impl<'h, M: Mode> Net<'h, M> { let area = unsafe { std::mem::transmute(&self.heap.0[heap_start .. heap_start + heap_size]) }; let mut net = Net::new_with_root(area, self.root.clone()); net.next = self.next.saturating_sub(heap_start); - net.head = if tid == 0 { net.head } else { Addr::NULL }; + net.heads = if tid == 0 { net.heads } else { [Addr::NULL; 4] }; net.tid = tid; net.tids = tids; net.tracer.set_tid(tid); diff --git a/src/run/port.rs b/src/run/port.rs index 34e6da95..e7376b9a 100644 --- a/src/run/port.rs +++ b/src/run/port.rs @@ -5,6 +5,8 @@ use super::*; /// The type of a port is determined by its *tag*, which is stored in the bottom /// three bits. /// +/// TODO: update +/// /// All tags other than [`Num`] divide the bits of the port as follows: /// - the top 16 bits are the *label*, accessible with [`Port::lab`] /// - the middle 45 bits are the non-alignment bits of the *address*, an @@ -18,86 +20,23 @@ use super::*; #[must_use] pub struct Port(pub u64); -bi_enum! { - #[repr(u8)] - #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] - pub enum Tag { - /// `Red` ports represent redirects, which are an implementation detail of - /// the atomic linking algorithm, and don't have a precise analogue in - /// interaction nets. - /// - /// These ports are never directly held, but rather replace the backlinks of - /// some var ports. They are used to resolve inter-thread conflicts, and - /// thus will never appear when single-threaded. - /// - /// See the documentation for the linking algorithm for more. - Red = 0, - /// A `Var` port represents an auxiliary port in the net. - /// - /// The address of this port represents the wire leaving this port, - /// accessible with `Port::wire`. - /// - /// The label of this port is currently unused and always 0. - Var = 1, - /// A `Ref` port represents the principal port of a nilary reference node. - /// - /// The address of this port is a pointer to the corresponding [`Def`]. - /// - /// The label of this port is always equivalent to `def.labs.min_safe`, and - /// is used as an optimization for the ref commutation interaction. - /// - /// Eraser nodes are represented by a null-pointer `Ref`, available as the - /// constant [`Port::ERA`]. - Ref = 2, - /// A `Num` port represents the principal port of a U60 node. - /// - /// The top 60 bits of the port are the value of this node, and are - /// accessible with [`Port::num`]. - /// - /// The 4th bit from the bottom is currently unused in this port. - Num = 3, - /// An `Op` port represents the principal port of an Op node. - /// - /// The label of this port is the corresponding operation, which can be - /// accessed with [`Port::op`]. - /// - /// The address of this port is the address of a two-word allocation, - /// storing the targets of the wires connected to the two auxiliary ports of - /// this node. - Op = 4, - /// A `Mat` port represents the principal port of a Mat node. - /// - /// The address of this port is the address of a two-word allocation, - /// storing the targets of the wires connected to the two auxiliary ports of - /// the node. - /// - /// The label of this port is currently unused and always 0. - Mat = 6, - /// A `Ctr` port represents the principal port of an binary interaction - /// combinator node. - /// - /// The label of this port is the label of the combinator; two combinators - /// annihilate if they have the same label, or commute otherwise. - /// - /// The address of this port is the address of a two-word allocation, - /// storing the targets of the wires connected to the two auxiliary ports of - /// the node. - Ctr = 7, - } -} - impl fmt::Debug for Port { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:016x?} ", self.0)?; match *self { Port::ERA => write!(f, "[ERA]"), - Port::FREE => write!(f, "[FREE]"), + Port::FREE_1 => write!(f, "[FREE 1]"), + Port::FREE_2 => write!(f, "[FREE 2]"), + Port::FREE_4 => write!(f, "[FREE 4]"), + Port::FREE_8 => write!(f, "[FREE 8]"), Port::GONE => write!(f, "[GONE]"), Port::LOCK => write!(f, "[LOCK]"), _ => match self.tag() { - Num => write!(f, "[Num {}]", self.num()), - Var | Red | Mat => write!(f, "[{:?} {:?}]", self.tag(), self.addr()), - Op | Ctr | Ref => write!(f, "[{:?} {:?} {:?}]", self.tag(), self.lab(), self.addr()), + Tag::Num => write!(f, "[Num {}]", self.num()), + Tag::Var | Tag::Red | Tag::Mat => write!(f, "[{:?} {:?}]", self.tag(), self.addr()), + Tag::Op | CtrN!() | AdtN!() | Tag::AdtZ | Tag::Ref => { + write!(f, "[{:?} {:?} {:?}]", self.tag(), self.lab(), self.addr()) + } }, } } @@ -105,10 +44,7 @@ impl fmt::Debug for Port { impl Port { /// The principal port of an eraser node. - pub const ERA: Port = Port(Ref as _); - /// A sentinel value used to indicate free memory; see the allocator for more - /// details. - pub const FREE: Port = Port(0x8000_0000_0000_0000); + pub const ERA: Port = Port(Tag::Ref as _); /// A sentinel value used to lock a wire; see the linking algorithm for more /// details. pub const LOCK: Port = Port(0xFFFF_FFFF_FFFF_FFF0); @@ -124,30 +60,62 @@ impl Port { /// Creates a new [`Var`] port with a given addr. #[inline(always)] - pub fn new_var(addr: Addr) -> Self { - Port::new(Var, 0, addr) + pub fn new_var(alloc_align: Align, addr: Addr) -> Self { + Port::new(Tag::Var, alloc_align as u16, addr) + } + + /// Creates a new [`Red`] port with a given addr. + #[inline(always)] + pub fn new_red(alloc_align: Align, addr: Addr) -> Self { + Port::new(Tag::Red, alloc_align as u16, addr) } /// Creates a new [`Num`] port with a given 60-bit numeric value. #[inline(always)] pub const fn new_num(val: u64) -> Self { - Port((val << 4) | (Num as u64)) + Port((val << 4) | (Tag::Num as u64)) } /// Creates a new [`Ref`] port corresponding to a given definition. #[inline(always)] pub fn new_ref(def: &Def) -> Port { - Port::new(Ref, def.labs.min_safe, Addr(def as *const _ as _)) + Port::new(Tag::Ref, def.labs.min_safe, Addr(def as *const _ as _)) + } + + /// TODO + #[inline(always)] + pub fn new_adtz(variant_count: u8, variant_index: u8) -> Self { + Port(Tag::AdtZ as u64 | ((variant_count as u64) << 16) | ((variant_index as u64) << 8)) + } + + /// TODO + #[inline(always)] + pub fn variant_count(&self) -> u8 { + (self.0 >> 16) as u8 + } + + /// TODO + #[inline(always)] + pub fn variant_index(&self) -> u8 { + (self.0 >> 8) as u8 + } + + /// TODO + #[inline(always)] + pub fn align(&self) -> Align { + unsafe { Align::from_unchecked((self.0 & 0b11) as u8) } } /// Accesses the tag of this port; this is valid for all ports. #[inline(always)] pub fn tag(&self) -> Tag { - unsafe { Tag::from_unchecked((self.0 & 0x7) as u8) } + unsafe { Tag::from_unchecked((self.0 & (1 << self.align().tag_bits()) - 1) as u8) } } + /// TODO #[inline(always)] pub fn is(&self, tag: Tag) -> bool { + // TODO: optimize self.tag() == tag } @@ -160,11 +128,11 @@ impl Port { /// Accesses the addr of this port; this is valid for all non-`Num` ports. #[inline(always)] pub const fn addr(&self) -> Addr { + // todo Addr((self.0 & 0x0000_FFFF_FFFF_FFF8) as usize as _) } - /// Accesses the operation of this port; this is valid for [`Op1`] and [`Op2`] - /// ports. + /// Accesses the operation of this port; this is valid for [`Opr`] ports. #[inline(always)] pub fn op(&self) -> Op { unsafe { Op::from_unchecked(self.lab()) } @@ -180,12 +148,12 @@ impl Port { /// non-sentinel [`Red`] ports. #[inline(always)] pub fn wire(&self) -> Wire { - Wire::new(self.addr()) + Wire::new(self.alloc_align(), self.addr()) } #[inline(always)] pub fn is_principal(&self) -> bool { - self.tag() >= Ref + self.align() != Align1 } /// Given a principal port, returns whether this principal port may be part of @@ -193,22 +161,37 @@ impl Port { /// need to be added to the redex list. #[inline(always)] pub fn is_skippable(&self) -> bool { - self.tag() == Num || self.tag() == Ref && self.lab() != u16::MAX + self.is(Tag::AdtZ) || self.is(Tag::Num) || self.is(Tag::Ref) && self.lab() != u16::MAX } /// Converts a [`Var`] port into a [`Red`] port with the same address. #[inline(always)] pub(super) fn redirect(&self) -> Port { - Port::new(Red, 0, self.addr()) + Port(self.0 ^ (Tag::Red as u64 ^ Tag::Var as u64)) } /// Converts a [`Red`] port into a [`Var`] port with the same address. #[inline(always)] pub(super) fn unredirect(&self) -> Port { - Port::new(Var, 0, self.addr()) + self.redirect() } pub(super) fn is_full_node(&self) -> bool { - self.tag() > Num + match self.tag() { + Tag::Op | Tag::Mat | CtrN!() | AdtN!() => true, + Tag::Red | Tag::Var | Tag::Num | Tag::Ref | Tag::AdtZ => false, + } + } + + /// TODO + #[inline(always)] + pub(super) fn alloc_align(&self) -> Align { + unsafe { Align::from_unchecked(self.lab() as u8) } + } + + /// TODO + #[inline(always)] + pub(super) fn is_ctr_ish(&self) -> bool { + (self.0 * 0b111) > 0b100 } } diff --git a/src/run/tag.rs b/src/run/tag.rs new file mode 100644 index 00000000..3042baff --- /dev/null +++ b/src/run/tag.rs @@ -0,0 +1,123 @@ +use super::*; + +bi_enum! { + #[repr(u8)] + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub enum Tag { + //-- Align1 --\\ + Red = 0b0_00, + Var = 0b1_00, + + //-- Align2 --\\ + Ctr2 = 0b01_01, + Adt2 = 0b11_01, + Num = 0b00_01, + Op = 0b10_01, + + //-- Align4 --\\ + Ctr3 = 0b001_10, + Ctr4 = 0b101_10, + Adt3 = 0b011_10, + Adt4 = 0b111_10, + Ref = 0b000_10, + Mat = 0b010_10, + AdtZ = 0b100_10, + // = 0b110_10, + + //-- Align8 --\\ + Ctr5 = 0b0001_11, + Ctr6 = 0b0101_11, + Ctr7 = 0b1001_11, + Ctr8 = 0b1101_11, + Adt5 = 0b0011_11, + Adt6 = 0b0111_11, + Adt7 = 0b1011_11, + Adt8 = 0b1111_11, + // = 0b0000_11, + // = 0b0010_11, + // = 0b0100_11, + // = 0b0110_11, + // = 0b1000_11, + // = 0b1010_11, + // = 0b1100_11, + // = 0b1110_11, + } +} + +impl Tag { + #[inline(always)] + pub(super) fn align(self) -> Align { + unsafe { Align::from_unchecked(self as u8 & 0b11) } + } + #[inline] + pub(super) fn width(self) -> u8 { + match self { + Tag::Num | Tag::Ref | Tag::AdtZ => 0, + Tag::Red | Tag::Var => 1, + Tag::Op | Tag::Mat => 2, + CtrN!() | AdtN!() => (1 << (self.align() as u8 - 1)) + 1 + (self as u8 >> 4), + } + } + #[inline] + pub(super) fn arity(self) -> u8 { + match self { + AdtN!() => self.width() - 1, + _ => self.width(), + } + } +} + +macro_rules! CtrN { + () => { + Tag::Ctr2 | Tag::Ctr3 | Tag::Ctr4 | Tag::Ctr5 | Tag::Ctr6 | Tag::Ctr7 | Tag::Ctr8 + }; +} + +macro_rules! AdtN { + () => { + Tag::Adt2 | Tag::Adt3 | Tag::Adt4 | Tag::Adt5 | Tag::Adt6 | Tag::Adt7 | Tag::Adt8 + }; +} + +pub(crate) use AdtN; +pub(crate) use CtrN; + +bi_enum! { + #[repr(u8)] + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub(crate) enum Align { + Align1 = 0b00, + Align2 = 0b01, + Align4 = 0b10, + Align8 = 0b11, + } +} + +pub(crate) use Align::*; + +impl Align { + #[inline(always)] + pub(super) fn tag_bits(self) -> u8 { + self as u8 + 3 + } + #[inline(always)] + pub(super) fn width(self) -> u8 { + 1 << self as u8 + } + #[inline(always)] + pub(super) fn next(self) -> Option { + match self { + Align1 => Some(Align2), + Align2 => Some(Align4), + Align4 => Some(Align8), + Align8 => None, + } + } +} + +#[test] +fn test_tag_width() { + use Tag::*; + assert_eq!([Ctr2, Ctr3, Ctr4, Ctr5, Ctr6, Ctr7, Ctr8].map(Tag::width), [2, 3, 4, 5, 6, 7, 8]); + assert_eq!([Adt2, Adt3, Adt4, Adt5, Adt6, Adt7, Adt8].map(Tag::width), [2, 3, 4, 5, 6, 7, 8]); +} diff --git a/src/run/wire.rs b/src/run/wire.rs index 7a79cd94..d27ee5ad 100644 --- a/src/run/wire.rs +++ b/src/run/wire.rs @@ -13,7 +13,7 @@ use super::*; /// Changes to the target are handled by the linker. #[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] #[must_use] -pub struct Wire(pub *const AtomicU64); +pub struct Wire(pub u64); impl fmt::Debug for Wire { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -27,28 +27,33 @@ unsafe impl Sync for Wire {} impl Wire { #[inline(always)] pub fn addr(&self) -> Addr { - Addr(self.0 as _) + Addr((self.0 & 0x0000_FFFF_FFFF_FFFF) as usize) } #[inline(always)] - pub fn new(addr: Addr) -> Wire { - Wire(addr.0 as _) + pub fn alloc_align(&self) -> Align { + unsafe { Align::from_unchecked((self.0 >> 48) as u8) } + } + + #[inline(always)] + pub fn new(alloc_align: Align, addr: Addr) -> Wire { + Wire(((alloc_align as u64) << 48) | (addr.0 as u64)) } #[inline(always)] fn target<'a>(&self) -> &'a AtomicU64 { if cfg!(feature = "_fuzz") { - assert_ne!(self.0 as usize, 0xfffffffffff0u64 as usize); - assert_ne!(self.0 as usize, 0); + assert_ne!(self.addr().0, 0xfffffffffff0u64 as usize); + assert_ne!(self.0, 0); } - unsafe { &*self.0 } + unsafe { &*(self.addr().0 as *const _) } } #[inline(always)] pub fn load_target(&self) -> Port { let port = Port(self.target().load(Relaxed)); if cfg!(feature = "_fuzz") { - assert_ne!(port, Port::FREE); + assert_ne!(port, Port::FREE_1); } port } @@ -67,18 +72,23 @@ impl Wire { pub fn swap_target(&self, value: Port) -> Port { let port = Port(self.target().swap(value.0, Relaxed)); if cfg!(feature = "_fuzz") { - assert_ne!(port, Port::FREE); + assert_ne!(port, Port::FREE_1); } port } + #[inline(always)] + pub fn as_var(&self) -> Port { + Port(self.0 | Tag::Var as u64) + } + // Takes a pointer's target. #[inline(always)] pub fn lock_target(&self) -> Port { loop { let got = self.swap_target(Port::LOCK); if cfg!(feature = "_fuzz") { - assert_ne!(got, Port::FREE); + assert_ne!(got, Port::FREE_1); } if got != Port::LOCK { return got; @@ -86,9 +96,4 @@ impl Wire { spin_loop(); } } - - #[inline(always)] - pub(super) fn as_var(&self) -> Port { - Port::new_var(self.addr()) - } } diff --git a/src/trace.rs b/src/trace.rs index 7bb961d1..b7d22d95 100644 --- a/src/trace.rs +++ b/src/trace.rs @@ -64,7 +64,7 @@ #![cfg_attr(not(feature = "trace"), allow(unused))] use std::{ - cell::UnsafeCell, + cell::{Cell, UnsafeCell}, fmt::{self, Debug, Formatter, Write}, sync::{ atomic::{AtomicBool, AtomicU64, Ordering}, @@ -84,10 +84,10 @@ pub struct Tracer(()); #[cfg(not(feature = "trace"))] impl Tracer { #[inline(always)] - pub fn sync(&mut self) {} + pub fn sync(&self) {} #[inline(always)] #[doc(hidden)] - pub fn trace(&mut self, _: A) {} + pub fn trace(&self, _: A) {} #[inline(always)] pub fn set_tid(&self, _: usize) {} } @@ -124,12 +124,12 @@ pub struct Tracer(TraceWriter); #[cfg(feature = "trace")] impl Tracer { #[inline(always)] - pub fn sync(&mut self) { + pub fn sync(&self) { self.0.sync() } #[inline(always)] #[doc(hidden)] - pub fn trace(&mut self, args: A) { + pub fn trace(&self, args: A) { self.0.trace::(args) } #[inline(always)] @@ -183,7 +183,7 @@ static ACTIVE_TRACERS: Mutex>> = Mutex::new(Vec::new()); struct TraceWriter { lock: &'static TraceLock, - nonce: u64, + nonce: Cell, } unsafe impl Send for TraceWriter {} @@ -197,13 +197,13 @@ impl Default for TraceWriter { let lock = unsafe { &*(&*boxed as *const _) }; let mut active_tracers = ACTIVE_TRACERS.lock().unwrap(); active_tracers.push(boxed); - TraceWriter { lock, nonce: TRACE_NONCE.fetch_add(1, Ordering::Relaxed) } + TraceWriter { lock, nonce: Cell::new(TRACE_NONCE.fetch_add(1, Ordering::Relaxed)) } } } impl TraceWriter { - fn sync(&mut self) { - self.nonce = TRACE_NONCE.fetch_add(1, Ordering::Relaxed); + fn sync(&self) { + self.nonce.set(TRACE_NONCE.fetch_add(1, Ordering::Relaxed)); } fn acquire(&self, cb: impl FnOnce(&mut TraceData)) { while self.lock.locked.compare_exchange_weak(false, true, Ordering::Relaxed, Ordering::Relaxed).is_err() { @@ -212,13 +212,13 @@ impl TraceWriter { cb(unsafe { &mut *self.lock.data.get() }); self.lock.locked.store(false, Ordering::Release); } - fn trace(&mut self, args: A) { + fn trace(&self, args: A) { if cfg!(feature = "_fuzz") { self.sync(); } let meta: &'static _ = &TraceMetadata { source: S::SOURCE, arg_fmts: A::FMTS }; self.acquire(|data| { - let nonce = self.nonce; + let nonce = self.nonce.get(); for arg in args.to_words().rev() { data.write_word(arg); } From 32b6073fe7c21f82aafec968d1a9c5e04d3263a8 Mon Sep 17 00:00:00 2001 From: tjjfvi Date: Wed, 6 Mar 2024 09:10:33 -0500 Subject: [PATCH 02/16] ... --- src/run/addr.rs | 7 ++++--- src/run/instruction.rs | 4 ++++ src/run/net.rs | 1 + src/run/port.rs | 11 ++++++----- src/run/tag.rs | 12 ++++++++++++ 5 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/run/addr.rs b/src/run/addr.rs index f19515f2..fb9d1cec 100644 --- a/src/run/addr.rs +++ b/src/run/addr.rs @@ -37,19 +37,20 @@ impl Addr { const HALF_MASK: usize = 0b1000; - /// TODO + /// Rounds this address down to be aligned to `align`. #[inline(always)] pub(super) fn floor(&self, align: Align) -> Self { Addr(self.0 & (usize::MAX << align.tag_bits())) } - /// TODO + /// Returns the other address of alignment `align` within alignment + /// `align.next()`. #[inline(always)] pub(super) fn other(&self, align: Align) -> Self { Addr(self.0 ^ (1 << align.tag_bits())) } - /// TODO + /// Offsets the address by a specified number of words. #[inline(always)] pub(super) fn offset(&self, words: usize) -> Self { Addr(self.0 + (words << 3)) diff --git a/src/run/instruction.rs b/src/run/instruction.rs index feacbf33..fc0aa7a0 100644 --- a/src/run/instruction.rs +++ b/src/run/instruction.rs @@ -25,6 +25,10 @@ use super::*; /// net.link(aw, bw); /// ``` /// +/// ```js +/// let a =5; +/// ``` +/// /// Each instruction documents both the native implementation and the polarity /// of each `TrgId`. /// diff --git a/src/run/net.rs b/src/run/net.rs index da04bb76..d0317064 100644 --- a/src/run/net.rs +++ b/src/run/net.rs @@ -100,6 +100,7 @@ impl<'a, M: Mode> Net<'a, M> { let next = self.weak_normal(prev, root.clone()); trace!(self, "got", next); if next.is_full_node() { + for i in 0 .. next.tag().arity() {} todo!(); // visit.push(Port::new_var( next.addr())); // visit.push(Port::new_var( next.addr().other_half())); diff --git a/src/run/port.rs b/src/run/port.rs index e7376b9a..b3519d76 100644 --- a/src/run/port.rs +++ b/src/run/port.rs @@ -84,7 +84,7 @@ impl Port { /// TODO #[inline(always)] - pub fn new_adtz(variant_count: u8, variant_index: u8) -> Self { + pub const fn new_adtz(variant_count: u8, variant_index: u8) -> Self { Port(Tag::AdtZ as u64 | ((variant_count as u64) << 16) | ((variant_index as u64) << 8)) } @@ -112,11 +112,12 @@ impl Port { unsafe { Tag::from_unchecked((self.0 & (1 << self.align().tag_bits()) - 1) as u8) } } - /// TODO + /// Checks if this port is of the given `tag`. #[inline(always)] pub fn is(&self, tag: Tag) -> bool { - // TODO: optimize - self.tag() == tag + // This could be `self.tag() == tag`, but this is more efficient when `tag` + // is a constant. + (self.0 & ((1 << tag.align().tag_bits()) - 1)) as u8 == tag as u8 } /// Accesses the label of this port; this is valid for all non-`Num` ports. @@ -192,6 +193,6 @@ impl Port { /// TODO #[inline(always)] pub(super) fn is_ctr_ish(&self) -> bool { - (self.0 * 0b111) > 0b100 + (self.0 & 0b111) > 0b100 } } diff --git a/src/run/tag.rs b/src/run/tag.rs index 3042baff..d5304d99 100644 --- a/src/run/tag.rs +++ b/src/run/tag.rs @@ -49,6 +49,8 @@ impl Tag { pub(super) fn align(self) -> Align { unsafe { Align::from_unchecked(self as u8 & 0b11) } } + + /// Returns the width -- the size of the allocation -- of nodes of this tag. #[inline] pub(super) fn width(self) -> u8 { match self { @@ -58,6 +60,9 @@ impl Tag { CtrN!() | AdtN!() => (1 << (self.align() as u8 - 1)) + 1 + (self as u8 >> 4), } } + + /// Returns the arity -- the number of auxiliary ports -- of nodes of this + /// tag. #[inline] pub(super) fn arity(self) -> u8 { match self { @@ -67,12 +72,14 @@ impl Tag { } } +/// Matches any `Ctr` tag. macro_rules! CtrN { () => { Tag::Ctr2 | Tag::Ctr3 | Tag::Ctr4 | Tag::Ctr5 | Tag::Ctr6 | Tag::Ctr7 | Tag::Ctr8 }; } +/// Matches any `Adt` tag except `AdtZ` (which is handled quite differently). macro_rules! AdtN { () => { Tag::Adt2 | Tag::Adt3 | Tag::Adt4 | Tag::Adt5 | Tag::Adt6 | Tag::Adt7 | Tag::Adt8 @@ -84,6 +91,9 @@ pub(crate) use CtrN; bi_enum! { #[repr(u8)] + /// The alignment of an [`Addr`], measured in words. + /// + /// The numeric representation of the alignment is `log2(align.width())`. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub(crate) enum Align { Align1 = 0b00, @@ -96,6 +106,7 @@ bi_enum! { pub(crate) use Align::*; impl Align { + /// The number of bits available for tagging in addresses of this alignment. #[inline(always)] pub(super) fn tag_bits(self) -> u8 { self as u8 + 3 @@ -104,6 +115,7 @@ impl Align { pub(super) fn width(self) -> u8 { 1 << self as u8 } + /// Returns the next largest alignment, if it exists. #[inline(always)] pub(super) fn next(self) -> Option { match self { From 44d37988ed3e4b22a6f955751551441e67f16093 Mon Sep 17 00:00:00 2001 From: tjjfvi Date: Thu, 14 Mar 2024 14:42:34 -0400 Subject: [PATCH 03/16] ... --- src/host/encode.rs | 13 ++-- src/host/readback.rs | 2 + src/run/def.rs | 2 + src/run/instruction.rs | 1 + src/run/interact.rs | 151 +++++++++++++++++++++++++---------------- src/run/net.rs | 2 + src/run/port.rs | 8 +++ src/run/tag.rs | 14 +++- src/stdlib.rs | 15 +++- 9 files changed, 138 insertions(+), 70 deletions(-) diff --git a/src/host/encode.rs b/src/host/encode.rs index 31bd7717..54882f7e 100644 --- a/src/host/encode.rs +++ b/src/host/encode.rs @@ -16,17 +16,17 @@ impl Host { /// Encode `tree` directly into `trg`, skipping the intermediate `Def` /// representation. pub fn encode_tree(&self, net: &mut run::Net, trg: run::Trg, tree: &Tree) { - let mut state = State { host: self, encoder: net, scope: Default::default() }; - state.visit_tree(tree, trg); - state.finish(); + // let mut state = State { host: self, encoder: net, scope: + // Default::default() }; state.visit_tree(tree, trg); + // state.finish(); } /// Encode the root of `ast_net` directly into `trg` and encode its redexes /// into `net` redex list. pub fn encode_net(&self, net: &mut run::Net, trg: run::Trg, ast_net: &Net) { - let mut state = State { host: self, encoder: net, scope: Default::default() }; - state.visit_net(ast_net, trg); - state.finish(); + // let mut state = State { host: self, encoder: net, scope: + // Default::default() }; state.visit_net(ast_net, trg); + // state.finish(); } } @@ -185,6 +185,7 @@ impl Encoder for InterpretedDef { } } +#[cfg(todo)] impl<'a, M: Mode> Encoder for run::Net<'a, M> { type Trg = run::Trg; fn link_const(&mut self, trg: Self::Trg, port: Port) { diff --git a/src/host/readback.rs b/src/host/readback.rs index 9d755b4b..3814988f 100644 --- a/src/host/readback.rs +++ b/src/host/readback.rs @@ -63,6 +63,7 @@ impl<'a> ReadbackState<'a> { let node = port.traverse_node(); Tree::Op { op, rhs: Box::new(self.read_wire(node.p1)), out: Box::new(self.read_wire(node.p2)) } } + #[cfg(todo)] Tag::Ctr => { let node = port.traverse_node(); Tree::Ctr { lab: node.lab, ports: vec![self.read_wire(node.p1), self.read_wire(node.p2)] } @@ -73,6 +74,7 @@ impl<'a> ReadbackState<'a> { let out = self.read_wire(node.p2); Tree::legacy_mat(arms, out).expect("invalid mat node") } + _ => todo!(), }) } } diff --git a/src/run/def.rs b/src/run/def.rs index cf9d8473..0368b763 100644 --- a/src/run/def.rs +++ b/src/run/def.rs @@ -239,6 +239,8 @@ impl AsDef for InterpretedDef { trgs.set_trg(TrgId::new(0), Trg::port(trg)); for i in instructions { unsafe { + todo!(); + #[cfg(todo)] match *i { Instruction::Const { trg, ref port } => trgs.set_trg(trg, Trg::port(port.clone())), Instruction::Link { a, b } => net.link_trg(trgs.get_trg(a), trgs.get_trg(b)), diff --git a/src/run/instruction.rs b/src/run/instruction.rs index fc0aa7a0..2c9c6858 100644 --- a/src/run/instruction.rs +++ b/src/run/instruction.rs @@ -111,6 +111,7 @@ impl fmt::Debug for TrgId { } } +#[cfg(todo)] impl<'a, M: Mode> Net<'a, M> { /// `trg ~ {#lab x y}` #[inline(always)] diff --git a/src/run/interact.rs b/src/run/interact.rs index 1590bddd..7125b59b 100644 --- a/src/run/interact.rs +++ b/src/run/interact.rs @@ -1,3 +1,5 @@ +use std::mem::MaybeUninit; + use super::*; impl<'a, M: Mode> Net<'a, M> { @@ -10,41 +12,32 @@ impl<'a, M: Mode> Net<'a, M> { match (a.tag(), b.tag()) { // not actually an active pair (Var | Red, _) | (_, Var | Red) => unreachable!(), - // nil-nil - (Ref, Ref | Num) if !a.is_skippable() => self.call(a, b), - (Ref | Num, Ref) if !b.is_skippable() => self.call(b, a), + + (Ref, _) if a != Port::ERA => self.call(a, b), + (_, Ref) if b != Port::ERA => self.call(b, a), + (Num | Ref | AdtZ, Num | Ref | AdtZ) => self.rwts.eras += 1, - // comm 2/2 - (Mat | Op, CtrN!() | AdtN!()) => self.comm2N(a, b), - (CtrN!() | AdtN!(), Mat | Op) => self.comm2N(b, a), - // anni - (CtrN!(), CtrN!()) => self.anniNM(a, b), - (Mat, Mat) | (Op, Op) => self.anni2(a, b), - // comm 2/0 - (Ref, CtrN!() | AdtN!()) if b.lab() >= a.lab() => self.comm0N(a, b), - (CtrN!() | AdtN!(), Ref) if a.lab() >= b.lab() => self.comm0N(b, a), - (Num, CtrN!() | AdtN!()) => self.comm0N(a, b), - (CtrN!() | AdtN!(), Num) => self.comm0N(b, a), - (AdtZ, Op | Mat) => self.comm02(a, b), - (Op | Mat, AdtZ) => self.comm02(a, b), - // TODO - (AdtN!() | AdtZ, CtrN!()) => self.adt_ctr(a, b), - (CtrN!(), AdtN!() | AdtZ) => self.adt_ctr(b, a), - (AdtN!() | AdtZ, AdtN!() | AdtZ) => todo!(), - // deref - (Ref, Mat | Op) if a == Port::ERA => self.comm02(a, b), - (Mat | Op, Ref) if b == Port::ERA => self.comm02(b, a), - (Ref, CtrN!() | AdtN!()) if a == Port::ERA => self.comm0N(a, b), - (CtrN!() | AdtN!(), Ref) if b == Port::ERA => self.comm0N(b, a), - (Ref, CtrN!() | AdtN!() | Mat | Op) => self.call(a, b), - (CtrN!() | AdtN!() | Mat | Op, Ref) => self.call(b, a), - // native ops - (Op, Num) => self.opr_num(a, b), - (Num, Op) => self.opr_num(b, a), + + (CtrN!(), CtrN!()) if a.lab() == b.lab() => self.anni(a, b), + + (AdtN!() | AdtZ, CtrN!()) if a.lab() == b.lab() => self.adt_ctr(a, b), + (CtrN!(), AdtN!() | AdtZ) if a.lab() == b.lab() => self.adt_ctr(b, a), + (AdtN!() | AdtZ, AdtN!() | AdtZ) if a.lab() == b.lab() => todo!(), + + (Mat, Mat) | (Op, Op) => self.anni(a, b), + + (CtrN!(), Mat) if a.lab() == 0 => todo!(), + (Mat, CtrN!()) if b.lab() == 0 => todo!(), + (Op, Op) if a.op() != b.op() => todo!(), + + (CtrN!(), CtrN!()) | (Op, Op) => self.anni(a, b), + + (Op, Num) => self.op_num(a, b), + (Num, Op) => self.op_num(b, a), (Mat, Num) => self.mat_num(a, b), (Num, Mat) => self.mat_num(b, a), - // todo: what should the semantics of these be? - (Op, Mat) | (Mat, Op) => unimplemented!("{:?}-{:?}", a.tag(), b.tag()), + + (_, _) => self.comm(a, b), } } @@ -209,26 +202,27 @@ impl<'a, M: Mode> Net<'a, M> { /// ``` #[inline(never)] pub fn mat_num(&mut self, a: Port, b: Port) { - trace!(self, a, b); - self.rwts.oper += 1; - let a = a.consume_node(); - let b = b.num(); - if b == 0 { - let x = self.create_node(Ctr, 0); - trace!(self, x.p0); - self.link_port_port(x.p2, Port::ERA); - self.link_wire_port(a.p2, x.p1); - self.link_wire_port(a.p1, x.p0); - } else { - let x = self.create_node(Tag::Ctr, 0); - let y = self.create_node(Tag::Ctr, 0); - trace!(self, x.p0, y.p0); - self.link_port_port(x.p1, Port::ERA); - self.link_port_port(x.p2, y.p0); - self.link_port_port(y.p1, Port::new_num(b - 1)); - self.link_wire_port(a.p2, y.p2); - self.link_wire_port(a.p1, x.p0); - } + todo!() + // trace!(self, a, b); + // self.rwts.oper += 1; + // let a = a.consume_node(); + // let b = b.num(); + // if b == 0 { + // let x = self.create_node(Ctr, 0); + // trace!(self, x.p0); + // self.link_port_port(x.p2, Port::ERA); + // self.link_wire_port(a.p2, x.p1); + // self.link_wire_port(a.p1, x.p0); + // } else { + // let x = self.create_node(Tag::Ctr, 0); + // let y = self.create_node(Tag::Ctr, 0); + // trace!(self, x.p0, y.p0); + // self.link_port_port(x.p1, Port::ERA); + // self.link_port_port(x.p2, y.p0); + // self.link_port_port(y.p1, Port::new_num(b - 1)); + // self.link_wire_port(a.p2, y.p2); + // self.link_wire_port(a.p1, x.p0); + // } } /// Interacts a number and a binary numeric operation node. @@ -276,19 +270,56 @@ impl<'a, M: Mode> Net<'a, M> { } } - fn comm2N(&mut self, a: Port, b: Port) { - todo!() - } - - fn anniNM(&mut self, a: Port, b: Port) { + fn adt_ctr(&mut self, adt: Port, ctr: Port) { + let ctr_arity = ctr.tag().arity(); todo!() } - fn comm0N(&mut self, a: Port, b: Port) { + fn anni(&self, a: Port, b: Port) { todo!() } - fn adt_ctr(&mut self, b: Port, a: Port) { - todo!() + fn comm(&mut self, a: Port, b: Port) { + let mut Bs = [const { MaybeUninit::::uninit() }; 8]; + let mut As = [const { MaybeUninit::::uninit() }; 8]; + let aa = a.tag().arity(); + // let aw = b.tag().width(); + let ba = b.tag().arity(); + // let bw = b.tag().width(); + let Bs = &mut Bs[0 .. aa as usize]; + let As = &mut As[0 .. ba as usize]; + if ba != 0 { + for B in &mut *Bs { + let addr = self.alloc(b.align()); + *B = MaybeUninit::new(b.with_addr(addr)); + } + } + if aa != 0 { + for A in &mut *As { + let addr = self.alloc(a.align()); + *A = MaybeUninit::new(a.with_addr(addr)); + } + } + for bi in 0 .. aa { + for ai in 0 .. ba { + unsafe { + self.link_port_port( + As.get_unchecked(ai as usize).assume_init_ref().aux_port(bi), + Bs.get_unchecked(bi as usize).assume_init_ref().aux_port(ai), + ); + } + } + } + // TODO: copy width - arity + for i in 0 .. aa { + unsafe { + self.link_wire_port(a.aux_port(i).wire(), Bs.get_unchecked(i as usize).assume_init_read()); + } + } + for i in 0 .. ba { + unsafe { + self.link_wire_port(b.aux_port(i).wire(), As.get_unchecked(i as usize).assume_init_read()); + } + } } } diff --git a/src/run/net.rs b/src/run/net.rs index d0317064..c0deb9e2 100644 --- a/src/run/net.rs +++ b/src/run/net.rs @@ -159,6 +159,8 @@ impl AsDef for ExpandDef { unreachable!() } Tag::Ref | Tag::Num | Tag::Var => net.link_port_port(def.data.out, port), + _ => todo!(), + #[cfg(todo)] tag @ (Tag::Op | Tag::Mat | Tag::Ctr) => { let old = port.consume_node(); let new = net.create_node(tag, old.lab); diff --git a/src/run/port.rs b/src/run/port.rs index b3519d76..b0ac76a5 100644 --- a/src/run/port.rs +++ b/src/run/port.rs @@ -195,4 +195,12 @@ impl Port { pub(super) fn is_ctr_ish(&self) -> bool { (self.0 & 0b111) > 0b100 } + + pub(super) fn aux_port(&self, i: u8) -> Port { + todo!() + } + + pub(super) fn with_addr(&self, addr: Addr) -> Port { + todo!() + } } diff --git a/src/run/tag.rs b/src/run/tag.rs index d5304d99..12c9e6d2 100644 --- a/src/run/tag.rs +++ b/src/run/tag.rs @@ -56,7 +56,8 @@ impl Tag { match self { Tag::Num | Tag::Ref | Tag::AdtZ => 0, Tag::Red | Tag::Var => 1, - Tag::Op | Tag::Mat => 2, + Tag::Op => 2, + Tag::Mat => 3, CtrN!() | AdtN!() => (1 << (self.align() as u8 - 1)) + 1 + (self as u8 >> 4), } } @@ -70,6 +71,14 @@ impl Tag { _ => self.width(), } } + + pub(super) fn ctr_with_arity(arity: u8) -> Tag { + let sub = arity - 1; + let ilog = unsafe { sub.checked_ilog2().unwrap_unchecked() as u8 }; + let ext = sub - (1 << ilog); + let tag = (ilog + 1) | 0b100 | (ext << 4); + unsafe { Tag::from_unchecked(tag) } + } } /// Matches any `Ctr` tag. @@ -132,4 +141,7 @@ fn test_tag_width() { use Tag::*; assert_eq!([Ctr2, Ctr3, Ctr4, Ctr5, Ctr6, Ctr7, Ctr8].map(Tag::width), [2, 3, 4, 5, 6, 7, 8]); assert_eq!([Adt2, Adt3, Adt4, Adt5, Adt6, Adt7, Adt8].map(Tag::width), [2, 3, 4, 5, 6, 7, 8]); + for t in [Ctr2, Ctr3, Ctr4, Ctr5, Ctr6, Ctr7, Ctr8] { + assert_eq!(Tag::ctr_with_arity(t.width()), t); + } } diff --git a/src/stdlib.rs b/src/stdlib.rs index 995c2f57..cd83932f 100644 --- a/src/stdlib.rs +++ b/src/stdlib.rs @@ -10,8 +10,12 @@ use crate::{ pub const IDENTITY: *const Def = const { &Def::new(LabSet::from_bits(&[1]), (call_identity, call_identity)) }.upcast(); fn call_identity(net: &mut Net, port: Port) { - let (a, b) = net.do_ctr(0, Trg::port(port)); - net.link_trg(a, b); + #[cfg(todo)] + { + let (a, b) = net.do_ctr(0, Trg::port(port)); + net.link_trg(a, b); + } + todo!() } /// The definition of `HVM.log`, parameterized by the readback function. @@ -25,10 +29,13 @@ pub struct LogDef(F); impl LogDef { pub fn new(f: F) -> Def { - Def::new(LabSet::ALL, LogDef(f)) + #[cfg(todo)] + Def::new(LabSet::ALL, LogDef(f)); + todo!() } } +#[cfg(todo)] impl AsDef for LogDef { unsafe fn call(def: *const Def, net: &mut Net, port: Port) { let def = unsafe { &*def }; @@ -91,6 +98,8 @@ impl AsDef for ActiveLogDef { } } Tag::Ref | Tag::Num | Tag::Var => net.link_port_port(def.data.out, port), + _ => todo!(), + #[cfg(todo)] tag @ (Tag::Op | Tag::Mat | Tag::Ctr) => { let old = port.consume_node(); let new = net.create_node(tag, old.lab); From b861263eeaeb38ccbc7481368c5ae54fb29d9a0c Mon Sep 17 00:00:00 2001 From: tjjfvi Date: Mon, 18 Mar 2024 10:53:11 -0400 Subject: [PATCH 04/16] ... --- src/host/encode.rs | 17 +++++++++-------- src/host/readback.rs | 3 +-- src/run/addr.rs | 2 -- src/run/allocator.rs | 6 ++++-- src/run/def.rs | 4 ++-- src/run/instruction.rs | 8 +++++--- src/run/interact.rs | 18 +++++++++++++----- src/run/net.rs | 3 ++- src/run/parallel.rs | 3 ++- src/run/port.rs | 13 +++++++------ src/run/tag.rs | 3 +++ src/stdlib.rs | 1 + src/trace.rs | 11 ++++++++++- 13 files changed, 59 insertions(+), 33 deletions(-) diff --git a/src/host/encode.rs b/src/host/encode.rs index 54882f7e..44ff8c69 100644 --- a/src/host/encode.rs +++ b/src/host/encode.rs @@ -16,17 +16,17 @@ impl Host { /// Encode `tree` directly into `trg`, skipping the intermediate `Def` /// representation. pub fn encode_tree(&self, net: &mut run::Net, trg: run::Trg, tree: &Tree) { - // let mut state = State { host: self, encoder: net, scope: - // Default::default() }; state.visit_tree(tree, trg); - // state.finish(); + let mut state = State { host: self, encoder: net, scope: Default::default() }; + state.visit_tree(tree, trg); + state.finish(); } /// Encode the root of `ast_net` directly into `trg` and encode its redexes /// into `net` redex list. pub fn encode_net(&self, net: &mut run::Net, trg: run::Trg, ast_net: &Net) { - // let mut state = State { host: self, encoder: net, scope: - // Default::default() }; state.visit_net(ast_net, trg); - // state.finish(); + let mut state = State { host: self, encoder: net, scope: Default::default() }; + state.visit_net(ast_net, trg); + state.finish(); } } @@ -185,7 +185,6 @@ impl Encoder for InterpretedDef { } } -#[cfg(todo)] impl<'a, M: Mode> Encoder for run::Net<'a, M> { type Trg = run::Trg; fn link_const(&mut self, trg: Self::Trg, port: Port) { @@ -207,7 +206,9 @@ impl<'a, M: Mode> Encoder for run::Net<'a, M> { self.do_op_num(op, trg, rhs) } fn mat(&mut self, trg: Self::Trg) -> (Self::Trg, Self::Trg) { - self.do_mat(trg) + #[cfg(todo)] + self.do_mat(trg); + todo!(); } fn wires(&mut self) -> (Self::Trg, Self::Trg, Self::Trg, Self::Trg) { self.do_wires() diff --git a/src/host/readback.rs b/src/host/readback.rs index 3814988f..02dd76dd 100644 --- a/src/host/readback.rs +++ b/src/host/readback.rs @@ -63,8 +63,7 @@ impl<'a> ReadbackState<'a> { let node = port.traverse_node(); Tree::Op { op, rhs: Box::new(self.read_wire(node.p1)), out: Box::new(self.read_wire(node.p2)) } } - #[cfg(todo)] - Tag::Ctr => { + Tag::Ctr2 => { let node = port.traverse_node(); Tree::Ctr { lab: node.lab, ports: vec![self.read_wire(node.p1), self.read_wire(node.p2)] } } diff --git a/src/run/addr.rs b/src/run/addr.rs index fb9d1cec..337fda97 100644 --- a/src/run/addr.rs +++ b/src/run/addr.rs @@ -35,8 +35,6 @@ impl Addr { unsafe { &*(self.0 as *const _) } } - const HALF_MASK: usize = 0b1000; - /// Rounds this address down to be aligned to `align`. #[inline(always)] pub(super) fn floor(&self, align: Align) -> Self { diff --git a/src/run/allocator.rs b/src/run/allocator.rs index 95139a53..484d6050 100644 --- a/src/run/allocator.rs +++ b/src/run/allocator.rs @@ -73,6 +73,7 @@ impl<'h> Allocator<'h> { } let mut align = Align1; if align == alloc_align { + trace!(self.tracer, "free"); return Self::push_addr(self.head(align), addr); } addr.val().store(align.free(), Relaxed); @@ -110,9 +111,10 @@ impl<'h> Allocator<'h> { } else { let index = self.next; self.next += 8; - Addr(&self.heap.0.get(index).expect("OOM") as *const _ as _) + trace!(self, index); + Addr(self.heap.0.get(index).expect("OOM") as *const AtomicU64 as usize) }; - trace!(self, addr); + trace!(self, align, addr); for i in 0 .. align.width() { addr.offset(i as usize).val().store(Port::LOCK.0, Relaxed); } diff --git a/src/run/def.rs b/src/run/def.rs index 0368b763..e7e8c281 100644 --- a/src/run/def.rs +++ b/src/run/def.rs @@ -239,8 +239,6 @@ impl AsDef for InterpretedDef { trgs.set_trg(TrgId::new(0), Trg::port(trg)); for i in instructions { unsafe { - todo!(); - #[cfg(todo)] match *i { Instruction::Const { trg, ref port } => trgs.set_trg(trg, Trg::port(port.clone())), Instruction::Link { a, b } => net.link_trg(trgs.get_trg(a), trgs.get_trg(b)), @@ -264,6 +262,7 @@ impl AsDef for InterpretedDef { let o = net.do_op_num(op, trgs.get_trg(trg), lhs); trgs.set_trg(out, o); } + #[cfg(todo)] Instruction::Mat { trg, lft, rgt } => { let (l, r) = net.do_mat(trgs.get_trg(trg)); trgs.set_trg(lft, l); @@ -276,6 +275,7 @@ impl AsDef for InterpretedDef { trgs.set_trg(bv, bvt); trgs.set_trg(bw, bwt); } + _ => todo!(), } } } diff --git a/src/run/instruction.rs b/src/run/instruction.rs index 2c9c6858..7910b401 100644 --- a/src/run/instruction.rs +++ b/src/run/instruction.rs @@ -111,13 +111,12 @@ impl fmt::Debug for TrgId { } } -#[cfg(todo)] impl<'a, M: Mode> Net<'a, M> { /// `trg ~ {#lab x y}` #[inline(always)] pub(crate) fn do_ctr(&mut self, lab: Lab, trg: Trg) -> (Trg, Trg) { let port = trg.target(); - if !M::LAZY && port.is(Tag::Ctr) && port.lab() == lab { + if !M::LAZY && port.is(Tag::Ctr2) && port.lab() == lab { trace!(self, "fast"); self.free_trg(trg); let node = port.consume_node(); @@ -128,7 +127,7 @@ impl<'a, M: Mode> Net<'a, M> { self.rwts.comm += 1; (Trg::port(port.clone()), Trg::port(port)) } else { - let n = self.create_node(Ctr, lab); + let n = self.create_node(Ctr2, lab); self.link_trg_port(trg, n.p0); (Trg::port(n.p1), Trg::port(n.p2)) } @@ -171,6 +170,7 @@ impl<'a, M: Mode> Net<'a, M> { } } + #[cfg(todo)] /// `trg ~ ?` #[inline(always)] pub(crate) fn do_mat(&mut self, trg: Trg) -> (Trg, Trg) { @@ -213,6 +213,7 @@ impl<'a, M: Mode> Net<'a, M> { ) } + #[cfg(todo)] /// `trg ~ ?<(x (y z)) out>` #[inline(always)] #[allow(unused)] // TODO: emit this instruction @@ -241,6 +242,7 @@ impl<'a, M: Mode> Net<'a, M> { } } + #[cfg(todo)] /// `trg ~ ?<(x y) out>` #[inline(always)] #[allow(unused)] // TODO: emit this instruction diff --git a/src/run/interact.rs b/src/run/interact.rs index 7125b59b..12e84d6a 100644 --- a/src/run/interact.rs +++ b/src/run/interact.rs @@ -24,13 +24,11 @@ impl<'a, M: Mode> Net<'a, M> { (CtrN!(), AdtN!() | AdtZ) if a.lab() == b.lab() => self.adt_ctr(b, a), (AdtN!() | AdtZ, AdtN!() | AdtZ) if a.lab() == b.lab() => todo!(), - (Mat, Mat) | (Op, Op) => self.anni(a, b), - (CtrN!(), Mat) if a.lab() == 0 => todo!(), (Mat, CtrN!()) if b.lab() == 0 => todo!(), (Op, Op) if a.op() != b.op() => todo!(), - (CtrN!(), CtrN!()) | (Op, Op) => self.anni(a, b), + (Mat, Mat) | (Op, Op) => self.anni(a, b), (Op, Num) => self.op_num(a, b), (Num, Op) => self.op_num(b, a), @@ -275,8 +273,18 @@ impl<'a, M: Mode> Net<'a, M> { todo!() } - fn anni(&self, a: Port, b: Port) { - todo!() + fn anni(&mut self, a: Port, b: Port) { + if a.tag() == b.tag() { + for i in 0 .. a.tag().arity() { + self.link_wire_wire(a.aux_port(i).wire(), b.aux_port(i).wire()); + } + for i in a.tag().arity() .. a.tag().width() { + self.free_wire(a.aux_port(i).wire()); + self.free_wire(b.aux_port(i).wire()); + } + } else { + todo!() + } } fn comm(&mut self, a: Port, b: Port) { diff --git a/src/run/net.rs b/src/run/net.rs index c0deb9e2..2944fdcd 100644 --- a/src/run/net.rs +++ b/src/run/net.rs @@ -113,7 +113,8 @@ impl<'a, M: Mode> Net<'a, M> { if M::LAZY { self.normal_from(self.root.clone()); } else { - self.expand(); + // todo! + // self.expand(); while !self.redexes.is_empty() { self.reduce(usize::MAX); } diff --git a/src/run/parallel.rs b/src/run/parallel.rs index 2695c786..805edeb8 100644 --- a/src/run/parallel.rs +++ b/src/run/parallel.rs @@ -24,7 +24,8 @@ impl<'h, M: Mode> Net<'h, M> { pub fn parallel_normal(&mut self) { assert!(!M::LAZY); - self.expand(); + // todo + // self.expand(); const SHARE_LIMIT: usize = 1 << 12; // max share redexes per split const LOCAL_LIMIT: usize = 1 << 18; // max local rewrites per epoch diff --git a/src/run/port.rs b/src/run/port.rs index b0ac76a5..516d5725 100644 --- a/src/run/port.rs +++ b/src/run/port.rs @@ -109,7 +109,7 @@ impl Port { /// Accesses the tag of this port; this is valid for all ports. #[inline(always)] pub fn tag(&self) -> Tag { - unsafe { Tag::from_unchecked((self.0 & (1 << self.align().tag_bits()) - 1) as u8) } + unsafe { Tag::from_unchecked((self.0 & ((1 << self.align().tag_bits()) - 1)) as u8) } } /// Checks if this port is of the given `tag`. @@ -128,9 +128,8 @@ impl Port { /// Accesses the addr of this port; this is valid for all non-`Num` ports. #[inline(always)] - pub const fn addr(&self) -> Addr { - // todo - Addr((self.0 & 0x0000_FFFF_FFFF_FFF8) as usize as _) + pub fn addr(&self) -> Addr { + Addr((self.0 & self.align().addr_mask()) as usize) } /// Accesses the operation of this port; this is valid for [`Opr`] ports. @@ -196,11 +195,13 @@ impl Port { (self.0 & 0b111) > 0b100 } + #[inline(always)] pub(super) fn aux_port(&self, i: u8) -> Port { - todo!() + Port::new_var(self.align(), self.addr().offset(i as usize)) } + #[inline(always)] pub(super) fn with_addr(&self, addr: Addr) -> Port { - todo!() + Port(self.0 & !self.align().addr_mask() | addr.0 as u64) } } diff --git a/src/run/tag.rs b/src/run/tag.rs index 12c9e6d2..9709ac4b 100644 --- a/src/run/tag.rs +++ b/src/run/tag.rs @@ -120,6 +120,9 @@ impl Align { pub(super) fn tag_bits(self) -> u8 { self as u8 + 3 } + pub(super) fn addr_mask(self) -> u64 { + 0x0000_FFFF_FFFF_FFFF & (u64::MAX << self.tag_bits()) + } #[inline(always)] pub(super) fn width(self) -> u8 { 1 << self as u8 diff --git a/src/stdlib.rs b/src/stdlib.rs index cd83932f..54e02676 100644 --- a/src/stdlib.rs +++ b/src/stdlib.rs @@ -115,6 +115,7 @@ impl AsDef for ActiveLogDef { /// Create a `Host` from a `Book`, including `hvm-core`'s built-in definitions pub fn create_host(book: &Book) -> Arc> { let host = Arc::new(Mutex::new(Host::default())); + #[cfg(todo)] host.lock().unwrap().insert_def( "HVM.log", DefRef::Owned(Box::new(crate::stdlib::LogDef::new({ diff --git a/src/trace.rs b/src/trace.rs index b7d22d95..b4be6ddb 100644 --- a/src/trace.rs +++ b/src/trace.rs @@ -74,7 +74,7 @@ use std::{ use crate::{ ops::Op, - run::{Addr, Port, Trg, Wire}, + run::{Addr, Align, Port, Trg, Wire}, }; #[cfg(not(feature = "trace"))] @@ -369,6 +369,15 @@ impl TraceArg for Op { } } +impl TraceArg for Align { + fn to_word(&self) -> u64 { + *self as u64 + } + fn from_word(word: u64) -> impl Debug { + unsafe { Align::try_from(word as u8).unwrap_unchecked() } + } +} + impl TraceArg for Addr { fn to_word(&self) -> u64 { self.0 as u64 From 0dc0c77f8cfb5209f13fc4794869f8cd2b28b011 Mon Sep 17 00:00:00 2001 From: tjjfvi Date: Mon, 18 Mar 2024 16:16:52 -0400 Subject: [PATCH 05/16] implement more interactions --- src/ast.rs | 1 + src/compile.rs | 3 +- src/host/encode.rs | 94 +++++++++++++++++++++++++++++------------- src/host/readback.rs | 25 ++++++++--- src/run/def.rs | 4 +- src/run/instruction.rs | 62 ++++++++++++++++++++++++++-- src/run/interact.rs | 43 +++++++++++++++++-- src/run/port.rs | 10 ++--- src/run/tag.rs | 22 +++++++--- 9 files changed, 209 insertions(+), 55 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 0e9adb7f..3586bb21 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -253,6 +253,7 @@ impl<'i> Parser<'i> { }; self.skip_trivia(); if self.peek_char().is_some_and(|x| x == ':') { + self.advance_char(); let variant_index = self.parse_int()?; self.consume(":")?; let variant_count = self.parse_int()?; diff --git a/src/compile.rs b/src/compile.rs index f2982294..faacfc48 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -65,7 +65,7 @@ fn compile_def(code: &mut String, host: &Host, name: &str, instr: &[Instruction] Instruction::LinkConst { trg, port } => { writeln!(code, "net.link_trg({trg}, Trg::port({}));", compile_port(host, port)) } - Instruction::Ctr { lab, trg, lft, rgt } => { + Instruction::Ctr2 { lab, trg, lft, rgt } => { writeln!(code, "let ({lft}, {rgt}) = net.do_ctr({lab}, {trg});") } Instruction::Op { op, trg, rhs, out } => { @@ -80,6 +80,7 @@ fn compile_def(code: &mut String, host: &Host, name: &str, instr: &[Instruction] Instruction::Wires { av, aw, bv, bw } => { writeln!(code, "let ({av}, {aw}, {bv}, {bw}) = net.do_wires();") } + _ => todo!(), }?; } writeln!(code, "}}")?; diff --git a/src/host/encode.rs b/src/host/encode.rs index 44ff8c69..05102198 100644 --- a/src/host/encode.rs +++ b/src/host/encode.rs @@ -1,3 +1,5 @@ +use arrayvec::ArrayVec; + use super::*; use crate::{ops::Op, run::Lab, util::maybe_grow}; @@ -69,33 +71,22 @@ impl<'a, E: Encoder> State<'a, E> { if ports.is_empty() { return self.visit_tree(&Tree::Era, trg); } - let mut trg = trg; - for port in &ports[0 .. ports.len() - 1] { - let (l, r) = self.encoder.ctr(*lab, trg); - self.visit_tree(port, l); - trg = r; + if ports.len() == 1 { + return self.visit_tree(&ports[0], trg); + } + for (i, t) in self.encoder.ctrn(*lab, trg, ports.len() as u8).into_iter().enumerate() { + self.visit_tree(&ports[i], t); } - self.visit_tree(ports.last().unwrap(), trg); } Tree::Adt { lab, variant_index, variant_count, fields } => { - let mut trg = trg; - for _ in 0 .. *variant_index { - let (l, r) = self.encoder.ctr(*lab, trg); - self.visit_tree(&Tree::Era, l); - trg = r; - } - let (mut l, mut r) = self.encoder.ctr(*lab, trg); - for field in fields { - let (x, y) = self.encoder.ctr(*lab, l); - self.visit_tree(field, x); - l = y; + for (i, t) in self + .encoder + .adtn(*lab, trg, *variant_index as u8, *variant_count as u8, fields.len() as u8) + .into_iter() + .enumerate() + { + self.visit_tree(&fields[i], t); } - for _ in 0 .. (*variant_count - *variant_index - 1) { - let (x, y) = self.encoder.ctr(*lab, r); - self.visit_tree(&Tree::Era, x); - r = y; - } - self.encoder.link(l, r); } Tree::Op { op, rhs: lft, out: rgt } => { let (l, r) = self.encoder.op(*op, trg); @@ -104,7 +95,7 @@ impl<'a, E: Encoder> State<'a, E> { } Tree::Mat { zero, succ, out } => { let (a, o) = self.encoder.mat(trg); - let (z, s) = self.encoder.ctr(0, a); + let (z, s) = self.encoder.ctr2(0, a); self.visit_tree(zero, z); self.visit_tree(succ, s); self.visit_tree(out, o); @@ -124,7 +115,16 @@ trait Encoder { fn link_const(&mut self, trg: Self::Trg, port: Port); fn link(&mut self, a: Self::Trg, b: Self::Trg); fn make_const(&mut self, port: Port) -> Self::Trg; - fn ctr(&mut self, lab: Lab, trg: Self::Trg) -> (Self::Trg, Self::Trg); + fn ctr2(&mut self, lab: Lab, trg: Self::Trg) -> (Self::Trg, Self::Trg); + fn ctrn(&mut self, lab: Lab, trg: Self::Trg, n: u8) -> ArrayVec; + fn adtn( + &mut self, + lab: Lab, + trg: Self::Trg, + variant_index: u8, + variant_count: u8, + arity: u8, + ) -> ArrayVec; fn op(&mut self, op: Op, trg: Self::Trg) -> (Self::Trg, Self::Trg); fn op_num(&mut self, op: Op, trg: Self::Trg, rhs: u64) -> Self::Trg; fn mat(&mut self, trg: Self::Trg) -> (Self::Trg, Self::Trg); @@ -152,12 +152,35 @@ impl Encoder for InterpretedDef { self.instr.push(Instruction::Const { trg, port }); trg } - fn ctr(&mut self, lab: Lab, trg: Self::Trg) -> (Self::Trg, Self::Trg) { + fn ctr2(&mut self, lab: Lab, trg: Self::Trg) -> (Self::Trg, Self::Trg) { let lft = self.new_trg_id(); let rgt = self.new_trg_id(); - self.instr.push(Instruction::Ctr { lab, trg, lft, rgt }); + self.instr.push(Instruction::Ctr2 { lab, trg, lft, rgt }); (lft, rgt) } + fn ctrn(&mut self, lab: Lab, trg: Self::Trg, n: u8) -> ArrayVec { + let mut ports = ArrayVec::new(); + for _ in 0 .. n { + ports.push(self.new_trg_id()); + } + self.instr.push(Instruction::CtrN { lab, trg, ports: ports.clone() }); + ports + } + fn adtn( + &mut self, + lab: Lab, + trg: Self::Trg, + variant_index: u8, + variant_count: u8, + arity: u8, + ) -> ArrayVec { + let mut fields = ArrayVec::new(); + for _ in 0 .. arity { + fields.push(self.new_trg_id()); + } + self.instr.push(Instruction::AdtN { lab, trg, variant_index, variant_count, fields: fields.clone() }); + fields + } fn op(&mut self, op: Op, trg: Self::Trg) -> (Self::Trg, Self::Trg) { let rhs = self.new_trg_id(); let out = self.new_trg_id(); @@ -196,8 +219,21 @@ impl<'a, M: Mode> Encoder for run::Net<'a, M> { fn make_const(&mut self, port: Port) -> Self::Trg { run::Trg::port(port) } - fn ctr(&mut self, lab: Lab, trg: Self::Trg) -> (Self::Trg, Self::Trg) { - self.do_ctr(lab, trg) + fn ctr2(&mut self, lab: Lab, trg: Self::Trg) -> (Self::Trg, Self::Trg) { + self.do_ctr2(lab, trg) + } + fn ctrn(&mut self, lab: Lab, trg: Self::Trg, n: u8) -> ArrayVec { + self.do_ctrn(lab, trg, n) + } + fn adtn( + &mut self, + lab: Lab, + trg: Self::Trg, + variant_index: u8, + variant_count: u8, + arity: u8, + ) -> ArrayVec { + self.do_adtn(lab, trg, variant_index, variant_count, arity) } fn op(&mut self, op: Op, trg: Self::Trg) -> (Self::Trg, Self::Trg) { self.do_op(op, trg) diff --git a/src/host/readback.rs b/src/host/readback.rs index 02dd76dd..2213b48b 100644 --- a/src/host/readback.rs +++ b/src/host/readback.rs @@ -1,3 +1,5 @@ +use self::run::{AdtN, CtrN}; + use super::*; use crate::util::maybe_grow; @@ -63,17 +65,30 @@ impl<'a> ReadbackState<'a> { let node = port.traverse_node(); Tree::Op { op, rhs: Box::new(self.read_wire(node.p1)), out: Box::new(self.read_wire(node.p2)) } } - Tag::Ctr2 => { - let node = port.traverse_node(); - Tree::Ctr { lab: node.lab, ports: vec![self.read_wire(node.p1), self.read_wire(node.p2)] } - } + // Tag::Ctr2 => { + // let node = port.traverse_node(); + // Tree::Ctr { lab: node.lab, ports: vec![self.read_wire(node.p1), self.read_wire(node.p2)] } + // } Tag::Mat => { let node = port.traverse_node(); let arms = self.read_wire(node.p1); let out = self.read_wire(node.p2); Tree::legacy_mat(arms, out).expect("invalid mat node") } - _ => todo!(), + CtrN!() => Tree::Ctr { + lab: port.lab(), + ports: (0 .. port.tag().width()).map(|i| self.read_wire(port.aux_port(i).wire())).collect(), + }, + AdtN!() | Tag::AdtZ => { + let adtz = + if port.is(Tag::AdtZ) { port.clone() } else { port.aux_port(port.tag().arity()).wire().load_target() }; + Tree::Adt { + lab: port.lab(), + variant_index: adtz.variant_index() as usize, + variant_count: adtz.variant_count() as usize, + fields: (0 .. port.tag().arity()).map(|i| self.read_wire(port.aux_port(i).wire())).collect(), + } + } }) } } diff --git a/src/run/def.rs b/src/run/def.rs index e7e8c281..154571f5 100644 --- a/src/run/def.rs +++ b/src/run/def.rs @@ -248,8 +248,8 @@ impl AsDef for InterpretedDef { } net.link_trg_port(trgs.get_trg(trg), port.clone()) } - Instruction::Ctr { lab, trg, lft, rgt } => { - let (l, r) = net.do_ctr(lab, trgs.get_trg(trg)); + Instruction::Ctr2 { lab, trg, lft, rgt } => { + let (l, r) = net.do_ctr2(lab, trgs.get_trg(trg)); trgs.set_trg(lft, l); trgs.set_trg(rgt, r); } diff --git a/src/run/instruction.rs b/src/run/instruction.rs index 7910b401..64145afc 100644 --- a/src/run/instruction.rs +++ b/src/run/instruction.rs @@ -1,3 +1,5 @@ +use arrayvec::ArrayVec; + use super::*; /// Each instruction corresponds to a fragment of a net that has a native @@ -48,11 +50,21 @@ pub enum Instruction { /// net.link_trg(trg, Trg::port(port)); /// ``` LinkConst { trg: TrgId, port: Port }, - /// See [`Net::do_ctr`]. + /// See [`Net::do_ctr2`]. + /// ```rust,ignore + /// let (lft, rgt) = net.do_ctr2(lab, trg); + /// ``` + Ctr2 { lab: Lab, trg: TrgId, lft: TrgId, rgt: TrgId }, + /// See [`Net::do_ctrn`]. + /// ```rust,ignore + /// let ports = net.do_ctrn(lab, trg, ports.len()); + /// ``` + CtrN { lab: Lab, trg: TrgId, ports: ArrayVec }, + /// See [`Net::do_ctrn`]. /// ```rust,ignore - /// let (lft, rgt) = net.do_ctr(lab, trg); + /// let ports = net.do_ctrn(lab, trg, variant_index, variant_count, fields.len() + 1); /// ``` - Ctr { lab: Lab, trg: TrgId, lft: TrgId, rgt: TrgId }, + AdtN { lab: Lab, trg: TrgId, variant_index: u8, variant_count: u8, fields: ArrayVec }, /// See [`Net::do_op`]. /// ```rust,ignore /// let (rhs, out) = net.do_op(lab, trg); @@ -114,7 +126,7 @@ impl fmt::Debug for TrgId { impl<'a, M: Mode> Net<'a, M> { /// `trg ~ {#lab x y}` #[inline(always)] - pub(crate) fn do_ctr(&mut self, lab: Lab, trg: Trg) -> (Trg, Trg) { + pub(crate) fn do_ctr2(&mut self, lab: Lab, trg: Trg) -> (Trg, Trg) { let port = trg.target(); if !M::LAZY && port.is(Tag::Ctr2) && port.lab() == lab { trace!(self, "fast"); @@ -133,6 +145,48 @@ impl<'a, M: Mode> Net<'a, M> { } } + /// `trg ~ {#lab ...}` + #[inline(always)] + pub(crate) fn do_ctrn(&mut self, lab: Lab, trg: Trg, n: u8) -> ArrayVec { + let tag = Tag::ctr_with_width(n); + let align = tag.align(); + let addr = self.alloc(align); + let mut out = ArrayVec::new(); + self.link_trg_port(trg, Port::new(tag, lab, addr)); + for i in 0 .. n { + unsafe { out.push_unchecked(Trg::port(Port::new_var(align, addr.offset(i as usize)))) } + } + out + } + + /// `trg ~ {lab:idx:count ...}` + #[inline(always)] + pub(crate) fn do_adtn( + &mut self, + lab: Lab, + trg: Trg, + variant_index: u8, + variant_count: u8, + arity: u8, + ) -> ArrayVec { + let adtz = Port::new_adtz(variant_index, variant_count); + let mut out = ArrayVec::new(); + if arity == 0 { + self.link_trg_port(trg, adtz); + } else { + let width = arity + 1; + let tag = Tag::adt_with_width(width); + let align = tag.align(); + let addr = self.alloc(align); + self.link_trg_port(trg, Port::new(tag, lab, addr)); + for i in 0 .. arity { + unsafe { out.push_unchecked(Trg::port(Port::new_var(align, addr.offset(i as usize)))) } + } + Wire::new(align, addr.offset(arity as usize)).set_target(adtz); + } + out + } + /// `trg ~ ` #[inline(always)] pub(crate) fn do_op(&mut self, op: Op, trg: Trg) -> (Trg, Trg) { diff --git a/src/run/interact.rs b/src/run/interact.rs index 12e84d6a..a5e5bbb2 100644 --- a/src/run/interact.rs +++ b/src/run/interact.rs @@ -270,7 +270,22 @@ impl<'a, M: Mode> Net<'a, M> { fn adt_ctr(&mut self, adt: Port, ctr: Port) { let ctr_arity = ctr.tag().arity(); - todo!() + let adtz = if adt.is(AdtZ) { adt.clone() } else { adt.aux_port(adt.tag().arity()).wire().swap_target(Port::LOCK) }; + if ctr_arity != adtz.variant_count() + 1 { + todo!(); + } + if adt.is(AdtZ) { + self.link_wire_wire(ctr.aux_port(adtz.variant_index()).wire(), ctr.aux_port(ctr_arity - 1).wire()); + } else { + self.link_wire_port(ctr.aux_port(ctr_arity - 1).wire(), adt.aux_port(adt.tag().arity())); + self.link_wire_port(ctr.aux_port(adtz.variant_index()).wire(), Port(adt.0 ^ 0b1000)); + } + for i in 0 .. adtz.variant_index() { + self.link_wire_port(ctr.aux_port(i).wire(), Port::ERA); + } + for i in adtz.variant_index() + 1 .. ctr_arity { + self.link_wire_port(ctr.aux_port(i).wire(), Port::ERA); + } } fn anni(&mut self, a: Port, b: Port) { @@ -288,12 +303,13 @@ impl<'a, M: Mode> Net<'a, M> { } fn comm(&mut self, a: Port, b: Port) { + trace!(self, a, b); let mut Bs = [const { MaybeUninit::::uninit() }; 8]; let mut As = [const { MaybeUninit::::uninit() }; 8]; let aa = a.tag().arity(); - // let aw = b.tag().width(); + let aw = a.tag().width(); let ba = b.tag().arity(); - // let bw = b.tag().width(); + let bw = b.tag().width(); let Bs = &mut Bs[0 .. aa as usize]; let As = &mut As[0 .. ba as usize]; if ba != 0 { @@ -301,12 +317,16 @@ impl<'a, M: Mode> Net<'a, M> { let addr = self.alloc(b.align()); *B = MaybeUninit::new(b.with_addr(addr)); } + } else { + Bs.fill_with(|| MaybeUninit::new(b.clone())); } if aa != 0 { for A in &mut *As { let addr = self.alloc(a.align()); *A = MaybeUninit::new(a.with_addr(addr)); } + } else { + As.fill_with(|| MaybeUninit::new(a.clone())); } for bi in 0 .. aa { for ai in 0 .. ba { @@ -318,7 +338,22 @@ impl<'a, M: Mode> Net<'a, M> { } } } - // TODO: copy width - arity + for i in aa .. aw { + let t = a.aux_port(i).wire().load_target(); + for A in &*As { + unsafe { + A.assume_init_ref().aux_port(i).wire().set_target(t.clone()); + } + } + } + for i in ba .. bw { + let t = b.aux_port(i).wire().load_target(); + for B in &*Bs { + unsafe { + B.assume_init_ref().aux_port(i).wire().set_target(t.clone()); + } + } + } for i in 0 .. aa { unsafe { self.link_wire_port(a.aux_port(i).wire(), Bs.get_unchecked(i as usize).assume_init_read()); diff --git a/src/run/port.rs b/src/run/port.rs index 516d5725..2a0cf889 100644 --- a/src/run/port.rs +++ b/src/run/port.rs @@ -84,19 +84,19 @@ impl Port { /// TODO #[inline(always)] - pub const fn new_adtz(variant_count: u8, variant_index: u8) -> Self { - Port(Tag::AdtZ as u64 | ((variant_count as u64) << 16) | ((variant_index as u64) << 8)) + pub const fn new_adtz(variant_index: u8, variant_count: u8) -> Self { + Port(Tag::AdtZ as u64 | ((variant_index as u64) << 16) | ((variant_count as u64) << 8)) } /// TODO #[inline(always)] - pub fn variant_count(&self) -> u8 { + pub fn variant_index(&self) -> u8 { (self.0 >> 16) as u8 } /// TODO #[inline(always)] - pub fn variant_index(&self) -> u8 { + pub fn variant_count(&self) -> u8 { (self.0 >> 8) as u8 } @@ -196,7 +196,7 @@ impl Port { } #[inline(always)] - pub(super) fn aux_port(&self, i: u8) -> Port { + pub(crate) fn aux_port(&self, i: u8) -> Port { Port::new_var(self.align(), self.addr().offset(i as usize)) } diff --git a/src/run/tag.rs b/src/run/tag.rs index 9709ac4b..ceb22a04 100644 --- a/src/run/tag.rs +++ b/src/run/tag.rs @@ -52,7 +52,7 @@ impl Tag { /// Returns the width -- the size of the allocation -- of nodes of this tag. #[inline] - pub(super) fn width(self) -> u8 { + pub(crate) fn width(self) -> u8 { match self { Tag::Num | Tag::Ref | Tag::AdtZ => 0, Tag::Red | Tag::Var => 1, @@ -65,20 +65,24 @@ impl Tag { /// Returns the arity -- the number of auxiliary ports -- of nodes of this /// tag. #[inline] - pub(super) fn arity(self) -> u8 { + pub(crate) fn arity(self) -> u8 { match self { AdtN!() => self.width() - 1, _ => self.width(), } } - pub(super) fn ctr_with_arity(arity: u8) -> Tag { - let sub = arity - 1; + pub(super) fn ctr_with_width(width: u8) -> Tag { + let sub = width - 1; let ilog = unsafe { sub.checked_ilog2().unwrap_unchecked() as u8 }; let ext = sub - (1 << ilog); let tag = (ilog + 1) | 0b100 | (ext << 4); unsafe { Tag::from_unchecked(tag) } } + + pub(super) fn adt_with_width(width: u8) -> Tag { + unsafe { Tag::from_unchecked(Tag::ctr_with_width(width) as u8 | 0b1000) } + } } /// Matches any `Ctr` tag. @@ -120,13 +124,16 @@ impl Align { pub(super) fn tag_bits(self) -> u8 { self as u8 + 3 } + pub(super) fn addr_mask(self) -> u64 { 0x0000_FFFF_FFFF_FFFF & (u64::MAX << self.tag_bits()) } + #[inline(always)] pub(super) fn width(self) -> u8 { 1 << self as u8 } + /// Returns the next largest alignment, if it exists. #[inline(always)] pub(super) fn next(self) -> Option { @@ -137,6 +144,10 @@ impl Align { Align8 => None, } } + + pub(super) fn of_width(width: u8) -> Self { + unsafe { Align::from_unchecked((width - 1).checked_ilog2().unwrap_unchecked() as u8 + 1) } + } } #[test] @@ -145,6 +156,7 @@ fn test_tag_width() { assert_eq!([Ctr2, Ctr3, Ctr4, Ctr5, Ctr6, Ctr7, Ctr8].map(Tag::width), [2, 3, 4, 5, 6, 7, 8]); assert_eq!([Adt2, Adt3, Adt4, Adt5, Adt6, Adt7, Adt8].map(Tag::width), [2, 3, 4, 5, 6, 7, 8]); for t in [Ctr2, Ctr3, Ctr4, Ctr5, Ctr6, Ctr7, Ctr8] { - assert_eq!(Tag::ctr_with_arity(t.width()), t); + assert_eq!(Tag::ctr_with_width(t.width()), t); + assert_eq!(Align::of_width(t.width()), t.align()); } } From 5b544f2ad082dd94de10dac648a11315dbe05da2 Mon Sep 17 00:00:00 2001 From: tjjfvi Date: Mon, 18 Mar 2024 16:22:11 -0400 Subject: [PATCH 06/16] increment rwts --- src/run/interact.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/run/interact.rs b/src/run/interact.rs index a5e5bbb2..08eeea00 100644 --- a/src/run/interact.rs +++ b/src/run/interact.rs @@ -269,6 +269,7 @@ impl<'a, M: Mode> Net<'a, M> { } fn adt_ctr(&mut self, adt: Port, ctr: Port) { + self.rwts.anni += 1; let ctr_arity = ctr.tag().arity(); let adtz = if adt.is(AdtZ) { adt.clone() } else { adt.aux_port(adt.tag().arity()).wire().swap_target(Port::LOCK) }; if ctr_arity != adtz.variant_count() + 1 { @@ -289,6 +290,7 @@ impl<'a, M: Mode> Net<'a, M> { } fn anni(&mut self, a: Port, b: Port) { + self.rwts.anni += 1; if a.tag() == b.tag() { for i in 0 .. a.tag().arity() { self.link_wire_wire(a.aux_port(i).wire(), b.aux_port(i).wire()); @@ -303,6 +305,11 @@ impl<'a, M: Mode> Net<'a, M> { } fn comm(&mut self, a: Port, b: Port) { + if a == Port::ERA || b == Port::ERA { + self.rwts.eras += 1; + } else { + self.rwts.comm += 1; + } trace!(self, a, b); let mut Bs = [const { MaybeUninit::::uninit() }; 8]; let mut As = [const { MaybeUninit::::uninit() }; 8]; From 1ccd48ec5393f12858caa0aaaef7b3caddaaa3bd Mon Sep 17 00:00:00 2001 From: tjjfvi Date: Wed, 20 Mar 2024 11:51:07 -0400 Subject: [PATCH 07/16] ... --- bar.hvmc | 3 + foo.hvmc | 32 +++++++ foo.hvml | 28 ++++++ src/compile.rs | 4 +- src/host/encode.rs | 22 +++-- src/run/def.rs | 25 ++++-- src/run/instruction.rs | 82 +++++++----------- src/run/interact.rs | 86 +++++++++---------- test.hvmc | 8 ++ test.hvml | 9 ++ ...e_run@stress_tests__all_tree.hvmc.snap.new | 21 +++++ ...__run@stress_tests__all_tree.hvmc.snap.new | 13 +++ 12 files changed, 216 insertions(+), 117 deletions(-) create mode 100644 bar.hvmc create mode 100644 foo.hvmc create mode 100644 foo.hvml create mode 100644 test.hvmc create mode 100644 test.hvml create mode 100644 tests/snapshots/tests__pre_reduce_run@stress_tests__all_tree.hvmc.snap.new create mode 100644 tests/snapshots/tests__run@stress_tests__all_tree.hvmc.snap.new diff --git a/bar.hvmc b/bar.hvmc new file mode 100644 index 00000000..d9290909 --- /dev/null +++ b/bar.hvmc @@ -0,0 +1,3 @@ + +@bar = (?<#0 #1 R> R) +@main = R & @bar ~ (#123 R) diff --git a/foo.hvmc b/foo.hvmc new file mode 100644 index 00000000..a04e3642 --- /dev/null +++ b/foo.hvmc @@ -0,0 +1,32 @@ +@S = (a {2 {2 a b} {2 * b}}) +@Z = {2 * {2 a a}} +@add$C0 = {2 {2 @add$C0 {2 (a a) (b c)}} (b {2 {2 c d} {2 * d}})} +@era = ({2 @era$C0 {2 @Z a}} a) +@era$C0 = {2 {2 @era$C0 {2 @Z a}} a} +@main = a +& @era ~ (b a) +& @pow ~ (c b) +& @S ~ (d c) +& @S ~ (e d) +& @S ~ (f e) +& @S ~ (g f) +& @S ~ (h g) +& @S ~ (i h) +& @S ~ (j i) +& @S ~ (k j) +& @S ~ (l k) +& @S ~ (m l) +& @S ~ (n m) +& @S ~ (o n) +& @S ~ (p o) +& @S ~ (q p) +& @S ~ (r q) +& @S ~ (s r) +& @S ~ (t s) +& @S ~ (u t) +& @S ~ (v u) +& @S ~ (w v) +& @S ~ (x w) +& @S ~ (@Z x) +@pow = ({2 @pow$C0 {2 {2 {2 @Z a} {2 * a}} b}} b) +@pow$C0 = {2 {3 {2 @pow$C0 {2 {2 {2 @Z a} {2 * a}} {2 @add$C0 {2 (b b) (c d)}}}} {2 @pow$C0 {2 {2 {2 @Z e} {2 * e}} c}}} d} diff --git a/foo.hvml b/foo.hvml new file mode 100644 index 00000000..94d980af --- /dev/null +++ b/foo.hvml @@ -0,0 +1,28 @@ +data Nat = (S pred) | Z + +add = λx λy + match x { + Z: y + S: (S (add x.pred y)) + } + +pow = λx + match x { + Z: (S Z) + S: (add (pow x.pred) (pow x.pred)) + } + +era = λx + match x { + Z: Z + S: (era x.pred) + } + +main = (era (pow + (S (S + (S (S (S (S + (S (S (S (S + (S (S (S (S + (S (S (S (S + (S (S (S (S + Z)))))))))))))))))))))))) diff --git a/src/compile.rs b/src/compile.rs index faacfc48..a77599e3 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -74,8 +74,8 @@ fn compile_def(code: &mut String, host: &Host, name: &str, instr: &[Instruction] Instruction::OpNum { op, trg, rhs, out } => { writeln!(code, "let {out} = net.do_op_num({op:?}, {trg}, {rhs});") } - Instruction::Mat { trg, lft, rgt } => { - writeln!(code, "let ({lft}, {rgt}) = net.do_mat({trg});") + Instruction::Mat { trg, zero, succ, out } => { + writeln!(code, "let ({zero}, {succ}, {out}) = net.do_mat({trg});") } Instruction::Wires { av, aw, bv, bw } => { writeln!(code, "let ({av}, {aw}, {bv}, {bw}) = net.do_wires();") diff --git a/src/host/encode.rs b/src/host/encode.rs index 05102198..54cf64a4 100644 --- a/src/host/encode.rs +++ b/src/host/encode.rs @@ -94,8 +94,7 @@ impl<'a, E: Encoder> State<'a, E> { self.visit_tree(rgt, r); } Tree::Mat { zero, succ, out } => { - let (a, o) = self.encoder.mat(trg); - let (z, s) = self.encoder.ctr2(0, a); + let (z, s, o) = self.encoder.mat(trg); self.visit_tree(zero, z); self.visit_tree(succ, s); self.visit_tree(out, o); @@ -127,7 +126,7 @@ trait Encoder { ) -> ArrayVec; fn op(&mut self, op: Op, trg: Self::Trg) -> (Self::Trg, Self::Trg); fn op_num(&mut self, op: Op, trg: Self::Trg, rhs: u64) -> Self::Trg; - fn mat(&mut self, trg: Self::Trg) -> (Self::Trg, Self::Trg); + fn mat(&mut self, trg: Self::Trg) -> (Self::Trg, Self::Trg, Self::Trg); fn wires(&mut self) -> (Self::Trg, Self::Trg, Self::Trg, Self::Trg); } @@ -192,11 +191,12 @@ impl Encoder for InterpretedDef { self.instr.push(Instruction::OpNum { op, trg, rhs, out }); out } - fn mat(&mut self, trg: Self::Trg) -> (Self::Trg, Self::Trg) { - let lft = self.new_trg_id(); - let rgt = self.new_trg_id(); - self.instr.push(Instruction::Mat { trg, lft, rgt }); - (lft, rgt) + fn mat(&mut self, trg: Self::Trg) -> (Self::Trg, Self::Trg, Self::Trg) { + let zero = self.new_trg_id(); + let succ = self.new_trg_id(); + let out = self.new_trg_id(); + self.instr.push(Instruction::Mat { trg, zero, succ, out }); + (zero, succ, out) } fn wires(&mut self) -> (Self::Trg, Self::Trg, Self::Trg, Self::Trg) { let av = self.new_trg_id(); @@ -241,10 +241,8 @@ impl<'a, M: Mode> Encoder for run::Net<'a, M> { fn op_num(&mut self, op: Op, trg: Self::Trg, rhs: u64) -> Self::Trg { self.do_op_num(op, trg, rhs) } - fn mat(&mut self, trg: Self::Trg) -> (Self::Trg, Self::Trg) { - #[cfg(todo)] - self.do_mat(trg); - todo!(); + fn mat(&mut self, trg: Self::Trg) -> (Self::Trg, Self::Trg, Self::Trg) { + self.do_mat(trg) } fn wires(&mut self) -> (Self::Trg, Self::Trg, Self::Trg, Self::Trg) { self.do_wires() diff --git a/src/run/def.rs b/src/run/def.rs index 154571f5..374e0d57 100644 --- a/src/run/def.rs +++ b/src/run/def.rs @@ -253,6 +253,20 @@ impl AsDef for InterpretedDef { trgs.set_trg(lft, l); trgs.set_trg(rgt, r); } + Instruction::CtrN { lab, trg, ref ports } => { + for (i, t) in net.do_ctrn(lab, trgs.get_trg(trg), ports.len() as u8).into_iter().enumerate() { + trgs.set_trg(ports[i], t); + } + } + Instruction::AdtN { lab, trg, variant_index, variant_count, ref fields } => { + for (i, t) in net + .do_adtn(lab, trgs.get_trg(trg), variant_index, variant_count, fields.len() as u8) + .into_iter() + .enumerate() + { + trgs.set_trg(fields[i], t); + } + } Instruction::Op { op, trg, rhs, out } => { let (r, o) = net.do_op(op, trgs.get_trg(trg)); trgs.set_trg(rhs, r); @@ -262,11 +276,11 @@ impl AsDef for InterpretedDef { let o = net.do_op_num(op, trgs.get_trg(trg), lhs); trgs.set_trg(out, o); } - #[cfg(todo)] - Instruction::Mat { trg, lft, rgt } => { - let (l, r) = net.do_mat(trgs.get_trg(trg)); - trgs.set_trg(lft, l); - trgs.set_trg(rgt, r); + Instruction::Mat { trg, zero, succ, out } => { + let (z, s, o) = net.do_mat(trgs.get_trg(trg)); + trgs.set_trg(zero, z); + trgs.set_trg(succ, s); + trgs.set_trg(out, o); } Instruction::Wires { av, aw, bv, bw } => { let (avt, awt, bvt, bwt) = net.do_wires(); @@ -275,7 +289,6 @@ impl AsDef for InterpretedDef { trgs.set_trg(bv, bvt); trgs.set_trg(bw, bwt); } - _ => todo!(), } } } diff --git a/src/run/instruction.rs b/src/run/instruction.rs index 64145afc..ff41e962 100644 --- a/src/run/instruction.rs +++ b/src/run/instruction.rs @@ -77,9 +77,9 @@ pub enum Instruction { OpNum { op: Op, trg: TrgId, rhs: u64, out: TrgId }, /// See [`Net::do_mat`]. /// ```rust,ignore - /// let (lft, rgt) = net.do_mat(trg); + /// let (zero, succ, out) = net.do_mat(trg); /// ``` - Mat { trg: TrgId, lft: TrgId, rgt: TrgId }, + Mat { trg: TrgId, zero: TrgId, succ: TrgId, out: TrgId }, /// See [`Net::do_wires`]. /// ```rust,ignore /// let (av, aw, bv, bw) = net.do_wires(); @@ -224,34 +224,47 @@ impl<'a, M: Mode> Net<'a, M> { } } + /// `trg ~ ?` + #[inline(always)] + pub(crate) fn do_mat(&mut self, trg: Trg) -> (Trg, Trg, Trg) { + let m = self.alloc(Align4); + let m0 = Port::new(Mat, 0, m); + let m1 = m0.aux_port(0); + let m2 = m0.aux_port(1); + let m3 = m0.aux_port(2); + self.link_trg_port(trg, m0); + (Trg::port(m1), Trg::port(m2), Trg::port(m3)) + } + #[cfg(todo)] - /// `trg ~ ?` + /// `trg ~ ?` #[inline(always)] - pub(crate) fn do_mat(&mut self, trg: Trg) -> (Trg, Trg) { + pub(crate) fn do_mat(&mut self, trg: Trg, out: Trg) -> (Trg, Trg) { let port = trg.target(); - if !M::LAZY && port.is(Tag::Num) { + if trg.target().is(Tag::Num) { self.rwts.oper += 1; self.free_trg(trg); let num = port.num(); - let c1 = self.create_node(Ctr, 0); if num == 0 { - self.link_port_port(c1.p2, Port::ERA); - (Trg::port(c1.p0), Trg::wire(self.create_wire_to(c1.p1))) + (out, Trg::port(Port::ERA)) } else { - let c2 = self.create_node(Ctr, 0); - self.link_port_port(c1.p1, Port::ERA); - self.link_port_port(c1.p2, c2.p0); - self.link_port_port(c2.p1, Port::new_num(num - 1)); - (Trg::port(c1.p0), Trg::wire(self.create_wire_to(c2.p2))) + let c2 = self.create_node(Ctr2, 0); + c2.p1.wire().set_target(Port::new_num(num - 1)); + self.link_trg_port(out, c2.p2); + (Trg::port(Port::ERA), Trg::port(c2.p0)) } - } else if !M::LAZY && port == Port::ERA { - self.rwts.eras += 1; - self.free_trg(trg); + } else if port == Port::ERA { + self.link_trg_port(out, Port::ERA); (Trg::port(Port::ERA), Trg::port(Port::ERA)) } else { - let m = self.create_node(Mat, 0); - self.link_trg_port(trg, m.p0); - (Trg::port(m.p1), Trg::port(m.p2)) + let m = self.alloc(Align4); + let m0 = Port::new(Mat, 0, m); + let m1 = m0.aux_port(0); + let m2 = m0.aux_port(1); + let m3 = m0.aux_port(2); + self.link_trg_port(out, m3); + self.link_trg_port(trg, m0); + (Trg::port(m1), Trg::port(m2)) } } @@ -295,35 +308,4 @@ impl<'a, M: Mode> Net<'a, M> { (Trg::port(c1.p1), Trg::port(c2.p1), Trg::port(c2.p2)) } } - - #[cfg(todo)] - /// `trg ~ ?<(x y) out>` - #[inline(always)] - #[allow(unused)] // TODO: emit this instruction - pub(crate) fn do_mat_con(&mut self, trg: Trg, out: Trg) -> (Trg, Trg) { - let port = trg.target(); - if trg.target().is(Tag::Num) { - self.rwts.oper += 1; - self.free_trg(trg); - let num = port.num(); - if num == 0 { - (out, Trg::port(Port::ERA)) - } else { - let c2 = self.create_node(Ctr, 0); - c2.p1.wire().set_target(Port::new_num(num - 1)); - self.link_trg_port(out, c2.p2); - (Trg::port(Port::ERA), Trg::port(c2.p0)) - } - } else if port == Port::ERA { - self.link_trg_port(out, Port::ERA); - (Trg::port(Port::ERA), Trg::port(Port::ERA)) - } else { - let m = self.create_node(Mat, 0); - let c1 = self.create_node(Ctr, 0); - self.link_port_port(m.p1, c1.p0); - self.link_trg_port(out, m.p2); - self.link_trg_port(trg, m.p0); - (Trg::port(c1.p1), Trg::port(c1.p2)) - } - } } diff --git a/src/run/interact.rs b/src/run/interact.rs index 08eeea00..27675ac2 100644 --- a/src/run/interact.rs +++ b/src/run/interact.rs @@ -171,56 +171,48 @@ impl<'a, M: Mode> Net<'a, M> { /// Interacts a number and a numeric match node. /// /// ```text - /// | - /// b (0) | b (n+1) - /// | | | - /// | | | - /// / \ | / \ - /// a /mat\ | a /mat\ - /// /_____\ | /_____\ - /// | | | | | - /// a1 | | a2 | a1 | | a2 - /// | - /// --------------------------- | --------------------------- mat_num - /// | _ _ _ _ _ - /// | / \ - /// | y2 | (n) y1 | - /// | _|___|_ | - /// | \ / | - /// _ | y \ / | - /// / \ | \ / | - /// x2 (*) | x1 | | x2 | (*) x1 | - /// _|___|_ | | _|___|_ | - /// \ / | | \ / | - /// x \ / | | x \ / | - /// \ / | | \ / | - /// | | | | | - /// a1 | | a2 | a1 | | a2 - /// | + /// | + /// b (0) | b (n+1) + /// | | | + /// | | | + /// / \ | / \ + /// / \ | / \ + /// a / mat \ | a / mat \ + /// /_______\ | /_______\ + /// / | \ | / | \ + /// a1 / | a2 \ a3 | a1 / | a2 \ a3 + /// | + /// ----------------------------- | ----------------------------- mat_num + /// | _ _ _ + /// | / \ + /// | x2 | (n) x1 | + /// | _|___|_ | + /// | \ / | + /// _ _ _ | x \ / | + /// / \ | \ / / + /// | (*) | | (*) | / + /// a1 | | a2 | a3 | a1 | | a2 | a3 + /// | /// ``` #[inline(never)] pub fn mat_num(&mut self, a: Port, b: Port) { - todo!() - // trace!(self, a, b); - // self.rwts.oper += 1; - // let a = a.consume_node(); - // let b = b.num(); - // if b == 0 { - // let x = self.create_node(Ctr, 0); - // trace!(self, x.p0); - // self.link_port_port(x.p2, Port::ERA); - // self.link_wire_port(a.p2, x.p1); - // self.link_wire_port(a.p1, x.p0); - // } else { - // let x = self.create_node(Tag::Ctr, 0); - // let y = self.create_node(Tag::Ctr, 0); - // trace!(self, x.p0, y.p0); - // self.link_port_port(x.p1, Port::ERA); - // self.link_port_port(x.p2, y.p0); - // self.link_port_port(y.p1, Port::new_num(b - 1)); - // self.link_wire_port(a.p2, y.p2); - // self.link_wire_port(a.p1, x.p0); - // } + trace!(self, a, b); + self.rwts.oper += 1; + let a1 = a.aux_port(0).wire(); + let a2 = a.aux_port(1).wire(); + let a3 = a.aux_port(2).wire(); + let b = b.num(); + if b == 0 { + self.link_wire_wire(a1, a3); + self.link_wire_port(a2, Port::ERA); + } else { + let x = self.create_node(Tag::Ctr2, 0); + trace!(self, x.p0); + self.link_port_port(x.p1, Port::new_num(b - 1)); + self.link_wire_port(a1, Port::ERA); + self.link_wire_port(a2, x.p0); + self.link_wire_port(a3, x.p2); + } } /// Interacts a number and a binary numeric operation node. diff --git a/test.hvmc b/test.hvmc new file mode 100644 index 00000000..5be8040f --- /dev/null +++ b/test.hvmc @@ -0,0 +1,8 @@ +@PowOfTwo = (?<(a a) @PowOfTwoHelp$C0 (#1 b)> b) +@PowOfTwoHelp$C0 = (<+ #1 <- #1 ?<(a a) @PowOfTwoHelp$C0 (b <* #2 c>)>>> (b c)) +@Sum = (?<(a a) @SumHelp$C0 (#0 b)> b) +@SumHelp$C0 = (<+ #1 <- #1 ?<(a a) @SumHelp$C0 (b c)>>> (<+ #1 b> c)) +@main = (a b) +& @Sum ~ (c b) +& @PowOfTwo ~ (a c) + diff --git a/test.hvml b/test.hvml new file mode 100644 index 00000000..d3638454 --- /dev/null +++ b/test.hvml @@ -0,0 +1,9 @@ +Main n = (Sum (PowOfTwo n)) + +PowOfTwo n = (PowOfTwoHelp 1 n) +PowOfTwoHelp acc 0 = acc +PowOfTwoHelp acc e = (* 2 (PowOfTwoHelp acc (- e 1))) + +Sum n = (SumHelp 0 n) +SumHelp acc 0 = acc +SumHelp acc n = (SumHelp (+ acc 1) (- n 1)) \ No newline at end of file diff --git a/tests/snapshots/tests__pre_reduce_run@stress_tests__all_tree.hvmc.snap.new b/tests/snapshots/tests__pre_reduce_run@stress_tests__all_tree.hvmc.snap.new new file mode 100644 index 00000000..21ba7c6e --- /dev/null +++ b/tests/snapshots/tests__pre_reduce_run@stress_tests__all_tree.hvmc.snap.new @@ -0,0 +1,21 @@ +--- +source: tests/tests.rs +assertion_line: 111 +expression: output +input_file: tests/programs/stress_tests/all_tree.hvmc +--- +(a (* a)) +pre-reduce: +RWTS : 31_457_294 +- ANNI : 13_631_494 +- COMM : 5_242_875 +- ERAS : 7_340_027 +- DREF : 3_145_747 +- OPER : 2_097_151 +run: +RWTS : 0 +- ANNI : 0 +- COMM : 0 +- ERAS : 0 +- DREF : 0 +- OPER : 0 diff --git a/tests/snapshots/tests__run@stress_tests__all_tree.hvmc.snap.new b/tests/snapshots/tests__run@stress_tests__all_tree.hvmc.snap.new new file mode 100644 index 00000000..69fca138 --- /dev/null +++ b/tests/snapshots/tests__run@stress_tests__all_tree.hvmc.snap.new @@ -0,0 +1,13 @@ +--- +source: tests/tests.rs +assertion_line: 88 +expression: output +input_file: tests/programs/stress_tests/all_tree.hvmc +--- +(a (* a)) +RWTS : 51_380_196 +- ANNI : 25_165_808 +- COMM : 5_242_875 +- ERAS : 7_340_027 +- DREF : 11_534_335 +- OPER : 2_097_151 From f98ea3b58977052b041e1c2072308a1428ef6d33 Mon Sep 17 00:00:00 2001 From: tjjfvi Date: Wed, 20 Mar 2024 13:41:33 -0400 Subject: [PATCH 08/16] ... --- src/host/encode.rs | 6 ++++++ src/host/readback.rs | 8 ++++---- src/lib.rs | 1 + src/run/allocator.rs | 6 ++++-- src/run/def.rs | 4 ++-- src/run/instruction.rs | 22 +++++++++++----------- src/run/interact.rs | 3 +++ src/run/linker.rs | 4 ++-- 8 files changed, 33 insertions(+), 21 deletions(-) diff --git a/src/host/encode.rs b/src/host/encode.rs index 54cf64a4..5cc83a25 100644 --- a/src/host/encode.rs +++ b/src/host/encode.rs @@ -74,6 +74,12 @@ impl<'a, E: Encoder> State<'a, E> { if ports.len() == 1 { return self.visit_tree(&ports[0], trg); } + if ports.len() == 2 { + let (a, b) = self.encoder.ctr2(*lab, trg); + self.visit_tree(&ports[0], a); + self.visit_tree(&ports[1], b); + return; + } for (i, t) in self.encoder.ctrn(*lab, trg, ports.len() as u8).into_iter().enumerate() { self.visit_tree(&ports[i], t); } diff --git a/src/host/readback.rs b/src/host/readback.rs index 2213b48b..c31f0d2c 100644 --- a/src/host/readback.rs +++ b/src/host/readback.rs @@ -70,10 +70,10 @@ impl<'a> ReadbackState<'a> { // Tree::Ctr { lab: node.lab, ports: vec![self.read_wire(node.p1), self.read_wire(node.p2)] } // } Tag::Mat => { - let node = port.traverse_node(); - let arms = self.read_wire(node.p1); - let out = self.read_wire(node.p2); - Tree::legacy_mat(arms, out).expect("invalid mat node") + let zero = Box::new(self.read_wire(port.aux_port(0).wire())); + let succ = Box::new(self.read_wire(port.aux_port(1).wire())); + let out = Box::new(self.read_wire(port.aux_port(2).wire())); + Tree::Mat { zero, succ, out } } CtrN!() => Tree::Ctr { lab: port.lab(), diff --git a/src/lib.rs b/src/lib.rs index b38219eb..65734dc9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ #![feature(const_type_id, extern_types, inline_const, generic_const_exprs, new_uninit)] #![cfg_attr(feature = "trace", feature(const_type_name))] #![allow(non_snake_case, incomplete_features)] +#![feature(stmt_expr_attributes)] // temp pub mod ast; pub mod compile; diff --git a/src/run/allocator.rs b/src/run/allocator.rs index 484d6050..2b39357c 100644 --- a/src/run/allocator.rs +++ b/src/run/allocator.rs @@ -109,8 +109,10 @@ impl<'h> Allocator<'h> { *head = next; addr } else { - let index = self.next; - self.next += 8; + let w = align.width() as usize; + let x = w - 1; + let index = (self.next + x) & !x; + self.next = index + w; trace!(self, index); Addr(self.heap.0.get(index).expect("OOM") as *const AtomicU64 as usize) }; diff --git a/src/run/def.rs b/src/run/def.rs index 374e0d57..f6c2ec1e 100644 --- a/src/run/def.rs +++ b/src/run/def.rs @@ -225,12 +225,12 @@ impl AsDef for InterpretedDef { struct Trgs(*mut Trg); impl Trgs { - #[inline(always)] + #[inline(never)] fn get_trg(&self, i: TrgId) -> Trg { unsafe { (*self.0.byte_offset(i.byte_offset as _)).clone() } } - #[inline(always)] + #[inline(never)] fn set_trg(&mut self, i: TrgId, trg: Trg) { unsafe { *self.0.byte_offset(i.byte_offset as _) = trg } } diff --git a/src/run/instruction.rs b/src/run/instruction.rs index ff41e962..ed20a5e7 100644 --- a/src/run/instruction.rs +++ b/src/run/instruction.rs @@ -34,7 +34,7 @@ use super::*; /// Each instruction documents both the native implementation and the polarity /// of each `TrgId`. /// -/// Some instructions take a [`Port`]; these must always be statically-valid +/// Some instructions take a [`Port`]; these must never be statically-valid /// ports -- that is, [`Ref`] or [`Num`] ports. #[derive(Debug, Clone)] pub enum Instruction { @@ -98,7 +98,7 @@ pub struct TrgId { /// Instead of storing the index directly, we store the byte offset, to save a /// shift instruction when indexing into the `Trg` vector in interpreted mode. /// - /// This is always `index * size_of::()`. + /// This is never `index * size_of::()`. pub(super) byte_offset: usize, } @@ -125,7 +125,7 @@ impl fmt::Debug for TrgId { impl<'a, M: Mode> Net<'a, M> { /// `trg ~ {#lab x y}` - #[inline(always)] + #[inline(never)] pub(crate) fn do_ctr2(&mut self, lab: Lab, trg: Trg) -> (Trg, Trg) { let port = trg.target(); if !M::LAZY && port.is(Tag::Ctr2) && port.lab() == lab { @@ -146,7 +146,7 @@ impl<'a, M: Mode> Net<'a, M> { } /// `trg ~ {#lab ...}` - #[inline(always)] + #[inline(never)] pub(crate) fn do_ctrn(&mut self, lab: Lab, trg: Trg, n: u8) -> ArrayVec { let tag = Tag::ctr_with_width(n); let align = tag.align(); @@ -160,7 +160,7 @@ impl<'a, M: Mode> Net<'a, M> { } /// `trg ~ {lab:idx:count ...}` - #[inline(always)] + #[inline(never)] pub(crate) fn do_adtn( &mut self, lab: Lab, @@ -188,7 +188,7 @@ impl<'a, M: Mode> Net<'a, M> { } /// `trg ~ ` - #[inline(always)] + #[inline(never)] pub(crate) fn do_op(&mut self, op: Op, trg: Trg) -> (Trg, Trg) { trace!(self.tracer, op, trg); let port = trg.target(); @@ -207,7 +207,7 @@ impl<'a, M: Mode> Net<'a, M> { } /// `trg ~ ` - #[inline(always)] + #[inline(never)] pub(crate) fn do_op_num(&mut self, op: Op, trg: Trg, rhs: u64) -> Trg { let port = trg.target(); if !M::LAZY && port.tag() == Num { @@ -225,7 +225,7 @@ impl<'a, M: Mode> Net<'a, M> { } /// `trg ~ ?` - #[inline(always)] + #[inline(never)] pub(crate) fn do_mat(&mut self, trg: Trg) -> (Trg, Trg, Trg) { let m = self.alloc(Align4); let m0 = Port::new(Mat, 0, m); @@ -238,7 +238,7 @@ impl<'a, M: Mode> Net<'a, M> { #[cfg(todo)] /// `trg ~ ?` - #[inline(always)] + #[inline(never)] pub(crate) fn do_mat(&mut self, trg: Trg, out: Trg) -> (Trg, Trg) { let port = trg.target(); if trg.target().is(Tag::Num) { @@ -268,7 +268,7 @@ impl<'a, M: Mode> Net<'a, M> { } } - #[inline(always)] + #[inline(never)] pub(crate) fn do_wires(&mut self) -> (Trg, Trg, Trg, Trg) { let a = self.alloc(Align2); let b = a.offset(1); @@ -282,7 +282,7 @@ impl<'a, M: Mode> Net<'a, M> { #[cfg(todo)] /// `trg ~ ?<(x (y z)) out>` - #[inline(always)] + #[inline(never)] #[allow(unused)] // TODO: emit this instruction pub(crate) fn do_mat_con_con(&mut self, trg: Trg, out: Trg) -> (Trg, Trg, Trg) { let port = trg.target(); diff --git a/src/run/interact.rs b/src/run/interact.rs index 27675ac2..37b8e753 100644 --- a/src/run/interact.rs +++ b/src/run/interact.rs @@ -282,6 +282,9 @@ impl<'a, M: Mode> Net<'a, M> { } fn anni(&mut self, a: Port, b: Port) { + // if a.tag().width() == 2 && b.tag().width() == 2 { + // return self.anni2(a, b); + // } self.rwts.anni += 1; if a.tag() == b.tag() { for i in 0 .. a.tag().arity() { diff --git a/src/run/linker.rs b/src/run/linker.rs index ea91e7d6..f9d61530 100644 --- a/src/run/linker.rs +++ b/src/run/linker.rs @@ -300,7 +300,7 @@ impl Trg { impl<'h, M: Mode> Linker<'h, M> { /// Links a `Trg` to a port, delegating to the appropriate method based on the /// type of `a`. - #[inline(always)] + #[inline(never)] pub fn link_trg_port(&mut self, a: Trg, b: Port) { match a.is_wire() { true => self.link_wire_port(a.as_wire(), b), @@ -310,7 +310,7 @@ impl<'h, M: Mode> Linker<'h, M> { /// Links two `Trg`s, delegating to the appropriate method based on the types /// of `a` and `b`. - #[inline(always)] + #[inline(never)] pub fn link_trg(&mut self, a: Trg, b: Trg) { match (a.is_wire(), b.is_wire()) { (true, true) => self.link_wire_wire(a.as_wire(), b.as_wire()), From 93ac1d0e8b36e24944cb296f40c78f14f1d0db5c Mon Sep 17 00:00:00 2001 From: tjjfvi Date: Tue, 26 Mar 2024 08:21:49 -0400 Subject: [PATCH 09/16] ... --- src/stdlib.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/stdlib.rs b/src/stdlib.rs index 40750ee6..7d001cbe 100644 --- a/src/stdlib.rs +++ b/src/stdlib.rs @@ -78,13 +78,13 @@ impl AsHostedDef for LogDef { /// Create a `Host` from a `Book`, including `hvm-core`'s built-in definitions pub fn create_host(book: &Book) -> Arc> { let host = Arc::new(Mutex::new(Host::default())); - host.lock().unwrap().insert_def("HVM.log", unsafe { - crate::stdlib::LogDef::new(host.clone(), { - move |tree| { - println!("{}", tree); - } - }) - }); + // host.lock().unwrap().insert_def("HVM.log", unsafe { + // crate::stdlib::LogDef::new(host.clone(), { + // move |tree| { + // println!("{}", tree); + // } + // }) + // }); host.lock().unwrap().insert_def("HVM.black_box", DefRef::Static(unsafe { &*IDENTITY })); host.lock().unwrap().insert_book(&book); host From 8bb2df93bb61bde6ab600fed622c125c828d0fbd Mon Sep 17 00:00:00 2001 From: tjjfvi Date: Tue, 26 Mar 2024 08:33:21 -0400 Subject: [PATCH 10/16] implement CtrN-CtrM anni --- src/run/interact.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/run/interact.rs b/src/run/interact.rs index ce301f00..e047ea7a 100644 --- a/src/run/interact.rs +++ b/src/run/interact.rs @@ -296,7 +296,20 @@ impl<'a, M: Mode> Net<'a, M> { self.free_wire(b.aux_port(i).wire()); } } else { - todo!() + let aw = a.tag().width(); + let bw = b.tag().width(); + let (a, b, aw, bw) = if aw > bw { (b, a, bw, aw) } else { (a, b, aw, bw) }; + let aws = aw - 1; + let cw = bw - aws; + let ct = Tag::ctr_with_width(cw); + let c = Port::new(ct, a.lab(), self.alloc(ct.align())); + for i in 0 .. aws { + self.link_wire_wire(a.aux_port(i).wire(), b.aux_port(i).wire()); + } + for i in 0 .. cw { + self.link_wire_port(b.aux_port(aws + i).wire(), c.aux_port(i)) + } + self.link_wire_port(a.aux_port(aws).wire(), c); } } From dba4d5f753094cccfeddfb287c5ffc2dfdd2563d Mon Sep 17 00:00:00 2001 From: tjjfvi Date: Tue, 26 Mar 2024 11:07:48 -0400 Subject: [PATCH 11/16] ... --- examples/sort/radix/radix_sort_ctr.hvm1 | 48 ++++++++++++------------- examples/sort/radix/radix_sort_ctr.hvmc | 2 +- radix_opt.hvmc | 39 ++++++++++++++++++++ src/run/interact.rs | 34 ++++++++++++++++-- 4 files changed, 95 insertions(+), 28 deletions(-) create mode 100644 radix_opt.hvmc diff --git a/examples/sort/radix/radix_sort_ctr.hvm1 b/examples/sort/radix/radix_sort_ctr.hvm1 index 123dd765..aaa9052f 100644 --- a/examples/sort/radix/radix_sort_ctr.hvm1 +++ b/examples/sort/radix/radix_sort_ctr.hvm1 @@ -26,30 +26,30 @@ // Radix : U60 -> Map (Radix n) = let r = Used - let r = (Data.U60.swap (& n 1) r Free) - let r = (Data.U60.swap (& n 2) r Free) - let r = (Data.U60.swap (& n 4) r Free) - let r = (Data.U60.swap (& n 8) r Free) - let r = (Data.U60.swap (& n 16) r Free) - let r = (Data.U60.swap (& n 32) r Free) - let r = (Data.U60.swap (& n 64) r Free) - let r = (Data.U60.swap (& n 128) r Free) - let r = (Data.U60.swap (& n 256) r Free) - let r = (Data.U60.swap (& n 512) r Free) - let r = (Data.U60.swap (& n 1024) r Free) - let r = (Data.U60.swap (& n 2048) r Free) - let r = (Data.U60.swap (& n 4096) r Free) - let r = (Data.U60.swap (& n 8192) r Free) - let r = (Data.U60.swap (& n 16384) r Free) - let r = (Data.U60.swap (& n 32768) r Free) - let r = (Data.U60.swap (& n 65536) r Free) - let r = (Data.U60.swap (& n 131072) r Free) - let r = (Data.U60.swap (& n 262144) r Free) - let r = (Data.U60.swap (& n 524288) r Free) - let r = (Data.U60.swap (& n 1048576) r Free) - let r = (Data.U60.swap (& n 2097152) r Free) - let r = (Data.U60.swap (& n 4194304) r Free) - let r = (Data.U60.swap (& n 8388608) r Free) + let r = (U60.swap (& n 1) r Free) + let r = (U60.swap (& n 2) r Free) + let r = (U60.swap (& n 4) r Free) + let r = (U60.swap (& n 8) r Free) + let r = (U60.swap (& n 16) r Free) + let r = (U60.swap (& n 32) r Free) + let r = (U60.swap (& n 64) r Free) + let r = (U60.swap (& n 128) r Free) + let r = (U60.swap (& n 256) r Free) + let r = (U60.swap (& n 512) r Free) + let r = (U60.swap (& n 1024) r Free) + let r = (U60.swap (& n 2048) r Free) + let r = (U60.swap (& n 4096) r Free) + let r = (U60.swap (& n 8192) r Free) + let r = (U60.swap (& n 16384) r Free) + let r = (U60.swap (& n 32768) r Free) + let r = (U60.swap (& n 65536) r Free) + let r = (U60.swap (& n 131072) r Free) + let r = (U60.swap (& n 262144) r Free) + let r = (U60.swap (& n 524288) r Free) + let r = (U60.swap (& n 1048576) r Free) + let r = (U60.swap (& n 2097152) r Free) + let r = (U60.swap (& n 4194304) r Free) + let r = (U60.swap (& n 8388608) r Free) r // Reverse : Arr -> Arr diff --git a/examples/sort/radix/radix_sort_ctr.hvmc b/examples/sort/radix/radix_sort_ctr.hvmc index 05bf998d..460111b2 100644 --- a/examples/sort/radix/radix_sort_ctr.hvmc +++ b/examples/sort/radix/radix_sort_ctr.hvmc @@ -16,7 +16,7 @@ & @sum ~ (b a) & @sort ~ (c b) & @rev ~ (d c) -& @gen ~ (#20 (#0 d)) +& @gen ~ (#22 (#0 d)) @merge = (((a a) (@merge$C2 (@merge$C7 (b c)))) (b c)) @merge$C0 = (* *) @merge$C1 = (* @merge$C0) diff --git a/radix_opt.hvmc b/radix_opt.hvmc new file mode 100644 index 00000000..f0d9a6f7 --- /dev/null +++ b/radix_opt.hvmc @@ -0,0 +1,39 @@ +@Node = (a b (:2:3 a b)) + +@Single = (a (:1:3 a)) + +@gen = (?<@Single @gen$C1 a> a) + +@gen$C1 = ({7 ?<@Single @gen$C1 (a b)> ?<@Single @gen$C1 (c d)>} <<< #1 {9 a <| #1 c>}> (:2:3 b d)) + +@main = a + & @sum ~ (b a) + & @sort ~ (c b) + & @rev ~ (d c) + & @gen ~ (#20 #0 d) + +@merge$C2 = (:0:1 (:1:3) (:1:3) *) + +@merge$C6 = (a (b ((:0:1) @merge$C2 @merge$C7 a d) ((:0:1) @merge$C2 @merge$C7 b f) (:2:3 d f))) + +@merge$C7 = (a b (:0:1 @Node * @merge$C6 a b)) + +@radix = ({3 <& #8388608 ?<@Node @swap$C2 (a (:0:3) b)>> <& #4194304 ?<@Node @swap$C2 (c (:0:3) a)>> <& #2097152 ?<@Node @swap$C2 (d (:0:3) c)>> <& #1048576 ?<@Node @swap$C2 (e (:0:3) d)>> <& #524288 ?<@Node @swap$C2 (f (:0:3) e)>> {3 <& #262144 ?<@Node @swap$C2 (g (:0:3) f)>> <& #131072 ?<@Node @swap$C2 (h (:0:3) g)>> <& #65536 ?<@Node @swap$C2 (i (:0:3) h)>> <& #32768 ?<@Node @swap$C2 (j (:0:3) i)>> <& #16384 ?<@Node @swap$C2 (k (:0:3) j)>> <& #8192 ?<@Node @swap$C2 (l (:0:3) k)>> {3 <& #4096 ?<@Node @swap$C2 (m (:0:3) l)>> <& #2048 ?<@Node @swap$C2 (n (:0:3) m)>> <& #1024 ?<@Node @swap$C2 (o (:0:3) n)>> <& #512 ?<@Node @swap$C2 (p (:0:3) o)>> <& #256 ?<@Node @swap$C2 (q (:0:3) p)>> <& #128 ?<@Node @swap$C2 (r (:0:3) q)>> {3 <& #64 ?<@Node @swap$C2 (s (:0:3) r)>> <& #32 ?<@Node @swap$C2 (t (:0:3) s)>> <& #16 ?<@Node @swap$C2 (u (:0:3) t)>> <& #8 ?<@Node @swap$C2 (v (:0:3) u)>> <& #4 ?<@Node @swap$C2 (w (:0:3) v)>> <& #2 ?<@Node @swap$C2 (x (:0:3) w)>> <& #1 ?<@Node @swap$C2 ((:1:3) (:0:3) x)>>}}}} b) + +@rev = (:0:1 (:0:3) @Single @rev$C1) + +@rev$C1 = (((:0:3) @Single @rev$C1 a) ((:0:3) @Single @rev$C1 b) (:2:3 b a)) + +@sort = (((:0:3) (@radix @to_map$C1 (:1:4) @Single @to_arr$C2 #0 a)) a) + +@sum = (:0:1 #0 (:0:1) @sum$C0) + +@sum$C0 = ((#0 (:0:1) @sum$C0 <+ b c>) (#0 (:0:1) @sum$C0 b) c) + +@swap$C1 = (a b (:2:3 b a)) + +@swap$C2 = (* @swap$C1) + +@to_arr$C2 = (((:1:4) @Single @to_arr$C2 a b) ((:1:4) @Single @to_arr$C2 c d) {5 <* #2 a> <* #2 <+ #1 c>>} (:2:3 b d)) + +@to_map$C1 = (((:0:3) (@radix @to_map$C1 (:0:1) @merge$C2 @merge$C7 b c)) ((:0:3) @radix @to_map$C1 b) c) diff --git a/src/run/interact.rs b/src/run/interact.rs index e047ea7a..764fdfdd 100644 --- a/src/run/interact.rs +++ b/src/run/interact.rs @@ -265,13 +265,41 @@ impl<'a, M: Mode> Net<'a, M> { self.rwts.anni += 1; let ctr_arity = ctr.tag().arity(); let adtz = if adt.is(AdtZ) { adt.clone() } else { adt.aux_port(adt.tag().arity()).wire().swap_target(Port::LOCK) }; - if ctr_arity != adtz.variant_count() + 1 { + if ctr_arity < adtz.variant_count() + 1 { + if ctr_arity <= adtz.variant_index() + 1 { + for i in 0 .. (ctr_arity - 1) { + self.link_wire_port(ctr.aux_port(i).wire(), Port::ERA); + } + let new_adtz = Port::new_adtz(adtz.variant_index() - (ctr_arity - 1), adtz.variant_count() - (ctr_arity - 1)); + self.link_wire_port( + ctr.aux_port(ctr_arity - 1).wire(), + if adt.is(AdtZ) { + new_adtz + } else { + adt.aux_port(adt.tag().arity()).wire().set_target(new_adtz); + adt + }, + ); + return; + } + dbg!(ctr_arity, adtz.variant_count(), adtz.variant_index()); todo!(); } + let out = if ctr_arity == adtz.variant_count() + 1 { + Trg::wire(ctr.aux_port(ctr_arity - 1).wire()) + } else { + let w = ctr_arity - adtz.variant_count(); + let t = Tag::ctr_with_width(w); + let port = Port::new(t, ctr.lab(), self.alloc(t.align())); + for i in 0 .. w { + self.link_wire_port(ctr.aux_port(adtz.variant_count() + i).wire(), port.aux_port(i)); + } + Trg::port(port) + }; if adt.is(AdtZ) { - self.link_wire_wire(ctr.aux_port(adtz.variant_index()).wire(), ctr.aux_port(ctr_arity - 1).wire()); + self.link_trg(out, Trg::wire(ctr.aux_port(adtz.variant_index()).wire())); } else { - self.link_wire_port(ctr.aux_port(ctr_arity - 1).wire(), adt.aux_port(adt.tag().arity())); + self.link_trg_port(out, adt.aux_port(adt.tag().arity())); self.link_wire_port(ctr.aux_port(adtz.variant_index()).wire(), Port(adt.0 ^ 0b1000)); } for i in 0 .. adtz.variant_index() { From afde18a80d0b52e4c08c8f90d3413bfbc3c1fe5d Mon Sep 17 00:00:00 2001 From: tjjfvi Date: Wed, 27 Mar 2024 09:09:40 -0400 Subject: [PATCH 12/16] ... --- examples/sort/bitonic/bitonic_sort_ctr.hvm1 | 8 +- examples/sort/bitonic/bitonic_sort_ctr.hvm2 | 40 ++++++++++ examples/sort/bitonic/bitonic_sort_ctr.hvmc | 87 +++++++++++++++++++++ examples/sort/bitonic/bitonic_sort_lam.hvmc | 2 +- src/host/encode.rs | 2 +- 5 files changed, 133 insertions(+), 6 deletions(-) create mode 100644 examples/sort/bitonic/bitonic_sort_ctr.hvm2 create mode 100644 examples/sort/bitonic/bitonic_sort_ctr.hvmc diff --git a/examples/sort/bitonic/bitonic_sort_ctr.hvm1 b/examples/sort/bitonic/bitonic_sort_ctr.hvm1 index 2f979ad8..0e654de8 100644 --- a/examples/sort/bitonic/bitonic_sort_ctr.hvm1 +++ b/examples/sort/bitonic/bitonic_sort_ctr.hvm1 @@ -1,9 +1,9 @@ // Atomic Swapper (HVM builtin) -//(Data.U60.swap 0 a b) = (Both a b) -//(Data.U60.swap n a b) = (Both b a) +//(U60.swap 0 a b) = (Both a b) +//(U60.swap n a b) = (Both b a) // Swaps distant values in parallel; corresponds to a Red Box -(Warp s (Leaf a) (Leaf b)) = (Data.U60.swap (^ (> a b) s) (Leaf a) (Leaf b)) +(Warp s (Leaf a) (Leaf b)) = (U60.swap (^ (> a b) s) (Leaf a) (Leaf b)) (Warp s (Both a b) (Both c d)) = (Join (Warp s a c) (Warp s b d)) // Rebuilds the warped tree in the original order @@ -33,4 +33,4 @@ (Sum (Leaf x)) = x (Sum (Both a b)) = (+ (Sum a) (Sum b)) -Main = (Sum (Sort 0 (Rev (Gen 18 0)))) +Main = (Sum (Sort 0 (Rev (Gen 19 0)))) diff --git a/examples/sort/bitonic/bitonic_sort_ctr.hvm2 b/examples/sort/bitonic/bitonic_sort_ctr.hvm2 new file mode 100644 index 00000000..ae46f8b6 --- /dev/null +++ b/examples/sort/bitonic/bitonic_sort_ctr.hvm2 @@ -0,0 +1,40 @@ + +data Tree = (Leaf a) | (Both a b) + +(U60.swap 0 a b) = (Both a b) +(U60.swap n a b) = (Both b a) + +// Swaps distant values in parallel; corresponds to a Red Box +(Warp s (Leaf a) (Leaf b)) = (U60.swap (^ (> a b) s) (Leaf a) (Leaf b)) +(Warp s (Both a b) (Both c d)) = (Join (Warp s a c) (Warp s b d)) +(Warp s * *) = * + +// Rebuilds the warped tree in the original order +(Join (Both a b) (Both c d)) = (Both (Both a c) (Both b d)) +(Join * *) = * + +// Recursively warps each sub-tree; corresponds to a Blue/Green Box +(Flow s (Leaf a)) = (Leaf a) +(Flow s (Both a b)) = (Down s (Warp s a b)) + +// Propagates Flow downwards +(Down s (Leaf a)) = (Leaf a) +(Down s (Both a b)) = (Both (Flow s a) (Flow s b)) + +// Bitonic Sort +(Sort s (Leaf a)) = (Leaf a) +(Sort s (Both a b)) = (Flow s (Both (Sort 0 a) (Sort 1 b))) + +// Generates a tree of depth `n` +(Gen 0 x) = (Leaf x) +(Gen n x) = let m = (- n 1); (Both (Gen m (* x 2)) (Gen m (+ (* x 2) 1))) + +// Reverses a tree +(Rev (Leaf x)) = (Leaf x) +(Rev (Both a b)) = (Both (Rev b) (Rev a)) + +// Sums a tree +(Sum (Leaf x)) = x +(Sum (Both a b)) = (+ (Sum a) (Sum b)) + +Main = (Sum (Sort 0 (Rev (Gen 20 0)))) diff --git a/examples/sort/bitonic/bitonic_sort_ctr.hvmc b/examples/sort/bitonic/bitonic_sort_ctr.hvmc new file mode 100644 index 00000000..97d69340 --- /dev/null +++ b/examples/sort/bitonic/bitonic_sort_ctr.hvmc @@ -0,0 +1,87 @@ +@Both = (a (b (* ((a (b c)) c)))) +@Down = (a ((@Down$C0 (@Down$C1 (a b))) b)) +@Down$C0 = (a (* b)) +& @Leaf ~ (a b) +@Down$C1 = (a (b ({3 c d} e))) +& @Both ~ (f (g e)) +& @Flow ~ (d (b g)) +& @Flow ~ (c (a f)) +@Flow = (a ((@Flow$C0 (@Flow$C1 (a b))) b)) +@Flow$C0 = (a (* b)) +& @Leaf ~ (a b) +@Flow$C1 = (a (b ({5 c d} e))) +& @Down ~ (c (f e)) +& @Warp ~ (d (a (b f))) +@Gen = (?<@Gen$C0 @Gen$C1 (a b)> (a b)) +@Gen$C0 = (a b) +& @Leaf ~ (a b) +@Gen$C1 = (<+ #1 <- #1 {9 a b}>> ({7 <* #2 c> <* #2 <+ #1 d>>} e)) +& @Both ~ (f (g e)) +& @Gen ~ (b (d g)) +& @Gen ~ (a (c f)) +@Join = ((@Join$C1 (@Join$C6 (a b))) (a b)) +@Join$C0 = (* *) +@Join$C1 = (* @Join$C0) +@Join$C2 = (* *) +@Join$C3 = (* @Join$C2) +@Join$C4 = (* @Join$C3) +@Join$C5 = (a (b (c (d e)))) +& @Both ~ (f (g e)) +& @Both ~ (d (b g)) +& @Both ~ (c (a f)) +@Join$C6 = (a (b ((@Join$C4 (@Join$C5 (a (b c)))) c))) +@Leaf = (a ((a b) (* b))) +@Rev = ((@Rev$C0 (@Rev$C1 a)) a) +@Rev$C0 = (a b) +& @Leaf ~ (a b) +@Rev$C1 = (a (b c)) +& @Both ~ (d (e c)) +& @Rev ~ (a e) +& @Rev ~ (b d) +@Sort = (a ((@Sort$C0 (@Sort$C3 (a b))) b)) +@Sort$C0 = (a (* b)) +& @Leaf ~ (a b) +@Sort$C1 = a +& @Sort ~ (#0 a) +@Sort$C2 = a +& @Sort ~ (#1 a) +@Sort$C3 = (a (b (c d))) +& @Flow ~ (c (e d)) +& @Both ~ (f (g e)) +& @Sort$C2 ~ (b g) +& @Sort$C1 ~ (a f) +@Sum = (((a a) (@Sum$C0 b)) b) +@Sum$C0 = (a (b c)) +& @Sum ~ (a <+ d c>) +& @Sum ~ (b d) +@U60.swap = (?<@U60.swap$C0 @U60.swap$C2 (a (b c))> (a (b c))) +@U60.swap$C0 = (a (b c)) +& @Both ~ (a (b c)) +@U60.swap$C1 = (a (b c)) +& @Both ~ (b (a c)) +@U60.swap$C2 = (* @U60.swap$C1) +@Warp = (a ((@Warp$C5 (@Warp$C11 (a (b c)))) (b c))) +@Warp$C0 = ({11 a b} (c ({13 <> a <^ c d>> e} f))) +& @U60.swap ~ (d (g (h f))) +& @Leaf ~ (b h) +& @Leaf ~ (e g) +@Warp$C1 = (* *) +@Warp$C10 = (a (b ({15 c d} (e (f g))))) +& @Join ~ (h (i g)) +& @Warp ~ (d (f (b i))) +& @Warp ~ (c (e (a h))) +@Warp$C11 = (a (b (c ((@Warp$C9 (@Warp$C10 (c (a (b d))))) d)))) +@Warp$C2 = (* @Warp$C1) +@Warp$C3 = (* @Warp$C2) +@Warp$C4 = (* @Warp$C3) +@Warp$C5 = (a (b ((@Warp$C0 (@Warp$C4 (b (a c)))) c))) +@Warp$C6 = (* *) +@Warp$C7 = (* @Warp$C6) +@Warp$C8 = (* @Warp$C7) +@Warp$C9 = (* @Warp$C8) +@main = a +& @Sum ~ (b a) +& @Sort ~ (#0 (c b)) +& @Rev ~ (d c) +& @Gen ~ (#19 (#0 d)) + diff --git a/examples/sort/bitonic/bitonic_sort_lam.hvmc b/examples/sort/bitonic/bitonic_sort_lam.hvmc index 89601038..90c4b989 100644 --- a/examples/sort/bitonic/bitonic_sort_lam.hvmc +++ b/examples/sort/bitonic/bitonic_sort_lam.hvmc @@ -36,7 +36,7 @@ & @sum ~ (b a) & @sort ~ (c (#0 b)) & @rev ~ (d c) -& @gen ~ (#10 (#0 d)) +& @gen ~ (#16 (#0 d)) @rev = ((@rev$S0 (@rev$S1 a)) a) @rev$S0 = (a b) & @Leaf ~ (a b) diff --git a/src/host/encode.rs b/src/host/encode.rs index 5cc83a25..a302ee35 100644 --- a/src/host/encode.rs +++ b/src/host/encode.rs @@ -12,7 +12,7 @@ impl Host { let mut state = State { host: self, encoder: &mut def, scope: Default::default() }; state.visit_net(net, TrgId::new(0)); state.finish(); - def + dbg!(def) } /// Encode `tree` directly into `trg`, skipping the intermediate `Def` From 96ea224041269f45e4479281706bc6b02b5a7b30 Mon Sep 17 00:00:00 2001 From: tjjfvi Date: Thu, 28 Mar 2024 10:07:22 -0400 Subject: [PATCH 13/16] ... --- src/run/allocator.rs | 2 +- src/run/def.rs | 4 ++-- src/run/instruction.rs | 18 +++++++++--------- src/run/interact.rs | 10 +++++----- src/run/linker.rs | 4 ++-- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/run/allocator.rs b/src/run/allocator.rs index 51216831..200790cf 100644 --- a/src/run/allocator.rs +++ b/src/run/allocator.rs @@ -118,7 +118,7 @@ impl<'h> Allocator<'h> { } /// Allocates a node, with a size specified by `align`. - #[inline(never)] + #[inline(always)] pub fn alloc(&mut self, align: Align) -> Addr { let head = self.head(align); let addr = if *head != Addr::NULL { diff --git a/src/run/def.rs b/src/run/def.rs index a581894e..67ef1cf8 100644 --- a/src/run/def.rs +++ b/src/run/def.rs @@ -225,12 +225,12 @@ impl AsHostedDef for InterpretedDef { struct Trgs(*mut Trg); impl Trgs { - #[inline(never)] + #[inline(always)] fn get_trg(&self, i: TrgId) -> Trg { unsafe { (*self.0.byte_offset(i.byte_offset as _)).clone() } } - #[inline(never)] + #[inline(always)] fn set_trg(&mut self, i: TrgId, trg: Trg) { unsafe { *self.0.byte_offset(i.byte_offset as _) = trg } } diff --git a/src/run/instruction.rs b/src/run/instruction.rs index 777c07be..dfac622e 100644 --- a/src/run/instruction.rs +++ b/src/run/instruction.rs @@ -125,7 +125,7 @@ impl fmt::Debug for TrgId { impl<'a, M: Mode> Net<'a, M> { /// `trg ~ {#lab x y}` - #[inline(never)] + #[inline(always)] pub(crate) fn do_ctr2(&mut self, lab: Lab, trg: Trg) -> (Trg, Trg) { let port = trg.target(); if !M::LAZY && port.is(Tag::Ctr2) && port.lab() == lab { @@ -147,7 +147,7 @@ impl<'a, M: Mode> Net<'a, M> { } /// `trg ~ {#lab ...}` - #[inline(never)] + #[inline(always)] pub(crate) fn do_ctrn(&mut self, lab: Lab, trg: Trg, n: u8) -> ArrayVec { let tag = Tag::ctr_with_width(n); let align = tag.align(); @@ -161,7 +161,7 @@ impl<'a, M: Mode> Net<'a, M> { } /// `trg ~ {lab:idx:count ...}` - #[inline(never)] + #[inline(always)] pub(crate) fn do_adtn( &mut self, lab: Lab, @@ -189,7 +189,7 @@ impl<'a, M: Mode> Net<'a, M> { } /// `trg ~ ` - #[inline(never)] + #[inline(always)] pub(crate) fn do_op(&mut self, op: Op, trg: Trg) -> (Trg, Trg) { trace!(self.tracer, op, trg); let port = trg.target(); @@ -209,7 +209,7 @@ impl<'a, M: Mode> Net<'a, M> { } /// `trg ~ ` - #[inline(never)] + #[inline(always)] pub(crate) fn do_op_num(&mut self, op: Op, trg: Trg, rhs: u64) -> Trg { let port = trg.target(); if !M::LAZY && port.tag() == Num { @@ -228,7 +228,7 @@ impl<'a, M: Mode> Net<'a, M> { } /// `trg ~ ?` - #[inline(never)] + #[inline(always)] pub(crate) fn do_mat(&mut self, trg: Trg) -> (Trg, Trg, Trg) { let m = self.alloc(Align4); let m0 = Port::new(Mat, 0, m); @@ -241,7 +241,7 @@ impl<'a, M: Mode> Net<'a, M> { #[cfg(todo)] /// `trg ~ ?` - #[inline(never)] + #[inline(always)] pub(crate) fn do_mat(&mut self, trg: Trg, out: Trg) -> (Trg, Trg) { let port = trg.target(); if trg.target().is(Tag::Num) { @@ -271,7 +271,7 @@ impl<'a, M: Mode> Net<'a, M> { } } - #[inline(never)] + #[inline(always)] pub(crate) fn do_wires(&mut self) -> (Trg, Trg, Trg, Trg) { let a = self.alloc(Align2); let b = a.offset(1); @@ -285,7 +285,7 @@ impl<'a, M: Mode> Net<'a, M> { #[cfg(todo)] /// `trg ~ ?<(x (y z)) out>` - #[inline(never)] + #[inline(always)] #[allow(unused)] // TODO: emit this instruction pub(crate) fn do_mat_con_con(&mut self, trg: Trg, out: Trg) -> (Trg, Trg, Trg) { let port = trg.target(); diff --git a/src/run/interact.rs b/src/run/interact.rs index 764fdfdd..66eb07c2 100644 --- a/src/run/interact.rs +++ b/src/run/interact.rs @@ -66,7 +66,7 @@ impl<'a, M: Mode> Net<'a, M> { /// b1 | | b2 /// /// ``` - #[inline(never)] + #[inline(always)] pub fn anni2(&mut self, a: Port, b: Port) { trace!(self, a, b); self.rwts.anni += 1; @@ -113,7 +113,7 @@ impl<'a, M: Mode> Net<'a, M> { /// b1 | | b2 /// /// ``` - #[inline(never)] + #[inline(always)] pub fn comm22(&mut self, a: Port, b: Port) { trace!(self, a, b); self.rwts.comm += 1; @@ -159,7 +159,7 @@ impl<'a, M: Mode> Net<'a, M> { /// b1 | | b2 /// /// ``` - #[inline(never)] + #[inline(always)] pub fn comm02(&mut self, a: Port, b: Port) { trace!(self, a, b); self.rwts.comm += 1; @@ -194,7 +194,7 @@ impl<'a, M: Mode> Net<'a, M> { /// a1 | | a2 | a3 | a1 | | a2 | a3 /// | /// ``` - #[inline(never)] + #[inline(always)] pub fn mat_num(&mut self, a: Port, b: Port) { trace!(self, a, b); self.rwts.oper += 1; @@ -240,7 +240,7 @@ impl<'a, M: Mode> Net<'a, M> { /// | a2 | a1 | | a2 /// | /// ``` - #[inline(never)] + #[inline(always)] pub fn op_num(&mut self, a: Port, b: Port) { trace!(self, a, b); let a = a.consume_node(); diff --git a/src/run/linker.rs b/src/run/linker.rs index 039857f5..6865edf3 100644 --- a/src/run/linker.rs +++ b/src/run/linker.rs @@ -308,7 +308,7 @@ impl Trg { impl<'h, M: Mode> Linker<'h, M> { /// Links a `Trg` to a port, delegating to the appropriate method based on the /// type of `a`. - #[inline(never)] + #[inline(always)] pub fn link_trg_port(&mut self, a: Trg, b: Port) { match a.is_wire() { true => self.link_wire_port(a.as_wire(), b), @@ -318,7 +318,7 @@ impl<'h, M: Mode> Linker<'h, M> { /// Links two `Trg`s, delegating to the appropriate method based on the types /// of `a` and `b`. - #[inline(never)] + #[inline(always)] pub fn link_trg(&mut self, a: Trg, b: Trg) { match (a.is_wire(), b.is_wire()) { (true, true) => self.link_wire_wire(a.as_wire(), b.as_wire()), From 73590169d0eb95ae3cc020a5aa2592b141efae52 Mon Sep 17 00:00:00 2001 From: tjjfvi Date: Thu, 28 Mar 2024 10:34:16 -0400 Subject: [PATCH 14/16] .... --- examples/sort/radix/radix_sort_ctr.hvmc | 2 +- radix_opt.hvmc | 2 +- src/main.rs | 4 ++++ src/run/allocator.rs | 12 +++++++++--- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/examples/sort/radix/radix_sort_ctr.hvmc b/examples/sort/radix/radix_sort_ctr.hvmc index 460111b2..2e29c278 100644 --- a/examples/sort/radix/radix_sort_ctr.hvmc +++ b/examples/sort/radix/radix_sort_ctr.hvmc @@ -16,7 +16,7 @@ & @sum ~ (b a) & @sort ~ (c b) & @rev ~ (d c) -& @gen ~ (#22 (#0 d)) +& @gen ~ (#18 (#0 d)) @merge = (((a a) (@merge$C2 (@merge$C7 (b c)))) (b c)) @merge$C0 = (* *) @merge$C1 = (* @merge$C0) diff --git a/radix_opt.hvmc b/radix_opt.hvmc index f0d9a6f7..e31e6a40 100644 --- a/radix_opt.hvmc +++ b/radix_opt.hvmc @@ -10,7 +10,7 @@ & @sum ~ (b a) & @sort ~ (c b) & @rev ~ (d c) - & @gen ~ (#20 #0 d) + & @gen ~ (#18 #0 d) @merge$C2 = (:0:1 (:1:3) (:1:3) *) diff --git a/src/main.rs b/src/main.rs index d0725f0b..1daaf9d5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -401,6 +401,10 @@ fn reduce_exprs(host: Arc>, exprs: &[Net], opts: &RuntimeOpts) { if opts.show_stats { print_stats(net, elapsed); } + dbg!(net.next); + dbg!(net.reuse); + dbg!(net.fresh); + dbg!(net.pad); }); } } diff --git a/src/run/allocator.rs b/src/run/allocator.rs index 200790cf..2a4947fc 100644 --- a/src/run/allocator.rs +++ b/src/run/allocator.rs @@ -44,8 +44,11 @@ impl Heap { pub struct Allocator<'h> { pub(super) tracer: Tracer, pub(super) heap: &'h Heap, - pub(super) next: usize, + pub next: usize, pub(super) heads: [Addr; 4], + pub reuse: usize, + pub fresh: usize, + pub pad: usize, } deref!({<'h>} Allocator<'h> => self.tracer: Tracer); @@ -67,7 +70,7 @@ impl Port { impl<'h> Allocator<'h> { pub fn new(heap: &'h Heap) -> Self { - Allocator { tracer: Tracer::default(), heap, next: 0, heads: [Addr::NULL; 4] } + Allocator { tracer: Tracer::default(), heap, next: 0, heads: [Addr::NULL; 4], reuse: 0, fresh: 0, pad: 0 } } fn head(&mut self, align: Align) -> &mut Addr { @@ -111,7 +114,7 @@ impl<'h> Allocator<'h> { let old_head = next_value; let new_head = addr; trace!(self.tracer, "appended", old_head, new_head); - return *self.head(align) = addr; + return *self.head(alloc_align) = addr; } align = next_align; } @@ -125,11 +128,14 @@ impl<'h> Allocator<'h> { let addr = *head; let next = Addr(head.val().load(Relaxed) as usize); *head = next; + self.reuse += 1; addr } else { + self.fresh += 1; let w = align.width() as usize; let x = w - 1; let index = (self.next + x) & !x; + self.pad += index - self.next; self.next = index + w; trace!(self, index); Addr(self.heap.0.get(index).expect("OOM") as *const AtomicU64 as usize) From e8a6332d7b2c87ec2883207ed4782af44b4eda27 Mon Sep 17 00:00:00 2001 From: tjjfvi Date: Thu, 28 Mar 2024 17:15:13 -0400 Subject: [PATCH 15/16] ... --- src/run/allocator.rs | 12 +++++++++++- src/run/instruction.rs | 8 ++++---- src/run/interact.rs | 21 ++++++++++++++------- src/run/net.rs | 2 +- src/run/node.rs | 6 +++--- 5 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/run/allocator.rs b/src/run/allocator.rs index 2a4947fc..f2a084fb 100644 --- a/src/run/allocator.rs +++ b/src/run/allocator.rs @@ -122,7 +122,7 @@ impl<'h> Allocator<'h> { /// Allocates a node, with a size specified by `align`. #[inline(always)] - pub fn alloc(&mut self, align: Align) -> Addr { + pub fn _alloc(&mut self, align: Align) -> Addr { let head = self.head(align); let addr = if *head != Addr::NULL { let addr = *head; @@ -147,6 +147,16 @@ impl<'h> Allocator<'h> { addr } + pub fn alloc(&mut self, tag: Tag) -> Addr { + let align = tag.align(); + // let align = Align4; + let addr = self._alloc(align); + for i in tag.width() .. align.width() { + self.free_word(addr.offset(i as usize), align); + } + addr + } + #[inline(always)] pub(crate) fn free_wire(&mut self, wire: Wire) { self.free_word(wire.addr(), wire.alloc_align()); diff --git a/src/run/instruction.rs b/src/run/instruction.rs index dfac622e..62c8ae73 100644 --- a/src/run/instruction.rs +++ b/src/run/instruction.rs @@ -151,7 +151,7 @@ impl<'a, M: Mode> Net<'a, M> { pub(crate) fn do_ctrn(&mut self, lab: Lab, trg: Trg, n: u8) -> ArrayVec { let tag = Tag::ctr_with_width(n); let align = tag.align(); - let addr = self.alloc(align); + let addr = self.alloc(tag); let mut out = ArrayVec::new(); self.link_trg_port(trg, Port::new(tag, lab, addr)); for i in 0 .. n { @@ -178,7 +178,7 @@ impl<'a, M: Mode> Net<'a, M> { let width = arity + 1; let tag = Tag::adt_with_width(width); let align = tag.align(); - let addr = self.alloc(align); + let addr = self.alloc(tag); self.link_trg_port(trg, Port::new(tag, lab, addr)); for i in 0 .. arity { unsafe { out.push_unchecked(Trg::port(Port::new_var(align, addr.offset(i as usize)))) } @@ -230,7 +230,7 @@ impl<'a, M: Mode> Net<'a, M> { /// `trg ~ ?` #[inline(always)] pub(crate) fn do_mat(&mut self, trg: Trg) -> (Trg, Trg, Trg) { - let m = self.alloc(Align4); + let m = self.alloc(Mat); let m0 = Port::new(Mat, 0, m); let m1 = m0.aux_port(0); let m2 = m0.aux_port(1); @@ -273,7 +273,7 @@ impl<'a, M: Mode> Net<'a, M> { #[inline(always)] pub(crate) fn do_wires(&mut self) -> (Trg, Trg, Trg, Trg) { - let a = self.alloc(Align2); + let a = self.alloc(Ctr2); let b = a.offset(1); ( Trg::port(Port::new_var(Align2, a.clone())), diff --git a/src/run/interact.rs b/src/run/interact.rs index 66eb07c2..6165b3ec 100644 --- a/src/run/interact.rs +++ b/src/run/interact.rs @@ -290,7 +290,7 @@ impl<'a, M: Mode> Net<'a, M> { } else { let w = ctr_arity - adtz.variant_count(); let t = Tag::ctr_with_width(w); - let port = Port::new(t, ctr.lab(), self.alloc(t.align())); + let port = Port::new(t, ctr.lab(), self.alloc(t)); for i in 0 .. w { self.link_wire_port(ctr.aux_port(adtz.variant_count() + i).wire(), port.aux_port(i)); } @@ -311,9 +311,9 @@ impl<'a, M: Mode> Net<'a, M> { } fn anni(&mut self, a: Port, b: Port) { - // if a.tag().width() == 2 && b.tag().width() == 2 { - // return self.anni2(a, b); - // } + if a.tag().width() == 2 && b.tag().width() == 2 { + return self.anni2(a, b); + } self.rwts.anni += 1; if a.tag() == b.tag() { for i in 0 .. a.tag().arity() { @@ -330,7 +330,7 @@ impl<'a, M: Mode> Net<'a, M> { let aws = aw - 1; let cw = bw - aws; let ct = Tag::ctr_with_width(cw); - let c = Port::new(ct, a.lab(), self.alloc(ct.align())); + let c = Port::new(ct, a.lab(), self.alloc(ct)); for i in 0 .. aws { self.link_wire_wire(a.aux_port(i).wire(), b.aux_port(i).wire()); } @@ -342,6 +342,13 @@ impl<'a, M: Mode> Net<'a, M> { } fn comm(&mut self, a: Port, b: Port) { + if a.tag().width() == 2 && b.tag().width() == 2 { + return self.comm22(a, b); + } else if a.tag().width() == 0 && b.tag().width() == 2 { + return self.comm02(a, b); + } else if b.tag().width() == 0 && a.tag().width() == 2 { + return self.comm02(b, a); + } if a == Port::ERA || b == Port::ERA { self.rwts.eras += 1; } else { @@ -358,7 +365,7 @@ impl<'a, M: Mode> Net<'a, M> { let As = &mut As[0 .. ba as usize]; if ba != 0 { for B in &mut *Bs { - let addr = self.alloc(b.align()); + let addr = self.alloc(b.tag()); *B = MaybeUninit::new(b.with_addr(addr)); } } else { @@ -366,7 +373,7 @@ impl<'a, M: Mode> Net<'a, M> { } if aa != 0 { for A in &mut *As { - let addr = self.alloc(a.align()); + let addr = self.alloc(a.tag()); *A = MaybeUninit::new(a.with_addr(addr)); } } else { diff --git a/src/run/net.rs b/src/run/net.rs index e64719c7..81c90530 100644 --- a/src/run/net.rs +++ b/src/run/net.rs @@ -17,7 +17,7 @@ impl<'h, M: Mode> Net<'h, M> { /// Creates an empty net with a given heap. pub fn new(heap: &'h Heap) -> Self { let mut net = Net::new_with_root(heap, Wire(0)); - net.root = Wire::new(Align2, net.alloc(Align2)); + net.root = Wire::new(Align2, net.alloc(Ctr2)); net } diff --git a/src/run/node.rs b/src/run/node.rs index 822b96d6..30b45eaf 100644 --- a/src/run/node.rs +++ b/src/run/node.rs @@ -35,7 +35,7 @@ impl<'a, M: Mode> Net<'a, M> { #[inline(always)] pub fn create_node(&mut self, tag: Tag, lab: Lab) -> CreatedNode { assert_eq!(tag.width(), 2); - let addr = self.alloc(tag.align()); + let addr = self.alloc(tag); CreatedNode { p0: Port::new(tag, lab, addr.clone()), p1: Port::new_var(Align2, addr), @@ -46,7 +46,7 @@ impl<'a, M: Mode> Net<'a, M> { /// Creates a wire an aux port pair. #[inline(always)] pub fn create_wire(&mut self) -> (Wire, Port) { - let addr = self.alloc(Align2); + let addr = self.alloc(Ctr2); (Wire::new(Align1, addr), Port::new_var(Align1, addr)) } @@ -54,7 +54,7 @@ impl<'a, M: Mode> Net<'a, M> { /// deadlock. #[inline(always)] pub fn create_wire_to(&mut self, port: Port) -> Wire { - let addr = self.alloc(Align1); + let addr = self.alloc(Var); let wire = Wire::new(Align1, addr); self.link_port_port(port, wire.as_var()); wire From d6c6db6e843664d99eb3c25ae7c2f5419b25e7b5 Mon Sep 17 00:00:00 2001 From: tjjfvi Date: Mon, 1 Apr 2024 13:16:44 -0400 Subject: [PATCH 16/16] ... --- src/host/encode.rs | 12 ++++---- src/run/interact.rs | 73 +++++++++++++++++++++++++++++++++++---------- src/run/linker.rs | 2 +- src/run/tag.rs | 37 +++++++++++++++++++++-- src/util/bi_enum.rs | 4 +-- 5 files changed, 101 insertions(+), 27 deletions(-) diff --git a/src/host/encode.rs b/src/host/encode.rs index a302ee35..f49dd1f6 100644 --- a/src/host/encode.rs +++ b/src/host/encode.rs @@ -74,12 +74,12 @@ impl<'a, E: Encoder> State<'a, E> { if ports.len() == 1 { return self.visit_tree(&ports[0], trg); } - if ports.len() == 2 { - let (a, b) = self.encoder.ctr2(*lab, trg); - self.visit_tree(&ports[0], a); - self.visit_tree(&ports[1], b); - return; - } + // if ports.len() == 2 { + // let (a, b) = self.encoder.ctr2(*lab, trg); + // self.visit_tree(&ports[0], a); + // self.visit_tree(&ports[1], b); + // return; + // } for (i, t) in self.encoder.ctrn(*lab, trg, ports.len() as u8).into_iter().enumerate() { self.visit_tree(&ports[i], t); } diff --git a/src/run/interact.rs b/src/run/interact.rs index 6165b3ec..4dc5d588 100644 --- a/src/run/interact.rs +++ b/src/run/interact.rs @@ -2,6 +2,8 @@ use std::mem::MaybeUninit; use super::*; +// type _Tag = [(); width(T) as usize]; + impl<'a, M: Mode> Net<'a, M> { /// Performs an interaction between two connected principal ports. #[inline(always)] @@ -310,22 +312,47 @@ impl<'a, M: Mode> Net<'a, M> { } } + fn _anni2(&mut self, a: Port, b: Port) { + self._anni(2, 2, 2, a, b); + } + + #[inline(always)] fn anni(&mut self, a: Port, b: Port) { - if a.tag().width() == 2 && b.tag().width() == 2 { - return self.anni2(a, b); - } + specialize_tag!(A = a.tag() => + specialize_tag!(B = b.tag() => + self.__anni::<{A.arity()}, {A.width()}, {A.width()}>(a, b) + ) + ) + // if a.tag().width() == 2 && b.tag().width() == 2 { + // return self._anni2(a, b); + // } + // self._foo(a, b); + // self._anni(a.tag().arity(), a.tag().width(), b.tag().width(), a, b); + } + + fn _foo(&mut self, a: Port, b: Port) { + self._anni(a.tag().arity(), a.tag().width(), b.tag().width(), a, b); + } + + fn __anni(&mut self, a: Port, b: Port) { + self._anni(AA, AW, BW, a, b) + } + + #[inline(always)] + fn _anni(&mut self, aa: u8, aw: u8, bw: u8, a: Port, b: Port) { + // if a.tag().width() == 2 && b.tag().width() == 2 { + // return self.anni2(a, b); + // } self.rwts.anni += 1; - if a.tag() == b.tag() { - for i in 0 .. a.tag().arity() { + if aw == bw { + for i in 0 .. aa { self.link_wire_wire(a.aux_port(i).wire(), b.aux_port(i).wire()); } - for i in a.tag().arity() .. a.tag().width() { + for i in aa .. aw { self.free_wire(a.aux_port(i).wire()); self.free_wire(b.aux_port(i).wire()); } } else { - let aw = a.tag().width(); - let bw = b.tag().width(); let (a, b, aw, bw) = if aw > bw { (b, a, bw, aw) } else { (a, b, aw, bw) }; let aws = aw - 1; let cw = bw - aws; @@ -342,13 +369,13 @@ impl<'a, M: Mode> Net<'a, M> { } fn comm(&mut self, a: Port, b: Port) { - if a.tag().width() == 2 && b.tag().width() == 2 { - return self.comm22(a, b); - } else if a.tag().width() == 0 && b.tag().width() == 2 { - return self.comm02(a, b); - } else if b.tag().width() == 0 && a.tag().width() == 2 { - return self.comm02(b, a); - } + // if a.tag().width() == 2 && b.tag().width() == 2 { + // return self.comm22(a, b); + // } else if a.tag().width() == 0 && b.tag().width() == 2 { + // return self.comm02(a, b); + // } else if b.tag().width() == 0 && a.tag().width() == 2 { + // return self.comm02(b, a); + // } if a == Port::ERA || b == Port::ERA { self.rwts.eras += 1; } else { @@ -417,3 +444,19 @@ impl<'a, M: Mode> Net<'a, M> { } } } + +const fn width(t: u8) -> u8 { + unsafe { Tag::from_unchecked(t) }.width() +} + +const fn arity(t: u8) -> u8 { + unsafe { Tag::from_unchecked(t) }.arity() +} + +macro_rules! IsTag { + ($T:ident) => { + ([(); arity($T) as usize], [(); width($T) as usize]) + }; +} + +use IsTag; diff --git a/src/run/linker.rs b/src/run/linker.rs index 6865edf3..73d32994 100644 --- a/src/run/linker.rs +++ b/src/run/linker.rs @@ -50,7 +50,7 @@ impl<'h, M: Mode> Linker<'h, M> { } /// Links two wires. - #[inline(always)] + #[inline(never)] pub fn link_wire_wire(&mut self, a_wire: Wire, b_wire: Wire) { trace!(self, a_wire, b_wire); let a_port = a_wire.lock_target(); diff --git a/src/run/tag.rs b/src/run/tag.rs index ceb22a04..bb41b6dc 100644 --- a/src/run/tag.rs +++ b/src/run/tag.rs @@ -44,15 +44,46 @@ bi_enum! { } } +#[rustfmt::skip] +macro_rules! specialize_tag { + ($CONST:ident = $tag:expr => $body:expr) => { + match $tag { + Tag::Red => { const $CONST: Tag = Tag::Red; $body } + Tag::Var => { const $CONST: Tag = Tag::Var; $body } + Tag::Ctr2 => { const $CONST: Tag = Tag::Ctr2; $body } + Tag::Adt2 => { const $CONST: Tag = Tag::Adt2; $body } + Tag::Num => { const $CONST: Tag = Tag::Num; $body } + Tag::Op => { const $CONST: Tag = Tag::Op; $body } + Tag::Ctr3 => { const $CONST: Tag = Tag::Ctr3; $body } + Tag::Ctr4 => { const $CONST: Tag = Tag::Ctr4; $body } + Tag::Adt3 => { const $CONST: Tag = Tag::Adt3; $body } + Tag::Adt4 => { const $CONST: Tag = Tag::Adt4; $body } + Tag::Ref => { const $CONST: Tag = Tag::Ref; $body } + Tag::Mat => { const $CONST: Tag = Tag::Mat; $body } + Tag::AdtZ => { const $CONST: Tag = Tag::AdtZ; $body } + Tag::Ctr5 => { const $CONST: Tag = Tag::Ctr5; $body } + Tag::Ctr6 => { const $CONST: Tag = Tag::Ctr6; $body } + Tag::Ctr7 => { const $CONST: Tag = Tag::Ctr7; $body } + Tag::Ctr8 => { const $CONST: Tag = Tag::Ctr8; $body } + Tag::Adt5 => { const $CONST: Tag = Tag::Adt5; $body } + Tag::Adt6 => { const $CONST: Tag = Tag::Adt6; $body } + Tag::Adt7 => { const $CONST: Tag = Tag::Adt7; $body } + Tag::Adt8 => { const $CONST: Tag = Tag::Adt8; $body } + } + }; +} + +pub(super) use specialize_tag; + impl Tag { #[inline(always)] - pub(super) fn align(self) -> Align { + pub(super) const fn align(self) -> Align { unsafe { Align::from_unchecked(self as u8 & 0b11) } } /// Returns the width -- the size of the allocation -- of nodes of this tag. #[inline] - pub(crate) fn width(self) -> u8 { + pub(crate) const fn width(self) -> u8 { match self { Tag::Num | Tag::Ref | Tag::AdtZ => 0, Tag::Red | Tag::Var => 1, @@ -65,7 +96,7 @@ impl Tag { /// Returns the arity -- the number of auxiliary ports -- of nodes of this /// tag. #[inline] - pub(crate) fn arity(self) -> u8 { + pub(crate) const fn arity(self) -> u8 { match self { AdtN!() => self.width() - 1, _ => self.width(), diff --git a/src/util/bi_enum.rs b/src/util/bi_enum.rs index faaf0b0f..05b68cd5 100644 --- a/src/util/bi_enum.rs +++ b/src/util/bi_enum.rs @@ -18,8 +18,8 @@ macro_rules! bi_enum { impl $Ty { #[allow(unused)] - pub unsafe fn from_unchecked(value: $uN) -> $Ty { - Self::try_from(value).unwrap_unchecked() + pub const unsafe fn from_unchecked(value: $uN) -> $Ty { + match value { $($value => $Ty::$Variant,)* _ => std::hint::unreachable_unchecked(), } } }