diff --git a/hoon/codegen/lib/line.hoon b/hoon/codegen/lib/line.hoon
index 36f76d2..4fe4eb1 100644
--- a/hoon/codegen/lib/line.hoon
+++ b/hoon/codegen/lib/line.hoon
@@ -1265,7 +1265,7 @@
hill
--
:: codegen interface
-:- %1
+=+ %1
|%
::
:: core reference
diff --git a/hoon/codegen/sur/gene.hoon b/hoon/codegen/sur/gene.hoon
index 2439fb7..566af83 100644
--- a/hoon/codegen/sur/gene.hoon
+++ b/hoon/codegen/sur/gene.hoon
@@ -202,11 +202,11 @@
::
:: long: starting label for direct calls axis 2
:: want: input registers for direct calls axis 6
-:: walt: input starting registers LR axis 30
-:: wish: starting label for indirect calls axis 62
-:: sire: input register for indirect calls axis 126
-:: will: code table for arm axis 254
-:: sans: next SSA register axis 255
+:: walt: input starting registers LR axis 14
+:: wish: starting label for indirect calls axis 30
+:: sire: input register for indirect calls axis 62
+:: will: code table for arm axis 126
+:: sans: next SSA register axis 127
+$ pile
$: long=bile
want=need
diff --git a/rust/ares/src/codegen.rs b/rust/ares/src/codegen.rs
new file mode 100644
index 0000000..56c830b
--- /dev/null
+++ b/rust/ares/src/codegen.rs
@@ -0,0 +1,423 @@
+use crate::interpreter::{inc, interpret, Context, Error, Result, BAIL_EXIT};
+use crate::jets::seam::util::get_by;
+use crate::jets::util::slot;
+use crate::mem::NockStack;
+use crate::noun::{DirectAtom, Noun, D, NOUN_NONE, T};
+use ares_macros::tas;
+use std::mem::size_of;
+use std::ptr::write_bytes;
+use std::slice::{from_raw_parts, from_raw_parts_mut};
+
+#[derive(Copy, Clone)]
+struct Frame {
+ /// Slow stack as a list
+ slow: Noun,
+ /// Mean stack as a list
+ mean: Noun,
+ /// Code table for current arm
+ pile: Noun,
+ /// Continuation label when returning to this frame
+ cont: Noun,
+ /// Result register when returning to this frame
+ salt: usize,
+ /// number of locals
+ vars: usize,
+}
+
+impl Frame {
+ fn init(&mut self, vars: usize, prev: Option<&Frame>) {
+ *self = Frame {
+ slow: prev.map_or(D(0), |f| f.slow),
+ mean: prev.map_or(D(0), |f| f.mean),
+ pile: NOUN_NONE,
+ cont: NOUN_NONE,
+ salt: usize::MAX,
+ vars,
+ };
+ unsafe { write_bytes((self as *mut Frame).add(1) as *mut u64, 0, vars) };
+ }
+
+ unsafe fn current<'a>(stack: &NockStack) -> &'a Self {
+ &(*(stack.get_frame_base() as *const Frame))
+ }
+
+ unsafe fn current_mut<'a>(stack: &NockStack) -> &'a mut Self {
+ &mut (*(stack.get_frame_base() as *mut Frame))
+ }
+
+ fn vars<'a>(&self) -> &'a [Noun] {
+ unsafe { from_raw_parts((self as *const Frame).add(1) as *const Noun, self.vars) }
+ }
+
+ fn vars_mut<'a>(&mut self) -> &'a mut [Noun] {
+ unsafe { from_raw_parts_mut((self as *mut Frame).add(1) as *mut Noun, self.vars) }
+ }
+
+ fn mean_push(&mut self, stack: &mut NockStack, entry: Noun) {
+ self.mean = T(stack, &[entry, self.mean]);
+ }
+
+ fn mean_pop(&mut self) {
+ self.mean = self
+ .mean
+ .as_cell()
+ .expect("Cannot pop empty mean stack")
+ .tail();
+ }
+
+ fn slow_push(&mut self, stack: &mut NockStack, entry: Noun) {
+ self.slow = T(stack, &[entry, self.slow]);
+ }
+
+ fn slow_pop(&mut self) {
+ self.slow = self
+ .slow
+ .as_cell()
+ .expect("Cannot pop empty slow stack")
+ .tail();
+ }
+}
+
+assert_eq_align!(Frame, u64, usize);
+assert_eq_size!(u64, usize);
+const FRAME_WORD_SIZE: usize = size_of::() / size_of::();
+
+fn push_interpreter_frame(stack: &mut NockStack, pile: Noun) {
+ let vars = pile_sans(pile);
+ let prev = unsafe { Frame::current(stack) };
+ stack.frame_push(FRAME_WORD_SIZE + vars);
+ let frame = unsafe { Frame::current_mut(stack) };
+ frame.init(vars, Some(prev));
+ frame.pile = pile;
+}
+
+fn push_outer_frame(stack: &mut NockStack, pile: Noun) {
+ let vars = pile_sans(pile);
+ stack.frame_push(FRAME_WORD_SIZE + vars);
+ let frame = unsafe { Frame::current_mut(stack) };
+ frame.init(vars, None);
+ frame.pile = pile;
+}
+
+const PEEK_AXIS: u64 = 4;
+const POKE_AXIS: u64 = 46;
+
+fn slam_line(context: &mut Context, arm_axis: u64, sample: Noun) -> Noun {
+ let axis_noun = DirectAtom::new_panic(arm_axis).as_noun();
+ let subject = T(&mut context.stack, &[sample, context.line]);
+ let sample_patch = T(&mut context.stack, &[D(6), D(0), D(2)]);
+ let arm_kick_form = T(&mut context.stack, &[D(9), axis_noun, D(0), D(3)]);
+ let gate_slam_form = T(
+ &mut context.stack,
+ &[D(9), D(2), D(10), sample_patch, arm_kick_form],
+ );
+ interpret(context, subject, gate_slam_form).expect("Crash in codegen")
+}
+
+fn cg_peek(context: &mut Context, subject: Noun, formula: Noun) -> Option {
+ assert!(!context.line.is_none());
+ let sample = T(&mut context.stack, &[subject, formula]);
+ let peek_result = slam_line(context, PEEK_AXIS, sample);
+ if unsafe { peek_result.raw_equals(D(0)) } {
+ None
+ } else {
+ let unit_cell = peek_result.as_cell().expect("Peek should return unit");
+ Some(unit_cell.tail())
+ }
+}
+
+fn cg_poke(context: &mut Context, slow: Noun, subject: Noun, formula: Noun) {
+ assert!(!context.line.is_none());
+ let sample = T(
+ &mut context.stack,
+ &[D(tas!(b"comp")), slow, subject, formula],
+ );
+ let result = slam_line(context, POKE_AXIS, sample);
+ let new_line = slot(result, 7).expect("Poke should return triple");
+ context.line = new_line;
+}
+
+/// Get the $pile for an arm, possibly updating the line core
+fn cg_indirect(
+ context: &mut Context,
+ hill: &mut Noun,
+ slow: Noun,
+ subject: Noun,
+ formula: Noun,
+) -> Noun {
+ let bell_hill = if let Some(res) = cg_peek(context, subject, formula) {
+ res
+ } else {
+ cg_poke(context, slow, subject, formula);
+ cg_peek(context, subject, formula).expect("Codegen peek should return value after poke.")
+ };
+ let bell_hill_cell = bell_hill
+ .as_cell()
+ .expect("Codegen successful peek should return pair");
+ get_by(
+ &mut context.stack,
+ &mut bell_hill_cell.tail(),
+ &mut bell_hill_cell.head(),
+ )
+ .expect("Codegen bell lookup should succeed.")
+ .expect("Codegen peek bell should be in hill")
+}
+
+pub fn cg_interpret(context: &mut Context, slow: Noun, subject: Noun, formula: Noun) -> Result {
+ let mut hill = NOUN_NONE;
+ let outer_pile = cg_indirect(context, &mut hill, slow, subject, formula);
+ let virtual_frame = context.stack.get_frame_pointer();
+ push_outer_frame(&mut context.stack, outer_pile);
+ let mut wish = pile_wish(outer_pile);
+ let (mut body, mut bend) = get_blob(context, outer_pile, &mut wish);
+ let sire = pile_sire(outer_pile);
+ (unsafe { Frame::current_mut(&context.stack).vars_mut() })[sire] = subject;
+ let inner_res = 'interpret: loop {
+ let frame = unsafe { Frame::current_mut(&context.stack) };
+ if let Ok(body_cell) = body.as_cell() {
+ body = body_cell.tail();
+ let inst_cell = body_cell
+ .head()
+ .as_cell()
+ .expect("Codegen instruction should be a cell");
+ let inst_tag = inst_cell
+ .head()
+ .as_atom()
+ .expect("Codegen instruction tag should be atom")
+ .as_u64()
+ .expect("codegen instruction tag should convert to u64");
+ match inst_tag {
+ tas!(b"imm") => {
+ let imm_cell = inst_cell.tail().as_cell().unwrap();
+ let imm_n = imm_cell.head();
+ let imm_d = imm_cell.tail().as_atom().unwrap().as_u64().unwrap() as usize;
+ frame.vars_mut()[imm_d] = imm_n;
+ }
+ tas!(b"mov") => {
+ let mov_cell = inst_cell.tail().as_cell().unwrap();
+ let mov_s = mov_cell.head().as_atom().unwrap().as_u64().unwrap() as usize;
+ let mov_d = mov_cell.tail().as_atom().unwrap().as_u64().unwrap() as usize;
+ frame.vars_mut()[mov_d] = frame.vars()[mov_s];
+ }
+ tas!(b"inc") => {
+ let inc_cell = inst_cell.tail().as_cell().unwrap();
+ let inc_s = inc_cell.head().as_atom().unwrap().as_u64().unwrap() as usize;
+ let inc_d = inc_cell.tail().as_atom().unwrap().as_u64().unwrap() as usize;
+ if let Ok(s_atom) = frame.vars()[inc_s].as_atom() {
+ frame.vars_mut()[inc_d] = inc(&mut context.stack, s_atom).as_noun();
+ } else {
+ break BAIL_EXIT;
+ }
+ }
+ tas!(b"con") => {
+ let con_cell = inst_cell.tail().as_cell().unwrap();
+ let con_h = con_cell.head().as_atom().unwrap().as_u64().unwrap() as usize;
+ let con_tell = con_cell.tail().as_cell().unwrap();
+ let con_t = con_tell.head().as_atom().unwrap().as_u64().unwrap() as usize;
+ let con_d = con_tell.tail().as_atom().unwrap().as_u64().unwrap() as usize;
+ frame.vars_mut()[con_d] = T(
+ &mut context.stack,
+ &[frame.vars()[con_h], frame.vars()[con_t]],
+ );
+ }
+ tas!(b"hed") => {
+ let hed_cell = inst_cell.tail().as_cell().unwrap();
+ let hed_s = hed_cell.head().as_atom().unwrap().as_u64().unwrap() as usize;
+ let hed_d = hed_cell.tail().as_atom().unwrap().as_u64().unwrap() as usize;
+ let s_noun = frame.vars()[hed_s];
+ if s_noun.is_none() {
+ frame.vars_mut()[hed_d] = NOUN_NONE;
+ } else if let Ok(s_cell) = frame.vars()[hed_s].as_cell() {
+ frame.vars_mut()[hed_d] = s_cell.head();
+ } else {
+ frame.vars_mut()[hed_d] = NOUN_NONE;
+ }
+ }
+ tas!(b"tal") => {
+ let tal_cell = inst_cell.tail().as_cell().unwrap();
+ let tal_s = tal_cell.head().as_atom().unwrap().as_u64().unwrap() as usize;
+ let tal_d = tal_cell.tail().as_atom().unwrap().as_u64().unwrap() as usize;
+ let s_noun = frame.vars()[tal_s];
+ if s_noun.is_none() {
+ frame.vars_mut()[tal_d] = NOUN_NONE;
+ } else if let Ok(s_cell) = frame.vars()[tal_s].as_cell() {
+ frame.vars_mut()[tal_d] = s_cell.tail();
+ } else {
+ frame.vars_mut()[tal_d] = NOUN_NONE;
+ }
+ }
+ tas!(b"men") => {
+ let men_cell = inst_cell.tail().as_cell().unwrap();
+ let men_l = men_cell.head();
+ assert!(men_l.is_atom());
+ let men_s = men_cell.tail().as_atom().unwrap().as_u64().unwrap() as usize;
+ let men_entry = T(&mut context.stack, &[men_l, frame.vars()[men_s]]);
+ frame.mean = T(&mut context.stack, &[men_entry, frame.mean])
+ }
+ tas!(b"man") => {
+ frame.mean = frame.mean.as_cell().unwrap().tail();
+ }
+ tas!(b"slo") => {
+ let slo_s = inst_cell.tail().as_atom().unwrap().as_u64().unwrap() as usize;
+ let slo_tag = frame.vars()[slo_s];
+ assert!(slo_tag.is_atom());
+ frame.slow = T(&mut context.stack, &[slo_tag, frame.slow]);
+ }
+ tas!(b"sld") => {
+ frame.slow = frame.slow.as_cell().unwrap().tail();
+ todo!("sld")
+ }
+ tas!(b"hit") => {
+ // XX TODO implement
+ }
+ tas!(b"slg") => {
+ let slg_s = inst_cell.tail().as_atom().unwrap().as_u64().unwrap() as usize;
+ context
+ .newt
+ .slog(&mut context.stack, 0, frame.vars()[slg_s]);
+ }
+ tas!(b"mew") => {
+ // XX TODO implement
+ }
+ tas!(b"tim") => {
+ // XX TODO implement
+ }
+ tas!(b"tom") => {
+ // XX TODO implement
+ }
+ tas!(b"mem") => {
+ // XX TODO implement
+ }
+ tas!(b"poi") => {
+ let poi_p = inst_cell.tail().as_atom().unwrap().as_u64().unwrap() as usize;
+ frame.vars_mut()[poi_p] = NOUN_NONE;
+ }
+ tas!(b"ipb") => {
+ let mut ipb_p = inst_cell.tail();
+ 'ipb: loop {
+ if unsafe { ipb_p.raw_equals(D(0)) } {
+ break 'ipb;
+ } else {
+ let p_cell = ipb_p.as_cell().unwrap();
+ ipb_p = p_cell.tail();
+ let p_i = p_cell.head().as_atom().unwrap().as_u64().unwrap() as usize;
+ if frame.vars()[p_i].is_none() {
+ break 'interpret BAIL_EXIT;
+ }
+ }
+ }
+ }
+ _ => {
+ panic!("Codegen instruction unsupported");
+ }
+ }
+ } else {
+ let inst_cell = bend
+ .as_cell()
+ .expect("Codegen instruction should be a cell");
+ let inst_tag = inst_cell
+ .head()
+ .as_atom()
+ .expect("Codegen instruction tag should be atom")
+ .as_u64()
+ .expect("codegen instruction tag should convert to u64");
+ match inst_tag {
+ tas!(b"clq") => {
+ todo!("clq")
+ }
+ tas!(b"eqq") => {
+ todo!("eqq")
+ }
+ tas!(b"brn") => {
+ todo!("brn")
+ }
+ tas!(b"hop") => {
+ todo!("hop")
+ }
+ tas!(b"hip") => {
+ todo!("hip")
+ }
+ tas!(b"lnk") => {
+ todo!("lnk")
+ }
+ tas!(b"cal") => {
+ todo!("cal")
+ }
+ tas!(b"caf") => {
+ todo!("caf")
+ }
+ tas!(b"lnt") => {
+ todo!("lnt")
+ }
+ tas!(b"jmp") => {
+ todo!("jmp")
+ }
+ tas!(b"jmf") => {
+ todo!("jmf")
+ }
+ tas!(b"spy") => {
+ todo!("spy")
+ }
+ tas!(b"mer") => {
+ todo!("mer")
+ }
+ tas!(b"don") => {
+ todo!("don")
+ }
+ tas!(b"bom") => {
+ todo!("bom")
+ }
+ _ => {
+ panic!("Codegen instruction unsupported");
+ }
+ }
+ }
+ };
+ match inner_res {
+ Ok(res) => inner_res,
+ Err(err) => exit(context, err),
+ }
+}
+
+/// Crash with an
+fn exit(context: &mut Context, err: Error) -> Result {
+ todo!("exit")
+}
+
+fn pile_sans(pile: Noun) -> usize {
+ (slot(pile, 127)
+ .expect("Codegen pile should have sans face")
+ .as_atom()
+ .expect("Codegen sans should be atom")
+ .as_u64()
+ .expect("Codegen sans too big")) as usize
+}
+
+fn pile_wish(pile: Noun) -> Noun {
+ slot(pile, 30).expect("Codegen pile should have wish face")
+}
+
+fn pile_sire(pile: Noun) -> usize {
+ (slot(pile, 62)
+ .expect("Codegen pile should have sire face")
+ .as_atom()
+ .expect("Codegen sire should be atom")
+ .as_u64()
+ .expect("Codegen sire too big")) as usize
+}
+
+fn pile_will(pile: Noun) -> Noun {
+ slot(pile, 126).expect("Codegen pile should have will face")
+}
+
+fn get_blob(context: &mut Context, pile: Noun, bile: &mut Noun) -> (Noun, Noun) {
+ let mut will = pile_will(pile);
+ let blob_with_biff = get_by(&mut context.stack, &mut will, bile)
+ .expect("Codegen bile lookup successful")
+ .expect("Codegen will has bile");
+ let blob_cell = slot(blob_with_biff, 3)
+ .expect("Codegen blob has tail")
+ .as_cell()
+ .expect("Codegen blob tail should be cell");
+ (blob_cell.head(), blob_cell.tail())
+}
diff --git a/rust/ares/src/interpreter.rs b/rust/ares/src/interpreter.rs
index c250d88..2d64efe 100644
--- a/rust/ares/src/interpreter.rs
+++ b/rust/ares/src/interpreter.rs
@@ -268,6 +268,7 @@ pub struct Context {
pub cold: Cold,
pub warm: Warm,
pub hot: Hot,
+ pub line: Noun,
pub cache: Hamt,
pub scry_stack: Noun,
pub trace_info: Option,
@@ -360,7 +361,7 @@ impl From for Error {
pub type Result = result::Result;
-const BAIL_EXIT: Result = Err(Error::Deterministic(Mote::Exit, D(0)));
+pub const BAIL_EXIT: Result = Err(Error::Deterministic(Mote::Exit, D(0)));
const BAIL_FAIL: Result = Err(Error::NonDeterministic(Mote::Fail, D(0)));
const BAIL_INTR: Result = Err(Error::NonDeterministic(Mote::Intr, D(0)));
diff --git a/rust/ares/src/jets.rs b/rust/ares/src/jets.rs
index cda3403..70cae28 100644
--- a/rust/ares/src/jets.rs
+++ b/rust/ares/src/jets.rs
@@ -310,7 +310,7 @@ pub mod util {
use super::*;
use crate::hamt::Hamt;
use crate::mem::NockStack;
- use crate::noun::{Atom, Noun, D, T};
+ use crate::noun::{Atom, Noun, D, NOUN_NONE, T};
use crate::unifying_equality::unifying_equality;
use assert_no_alloc::assert_no_alloc;
use ibig::UBig;
@@ -322,6 +322,7 @@ pub mod util {
let warm = Warm::new(&mut stack);
let hot = Hot::init(&mut stack, URBIT_HOT_STATE);
let cache = Hamt::::new(&mut stack);
+ let line = NOUN_NONE;
Context {
stack,
@@ -330,6 +331,7 @@ pub mod util {
warm,
hot,
cache,
+ line,
scry_stack: D(0),
trace_info: None,
}
diff --git a/rust/ares/src/jets/seam.rs b/rust/ares/src/jets/seam.rs
index 0e4ba5f..c778649 100644
--- a/rust/ares/src/jets/seam.rs
+++ b/rust/ares/src/jets/seam.rs
@@ -5,7 +5,6 @@
// use crate::jets::util::*;
// use crate::jets::Result;
// use crate::noun::{IndirectAtom, Noun, D};
-
use self::util::*;
crate::gdb!();
@@ -13,14 +12,14 @@ crate::gdb!();
// XX TODO actual jets
pub mod util {
- use crate::mug::mug_u32;
- use crate::unifying_equality::unifying_equality;
- use crate::mem::NockStack;
use crate::jets::math::util::lth_b;
use crate::jets::util::slot;
- use crate::noun::{Noun, D};
- use either::Either::*;
use crate::jets::JetErr;
+ use crate::mem::NockStack;
+ use crate::mug::mug_u32;
+ use crate::noun::{Noun, D};
+ use crate::unifying_equality::unifying_equality;
+ use either::Either::*;
pub fn dor_b(stack: &mut NockStack, a: &mut Noun, b: &mut Noun) -> bool {
let mut ap = a as *mut Noun;
@@ -38,10 +37,14 @@ pub mod util {
} else {
break true;
}
- },
+ }
Right(a_cell) => {
if let Ok(b_cell) = (*bp).as_cell() {
- if unifying_equality(stack, a_cell.head_as_mut(), b_cell.head_as_mut()) {
+ if unifying_equality(
+ stack,
+ a_cell.head_as_mut(),
+ b_cell.head_as_mut(),
+ ) {
ap = a_cell.tail_as_mut();
bp = b_cell.tail_as_mut();
continue;
@@ -70,7 +73,11 @@ pub mod util {
}
}
- pub fn get_by(stack: &mut NockStack, a: &mut Noun, b: &mut Noun) -> Result