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