diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 789f1a49..7a21a85a 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -20,3 +20,7 @@ workspace = true [features] vine = ["dep:vine", "dep:vine-lsp"] default = ["vine"] + +[[bin]] +name = "vine" +required-features = ["vine"] diff --git a/cli/src/common.rs b/cli/src/common.rs index 47b03d25..019a122a 100644 --- a/cli/src/common.rs +++ b/cli/src/common.rs @@ -27,24 +27,22 @@ pub struct RunArgs { impl RunArgs { pub fn run(self, nets: Nets) { - { - let mut host = &mut Host::default(); - let heap = Heap::new(); - let mut extrinsics = Extrinsics::default(); + let mut host = &mut Host::default(); + let heap = Heap::new(); + let mut extrinsics = Extrinsics::default(); - host.register_default_extrinsics(&mut extrinsics); - host.insert_nets(&nets); - let main = host.get("::main").expect("missing main"); - let mut ivm = IVM::new(&heap, &extrinsics); - ivm.boot(main, host.new_io()); - if self.workers > 0 { - ivm.normalize_parallel(self.workers) - } else { - ivm.normalize(); - } - if !self.no_stats { - eprintln!("{}", ivm.stats); - } + host.register_default_extrinsics(&mut extrinsics); + host.insert_nets(&nets); + let main = host.get("::main").expect("missing main"); + let mut ivm = IVM::new(&heap, &extrinsics); + ivm.boot(main, host.new_io()); + if self.workers > 0 { + ivm.normalize_parallel(self.workers) + } else { + ivm.normalize(); + } + if !self.no_stats { + eprintln!("{}", ivm.stats); } } } diff --git a/ivm/src/allocator.rs b/ivm/src/allocator.rs index 8f8d1cd5..cd30d9de 100644 --- a/ivm/src/allocator.rs +++ b/ivm/src/allocator.rs @@ -36,7 +36,7 @@ impl<'ivm> Allocator<'ivm> { } } -impl<'ext, 'ivm> IVM<'ext, 'ivm> { +impl<'ivm, 'ext> IVM<'ivm, 'ext> { /// Allocates a new binary node with a given `tag` and `label`. /// /// ## Safety diff --git a/ivm/src/ext.rs b/ivm/src/ext.rs index 9bfe8368..bc7a1296 100644 --- a/ivm/src/ext.rs +++ b/ivm/src/ext.rs @@ -6,203 +6,50 @@ use core::{ fmt::{self, Debug}, marker::PhantomData, - ops::{Add, Div, Mul, Sub}, -}; -use std::{ - collections::HashMap, - io::{self, Read, Write}, }; use crate::port::Tag; -macro_rules! define_ext_fns { - ($map:ident,$self:ident, $($name:expr => |$a:ident, $b: ident| $body:expr ),*) => { - $($map.insert($name.to_string(), $self.register_ext_fn(move |[$a, $b]| [$body]).unwrap());)* - }; -} #[derive(Default)] pub struct Extrinsics<'ivm> { ext_fns: Vec, ExtVal<'ivm>) -> ExtVal<'ivm> + Sync + 'ivm>>, - // amount of registered light exttys + // amount of registered light (unboxed) ext types light_ext_ty: u16, n32_ext_ty: Option>, - io_ext_ty: Option>, phantom: PhantomData &'ivm ()>, } impl<'ivm> Extrinsics<'ivm> { - pub const MAX_EXT_FN_KIND_COUNT: usize = 0x8FFF; - pub const MAX_LIGHT_EXT_TY_COUNT: usize = 0x8FFF; - pub const MAX_RC_EX_TTY_COUNT: usize = 0x8FFF; + pub const MAX_EXT_FN_KIND_COUNT: usize = 0x7FFF; + pub const MAX_LIGHT_EXT_TY_COUNT: usize = 0x7FFF; pub fn register_ext_fn( &mut self, f: impl Fn([ExtVal<'ivm>; 2]) -> [ExtVal<'ivm>; 1] + Sync + 'ivm, - ) -> Option> { + ) -> ExtFn<'ivm> { if self.ext_fns.len() >= Self::MAX_EXT_FN_KIND_COUNT { - None + panic!("IVM reached maximum amount of registered extrinsic functions."); } else { let ext_fn = ExtFn(self.ext_fns.len() as u16, PhantomData); self.ext_fns.push(Box::new(move |a, b| f([a, b])[0])); - Some(ext_fn) + ext_fn } } - pub fn register_light_ext_ty(&mut self) -> Option> { + pub fn register_light_ext_ty(&mut self) -> ExtTy<'ivm> { if self.light_ext_ty as usize >= Self::MAX_LIGHT_EXT_TY_COUNT { - None + panic!("IVM reached maximum amount of registered extrinsic unboxed types."); } else { let ext_ty = ExtTy::from_id_and_rc(self.light_ext_ty, false); self.light_ext_ty += 1; - Some(ext_ty) + ext_ty } } - /// Some extrinsics are built-in with IVM - pub fn register_builtin_extrinsics( - &mut self, - ) -> (HashMap>, HashMap>) { - let mut ext_fn_map = HashMap::new(); - let mut ext_ty_map = HashMap::new(); - let n32_ext_ty = self.register_light_ext_ty().expect("reached maximum amount of extrinsics!"); - let f32_ext_ty = self.register_light_ext_ty().expect("reached maximum amount of extrinsics!"); - let io_ext_ty = self.register_light_ext_ty().expect("reached maximum amount of extrinsics!"); - ext_ty_map.insert("N32".into(), n32_ext_ty); - ext_ty_map.insert("F32".into(), f32_ext_ty); - ext_ty_map.insert("IO".into(), io_ext_ty); - self.n32_ext_ty = Some(n32_ext_ty); - self.io_ext_ty = Some(io_ext_ty); - enum NumericType { - F32, - N32, - } - fn ty_to_numeric_type<'ivm>( - a: ExtVal<'ivm>, - n32_ext_ty: ExtTy<'ivm>, - f32_ext_ty: ExtTy<'ivm>, - ) -> Option { - if a.ty() == n32_ext_ty { - Some(NumericType::N32) - } else if a.ty() == f32_ext_ty { - Some(NumericType::F32) - } else { - None - } - } - fn numeric_op<'ivm>( - n32_ext_ty: ExtTy<'ivm>, - f32_ext_ty: ExtTy<'ivm>, - a: ExtVal<'ivm>, - b: ExtVal<'ivm>, - f_n32: fn(u32, u32) -> u32, - f_f32: fn(f32, f32) -> f32, - ) -> ExtVal<'ivm> { - match ( - ty_to_numeric_type(a, n32_ext_ty, f32_ext_ty), - ty_to_numeric_type(b, n32_ext_ty, f32_ext_ty), - ) { - (Some(NumericType::N32), Some(NumericType::N32)) => { - ExtVal::new(n32_ext_ty, f_n32(a.as_ty(&n32_ext_ty), b.as_ty(&n32_ext_ty))) - } - (Some(NumericType::F32), Some(NumericType::F32)) => ExtVal::new( - f32_ext_ty, - f_f32(f32::from_bits(a.as_ty(&f32_ext_ty)), f32::from_bits(b.as_ty(&f32_ext_ty))) - .to_bits(), - ), - (Some(NumericType::N32), Some(NumericType::F32)) => ExtVal::new( - f32_ext_ty, - f_f32(a.as_ty(&n32_ext_ty) as f32, f32::from_bits(b.as_ty(&f32_ext_ty))).to_bits(), - ), - (Some(NumericType::F32), Some(NumericType::N32)) => ExtVal::new( - f32_ext_ty, - f_f32(f32::from_bits(a.as_ty(&f32_ext_ty)), b.as_ty(&n32_ext_ty) as f32).to_bits(), - ), - _ => unimplemented!(), - } - } - - fn comparison<'ivm>( - n32_ext_ty: ExtTy<'ivm>, - f32_ext_ty: ExtTy<'ivm>, - a: ExtVal<'ivm>, - b: ExtVal<'ivm>, - f_u32: fn(u32, u32) -> bool, - f_f32: fn(f32, f32) -> bool, - ) -> ExtVal<'ivm> { - ExtVal::new( - n32_ext_ty, - u32::from( - match ( - ty_to_numeric_type(a, n32_ext_ty, f32_ext_ty), - ty_to_numeric_type(b, n32_ext_ty, f32_ext_ty), - ) { - (Some(NumericType::N32), Some(NumericType::N32)) => { - f_u32(a.as_ty(&n32_ext_ty), b.as_ty(&n32_ext_ty)) - } - (Some(NumericType::F32), Some(NumericType::F32)) => { - f_f32(f32::from_bits(a.as_ty(&f32_ext_ty)), f32::from_bits(b.as_ty(&f32_ext_ty))) - } - (Some(NumericType::N32), Some(NumericType::F32)) => { - f_f32(a.as_ty(&n32_ext_ty) as f32, f32::from_bits(b.as_ty(&f32_ext_ty))) - } - (Some(NumericType::F32), Some(NumericType::N32)) => { - f_f32(f32::from_bits(a.as_ty(&f32_ext_ty)), b.as_ty(&n32_ext_ty) as f32) - } - _ => unimplemented!(), - }, - ), - ) - } - define_ext_fns!(ext_fn_map, self, - "seq" => |a, _b| a, - - "add" => |a, b| numeric_op(n32_ext_ty, f32_ext_ty, a, b, u32::wrapping_add, f32::add), - "sub" => |a, b| numeric_op(n32_ext_ty, f32_ext_ty, a, b, u32::wrapping_sub, f32::sub), - "mul" => |a, b| numeric_op(n32_ext_ty, f32_ext_ty, a, b, u32::wrapping_mul, f32::mul), - "div" => |a, b| numeric_op(n32_ext_ty, f32_ext_ty, a, b, u32::wrapping_div, f32::div), - "rem" => |a, b| numeric_op(n32_ext_ty, f32_ext_ty, a, b, u32::wrapping_rem, f32::rem_euclid), - - "eq" => |a, b| comparison(n32_ext_ty, f32_ext_ty, a, b, |a, b| a == b, |a, b| a == b), - "ne" => |a, b| comparison(n32_ext_ty, f32_ext_ty, a, b, |a, b| a != b, |a, b| a != b), - "lt" => |a, b| comparison(n32_ext_ty, f32_ext_ty, a, b, |a, b| a < b, |a, b| a < b), - "le" => |a, b| comparison(n32_ext_ty, f32_ext_ty, a, b, |a, b| a <= b, |a, b| a <= b), - - "n32_shl" => |a, b| ExtVal::new(n32_ext_ty, a.as_ty(&n32_ext_ty).wrapping_shl(b.as_ty(&n32_ext_ty))), - "n32_shr" => |a, b| ExtVal::new(n32_ext_ty, a.as_ty(&n32_ext_ty).wrapping_shr(b.as_ty(&n32_ext_ty))), - "n32_rotl" => |a, b| ExtVal::new(n32_ext_ty, a.as_ty(&n32_ext_ty).rotate_left(b.as_ty(&n32_ext_ty))), - "n32_rotr" => |a, b| ExtVal::new(n32_ext_ty, a.as_ty(&n32_ext_ty).rotate_right(b.as_ty(&n32_ext_ty))), - - "n32_and" => |a, b| ExtVal::new(n32_ext_ty, a.as_ty(&n32_ext_ty) & b.as_ty(&n32_ext_ty)), - "n32_or" => |a, b| ExtVal::new(n32_ext_ty, a.as_ty(&n32_ext_ty) | b.as_ty(&n32_ext_ty)), - "n32_xor" => |a, b| ExtVal::new(n32_ext_ty, a.as_ty(&n32_ext_ty) ^ b.as_ty(&n32_ext_ty)), - - "n32_add_high" => |a, b| ExtVal::new(n32_ext_ty, (((a.as_ty(&n32_ext_ty) as u64) + (b.as_ty(&n32_ext_ty) as u64)) >> 32) as u32), - "n32_mul_high" => |a, b| ExtVal::new(n32_ext_ty, (((a.as_ty(&n32_ext_ty) as u64) * (b.as_ty(&n32_ext_ty) as u64)) >> 32) as u32), - - "io_print_char" => |a, b| { - a.as_ty(&io_ext_ty); - print!("{}", char::try_from(b.as_ty(&n32_ext_ty)).unwrap()); - ExtVal::new(io_ext_ty, 0) - }, - "io_print_byte" => |a, b| { - a.as_ty(&io_ext_ty); - io::stdout().write_all(&[b.as_ty(&n32_ext_ty) as u8]).unwrap(); - ExtVal::new(io_ext_ty, 0) - }, - "io_flush" => |a, _b| { - a.as_ty(&io_ext_ty); - io::stdout().flush().unwrap(); - ExtVal::new(io_ext_ty, 0) - }, - "io_read_byte" => |a, b| { - a.as_ty(&io_ext_ty); - let default = b.as_ty(&n32_ext_ty) as u8; - let mut buf = [default]; - _ = io::stdin().read(&mut buf).unwrap(); - ExtVal::new(n32_ext_ty, buf[0] as u32) - } - ); - (ext_fn_map, ext_ty_map) + pub fn register_n32_ext_ty(&mut self) -> ExtTy<'ivm> { + let n32_ext_ty = self.register_light_ext_ty(); + assert!(self.n32_ext_ty.replace(n32_ext_ty).is_none()); + n32_ext_ty } pub fn call( &self, diff --git a/ivm/src/instruction.rs b/ivm/src/instruction.rs index 5a1b9877..8cc10909 100644 --- a/ivm/src/instruction.rs +++ b/ivm/src/instruction.rs @@ -106,7 +106,7 @@ impl Debug for Register { } } -impl<'ext, 'ivm> IVM<'ext, 'ivm> { +impl<'ivm, 'ext> IVM<'ivm, 'ext> { /// Links the given `port` to the given `register`. /// /// ## Safety diff --git a/ivm/src/interact.rs b/ivm/src/interact.rs index 0e27d85d..f66e2957 100644 --- a/ivm/src/interact.rs +++ b/ivm/src/interact.rs @@ -13,7 +13,7 @@ macro_rules! sym { }; } -impl<'ext, 'ivm> IVM<'ext, 'ivm> { +impl<'ivm, 'ext> IVM<'ivm, 'ext> { /// Link two ports. pub fn link(&mut self, a: Port<'ivm>, b: Port<'ivm>) { use Tag::*; diff --git a/ivm/src/ivm.rs b/ivm/src/ivm.rs index 5fb02b38..1a52567d 100644 --- a/ivm/src/ivm.rs +++ b/ivm/src/ivm.rs @@ -10,7 +10,7 @@ use crate::{ }; /// An Interaction Virtual Machine. -pub struct IVM<'ext, 'ivm> { +pub struct IVM<'ivm, 'ext> { /// Execution statistics of this IVM. pub stats: Stats, @@ -30,7 +30,7 @@ pub struct IVM<'ext, 'ivm> { pub(crate) extrinsics: &'ext Extrinsics<'ivm>, } -impl<'ivm, 'ext> IVM<'ext, 'ivm> { +impl<'ivm, 'ext> IVM<'ivm, 'ext> { /// Creates a new IVM with a given heap. pub fn new(heap: &'ivm Heap, extrinsics: &'ext Extrinsics<'ivm>) -> Self { Self::new_from_allocator(Allocator::new(heap), extrinsics) diff --git a/ivm/src/parallel.rs b/ivm/src/parallel.rs index 18a98959..dda3c751 100644 --- a/ivm/src/parallel.rs +++ b/ivm/src/parallel.rs @@ -7,7 +7,7 @@ use std::{ use crate::{ivm::IVM, port::Port}; -impl<'ext, 'ivm> IVM<'ext, 'ivm> { +impl<'ivm, 'ext> IVM<'ivm, 'ext> { pub fn normalize_parallel(&mut self, threads: usize) { self.do_fast(); @@ -54,8 +54,8 @@ struct Msg<'ivm> { #[derive(Default)] #[repr(align(256))] -struct Shared<'ext, 'ivm> { - ivm_return: OnceLock>, +struct Shared<'ivm, 'ext> { + ivm_return: OnceLock>, msg: Mutex>, condvar: Condvar, } @@ -72,15 +72,15 @@ enum MsgKind { Exit, } -struct Worker<'w, 'ext, 'ivm> { - ivm: IVM<'ext, 'ivm>, - shared: &'w Shared<'ext, 'ivm>, +struct Worker<'w, 'ivm, 'ext> { + ivm: IVM<'ivm, 'ext>, + shared: &'w Shared<'ivm, 'ext>, dispatch: Thread, } const ERA_LENGTH: u32 = 512; -impl<'w, 'ext, 'ivm> Worker<'w, 'ext, 'ivm> { +impl<'w, 'ivm, 'ext> Worker<'w, 'ivm, 'ext> { fn execute(mut self) { self.work(); self.shared.ivm_return.set(self.ivm).ok().unwrap(); @@ -142,16 +142,16 @@ impl<'w, 'ext, 'ivm> Worker<'w, 'ext, 'ivm> { } } -struct WorkerHandle<'w, 'ext, 'ivm> { - shared: &'w Shared<'ext, 'ivm>, +struct WorkerHandle<'w, 'ivm, 'ext> { + shared: &'w Shared<'ivm, 'ext>, } -struct Dispatch<'w, 'ext, 'ivm> { - active: Vec>, - idle: Vec>, +struct Dispatch<'w, 'ivm, 'ext> { + active: Vec>, + idle: Vec>, } -impl<'w, 'ext, 'ivm> Dispatch<'w, 'ext, 'ivm> { +impl<'w, 'ivm, 'ext> Dispatch<'w, 'ivm, 'ext> { fn execute(mut self) { loop { let mut i = 0; diff --git a/ivy/src/host.rs b/ivy/src/host.rs index b68a643d..778007ad 100644 --- a/ivy/src/host.rs +++ b/ivy/src/host.rs @@ -6,10 +6,11 @@ use indexmap::{ }; use ivm::{ - ext::{ExtFn, ExtTy, ExtVal, Extrinsics}, + ext::{ExtFn, ExtTy, ExtVal}, global::Global, }; +mod ext; mod readback; mod serialize; @@ -37,17 +38,6 @@ pub struct Host<'ivm> { } impl<'ivm> Host<'ivm> { - pub fn register_default_extrinsics(&mut self, extrinsics: &mut Extrinsics<'ivm>) { - let (fns, tys) = extrinsics.register_builtin_extrinsics(); - for (k, v) in tys { - self.ext_tys.insert(k.clone(), v); - self.reverse_ext_tys.insert(v, k); - } - for (k, v) in fns { - self.ext_fns.insert(k.clone(), v); - self.reverse_ext_fns.insert(v, k); - } - } pub fn get(&self, name: &str) -> Option<&'ivm Global<'ivm>> { Some(unsafe { &**self.globals.get(name)? }) } diff --git a/ivy/src/host/ext.rs b/ivy/src/host/ext.rs new file mode 100644 index 00000000..5672f7c7 --- /dev/null +++ b/ivy/src/host/ext.rs @@ -0,0 +1,157 @@ +use super::Host; +use core::ops::{Add, Div, Mul, Sub}; +use ivm::ext::{ExtFn, ExtTy, ExtVal, Extrinsics}; +use std::io::{self, Read, Write}; +macro_rules! define_ext_fns { + ($self:ident,$ext:ident, $($name:expr => |$a:ident, $b: ident| $body:expr ),*) => { + $($self.register_ext_fn($name.into(), $ext.register_ext_fn(move |[$a, $b]| [$body]));)* + }; +} +impl<'ivm> Host<'ivm> { + pub fn register_ext_fn(&mut self, name: String, ty: ExtFn<'ivm>) { + self.ext_fns.insert(name.clone(), ty); + self.reverse_ext_fns.insert(ty, name); + } + pub fn register_ext_ty(&mut self, name: String, ty: ExtTy<'ivm>) { + self.ext_tys.insert(name.clone(), ty); + self.reverse_ext_tys.insert(ty, name); + } + pub fn register_default_extrinsics(&mut self, extrinsics: &mut Extrinsics<'ivm>) { + let n32_ext_ty = extrinsics.register_n32_ext_ty(); + let f32_ext_ty = extrinsics.register_light_ext_ty(); + let io_ext_ty = extrinsics.register_light_ext_ty(); + self.register_ext_ty("N32".into(), n32_ext_ty); + self.register_ext_ty("F32".into(), f32_ext_ty); + self.register_ext_ty("IO".into(), io_ext_ty); + define_ext_fns!(self, extrinsics, + "seq" => |a, _b| a, + + "add" => |a, b| numeric_op(n32_ext_ty, f32_ext_ty, a, b, u32::wrapping_add, f32::add), + "sub" => |a, b| numeric_op(n32_ext_ty, f32_ext_ty, a, b, u32::wrapping_sub, f32::sub), + "mul" => |a, b| numeric_op(n32_ext_ty, f32_ext_ty, a, b, u32::wrapping_mul, f32::mul), + "div" => |a, b| numeric_op(n32_ext_ty, f32_ext_ty, a, b, u32::wrapping_div, f32::div), + "rem" => |a, b| numeric_op(n32_ext_ty, f32_ext_ty, a, b, u32::wrapping_rem, f32::rem_euclid), + + "eq" => |a, b| comparison(n32_ext_ty, f32_ext_ty, a, b, |a, b| a == b, |a, b| a == b), + "ne" => |a, b| comparison(n32_ext_ty, f32_ext_ty, a, b, |a, b| a != b, |a, b| a != b), + "lt" => |a, b| comparison(n32_ext_ty, f32_ext_ty, a, b, |a, b| a < b, |a, b| a < b), + "le" => |a, b| comparison(n32_ext_ty, f32_ext_ty, a, b, |a, b| a <= b, |a, b| a <= b), + + "n32_shl" => |a, b| ExtVal::new(n32_ext_ty, a.as_ty(&n32_ext_ty).wrapping_shl(b.as_ty(&n32_ext_ty))), + "n32_shr" => |a, b| ExtVal::new(n32_ext_ty, a.as_ty(&n32_ext_ty).wrapping_shr(b.as_ty(&n32_ext_ty))), + "n32_rotl" => |a, b| ExtVal::new(n32_ext_ty, a.as_ty(&n32_ext_ty).rotate_left(b.as_ty(&n32_ext_ty))), + "n32_rotr" => |a, b| ExtVal::new(n32_ext_ty, a.as_ty(&n32_ext_ty).rotate_right(b.as_ty(&n32_ext_ty))), + + "n32_and" => |a, b| ExtVal::new(n32_ext_ty, a.as_ty(&n32_ext_ty) & b.as_ty(&n32_ext_ty)), + "n32_or" => |a, b| ExtVal::new(n32_ext_ty, a.as_ty(&n32_ext_ty) | b.as_ty(&n32_ext_ty)), + "n32_xor" => |a, b| ExtVal::new(n32_ext_ty, a.as_ty(&n32_ext_ty) ^ b.as_ty(&n32_ext_ty)), + + "n32_add_high" => |a, b| ExtVal::new(n32_ext_ty, (((a.as_ty(&n32_ext_ty) as u64) + (b.as_ty(&n32_ext_ty) as u64)) >> 32) as u32), + "n32_mul_high" => |a, b| ExtVal::new(n32_ext_ty, (((a.as_ty(&n32_ext_ty) as u64) * (b.as_ty(&n32_ext_ty) as u64)) >> 32) as u32), + + "io_print_char" => |a, b| { + a.as_ty(&io_ext_ty); + print!("{}", char::try_from(b.as_ty(&n32_ext_ty)).unwrap()); + ExtVal::new(io_ext_ty, 0) + }, + "io_print_byte" => |a, b| { + a.as_ty(&io_ext_ty); + io::stdout().write_all(&[b.as_ty(&n32_ext_ty) as u8]).unwrap(); + ExtVal::new(io_ext_ty, 0) + }, + "io_flush" => |a, _b| { + a.as_ty(&io_ext_ty); + io::stdout().flush().unwrap(); + ExtVal::new(io_ext_ty, 0) + }, + "io_read_byte" => |a, b| { + a.as_ty(&io_ext_ty); + let default = b.as_ty(&n32_ext_ty) as u8; + let mut buf = [default]; + _ = io::stdin().read(&mut buf).unwrap(); + ExtVal::new(n32_ext_ty, buf[0] as u32) + } + ); + enum NumericType { + F32, + N32, + } + fn ty_to_numeric_type<'ivm>( + a: ExtVal<'ivm>, + n32_ext_ty: ExtTy<'ivm>, + f32_ext_ty: ExtTy<'ivm>, + ) -> Option { + if a.ty() == n32_ext_ty { + Some(NumericType::N32) + } else if a.ty() == f32_ext_ty { + Some(NumericType::F32) + } else { + None + } + } + fn numeric_op<'ivm>( + n32_ext_ty: ExtTy<'ivm>, + f32_ext_ty: ExtTy<'ivm>, + a: ExtVal<'ivm>, + b: ExtVal<'ivm>, + f_n32: fn(u32, u32) -> u32, + f_f32: fn(f32, f32) -> f32, + ) -> ExtVal<'ivm> { + match ( + ty_to_numeric_type(a, n32_ext_ty, f32_ext_ty), + ty_to_numeric_type(b, n32_ext_ty, f32_ext_ty), + ) { + (Some(NumericType::N32), Some(NumericType::N32)) => { + ExtVal::new(n32_ext_ty, f_n32(a.as_ty(&n32_ext_ty), b.as_ty(&n32_ext_ty))) + } + (Some(NumericType::F32), Some(NumericType::F32)) => ExtVal::new( + f32_ext_ty, + f_f32(f32::from_bits(a.as_ty(&f32_ext_ty)), f32::from_bits(b.as_ty(&f32_ext_ty))) + .to_bits(), + ), + (Some(NumericType::N32), Some(NumericType::F32)) => ExtVal::new( + f32_ext_ty, + f_f32(a.as_ty(&n32_ext_ty) as f32, f32::from_bits(b.as_ty(&f32_ext_ty))).to_bits(), + ), + (Some(NumericType::F32), Some(NumericType::N32)) => ExtVal::new( + f32_ext_ty, + f_f32(f32::from_bits(a.as_ty(&f32_ext_ty)), b.as_ty(&n32_ext_ty) as f32).to_bits(), + ), + _ => unimplemented!(), + } + } + + fn comparison<'ivm>( + n32_ext_ty: ExtTy<'ivm>, + f32_ext_ty: ExtTy<'ivm>, + a: ExtVal<'ivm>, + b: ExtVal<'ivm>, + f_u32: fn(u32, u32) -> bool, + f_f32: fn(f32, f32) -> bool, + ) -> ExtVal<'ivm> { + ExtVal::new( + n32_ext_ty, + u32::from( + match ( + ty_to_numeric_type(a, n32_ext_ty, f32_ext_ty), + ty_to_numeric_type(b, n32_ext_ty, f32_ext_ty), + ) { + (Some(NumericType::N32), Some(NumericType::N32)) => { + f_u32(a.as_ty(&n32_ext_ty), b.as_ty(&n32_ext_ty)) + } + (Some(NumericType::F32), Some(NumericType::F32)) => { + f_f32(f32::from_bits(a.as_ty(&f32_ext_ty)), f32::from_bits(b.as_ty(&f32_ext_ty))) + } + (Some(NumericType::N32), Some(NumericType::F32)) => { + f_f32(a.as_ty(&n32_ext_ty) as f32, f32::from_bits(b.as_ty(&f32_ext_ty))) + } + (Some(NumericType::F32), Some(NumericType::N32)) => { + f_f32(f32::from_bits(a.as_ty(&f32_ext_ty)), b.as_ty(&n32_ext_ty) as f32) + } + _ => unimplemented!(), + }, + ), + ) + } + } +} diff --git a/ivy/src/host/readback.rs b/ivy/src/host/readback.rs index dbf21ed9..e749b487 100644 --- a/ivy/src/host/readback.rs +++ b/ivy/src/host/readback.rs @@ -10,20 +10,20 @@ use ivm::{ use crate::{ast::Tree, host::Host}; impl<'ivm> Host<'ivm> { - pub fn read<'ext>(&self, ivm: &IVM<'ext, 'ivm>, port: &Port<'ivm>) -> Tree { + pub fn read<'ext>(&self, ivm: &IVM<'ivm, 'ext>, port: &Port<'ivm>) -> Tree { Reader::new(ivm, self).read_port(port) } } -struct Reader<'ctx, 'ext, 'ivm> { - ivm: &'ctx IVM<'ext, 'ivm>, +struct Reader<'ctx, 'ivm, 'ext> { + ivm: &'ctx IVM<'ivm, 'ext>, host: &'ctx Host<'ivm>, vars: HashMap, next_var: usize, } -impl<'ctx, 'ext, 'ivm> Reader<'ctx, 'ext, 'ivm> { - fn new(ivm: &'ctx IVM<'ext, 'ivm>, host: &'ctx Host<'ivm>) -> Self { +impl<'ctx, 'ivm, 'ext> Reader<'ctx, 'ivm, 'ext> { + fn new(ivm: &'ctx IVM<'ivm, 'ext>, host: &'ctx Host<'ivm>) -> Self { Reader { ivm, host, vars: HashMap::new(), next_var: 0 } } diff --git a/ivy/src/repl.rs b/ivy/src/repl.rs index 15e17e53..bb7e33ef 100644 --- a/ivy/src/repl.rs +++ b/ivy/src/repl.rs @@ -14,14 +14,14 @@ use crate::{ parser::{IvyParser, ParseError}, }; -pub struct Repl<'host, 'ctx, 'ext, 'ivm> { +pub struct Repl<'host, 'ctx, 'ivm, 'ext> { pub host: &'host mut Host<'ivm>, - pub ivm: &'ctx mut IVM<'ext, 'ivm>, + pub ivm: &'ctx mut IVM<'ivm, 'ext>, pub vars: IndexMap>, } -impl<'host, 'ctx, 'ext, 'ivm> Repl<'host, 'ctx, 'ext, 'ivm> { - pub fn new(host: &'host mut Host<'ivm>, ivm: &'ctx mut IVM<'ext, 'ivm>) -> Self { +impl<'host, 'ctx, 'ivm, 'ext> Repl<'host, 'ctx, 'ivm, 'ext> { + pub fn new(host: &'host mut Host<'ivm>, ivm: &'ctx mut IVM<'ivm, 'ext>) -> Self { let vars = [("io".to_owned(), Port::new_ext_val(host.new_io()))].into_iter().collect(); Self { host, ivm, vars } } diff --git a/vine/src/repl.rs b/vine/src/repl.rs index 9c9aa849..87a55dcf 100644 --- a/vine/src/repl.rs +++ b/vine/src/repl.rs @@ -35,9 +35,9 @@ use crate::{ visit::VisitMut, }; -pub struct Repl<'core, 'ctx, 'ext, 'ivm> { +pub struct Repl<'core, 'ctx, 'ivm, 'ext> { host: &'ivm mut Host<'ivm>, - ivm: &'ctx mut IVM<'ext, 'ivm>, + ivm: &'ctx mut IVM<'ivm, 'ext>, core: &'core Core<'core>, compiler: Compiler<'core>, repl_mod: DefId, @@ -56,10 +56,10 @@ struct Var<'ivm> { space: Port<'ivm>, } -impl<'core, 'ctx, 'ext, 'ivm> Repl<'core, 'ctx, 'ext, 'ivm> { +impl<'core, 'ctx, 'ivm, 'ext> Repl<'core, 'ctx, 'ivm, 'ext> { pub fn new( mut host: &'ivm mut Host<'ivm>, - ivm: &'ctx mut IVM<'ext, 'ivm>, + ivm: &'ctx mut IVM<'ivm, 'ext>, core: &'core Core<'core>, libs: Vec, ) -> Result { @@ -135,10 +135,10 @@ impl<'core, 'ctx, 'ext, 'ivm> Repl<'core, 'ctx, 'ext, 'ivm> { name: &mut name, })?; - struct ExecHooks<'core, 'ext, 'ivm, 'a> { + struct ExecHooks<'core, 'ivm, 'ext, 'a> { repl_mod: DefId, vars: &'a mut HashMap, Var<'ivm>>, - ivm: &'a mut IVM<'ext, 'ivm>, + ivm: &'a mut IVM<'ivm, 'ext>, locals: &'a mut BTreeMap>, block: &'a mut Block<'core>, unifier: &'a mut Unifier<'core>,