initial poc
This commit is contained in:
commit
9f16fef6c2
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
target
|
1060
Cargo.lock
generated
Normal file
1060
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
7
Cargo.toml
Normal file
7
Cargo.toml
Normal file
|
@ -0,0 +1,7 @@
|
|||
[workspace]
|
||||
members=[ "wars", "wars-macro","wars-rt", "wars-test"]
|
||||
resolver="2"
|
||||
|
||||
[workspace.dependencies]
|
||||
|
||||
portal-pc-waffle = {git="https://github.com/portal-co/waffle-.git",branch="pr/changes2"}
|
19
wars-macro/Cargo.toml
Normal file
19
wars-macro/Cargo.toml
Normal file
|
@ -0,0 +1,19 @@
|
|||
[package]
|
||||
name = "wars-macro"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
expander = {version="2.1.0",features=["pretty"]}
|
||||
proc-macro2 = "1.0.85"
|
||||
quote = "1.0.36"
|
||||
syn = "2.0.66"
|
||||
wars = { version = "0.1.0", path = "../wars" }
|
||||
wars-rt = { version = "0.1.0", path = "../wars-rt" }
|
||||
wat = "1.209.1"
|
||||
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
94
wars-macro/src/lib.rs
Normal file
94
wars-macro/src/lib.rs
Normal file
|
@ -0,0 +1,94 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use expander::{Edition, Expander};
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro2::Span;
|
||||
use quote::quote;
|
||||
use syn::{parse::Parse, parse_macro_input, Ident, Path, Token};
|
||||
use wars::Opts;
|
||||
|
||||
struct O {
|
||||
pub crate_path: syn::Path,
|
||||
pub module: Vec<u8>,
|
||||
pub name: Ident,
|
||||
// pub cfg: Arc<dyn ImportCfg>,
|
||||
}
|
||||
// struct NoopCfg {}
|
||||
// impl ImportCfg for NoopCfg {
|
||||
// fn import(&self, module: &str, name: &str) -> proc_macro2::TokenStream {
|
||||
// quote! {
|
||||
// compile_error!("import used")
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
impl Parse for O {
|
||||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||
let mut o = O {
|
||||
crate_path: syn::parse(quote! {::wars_rt}.into())?,
|
||||
module: vec![],
|
||||
name: Ident::new("Wars", Span::call_site()),
|
||||
// cfg: Arc::new(NoopCfg {}),
|
||||
};
|
||||
while input.lookahead1().peek(Ident) {
|
||||
let i: Ident = input.parse()?;
|
||||
let _eq: Token![=] = input.parse()?;
|
||||
match i.to_string().as_str() {
|
||||
"crate_path" => {
|
||||
let s: syn::LitStr = input.parse()?;
|
||||
o.crate_path = s.parse()?;
|
||||
}
|
||||
"env" => {
|
||||
let s: syn::LitStr = input.parse()?;
|
||||
let sp = s.span();
|
||||
let s = std::env::var(s.value()).map_err(|x| syn::Error::new(sp, x))?;
|
||||
let x = std::fs::read(s).map_err(|x| syn::Error::new(sp, x))?;
|
||||
o.module = x;
|
||||
}
|
||||
"file" => {
|
||||
let s: syn::LitStr = input.parse()?;
|
||||
let sp = s.span();
|
||||
let x = std::fs::read(s.value()).map_err(|x| syn::Error::new(sp, x))?;
|
||||
o.module = x;
|
||||
}
|
||||
"inline" => {
|
||||
let s: syn::LitStr = input.parse()?;
|
||||
let sp = s.span();
|
||||
let x = wat::parse_str(&s.value()).map_err(|x| syn::Error::new(sp, x))?;
|
||||
o.module = x;
|
||||
}
|
||||
"name" => {
|
||||
o.name = input.parse()?;
|
||||
}
|
||||
_ => return Err(syn::Error::new(i.span(), "unexpected type")),
|
||||
};
|
||||
let _comma: Token![,] = input.parse()?;
|
||||
}
|
||||
// while input.lookahead1().peek(Token![;]){
|
||||
// let _semi: Token![;] = input.parse()?;
|
||||
// }
|
||||
Ok(o)
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn wars(a: TokenStream) -> TokenStream {
|
||||
let o = parse_macro_input!(a as O);
|
||||
let x = wars::go(&Opts {
|
||||
crate_path: o.crate_path,
|
||||
module: o.module,
|
||||
name: o.name,
|
||||
// cfg: o.cfg,
|
||||
});
|
||||
let expanded = Expander::new("wars")
|
||||
.add_comment("This is generated code!".to_owned())
|
||||
.fmt(Edition::_2021)
|
||||
.verbose(true)
|
||||
// common way of gating this, by making it part of the default feature set
|
||||
.dry(cfg!(feature = "no-file-expansion"))
|
||||
.write_to_out_dir(x.clone())
|
||||
.unwrap_or_else(|e| {
|
||||
eprintln!("Failed to write to file: {:?}", e);
|
||||
x
|
||||
});
|
||||
expanded.into()
|
||||
}
|
18
wars-macro/tests/a.rs
Normal file
18
wars-macro/tests/a.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
wars_macro::wars!(
|
||||
inline = "
|
||||
(module
|
||||
(func (result i32) call 2 call 1)
|
||||
(func (result i32)
|
||||
i32.const 0
|
||||
(if
|
||||
(then i32.const 0
|
||||
return_call 0
|
||||
)
|
||||
(else i32.const 1)
|
||||
)
|
||||
)
|
||||
(func)
|
||||
)
|
||||
|
||||
",
|
||||
);
|
7
wars-macro/tests/b.rs
Normal file
7
wars-macro/tests/b.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
wars_macro::wars!(
|
||||
file = "target/wasm32-unknown-unknown/debug/wars_test.wasm",
|
||||
);
|
||||
|
||||
fn x<A: Wars>(){
|
||||
|
||||
}
|
54108
wars-macro/tests/out.rs.x
Normal file
54108
wars-macro/tests/out.rs.x
Normal file
File diff suppressed because it is too large
Load diff
54224
wars-macro/tests/out.rs.y
Normal file
54224
wars-macro/tests/out.rs.y
Normal file
File diff suppressed because it is too large
Load diff
14
wars-rt/Cargo.toml
Normal file
14
wars-rt/Cargo.toml
Normal file
|
@ -0,0 +1,14 @@
|
|||
[package]
|
||||
name = "wars-rt"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.86"
|
||||
castaway = "0.2.2"
|
||||
derive_more = "0.99.17"
|
||||
paste = "1.0.15"
|
||||
tramp = "0.3.0"
|
||||
tuple_list = "0.1.3"
|
202
wars-rt/src/func.rs
Normal file
202
wars-rt/src/func.rs
Normal file
|
@ -0,0 +1,202 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use anyhow::Context;
|
||||
use tramp::{tramp, BorrowRec, Thunk};
|
||||
pub trait CtxSpec: Sized {
|
||||
type ExternRef: Clone;
|
||||
}
|
||||
pub enum Value<C: CtxSpec> {
|
||||
I32(u32),
|
||||
I64(u64),
|
||||
F32(f32),
|
||||
F64(f64),
|
||||
FunRef(
|
||||
Arc<
|
||||
dyn for<'a> Fn(
|
||||
&'a mut C,
|
||||
Vec<Value<C>>,
|
||||
) -> tramp::BorrowRec<'a, anyhow::Result<Vec<Value<C>>>>
|
||||
+ 'static,
|
||||
>,
|
||||
),
|
||||
Null,
|
||||
ExRef(C::ExternRef),
|
||||
}
|
||||
pub fn call_ref<'a, A: CoeVec<C> + 'static, B: CoeVec<C> + 'static, C: CtxSpec + 'static>(
|
||||
ctx: &'a mut C,
|
||||
go: Df<A,B,C>,
|
||||
a: A,
|
||||
) -> tramp::BorrowRec<'a, anyhow::Result<B>> {
|
||||
// let go: Df<A, B, C> = cast(go);
|
||||
go(ctx, a)
|
||||
}
|
||||
|
||||
impl<C: CtxSpec> Clone for Value<C> {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Self::I32(arg0) => Self::I32(arg0.clone()),
|
||||
Self::I64(arg0) => Self::I64(arg0.clone()),
|
||||
Self::F32(arg0) => Self::F32(arg0.clone()),
|
||||
Self::F64(arg0) => Self::F64(arg0.clone()),
|
||||
Self::FunRef(arg0) => Self::FunRef(arg0.clone()),
|
||||
Self::Null => Self::Null,
|
||||
Self::ExRef(e) => Self::ExRef(e.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
pub trait Coe<C: CtxSpec>: Sized {
|
||||
fn coe(self) -> Value<C>;
|
||||
fn uncoe(x: Value<C>) -> anyhow::Result<Self>;
|
||||
}
|
||||
pub fn cast<A: Coe<C> + 'static, B: Coe<C> + 'static, C: CtxSpec>(a: A) -> B {
|
||||
let a = match castaway::cast!(a, B) {
|
||||
Ok(b) => return b,
|
||||
Err(a) => a,
|
||||
};
|
||||
B::uncoe(A::coe(a)).unwrap()
|
||||
}
|
||||
impl<C: CtxSpec> Coe<C> for Value<C> {
|
||||
fn coe(self) -> Value<C> {
|
||||
self
|
||||
}
|
||||
|
||||
fn uncoe(x: Value<C>) -> anyhow::Result<Self> {
|
||||
Ok(x)
|
||||
}
|
||||
}
|
||||
impl<C: CtxSpec, D: Coe<C>> Coe<C> for Option<D> {
|
||||
fn coe(self) -> Value<C> {
|
||||
match self {
|
||||
None => Value::Null,
|
||||
Some(d) => d.coe(),
|
||||
}
|
||||
}
|
||||
|
||||
fn uncoe(x: Value<C>) -> anyhow::Result<Self> {
|
||||
if let Value::Null = x {
|
||||
return Ok(None);
|
||||
}
|
||||
return Ok(Some(D::uncoe(x)?));
|
||||
}
|
||||
}
|
||||
macro_rules! coe_impl_prim {
|
||||
($a:tt in $b:ident) => {
|
||||
impl<C: CtxSpec> Coe<C> for $a {
|
||||
fn coe(self) -> Value<C> {
|
||||
Value::$b(self)
|
||||
}
|
||||
fn uncoe(x: Value<C>) -> anyhow::Result<Self> {
|
||||
match x {
|
||||
Value::$b(a) => Ok(a),
|
||||
_ => anyhow::bail!("invalid type"),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
coe_impl_prim!(u32 in I32);
|
||||
coe_impl_prim!(u64 in I64);
|
||||
coe_impl_prim!(f32 in F32);
|
||||
coe_impl_prim!(f64 in F64);
|
||||
pub trait CoeVec<C: CtxSpec>: Sized {
|
||||
fn coe(self) -> Vec<Value<C>>;
|
||||
fn uncoe(a: Vec<Value<C>>) -> anyhow::Result<Self>;
|
||||
}
|
||||
impl<C: CtxSpec> CoeVec<C> for () {
|
||||
fn coe(self) -> Vec<Value<C>> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn uncoe(a: Vec<Value<C>>) -> anyhow::Result<Self> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl<C: CtxSpec, A: Coe<C>, B: CoeVec<C>> CoeVec<C> for (A, B) {
|
||||
fn coe(self) -> Vec<Value<C>> {
|
||||
let mut a = self.1.coe();
|
||||
a.push(self.0.coe());
|
||||
return a;
|
||||
}
|
||||
|
||||
fn uncoe(mut a: Vec<Value<C>>) -> anyhow::Result<Self> {
|
||||
let Some(x) = a.pop() else {
|
||||
anyhow::bail!("list too small")
|
||||
};
|
||||
let y = A::uncoe(x).context("invalid item (note coe lists are REVERSED)")?;
|
||||
let z = B::uncoe(a)?;
|
||||
Ok((y, z))
|
||||
}
|
||||
}
|
||||
pub fn map_rec<'a, T: 'a, U>(
|
||||
r: BorrowRec<'a, T>,
|
||||
go: impl FnOnce(T) -> U + 'a,
|
||||
) -> BorrowRec<'a, U> {
|
||||
match r {
|
||||
BorrowRec::Ret(a) => BorrowRec::Ret(go(a)),
|
||||
BorrowRec::Call(t) => BorrowRec::Call(Thunk::new(move || {
|
||||
let t = t.compute();
|
||||
map_rec(t, go)
|
||||
})),
|
||||
}
|
||||
}
|
||||
pub type Df<A, B, C> =
|
||||
Arc<dyn for<'a> Fn(&'a mut C, A) -> tramp::BorrowRec<'a, anyhow::Result<B>> + 'static>;
|
||||
|
||||
pub fn da<
|
||||
A,
|
||||
B,
|
||||
C,
|
||||
F: for<'a> Fn(&'a mut C, A) -> tramp::BorrowRec<'a, anyhow::Result<B>> + 'static,
|
||||
>(
|
||||
f: F,
|
||||
) -> Df<A,B,C> {
|
||||
Arc::new(f)
|
||||
}
|
||||
|
||||
impl<C: CtxSpec + 'static, A: CoeVec<C> + 'static, B: CoeVec<C> + 'static> Coe<C> for Df<A, B, C> {
|
||||
fn coe(self) -> Value<C> {
|
||||
pub fn x<
|
||||
C: CtxSpec,
|
||||
T: for<'a> Fn(
|
||||
&'a mut C,
|
||||
Vec<Value<C>>,
|
||||
) -> tramp::BorrowRec<'a, anyhow::Result<Vec<Value<C>>>>
|
||||
+ 'static,
|
||||
>(
|
||||
a: T,
|
||||
) -> T {
|
||||
return a;
|
||||
}
|
||||
Value::FunRef(Arc::new(x(move |ctx, x| {
|
||||
let x = match A::uncoe(x) {
|
||||
Ok(x) => x,
|
||||
Err(e) => return BorrowRec::Ret(Err(e)),
|
||||
};
|
||||
let x = self(ctx, x);
|
||||
map_rec(x, |a| a.map(|b| b.coe()))
|
||||
})))
|
||||
}
|
||||
|
||||
fn uncoe(x: Value<C>) -> anyhow::Result<Self> {
|
||||
let Value::FunRef(x) = x else {
|
||||
anyhow::bail!("invalid value")
|
||||
};
|
||||
Ok(Arc::new(move |ctx, a| {
|
||||
let v = a.coe();
|
||||
let v = x(ctx, v);
|
||||
map_rec(v, |a| a.and_then(B::uncoe))
|
||||
}))
|
||||
}
|
||||
}
|
||||
pub trait Call<A, B, C>:
|
||||
for<'a> Fn(&'a mut C, A) -> tramp::BorrowRec<'a, anyhow::Result<B>> + 'static
|
||||
{
|
||||
fn call(&self, c: &mut C, a: A) -> anyhow::Result<B>;
|
||||
}
|
||||
impl<A, B, C, T: for<'a> Fn(&'a mut C, A) -> tramp::BorrowRec<'a, anyhow::Result<B>> + 'static>
|
||||
Call<A, B, C> for T
|
||||
{
|
||||
fn call(&self, c: &mut C, a: A) -> anyhow::Result<B> {
|
||||
tramp((self)(c, a))
|
||||
}
|
||||
}
|
203
wars-rt/src/lib.rs
Normal file
203
wars-rt/src/lib.rs
Normal file
|
@ -0,0 +1,203 @@
|
|||
pub mod func;
|
||||
use func::CtxSpec;
|
||||
pub use func::Value;
|
||||
|
||||
pub mod _rexport {
|
||||
pub use anyhow;
|
||||
pub use tramp;
|
||||
pub use tuple_list;
|
||||
}
|
||||
macro_rules! int_ty{
|
||||
($int:ty => $p:ident) => {
|
||||
paste::paste!{
|
||||
pub fn [<$p add>](a: $int, b: $int) -> anyhow::Result<tuple_list::tuple_list_type!($int)> {
|
||||
Ok(tuple_list::tuple_list!(a.wrapping_add(b)))
|
||||
}
|
||||
pub fn [<$p mul>](a: $int, b: $int) -> anyhow::Result<tuple_list::tuple_list_type!($int)> {
|
||||
Ok(tuple_list::tuple_list!(a.wrapping_mul(b)))
|
||||
}
|
||||
pub fn [<$p and>](a: $int, b: $int) -> anyhow::Result<tuple_list::tuple_list_type!($int)> {
|
||||
Ok(tuple_list::tuple_list!(a & b))
|
||||
}
|
||||
pub fn [<$p or>](a: $int, b: $int) -> anyhow::Result<tuple_list::tuple_list_type!($int)> {
|
||||
Ok(tuple_list::tuple_list!(a | b))
|
||||
}
|
||||
pub fn [<$p xor>](a: $int, b: $int) -> anyhow::Result<tuple_list::tuple_list_type!($int)> {
|
||||
Ok(tuple_list::tuple_list!(a ^ b))
|
||||
}
|
||||
pub fn [<$p shl>](a: $int, b: $int) -> anyhow::Result<tuple_list::tuple_list_type!($int)> {
|
||||
Ok(tuple_list::tuple_list!(a << b))
|
||||
}
|
||||
pub fn [<$p shru>](a: $int, b: $int) -> anyhow::Result<tuple_list::tuple_list_type!($int)> {
|
||||
Ok(tuple_list::tuple_list!(a >> b))
|
||||
}
|
||||
pub fn [<$p divu>](a: $int, b: $int) -> anyhow::Result<tuple_list::tuple_list_type!($int)> {
|
||||
Ok(tuple_list::tuple_list!(a / b))
|
||||
}
|
||||
pub fn [<$p rotl>](a: $int, b: $int) -> anyhow::Result<tuple_list::tuple_list_type!($int)> {
|
||||
Ok(tuple_list::tuple_list!(a.rotate_left((b & 0xffffffff) as u32)))
|
||||
}
|
||||
pub fn [<$p clz>](a: $int) -> anyhow::Result<tuple_list::tuple_list_type!($int)> {
|
||||
Ok(tuple_list::tuple_list!(a.leading_zeros() as $int))
|
||||
}
|
||||
pub fn [<$p ctz>](a: $int) -> anyhow::Result<tuple_list::tuple_list_type!($int)> {
|
||||
Ok(tuple_list::tuple_list!(a.trailing_zeros() as $int))
|
||||
}
|
||||
//comparisons
|
||||
pub fn [<$p eqz>](a: $int) -> anyhow::Result<tuple_list::tuple_list_type!(u32)> {
|
||||
Ok(tuple_list::tuple_list!(if a == 0{
|
||||
1
|
||||
}else{
|
||||
0
|
||||
}))
|
||||
}
|
||||
pub fn [<$p eq>](a: $int, b: $int) -> anyhow::Result<tuple_list::tuple_list_type!(u32)> {
|
||||
Ok(tuple_list::tuple_list!(if a == b{
|
||||
1
|
||||
}else{
|
||||
0
|
||||
}))
|
||||
}
|
||||
pub fn [<$p ne>](a: $int, b: $int) -> anyhow::Result<tuple_list::tuple_list_type!(u32)> {
|
||||
Ok(tuple_list::tuple_list!(if a != b{
|
||||
1
|
||||
}else{
|
||||
0
|
||||
}))
|
||||
}
|
||||
pub fn [<$p ltu>](a: $int, b: $int) -> anyhow::Result<tuple_list::tuple_list_type!(u32)> {
|
||||
Ok(tuple_list::tuple_list!(if a < b{
|
||||
1
|
||||
}else{
|
||||
0
|
||||
}))
|
||||
}
|
||||
pub fn [<$p gtu>](a: $int, b: $int) -> anyhow::Result<tuple_list::tuple_list_type!(u32)> {
|
||||
Ok(tuple_list::tuple_list!(if a > b{
|
||||
1
|
||||
}else{
|
||||
0
|
||||
}))
|
||||
}
|
||||
pub fn [<$p leu>](a: $int, b: $int) -> anyhow::Result<tuple_list::tuple_list_type!(u32)> {
|
||||
Ok(tuple_list::tuple_list!(if a <= b{
|
||||
1
|
||||
}else{
|
||||
0
|
||||
}))
|
||||
}
|
||||
pub fn [<$p geu>](a: $int, b: $int) -> anyhow::Result<tuple_list::tuple_list_type!(u32)> {
|
||||
Ok(tuple_list::tuple_list!(if a >= b{
|
||||
1
|
||||
}else{
|
||||
0
|
||||
}))
|
||||
}
|
||||
//signed
|
||||
pub fn [<$p lts>](a: $int, b: $int) -> anyhow::Result<tuple_list::tuple_list_type!(u32)> {
|
||||
let a = a as $p;
|
||||
let b = b as $p;
|
||||
Ok(tuple_list::tuple_list!(if a < b{
|
||||
1
|
||||
}else{
|
||||
0
|
||||
}))
|
||||
}
|
||||
pub fn [<$p gts>](a: $int, b: $int) -> anyhow::Result<tuple_list::tuple_list_type!(u32)> {
|
||||
let a = a as $p;
|
||||
let b = b as $p;
|
||||
Ok(tuple_list::tuple_list!(if a > b{
|
||||
1
|
||||
}else{
|
||||
0
|
||||
}))
|
||||
}
|
||||
pub fn [<$p les>](a: $int, b: $int) -> anyhow::Result<tuple_list::tuple_list_type!(u32)> {
|
||||
let a = a as $p;
|
||||
let b = b as $p;
|
||||
Ok(tuple_list::tuple_list!(if a <= b{
|
||||
1
|
||||
}else{
|
||||
0
|
||||
}))
|
||||
}
|
||||
pub fn [<$p ges>](a: $int, b: $int) -> anyhow::Result<tuple_list::tuple_list_type!(u32)> {
|
||||
let a = a as $p;
|
||||
let b = b as $p;
|
||||
Ok(tuple_list::tuple_list!(if a >= b{
|
||||
1
|
||||
}else{
|
||||
0
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn [<$p sub>](a: $int, b: $int) -> anyhow::Result<tuple_list::tuple_list_type!($int)> {
|
||||
Ok(tuple_list::tuple_list!(a.wrapping_sub(b)))
|
||||
}
|
||||
//LOADS and STORES
|
||||
pub fn [<$p load>]<T: TryInto<usize>>(a: &mut Vec<u8>, b: T) -> anyhow::Result<tuple_list::tuple_list_type!($int)> where T::Error: std::error::Error + Send + Sync + 'static{
|
||||
let r = &a[b.try_into()?..][..std::mem::size_of::<$int>()];
|
||||
Ok(tuple_list::tuple_list!($int::from_ne_bytes(r.try_into()?)))
|
||||
}
|
||||
pub fn [<$p store>]<T: TryInto<usize>>(a: &mut Vec<u8>, b: T, c: $int) -> anyhow::Result<()> where T::Error: std::error::Error + Send + Sync + 'static{
|
||||
let mut r = &mut a[b.try_into()?..][..std::mem::size_of::<$int>()];
|
||||
r.copy_from_slice(&c.to_ne_bytes());
|
||||
Ok(())
|
||||
}
|
||||
//8 BIT
|
||||
pub fn [<$p load8u>]<T: TryInto<usize>>(a: &mut Vec<u8>, b: T) -> anyhow::Result<tuple_list::tuple_list_type!($int)> where T::Error: std::error::Error + Send + Sync + 'static{
|
||||
let r = a[b.try_into()?..][0];
|
||||
Ok(tuple_list::tuple_list!(r as $int))
|
||||
}
|
||||
pub fn [<$p load8s>]<T: TryInto<usize>>(a: &mut Vec<u8>, b: T) -> anyhow::Result<tuple_list::tuple_list_type!($int)> where T::Error: std::error::Error + Send + Sync + 'static{
|
||||
let r = a[b.try_into()?..][0];
|
||||
Ok(tuple_list::tuple_list!(r as i8 as $p as $int))
|
||||
}
|
||||
pub fn [<$p store8>]<T: TryInto<usize>>(a: &mut Vec<u8>, b: T, c: $int) -> anyhow::Result<()> where T::Error: std::error::Error + Send + Sync + 'static{
|
||||
let mut r = &mut a[b.try_into()?..][..1];
|
||||
r[0] = (c & 0xff) as u8;
|
||||
Ok(())
|
||||
}
|
||||
//16 BIT
|
||||
pub fn [<$p load16u>]<T: TryInto<usize>>(a: &mut Vec<u8>, b: T) -> anyhow::Result<tuple_list::tuple_list_type!($int)> where T::Error: std::error::Error + Send + Sync + 'static{
|
||||
let r = &a[b.try_into()?..][..2];
|
||||
let r = u16::from_ne_bytes(r.try_into()?);
|
||||
Ok(tuple_list::tuple_list!(r as $int))
|
||||
}
|
||||
pub fn [<$p load16s>]<T: TryInto<usize>>(a: &mut Vec<u8>, b: T) -> anyhow::Result<tuple_list::tuple_list_type!($int)> where T::Error: std::error::Error + Send + Sync + 'static{
|
||||
let r = &a[b.try_into()?..][..2];
|
||||
let r = u16::from_ne_bytes(r.try_into()?);
|
||||
Ok(tuple_list::tuple_list!(r as i16 as $p as $int))
|
||||
}
|
||||
pub fn [<$p store16>]<T: TryInto<usize>>(a: &mut Vec<u8>, b: T, c: $int) -> anyhow::Result<()> where T::Error: std::error::Error + Send + Sync + 'static{
|
||||
let mut r = &mut a[b.try_into()?..][..2];
|
||||
r.copy_from_slice(&((c & 0xff) as u16).to_ne_bytes());
|
||||
Ok(())
|
||||
}
|
||||
//32 BIT
|
||||
pub fn [<$p load32u>]<T: TryInto<usize>>(a: &mut Vec<u8>, b: T) -> anyhow::Result<tuple_list::tuple_list_type!($int)> where T::Error: std::error::Error + Send + Sync + 'static{
|
||||
let r = &a[b.try_into()?..][..4];
|
||||
let r = u32::from_ne_bytes(r.try_into()?);
|
||||
Ok(tuple_list::tuple_list!(r as $int))
|
||||
}
|
||||
pub fn [<$p load32s>]<T: TryInto<usize>>(a: &mut Vec<u8>, b: T) -> anyhow::Result<tuple_list::tuple_list_type!($int)> where T::Error: std::error::Error + Send + Sync + 'static{
|
||||
let r = &a[b.try_into()?..][..4];
|
||||
let r = u32::from_ne_bytes(r.try_into()?);
|
||||
Ok(tuple_list::tuple_list!(r as i32 as $p as $int))
|
||||
}
|
||||
pub fn [<$p store32>]<T: TryInto<usize>>(a: &mut Vec<u8>, b: T, c: $int) -> anyhow::Result<()> where T::Error: std::error::Error + Send + Sync + 'static{
|
||||
let mut r = &mut a[b.try_into()?..][..4];
|
||||
r.copy_from_slice(&((c & 0xffffff) as u32).to_ne_bytes());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
int_ty!(u32 => i32);
|
||||
int_ty!(u64 => i64);
|
||||
pub fn select<T>(u: u32, t: T, t2: T) -> anyhow::Result<tuple_list::tuple_list_type!(T)> {
|
||||
Ok(tuple_list::tuple_list!(if u != 0 { t } else { t2 }))
|
||||
}
|
||||
pub fn i32wrapi64(a: u64) -> anyhow::Result<tuple_list::tuple_list_type!(u32)> {
|
||||
return Ok(tuple_list::tuple_list!((a & 0xffffffff) as u32));
|
||||
}
|
11
wars-test/Cargo.toml
Normal file
11
wars-test/Cargo.toml
Normal file
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "wars-test"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
2
wars-test/build.sh
Normal file
2
wars-test/build.sh
Normal file
|
@ -0,0 +1,2 @@
|
|||
cd $(dirname $0)
|
||||
cargo build --target wasm32-unknown-unknown
|
8
wars-test/src/lib.rs
Normal file
8
wars-test/src/lib.rs
Normal file
|
@ -0,0 +1,8 @@
|
|||
#[no_mangle]
|
||||
pub fn add(left: usize, right: usize) -> usize {
|
||||
left + right
|
||||
}
|
||||
#[no_mangle]
|
||||
pub fn memory_op(a: &str) -> String{
|
||||
return a.to_owned();
|
||||
}
|
14
wars/Cargo.toml
Normal file
14
wars/Cargo.toml
Normal file
|
@ -0,0 +1,14 @@
|
|||
[package]
|
||||
name = "wars"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
portal-pc-waffle.workspace = true
|
||||
proc-macro2 = "1.0.85"
|
||||
quote = "1.0.36"
|
||||
relooper = "0.1.0"
|
||||
syn = "2.0.66"
|
||||
|
1007
wars/src/lib.rs
Normal file
1007
wars/src/lib.rs
Normal file
File diff suppressed because it is too large
Load diff
74
wars/src/unswitch.rs
Normal file
74
wars/src/unswitch.rs
Normal file
|
@ -0,0 +1,74 @@
|
|||
use std::iter::empty;
|
||||
|
||||
use waffle::{
|
||||
Block, ExportKind, Func, FuncDecl, Import, ImportKind, Memory, MemoryArg, MemoryData, Module,
|
||||
Operator, Signature, SignatureData, Table, Type, Value, ValueDef,
|
||||
};
|
||||
use waffle::{BlockTarget, FunctionBody, Terminator};
|
||||
|
||||
pub fn go(f: &mut FunctionBody) {
|
||||
let vz = f.arg_pool.from_iter(empty());
|
||||
let tz = f.type_pool.from_iter(empty());
|
||||
let ti = f.type_pool.from_iter(vec![Type::I32].into_iter());
|
||||
let ia = f.add_value(ValueDef::Operator(Operator::I32Const { value: 1 }, vz, ti));
|
||||
f.append_to_block(f.entry, ia);
|
||||
loop {
|
||||
let mut i = f.blocks.entries();
|
||||
let (b, value, targets, default) = 'gather: loop {
|
||||
let Some(a) = i.next() else {
|
||||
drop(i);
|
||||
f.recompute_edges();
|
||||
return;
|
||||
};
|
||||
if let Terminator::Select {
|
||||
value,
|
||||
targets,
|
||||
default,
|
||||
} = a.1.clone().terminator
|
||||
{
|
||||
break 'gather (a.0, value, targets.clone(), default);
|
||||
}
|
||||
};
|
||||
drop(i);
|
||||
f.blocks[b].terminator = Terminator::None;
|
||||
if targets.len() == 0 {
|
||||
f.set_terminator(b, Terminator::Br { target: default });
|
||||
continue;
|
||||
}
|
||||
if targets.len() == 1 {
|
||||
f.set_terminator(
|
||||
b,
|
||||
Terminator::CondBr {
|
||||
cond: value,
|
||||
if_true: default,
|
||||
if_false: targets[0].clone(),
|
||||
},
|
||||
);
|
||||
continue;
|
||||
}
|
||||
let t2 = targets[1..].to_vec();
|
||||
let n = f.add_block();
|
||||
let vs = f.arg_pool.from_iter(vec![value, ia].into_iter());
|
||||
let ic = f.add_value(ValueDef::Operator(Operator::I32Sub, vs, ti));
|
||||
f.append_to_block(n, ic);
|
||||
f.set_terminator(
|
||||
n,
|
||||
Terminator::Select {
|
||||
value: ic,
|
||||
targets: t2,
|
||||
default: default,
|
||||
},
|
||||
);
|
||||
f.set_terminator(
|
||||
b,
|
||||
Terminator::CondBr {
|
||||
cond: value,
|
||||
if_true: BlockTarget {
|
||||
block: n,
|
||||
args: vec![],
|
||||
},
|
||||
if_false: targets[0].clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue