From c40e9c4df15f1de367a3b2ea43ef5b8567e567dd Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Sat, 16 Aug 2025 14:47:06 +0200 Subject: [PATCH 001/186] initial commit --- Cargo.lock | 14 ++++ Cargo.toml | 2 + crates/ir2/Cargo.toml | 35 ++++++++++ crates/ir2/build.rs | 31 +++++++++ crates/ir2/build/display.rs | 39 +++++++++++ crates/ir2/build/isa.rs | 11 ++++ crates/ir2/build/mod.rs | 17 +++++ crates/ir2/build/op.rs | 80 +++++++++++++++++++++++ crates/ir2/build/token.rs | 126 ++++++++++++++++++++++++++++++++++++ crates/ir2/src/lib.rs | 1 + 10 files changed, 356 insertions(+) create mode 100644 crates/ir2/Cargo.toml create mode 100644 crates/ir2/build.rs create mode 100644 crates/ir2/build/display.rs create mode 100644 crates/ir2/build/isa.rs create mode 100644 crates/ir2/build/mod.rs create mode 100644 crates/ir2/build/op.rs create mode 100644 crates/ir2/build/token.rs create mode 100644 crates/ir2/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 4012e18434..4ee2d9a319 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -813,6 +813,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" +[[package]] +name = "indoc" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" + [[package]] name = "io-extras" version = "0.18.4" @@ -1844,6 +1850,14 @@ dependencies = [ "wasmi_core 0.51.0", ] +[[package]] +name = "wasmi_ir2" +version = "0.51.0" +dependencies = [ + "indoc", + "wasmi_core 0.51.0", +] + [[package]] name = "wasmi_wasi" version = "0.51.0" diff --git a/Cargo.toml b/Cargo.toml index 15a6a69668..9e02ddebe0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ members = [ "crates/wasmi", "crates/wasi", "crates/ir", + "crates/ir2", "crates/fuzz", "crates/wast", "fuzz", @@ -34,6 +35,7 @@ wasmi = { version = "0.51.0", path = "crates/wasmi", default-features = false } wasmi_wasi = { version = "0.51.0", path = "crates/wasi", default-features = false } wasmi_core = { version = "0.51.0", path = "crates/core", default-features = false } wasmi_ir = { version = "0.51.0", path = "crates/ir", default-features = false } +wasmi_ir2 = { version = "0.51.0", path = "crates/ir2", default-features = false } wasmi_collections = { version = "0.51.0", path = "crates/collections", default-features = false } wasmi_c_api_impl = { version = "0.51.0", path = "crates/c_api" } wasmi_c_api_macros = { version = "0.51.0", path = "crates/c_api/macro" } diff --git a/crates/ir2/Cargo.toml b/crates/ir2/Cargo.toml new file mode 100644 index 0000000000..3d295d8689 --- /dev/null +++ b/crates/ir2/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "wasmi_ir2" +version.workspace = true +rust-version.workspace = true +documentation = "https://docs.rs/wasmi_ir2/" +description = "WebAssembly interpreter internal bytecode representation" +authors.workspace = true +repository.workspace = true +edition.workspace = true +readme.workspace = true +license.workspace = true +keywords.workspace = true +categories.workspace = true +exclude = [ + "benches/wat", + "benches/wasm", + "tests/spec/testsuite", + "**.wast", +] + +[dependencies] +wasmi_core = { workspace = true } + +[build-dependencies] +indoc = "2" + +[features] +default = ["std"] +std = [ + "wasmi_core/std", +] +simd = ["wasmi_core/simd"] + +[package.metadata.docs.rs] +features = ["std", "simd"] diff --git a/crates/ir2/build.rs b/crates/ir2/build.rs new file mode 100644 index 0000000000..7cdfd2da16 --- /dev/null +++ b/crates/ir2/build.rs @@ -0,0 +1,31 @@ +use std::{fs, path::Path, env, path::PathBuf}; + +#[path = "build/mod.rs"] +mod build; + +fn main() { + watch_dir_recursively(Path::new("build")); + let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); + build::generate_code(&out_dir).unwrap() +} + +fn watch_dir_recursively(path: &Path) { + if !path.is_dir() { + return; + } + let entries = match fs::read_dir(path) { + Ok(entries) => entries, + Err(error) => panic!("failed to read directory: {error}"), + }; + for entry in entries { + let entry = match entry { + Ok(entry) => entry, + Err(error) => panic!("failed to read directory entry: {error}"), + }; + let path = entry.path(); + if path.is_file() { + println!("cargo:rerun-if-changed={}", path.display()); + } + watch_dir_recursively(&path); + } +} diff --git a/crates/ir2/build/display.rs b/crates/ir2/build/display.rs new file mode 100644 index 0000000000..3b4add0799 --- /dev/null +++ b/crates/ir2/build/display.rs @@ -0,0 +1,39 @@ +use indoc::indoc; +use core::fmt::{self, Display}; +use crate::build::op::{UnaryOp, BinaryOp, Ty}; +use crate::build::token::{CamelCase, SnakeCase, Ident}; + +pub struct DisplayEnum(T); + +impl Display for DisplayEnum { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let ident = CamelCase(self.0.ident); + let result_ty = self.0.result_ty; + let input_ty = self.0.input_ty; + let result_ident = CamelCase(Ident::from(result_ty)); + write!(f, + "/ + {result_ident}{ident} {{\n + ", + ) + // write!(f, indoc! {" + // {result_ident}{ident} + + // ", + // result_ident = CamelCase(Ident::from(result_ty)), + // }) + } +} + +impl Display for Ty { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let s = match self { + Ty::I32 => "i32", + Ty::I64 => "i64", + Ty::F32 => "f32", + Ty::F64 => "f64", + Ty::Ref => "ref", + }; + write!(f, s) + } +} diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs new file mode 100644 index 0000000000..df607ff143 --- /dev/null +++ b/crates/ir2/build/isa.rs @@ -0,0 +1,11 @@ +use crate::build::Op; + +pub struct Isa { + ops: Vec, +} + +impl Isa { + pub fn push_op(&mut self, op: Op) { + self.ops.push(op); + } +} diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs new file mode 100644 index 0000000000..20132f1f65 --- /dev/null +++ b/crates/ir2/build/mod.rs @@ -0,0 +1,17 @@ +pub mod token; +mod op; +mod isa; +mod display; + +use std::path::Path; +use self::token::{Ident, CamelCase, SnakeCase}; +use self::op::{Op, BinaryOp, UnaryOp}; +use std::io::Error as IoError; +use indoc::indoc; + +pub fn generate_code(out_dir: &Path) -> Result<(), IoError> { + // let mut ctx = Context::default(); + // define_ops(&mut ctx); + // generate_ops(&ctx)?; + Ok(()) +} diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs new file mode 100644 index 0000000000..a5b2d9d27a --- /dev/null +++ b/crates/ir2/build/op.rs @@ -0,0 +1,80 @@ +use crate::build::Ident; + +#[derive(Copy, Clone)] +pub enum Op { + Binary(BinaryOp), +} + +#[derive(Copy, Clone)] +pub struct UnaryOp { + pub ident: Ident, + pub result_ty: Ty, + pub input_ty: Ty, +} + +impl UnaryOp { + pub fn new_conversion(ident: Ident, result_ty: Ty, input_ty: Ty) -> Self { + Self { + ident, + result_ty, + input_ty, + } + } + + pub fn new(ident: Ident, ty: Ty) -> Self { + Self { + ident, + result_ty: ty, + input_ty: ty, + } + } +} + +#[derive(Copy, Clone)] +pub struct BinaryOp { + pub ident: Ident, + pub result_ty: Ty, + pub input_ty: Ty, + pub commutative: bool, +} + +impl BinaryOp { + pub fn new_commutative(ident: Ident, result_ty: Ty, input_ty: Ty) -> Self { + Self { + ident, + result_ty, + input_ty, + commutative: true, + } + } + + pub fn new(ident: Ident, result_ty: Ty, input_ty: Ty) -> Self { + Self { + ident, + result_ty, + input_ty, + commutative: false, + } + } +} + +#[derive(Copy, Clone)] +pub enum Ty { + I32, + I64, + F32, + F64, + Ref, +} + +impl From for Ident { + fn from(ty: Ty) -> Self { + match ty { + Ty::I32 => Self::I32, + Ty::I64 => Self::I64, + Ty::F32 => Self::F32, + Ty::F64 => Self::F64, + Ty::Ref => Self::Ref, + } + } +} diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs new file mode 100644 index 0000000000..d55d4fadab --- /dev/null +++ b/crates/ir2/build/token.rs @@ -0,0 +1,126 @@ +use core::fmt::{self, Display}; + +/// Camel-case tokens, e.g. `HelloWorld`. +pub struct CamelCase(pub T); + +/// Snake-case tokens, e.g. `hello_world`. +pub struct SnakeCase(pub T); + +macro_rules! define_ident { + ( + $( + $camel_ident:ident: $snake_ident:ident + ),* $(,)? + ) => { + #[derive(Copy, Clone)] + pub enum Ident { + $( $camel_ident ),* + } + + impl Display for CamelCase { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let frag: &'static str = match self.0 { + $( + Ident::$camel_ident => stringify!($camel_ident), + )* + }; + write!(f, "{frag}") + } + } + + impl Display for SnakeCase { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let frag: &'static str = match self.0 { + $( + Ident::$camel_ident => stringify!($snake_ident), + )* + }; + write!(f, "{frag}") + } + } + }; +} +define_ident!( + Add: add, + Sub: sub, + Mul: mul, + Div: div, + Sdiv: sdiv, + Udiv: udiv, + Srem: srem, + Urem: urem, + Min: min, + Max: max, + Copysign: copysign, + + Shl: shl, + Sshr: sshr, + Ushr: ushr, + Rotl: rotl, + Rotr: rotr, + + Eq: eq, + Ne: ne, + Slt: slt, + Ult: ult, + Sle: sle, + Ule: ule, + Lt: lt, + Le: le, + NotLt: not_lt, + NotLe: not_le, + + And: and, + Or: or, + NotAnd: not_and, + NotOr: not_or, + + BitAnd: bit_and, + BitOr: bit_or, + BitXor: bit_xor, + + Popcnt: popcnt, + Clz: clz, + Ctz: ctz, + + Not: not, + Abs: abs, + Neg: neg, + Ceil: ceil, + Floor: floor, + Trunc: trunc, + Nearest: nearest, + Sqrt: sqrt, + + Return: r#return, + Branch: branch, + Select: select, + Store: store, + Load: load, + + Copy: copy, + Fill: fill, + Init: init, + Grow: grow, + Get: get, + Set: set, + + Table: table, + Memory: memory, + Func: func, + Global: global, + Elem: elem, + Data: data, + Trap: trap, + + Call: call, + CallIndirect: call_indirect, + ReturnCall: return_call, + ReturnCallIndirect: return_call_indirect, + + I32: r#i32, + I64: r#i64, + F32: r#f32, + F64: r#f64, + Ref: r#ref, +); diff --git a/crates/ir2/src/lib.rs b/crates/ir2/src/lib.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/crates/ir2/src/lib.rs @@ -0,0 +1 @@ + From 1842706335cfd5e7cca7c0bad8db76b11fb7c170 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Tue, 19 Aug 2025 13:22:01 +0200 Subject: [PATCH 002/186] remove indoc dependency --- Cargo.lock | 7 ------- crates/ir2/Cargo.toml | 3 --- 2 files changed, 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4ee2d9a319..7d02089c0b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -813,12 +813,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" -[[package]] -name = "indoc" -version = "2.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" - [[package]] name = "io-extras" version = "0.18.4" @@ -1854,7 +1848,6 @@ dependencies = [ name = "wasmi_ir2" version = "0.51.0" dependencies = [ - "indoc", "wasmi_core 0.51.0", ] diff --git a/crates/ir2/Cargo.toml b/crates/ir2/Cargo.toml index 3d295d8689..e6f84f5a07 100644 --- a/crates/ir2/Cargo.toml +++ b/crates/ir2/Cargo.toml @@ -21,9 +21,6 @@ exclude = [ [dependencies] wasmi_core = { workspace = true } -[build-dependencies] -indoc = "2" - [features] default = ["std"] std = [ From 593836d904aafef26c4337074da6c2c27fa75d82 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 20 Aug 2025 17:23:31 +0200 Subject: [PATCH 003/186] initial commit --- crates/ir2/build.rs | 8 +- crates/ir2/build/display.rs | 161 +++++- crates/ir2/build/isa.rs | 64 ++- crates/ir2/build/mod.rs | 58 +- crates/ir2/build/op.rs | 1058 ++++++++++++++++++++++++++++++++++- crates/ir2/build/token.rs | 73 ++- crates/ir2/src/lib.rs | 4 + crates/ir2/src/ops.rs | 1 + 8 files changed, 1325 insertions(+), 102 deletions(-) create mode 100644 crates/ir2/src/ops.rs diff --git a/crates/ir2/build.rs b/crates/ir2/build.rs index 7cdfd2da16..e17bbad8da 100644 --- a/crates/ir2/build.rs +++ b/crates/ir2/build.rs @@ -1,4 +1,10 @@ -use std::{fs, path::Path, env, path::PathBuf}; +#![allow(warnings)] + +use std::{ + env, + fs, + path::{Path, PathBuf}, +}; #[path = "build/mod.rs"] mod build; diff --git a/crates/ir2/build/display.rs b/crates/ir2/build/display.rs index 3b4add0799..c2c055c583 100644 --- a/crates/ir2/build/display.rs +++ b/crates/ir2/build/display.rs @@ -1,39 +1,142 @@ -use indoc::indoc; +use crate::build::{ + isa::Isa, + op::{BinaryOp, FieldTy, Input, Op, Ty, UnaryOp}, + token::{CamelCase, Ident, SnakeCase}, +}; use core::fmt::{self, Display}; -use crate::build::op::{UnaryOp, BinaryOp, Ty}; -use crate::build::token::{CamelCase, SnakeCase, Ident}; -pub struct DisplayEnum(T); +#[derive(Copy, Clone, Default)] +pub struct Indent(usize); -impl Display for DisplayEnum { +impl Indent { + pub fn inc(self) -> Self { + Self(self.0 + 1) + } +} + +impl Display for Indent { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let ident = CamelCase(self.0.ident); - let result_ty = self.0.result_ty; - let input_ty = self.0.input_ty; - let result_ident = CamelCase(Ident::from(result_ty)); - write!(f, - "/ - {result_ident}{ident} {{\n - ", - ) - // write!(f, indoc! {" - // {result_ident}{ident} - - // ", - // result_ident = CamelCase(Ident::from(result_ty)), - // }) + for _ in 0..self.0 { + write!(f, " ")?; + } + Ok(()) + } +} + +pub struct DisplayEnum { + pub val: T, + pub indent: Indent, +} + +impl DisplayEnum { + pub fn new(val: T, indent: Indent) -> Self { + Self { val, indent } + } + + pub fn scoped(&self, val: V) -> DisplayEnum { + DisplayEnum { + val, + indent: self.indent.inc(), + } + } + + pub fn map(&self, val: V) -> DisplayEnum { + DisplayEnum { + val, + indent: self.indent, + } } } -impl Display for Ty { +impl Display for DisplayEnum { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let s = match self { - Ty::I32 => "i32", - Ty::I64 => "i64", - Ty::F32 => "f32", - Ty::F64 => "f64", - Ty::Ref => "ref", - }; - write!(f, s) + let indent = self.indent; + write!( + f, + "\ + {indent}pub enum Instruction {{\n\ + " + )?; + for op in &self.val.ops { + write!(f, "{}", self.scoped(op))?; + } + write!( + f, + "\ + {indent}}}\n\ + " + )?; + Ok(()) + } +} + +impl Display for DisplayEnum<&'_ Op> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.val { + Op::Unary(op) => write!(f, "{}", self.map(op)), + Op::Binary(_op) => Ok(()), + Op::CmpBranch(_op) => Ok(()), + Op::CmpSelect(_op) => Ok(()), + Op::Load(_op) => Ok(()), + Op::Store(_op) => Ok(()), + Op::Generic0(_op) => Ok(()), + Op::Generic1(_op) => Ok(()), + Op::Generic2(_op) => Ok(()), + Op::Generic3(_op) => Ok(()), + Op::Generic4(_op) => Ok(()), + } + } +} + +impl Display for DisplayEnum<&'_ UnaryOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.val.kind.is_conversion() { + self.display_unary(f) + } else { + self.display_conversion(f) + } + } +} + +impl DisplayEnum<&'_ UnaryOp> { + fn display_unary(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let kind = self.val.kind; + let ident = CamelCase(kind.ident()); + let result_ident = CamelCase(Ident::from(kind.result_ty())); + let result_field = FieldTy::Stack; + let value_field = FieldTy::Stack; + let indent0 = self.indent; + let indent1 = indent0.inc(); + write!( + f, + "\ + {indent0}{result_ident}{ident}_Ss {{\n\ + {indent1}result: {result_field},\n\ + {indent1}value: {value_field},\n\ + {indent0}}}\n\ + ", + ) + } + + fn display_conversion(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let kind = self.val.kind; + let ident = CamelCase(kind.ident()); + let result_ident = CamelCase(Ident::from(kind.result_ty())); + let input_ident = CamelCase(Ident::from(kind.input_ty())); + let result_id = CamelCase(Input::Stack); + let value_id = CamelCase(Input::Stack); + let result_field = FieldTy::Stack; + let value_field = FieldTy::Stack; + let indent0 = self.indent; + let indent1 = indent0.inc(); + write!( + f, + "\ + {indent0}{result_ident}{ident}{input_ident}_Ss {{\n\ + {indent1}result: {result_field},\n\ + {indent1}value: {value_field},\n\ + {indent0}}}\n\ + ", + ) } } diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index df607ff143..7cac50d10f 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -1,11 +1,69 @@ -use crate::build::Op; +use crate::build::{ + op::{UnaryOp, UnaryOpKind}, + Op, +}; +#[derive(Default)] pub struct Isa { - ops: Vec, + pub ops: Vec, } impl Isa { - pub fn push_op(&mut self, op: Op) { + fn push_op(&mut self, op: Op) { self.ops.push(op); } } + +pub fn wasmi_isa() -> Isa { + let mut isa = Isa::default(); + add_unary_ops(&mut isa); + isa +} + +fn add_unary_ops(isa: &mut Isa) { + let ops = [ + // i32 + UnaryOpKind::I32Clz, + UnaryOpKind::I32Ctz, + UnaryOpKind::I32Popcnt, + UnaryOpKind::I32Sext8, + UnaryOpKind::I32Sext16, + UnaryOpKind::I32WrapI64, + // i64 + UnaryOpKind::I64Clz, + UnaryOpKind::I64Ctz, + UnaryOpKind::I64Popcnt, + UnaryOpKind::I64Sext8, + UnaryOpKind::I64Sext16, + UnaryOpKind::I64Sext32, + // f32 + UnaryOpKind::F32Abs, + UnaryOpKind::F32Neg, + UnaryOpKind::F32Ceil, + UnaryOpKind::F32Floor, + UnaryOpKind::F32Trunc, + UnaryOpKind::F32Nearest, + UnaryOpKind::F32Sqrt, + UnaryOpKind::F32ConvertS32, + UnaryOpKind::F32ConvertU32, + UnaryOpKind::F32ConvertS64, + UnaryOpKind::F32ConvertU64, + UnaryOpKind::F32DemoteF64, + // f64 + UnaryOpKind::F64Abs, + UnaryOpKind::F64Neg, + UnaryOpKind::F64Ceil, + UnaryOpKind::F64Floor, + UnaryOpKind::F64Trunc, + UnaryOpKind::F64Nearest, + UnaryOpKind::F64Sqrt, + UnaryOpKind::F64ConvertS32, + UnaryOpKind::F64ConvertU32, + UnaryOpKind::F64ConvertS64, + UnaryOpKind::F64ConvertU64, + UnaryOpKind::F64PromoteF32, + ]; + for op in ops { + isa.push_op(Op::Unary(UnaryOp::new(op))); + } +} diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index 20132f1f65..d750c0137e 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -1,15 +1,55 @@ -pub mod token; -mod op; -mod isa; mod display; +mod isa; +mod op; +pub mod token; + +use self::{ + display::{DisplayEnum, Indent}, + isa::Isa, + op::{BinaryOp, Op, UnaryOp}, + token::{CamelCase, Ident, SnakeCase}, +}; +use core::fmt::{self, Display, Error as FmtError, Write as _}; +use std::{fs, io::Error as IoError, path::Path}; -use std::path::Path; -use self::token::{Ident, CamelCase, SnakeCase}; -use self::op::{Op, BinaryOp, UnaryOp}; -use std::io::Error as IoError; -use indoc::indoc; +#[derive(Debug)] +pub enum Error { + Io(IoError), + Fmt(FmtError), +} + +impl From for Error { + fn from(error: IoError) -> Self { + Self::Io(error) + } +} + +impl From for Error { + fn from(error: FmtError) -> Self { + Self::Fmt(error) + } +} + +impl Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Error::Io(error) => error.fmt(f), + Error::Fmt(error) => error.fmt(f), + } + } +} -pub fn generate_code(out_dir: &Path) -> Result<(), IoError> { +pub fn generate_code(out_dir: &Path) -> Result<(), Error> { + let mut contents = String::new(); + let isa = isa::wasmi_isa(); + write!( + &mut contents, + "{}", + >::new(isa, Indent::default()) + )?; + std::println!("out_dir = {out_dir:?}"); + fs::create_dir_all(out_dir)?; + fs::write(out_dir.join("instruction.rs"), contents)?; // let mut ctx = Context::default(); // define_ops(&mut ctx); // generate_ops(&ctx)?; diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index a5b2d9d27a..bcdfef2863 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -1,80 +1,1076 @@ -use crate::build::Ident; +use crate::build::{CamelCase, Ident, SnakeCase}; +use core::fmt::{self, Display}; #[derive(Copy, Clone)] pub enum Op { + Unary(UnaryOp), Binary(BinaryOp), + CmpBranch(CmpBranchOp), + CmpSelect(CmpSelectOp), + Load(LoadOp), + Store(StoreOp), + Generic0(GenericOp<0>), + Generic1(GenericOp<1>), + Generic2(GenericOp<2>), + Generic3(GenericOp<3>), + Generic4(GenericOp<4>), } #[derive(Copy, Clone)] -pub struct UnaryOp { +pub struct GenericOp { pub ident: Ident, - pub result_ty: Ty, - pub input_ty: Ty, + pub fields: [Field; N], +} + +#[derive(Copy, Clone)] +pub struct Field { + ident: Ident, + ty: FieldTy, +} + +#[derive(Copy, Clone)] +pub struct UnaryOp { + pub kind: UnaryOpKind, } impl UnaryOp { - pub fn new_conversion(ident: Ident, result_ty: Ty, input_ty: Ty) -> Self { - Self { - ident, - result_ty, - input_ty, + pub fn new(kind: UnaryOpKind) -> Self { + Self { kind } + } +} + +#[derive(Copy, Clone)] +pub enum UnaryOpKind { + I32Clz, + I32Ctz, + I32Popcnt, + + I64Clz, + I64Ctz, + I64Popcnt, + + I32WrapI64, + + I32Sext8, + I32Sext16, + I64Sext8, + I64Sext16, + I64Sext32, + + F32Abs, + F32Neg, + F32Ceil, + F32Floor, + F32Trunc, + F32Nearest, + F32Sqrt, + + F64Abs, + F64Neg, + F64Ceil, + F64Floor, + F64Trunc, + F64Nearest, + F64Sqrt, + + S32TruncF32, + U32TruncF32, + S32TruncF64, + U32TruncF64, + S64TruncF32, + U64TruncF32, + S64TruncF64, + U64TruncF64, + + S32TruncSatF32, + U32TruncSatF32, + S32TruncSatF64, + U32TruncSatF64, + S64TruncSatF32, + U64TruncSatF32, + S64TruncSatF64, + U64TruncSatF64, + + F32DemoteF64, + F64PromoteF32, + + F32ConvertS32, + F32ConvertU32, + F32ConvertS64, + F32ConvertU64, + + F64ConvertS32, + F64ConvertU32, + F64ConvertS64, + F64ConvertU64, +} + +impl UnaryOpKind { + pub fn is_conversion(&self) -> bool { + self.input_ty() != self.result_ty() + } + + pub fn input_ty(&self) -> Ty { + match self { + | Self::I32Clz | Self::I32Ctz | Self::I32Popcnt => Ty::I32, + | Self::I64Clz | Self::I64Ctz | Self::I64Popcnt | Self::I32WrapI64 => Ty::I64, + | Self::I32Sext8 | Self::I32Sext16 => Ty::I32, + | Self::I64Sext8 | Self::I64Sext16 | Self::I64Sext32 => Ty::I64, + | Self::F32Abs + | Self::F32Neg + | Self::F32Ceil + | Self::F32Floor + | Self::F32Trunc + | Self::F32Nearest + | Self::F32Sqrt => Ty::F32, + | Self::F64Abs + | Self::F64Neg + | Self::F64Ceil + | Self::F64Floor + | Self::F64Trunc + | Self::F64Nearest + | Self::F64Sqrt => Ty::F64, + | Self::S32TruncF32 | Self::U32TruncF32 => Ty::F32, + | Self::S32TruncF64 | Self::U32TruncF64 => Ty::F64, + | Self::S64TruncF32 | Self::U64TruncF32 => Ty::F32, + | Self::S64TruncF64 | Self::U64TruncF64 => Ty::F64, + | Self::S32TruncSatF32 | Self::U32TruncSatF32 => Ty::F32, + | Self::S32TruncSatF64 | Self::U32TruncSatF64 => Ty::F64, + | Self::S64TruncSatF32 | Self::U64TruncSatF32 => Ty::F32, + | Self::S64TruncSatF64 | Self::U64TruncSatF64 | Self::F32DemoteF64 => Ty::F64, + | Self::F64PromoteF32 => Ty::F32, + | Self::F32ConvertS32 | Self::F32ConvertU32 => Ty::I32, + | Self::F32ConvertS64 | Self::F32ConvertU64 => Ty::I64, + | Self::F64ConvertS32 | Self::F64ConvertU32 => Ty::I32, + | Self::F64ConvertS64 | Self::F64ConvertU64 => Ty::I64, + } + } + + pub fn result_ty(&self) -> Ty { + match self { + | Self::I32Clz | Self::I32Ctz | Self::I32Popcnt => Ty::I32, + | Self::I64Clz | Self::I64Ctz | Self::I64Popcnt => Ty::I64, + | Self::I32WrapI64 | Self::I32Sext8 | Self::I32Sext16 => Ty::I32, + | Self::I64Sext8 | Self::I64Sext16 | Self::I64Sext32 => Ty::I64, + | Self::F32Abs + | Self::F32Neg + | Self::F32Ceil + | Self::F32Floor + | Self::F32Trunc + | Self::F32Nearest + | Self::F32Sqrt => Ty::F32, + | Self::F64Abs + | Self::F64Neg + | Self::F64Ceil + | Self::F64Floor + | Self::F64Trunc + | Self::F64Nearest + | Self::F64Sqrt => Ty::F64, + | Self::S32TruncF32 | Self::U32TruncF32 | Self::S32TruncF64 | Self::U32TruncF64 => { + Ty::I32 + } + | Self::S64TruncF32 | Self::U64TruncF32 | Self::S64TruncF64 | Self::U64TruncF64 => { + Ty::I64 + } + | Self::S32TruncSatF32 + | Self::U32TruncSatF32 + | Self::S32TruncSatF64 + | Self::U32TruncSatF64 => Ty::I32, + | Self::S64TruncSatF32 + | Self::U64TruncSatF32 + | Self::S64TruncSatF64 + | Self::U64TruncSatF64 => Ty::I64, + | Self::F32DemoteF64 => Ty::F32, + | Self::F64PromoteF32 => Ty::F64, + | Self::F32ConvertS32 + | Self::F32ConvertU32 + | Self::F32ConvertS64 + | Self::F32ConvertU64 => Ty::F32, + | Self::F64ConvertS32 + | Self::F64ConvertU32 + | Self::F64ConvertS64 + | Self::F64ConvertU64 => Ty::F64, } } - pub fn new(ident: Ident, ty: Ty) -> Self { - Self { - ident, - result_ty: ty, - input_ty: ty, + pub fn ident(&self) -> Ident { + match self { + Self::I32Clz => Ident::Clz, + Self::I32Ctz => Ident::Ctz, + Self::I32Popcnt => Ident::Popcnt, + Self::I64Clz => Ident::Clz, + Self::I64Ctz => Ident::Ctz, + Self::I64Popcnt => Ident::Popcnt, + Self::I32WrapI64 => Ident::Wrap, + Self::I32Sext8 => Ident::Sext8, + Self::I32Sext16 => Ident::Sext16, + Self::I64Sext8 => Ident::Sext8, + Self::I64Sext16 => Ident::Sext16, + Self::I64Sext32 => Ident::Sext32, + Self::F32Abs => Ident::Abs, + Self::F32Neg => Ident::Neg, + Self::F32Ceil => Ident::Ceil, + Self::F32Floor => Ident::Floor, + Self::F32Trunc => Ident::Trunc, + Self::F32Nearest => Ident::Nearest, + Self::F32Sqrt => Ident::Sqrt, + Self::F64Abs => Ident::Abs, + Self::F64Neg => Ident::Neg, + Self::F64Ceil => Ident::Ceil, + Self::F64Floor => Ident::Floor, + Self::F64Trunc => Ident::Trunc, + Self::F64Nearest => Ident::Nearest, + Self::F64Sqrt => Ident::Sqrt, + Self::S32TruncF32 => Ident::Trunc, + Self::U32TruncF32 => Ident::Trunc, + Self::S32TruncF64 => Ident::Trunc, + Self::U32TruncF64 => Ident::Trunc, + Self::S64TruncF32 => Ident::Trunc, + Self::U64TruncF32 => Ident::Trunc, + Self::S64TruncF64 => Ident::Trunc, + Self::U64TruncF64 => Ident::Trunc, + Self::S32TruncSatF32 => Ident::TruncSat, + Self::U32TruncSatF32 => Ident::TruncSat, + Self::S32TruncSatF64 => Ident::TruncSat, + Self::U32TruncSatF64 => Ident::TruncSat, + Self::S64TruncSatF32 => Ident::TruncSat, + Self::U64TruncSatF32 => Ident::TruncSat, + Self::S64TruncSatF64 => Ident::TruncSat, + Self::U64TruncSatF64 => Ident::TruncSat, + Self::F32DemoteF64 => Ident::Demote, + Self::F64PromoteF32 => Ident::Promote, + Self::F32ConvertS32 => Ident::Convert, + Self::F32ConvertU32 => Ident::Convert, + Self::F32ConvertS64 => Ident::Convert, + Self::F32ConvertU64 => Ident::Convert, + Self::F64ConvertS32 => Ident::Convert, + Self::F64ConvertU32 => Ident::Convert, + Self::F64ConvertS64 => Ident::Convert, + Self::F64ConvertU64 => Ident::Convert, } } } #[derive(Copy, Clone)] pub struct BinaryOp { - pub ident: Ident, - pub result_ty: Ty, - pub input_ty: Ty, - pub commutative: bool, + pub kind: BinaryOpKind, + pub lhs: FieldTy, + pub rhs: FieldTy, } -impl BinaryOp { - pub fn new_commutative(ident: Ident, result_ty: Ty, input_ty: Ty) -> Self { - Self { - ident, - result_ty, - input_ty, - commutative: true, +#[derive(Copy, Clone)] +pub enum BinaryOpKind { + // Compare operators. + Cmp(CmpOpKind), + // Binary operators: i32 + I32Add, + I32Sub, + I32Mul, + S32Div, + U32Div, + S32Rem, + U32Rem, + I32BitAnd, + I32BitOr, + I32BitXor, + I32Shl, + S32Shr, + U32Shr, + I32Rotl, + I32Rotr, + // Binary operators: i64 + I64Add, + I64Sub, + I64Mul, + S64Div, + U64Div, + S64Rem, + U64Rem, + I64BitAnd, + I64BitOr, + I64BitXor, + I64Shl, + S64Shr, + U64Shr, + I64Rotl, + I64Rotr, + // Binary operators: f32 + F32Add, + F32Sub, + F32Mul, + F32Div, + F32Min, + F32Max, + F32Copysign, + // Binary operators: f64 + F64Add, + F64Sub, + F64Mul, + F64Div, + F64Min, + F64Max, + F64Copysign, +} + +impl BinaryOpKind { + pub fn ident(&self) -> Ident { + match self { + Self::Cmp(cmp) => cmp.ident(), + Self::I32Add => Ident::Add, + Self::I32Sub => Ident::Sub, + Self::I32Mul => Ident::Mul, + Self::S32Div => Ident::Div, + Self::U32Div => Ident::Div, + Self::S32Rem => Ident::Rem, + Self::U32Rem => Ident::Rem, + Self::I32BitAnd => Ident::BitAnd, + Self::I32BitOr => Ident::BitOr, + Self::I32BitXor => Ident::BitXor, + Self::I32Shl => Ident::Shl, + Self::S32Shr => Ident::Shr, + Self::U32Shr => Ident::Shr, + Self::I32Rotl => Ident::Rotl, + Self::I32Rotr => Ident::Rotr, + Self::I64Add => Ident::Add, + Self::I64Sub => Ident::Sub, + Self::I64Mul => Ident::Mul, + Self::S64Div => Ident::Div, + Self::U64Div => Ident::Div, + Self::S64Rem => Ident::Rem, + Self::U64Rem => Ident::Rem, + Self::I64BitAnd => Ident::BitAnd, + Self::I64BitOr => Ident::BitOr, + Self::I64BitXor => Ident::BitXor, + Self::I64Shl => Ident::Shl, + Self::S64Shr => Ident::Shr, + Self::U64Shr => Ident::Shr, + Self::I64Rotl => Ident::Rotl, + Self::I64Rotr => Ident::Rotr, + Self::F32Add => Ident::Add, + Self::F32Sub => Ident::Sub, + Self::F32Mul => Ident::Mul, + Self::F32Div => Ident::Div, + Self::F32Min => Ident::Min, + Self::F32Max => Ident::Max, + Self::F32Copysign => Ident::Copysign, + Self::F64Add => Ident::Add, + Self::F64Sub => Ident::Sub, + Self::F64Mul => Ident::Mul, + Self::F64Div => Ident::Div, + Self::F64Min => Ident::Min, + Self::F64Max => Ident::Max, + Self::F64Copysign => Ident::Copysign, } } - pub fn new(ident: Ident, result_ty: Ty, input_ty: Ty) -> Self { - Self { - ident, - result_ty, - input_ty, - commutative: false, + pub fn lhs_field(&self, input: Input) -> FieldTy { + match input { + Input::Stack => return FieldTy::Stack, + Input::Immediate => match self { + | Self::Cmp(cmp) => cmp.input_field(input), + | Self::I32Add + | Self::I32Sub + | Self::I32Mul + | Self::S32Div + | Self::U32Div + | Self::S32Rem + | Self::U32Rem + | Self::I32BitAnd + | Self::I32BitOr + | Self::I32BitXor + | Self::I32Shl + | Self::S32Shr + | Self::U32Shr + | Self::I32Rotl + | Self::I32Rotr => FieldTy::I32, + | Self::I64Add + | Self::I64Sub + | Self::I64Mul + | Self::S64Div + | Self::U64Div + | Self::S64Rem + | Self::U64Rem + | Self::I64BitAnd + | Self::I64BitOr + | Self::I64BitXor + | Self::I64Shl + | Self::S64Shr + | Self::U64Shr + | Self::I64Rotl + | Self::I64Rotr => FieldTy::I64, + | Self::F32Add + | Self::F32Sub + | Self::F32Mul + | Self::F32Div + | Self::F32Min + | Self::F32Max + | Self::F32Copysign => FieldTy::F32, + | Self::F64Add + | Self::F64Sub + | Self::F64Mul + | Self::F64Div + | Self::F64Min + | Self::F64Max + | Self::F64Copysign => FieldTy::F64, + }, + } + } + + pub fn rhs_field(&self, input: Input) -> FieldTy { + match input { + Input::Stack => return FieldTy::Stack, + Input::Immediate => match self { + | Self::Cmp(cmp) => cmp.input_field(input), + | Self::I32Add + | Self::I32Sub + | Self::I32Mul + | Self::I32BitAnd + | Self::I32BitOr + | Self::I32BitXor => FieldTy::I32, + | Self::I32Shl | Self::S32Shr | Self::U32Shr | Self::I32Rotl | Self::I32Rotr => { + FieldTy::U8 + } + | Self::S32Div | Self::U32Div | Self::S32Rem | Self::U32Rem => FieldTy::NonZeroU32, + | Self::I64Add + | Self::I64Sub + | Self::I64Mul + | Self::I64BitAnd + | Self::I64BitOr + | Self::I64BitXor => FieldTy::I64, + | Self::I64Shl | Self::S64Shr | Self::U64Shr | Self::I64Rotl | Self::I64Rotr => { + FieldTy::U8 + } + | Self::S64Div | Self::U64Div | Self::S64Rem | Self::U64Rem => FieldTy::NonZeroU64, + | Self::F32Add + | Self::F32Sub + | Self::F32Mul + | Self::F32Div + | Self::F32Min + | Self::F32Max => FieldTy::F32, + | Self::F32Copysign => FieldTy::SignF32, + | Self::F64Add + | Self::F64Sub + | Self::F64Mul + | Self::F64Div + | Self::F64Min + | Self::F64Max => FieldTy::F64, + | Self::F64Copysign => FieldTy::SignF64, + }, + } + } + + pub fn result_ty(&self) -> Ty { + match self { + | Self::Cmp(_) => Ty::I32, + | Self::I32Add + | Self::I32Sub + | Self::I32Mul + | Self::S32Div + | Self::U32Div + | Self::S32Rem + | Self::U32Rem + | Self::I32BitAnd + | Self::I32BitOr + | Self::I32BitXor + | Self::I32Shl + | Self::S32Shr + | Self::U32Shr + | Self::I32Rotl + | Self::I32Rotr => Ty::I32, + | Self::I64Add + | Self::I64Sub + | Self::I64Mul + | Self::S64Div + | Self::U64Div + | Self::S64Rem + | Self::U64Rem + | Self::I64BitAnd + | Self::I64BitOr + | Self::I64BitXor + | Self::I64Shl + | Self::S64Shr + | Self::U64Shr + | Self::I64Rotl + | Self::I64Rotr => Ty::I64, + | Self::F32Add + | Self::F32Sub + | Self::F32Mul + | Self::F32Div + | Self::F32Min + | Self::F32Max + | Self::F32Copysign => Ty::F32, + | Self::F64Add + | Self::F64Sub + | Self::F64Mul + | Self::F64Div + | Self::F64Min + | Self::F64Max + | Self::F64Copysign => Ty::F64, + } + } + + pub fn input_ty(&self) -> Ty { + match self { + | Self::Cmp(cmp) => cmp.input_ty(), + | Self::I32Add + | Self::I32Sub + | Self::I32Mul + | Self::S32Div + | Self::U32Div + | Self::S32Rem + | Self::U32Rem + | Self::I32BitAnd + | Self::I32BitOr + | Self::I32BitXor + | Self::I32Shl + | Self::S32Shr + | Self::U32Shr + | Self::I32Rotl + | Self::I32Rotr => Ty::I32, + | Self::I64Add + | Self::I64Sub + | Self::I64Mul + | Self::S64Div + | Self::U64Div + | Self::S64Rem + | Self::U64Rem + | Self::I64BitAnd + | Self::I64BitOr + | Self::I64BitXor + | Self::I64Shl + | Self::S64Shr + | Self::U64Shr + | Self::I64Rotl + | Self::I64Rotr => Ty::I64, + | Self::F32Add + | Self::F32Sub + | Self::F32Mul + | Self::F32Div + | Self::F32Min + | Self::F32Max + | Self::F32Copysign => Ty::F32, + | Self::F64Add + | Self::F64Sub + | Self::F64Mul + | Self::F64Div + | Self::F64Min + | Self::F64Max + | Self::F64Copysign => Ty::F64, + } + } + + pub fn commutativity(&self) -> Commutativity { + match self { + | Self::Cmp(cmp) => cmp.commutativity(), + | Self::I32Add + | Self::I32Mul + | Self::I32BitAnd + | Self::I32BitOr + | Self::I32BitXor + | Self::I64Add + | Self::I64Mul + | Self::I64BitAnd + | Self::I64BitOr + | Self::I64BitXor => Commutativity::Commutative, + _ => Commutativity::NonCommutative, } } } #[derive(Copy, Clone)] +pub enum Commutativity { + Commutative, + NonCommutative, +} + +impl BinaryOp { + pub fn new(kind: BinaryOpKind, lhs: FieldTy, rhs: FieldTy) -> Self { + Self { kind, lhs, rhs } + } +} + +#[derive(Copy, Clone)] +pub struct CmpBranchOp { + pub cmp: CmpOpKind, + pub lhs: Input, + pub rhs: Input, +} + +impl CmpBranchOp { + pub fn new(cmp: CmpOpKind, lhs: Input, rhs: Input) -> Self { + Self { cmp, lhs, rhs } + } +} + +#[derive(Copy, Clone)] +pub struct CmpSelectOp { + pub cmp: CmpOpKind, + pub lhs: Input, + pub rhs: Input, +} + +impl CmpSelectOp { + pub fn new(cmp: CmpOpKind, lhs: Input, rhs: Input) -> Self { + Self { cmp, lhs, rhs } + } +} + +#[derive(Copy, Clone, PartialEq, Eq)] pub enum Ty { + /// A general 32-bit integer type. I32, + /// A general 64-bit integer type. I64, + /// A signed 32-bit integer type. + S32, + /// A signed 64-bit integer type. + S64, + /// A unsigned 32-bit integer type. + U32, + /// A unsigned 64-bit integer type. + U64, + /// A 32-bit float type. F32, + /// A 64-bit float type. F64, + /// A general reference type. Ref, } +impl Display for Ty { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let s = match self { + Ty::I32 => "i32", + Ty::I64 => "i64", + Ty::S32 => "i32", + Ty::S64 => "i64", + Ty::U32 => "u32", + Ty::U64 => "u64", + Ty::F32 => "f32", + Ty::F64 => "f64", + Ty::Ref => "ref", + }; + write!(f, "{s}") + } +} + impl From for Ident { fn from(ty: Ty) -> Self { match ty { Ty::I32 => Self::I32, Ty::I64 => Self::I64, + Ty::S32 => Self::S32, + Ty::S64 => Self::S64, + Ty::U32 => Self::U32, + Ty::U64 => Self::U64, Ty::F32 => Self::F32, Ty::F64 => Self::F64, Ty::Ref => Self::Ref, } } } + +#[derive(Copy, Clone)] +pub enum FieldTy { + Stack, + StackSpan, + BoundedStackSpan, + U8, + U32, + U64, + I8, + I16, + I32, + I64, + F32, + F64, + NonZeroU32, + NonZeroU64, + NonZeroI32, + NonZeroI64, + SignF32, + SignF64, + Address, + Offset16, + BranchOffset, + Memory, + Table, + Global, + Func, + FuncType, + InternalFunc, + Elem, + Data, + TrapCode, + BlockFuel, +} + +impl Display for FieldTy { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let s = match self { + Self::Stack => "Stack", + Self::StackSpan => "StackSpan", + Self::BoundedStackSpan => "BoundedStackSpan", + Self::U8 => "u8", + Self::U32 => "u32", + Self::U64 => "u64", + Self::I8 => "i8", + Self::I16 => "i16", + Self::I32 => "i32", + Self::I64 => "i64", + Self::F32 => "f32", + Self::F64 => "f64", + Self::NonZeroU32 => "NonZero", + Self::NonZeroU64 => "NonZero", + Self::NonZeroI32 => "NonZero", + Self::NonZeroI64 => "NonZero", + Self::SignF32 => "Sign", + Self::SignF64 => "Sign", + Self::Address => "Address", + Self::Offset16 => "Offset16", + Self::BranchOffset => "BranchOffset", + Self::Memory => "Memory", + Self::Table => "Table", + Self::Global => "Global", + Self::Func => "Func", + Self::FuncType => "FuncType", + Self::InternalFunc => "InternalFunc", + Self::Elem => "Elem", + Self::Data => "Data", + Self::TrapCode => "TrapCode", + Self::BlockFuel => "BlockFuel", + }; + write!(f, "{s}") + } +} + +#[derive(Copy, Clone)] +pub enum CmpOpKind { + I32Eq, + I32NotEq, + I32And, + I32NotAnd, + I32Or, + I32NotOr, + S32Lt, + U32Lt, + S32Le, + U32Le, + + I64Eq, + I64NotEq, + I64And, + I64NotAnd, + I64Or, + I64NotOr, + S64Lt, + U64Lt, + S64Le, + U64Le, + + F32Eq, + F32NotEq, + F32Lt, + F32NotLt, + F32Le, + F32NotLe, + + F64Eq, + F64NotEq, + F64Lt, + F64NotLt, + F64Le, + F64NotLe, +} + +impl CmpOpKind { + pub fn commutativity(&self) -> Commutativity { + match self { + | Self::I32Eq + | Self::I32NotEq + | Self::I32And + | Self::I32NotAnd + | Self::I32Or + | Self::I32NotOr + | Self::I64Eq + | Self::I64NotEq + | Self::I64And + | Self::I64NotAnd + | Self::I64Or + | Self::I64NotOr + | Self::F32Eq + | Self::F32NotEq + | Self::F64Eq + | Self::F64NotEq => Commutativity::Commutative, + _ => Commutativity::NonCommutative, + } + } + + pub fn input_field(&self, input: Input) -> FieldTy { + match input { + Input::Stack => FieldTy::Stack, + Input::Immediate => match self { + | Self::I32Eq + | Self::I32NotEq + | Self::I32And + | Self::I32NotAnd + | Self::I32Or + | Self::I32NotOr + | Self::S32Lt + | Self::S32Le => FieldTy::I32, + | Self::U32Lt | Self::U32Le => FieldTy::U32, + | Self::I64Eq + | Self::I64NotEq + | Self::I64And + | Self::I64NotAnd + | Self::I64Or + | Self::I64NotOr + | Self::S64Lt + | Self::S64Le => FieldTy::I64, + | Self::U64Lt | Self::U64Le => FieldTy::U64, + | Self::F32Eq + | Self::F32NotEq + | Self::F32Lt + | Self::F32NotLt + | Self::F32Le + | Self::F32NotLe => FieldTy::F32, + | Self::F64Eq + | Self::F64NotEq + | Self::F64Lt + | Self::F64NotLt + | Self::F64Le + | Self::F64NotLe => FieldTy::F64, + }, + } + } + + pub fn input_ty(&self) -> Ty { + match self { + | Self::I32Eq + | Self::I32NotEq + | Self::I32And + | Self::I32NotAnd + | Self::I32Or + | Self::I32NotOr + | Self::S32Lt + | Self::U32Lt + | Self::S32Le + | Self::U32Le => Ty::I32, + | Self::I64Eq + | Self::I64NotEq + | Self::I64And + | Self::I64NotAnd + | Self::I64Or + | Self::I64NotOr + | Self::S64Lt + | Self::U64Lt + | Self::S64Le + | Self::U64Le => Ty::I64, + | Self::F32Eq + | Self::F32NotEq + | Self::F32Lt + | Self::F32NotLt + | Self::F32Le + | Self::F32NotLe => Ty::F32, + | Self::F64Eq + | Self::F64NotEq + | Self::F64Lt + | Self::F64NotLt + | Self::F64Le + | Self::F64NotLe => Ty::F64, + } + } + + pub fn ident(&self) -> Ident { + match self { + Self::I32Eq => Ident::Eq, + Self::I32NotEq => Ident::NotEq, + Self::I32And => Ident::And, + Self::I32NotAnd => Ident::NotAnd, + Self::I32Or => Ident::Or, + Self::I32NotOr => Ident::NotOr, + Self::S32Lt => Ident::Lt, + Self::U32Lt => Ident::Lt, + Self::S32Le => Ident::Le, + Self::U32Le => Ident::Le, + Self::I64Eq => Ident::Eq, + Self::I64NotEq => Ident::NotEq, + Self::I64And => Ident::And, + Self::I64NotAnd => Ident::NotAnd, + Self::I64Or => Ident::Or, + Self::I64NotOr => Ident::NotOr, + Self::S64Lt => Ident::Lt, + Self::U64Lt => Ident::Lt, + Self::S64Le => Ident::Le, + Self::U64Le => Ident::Le, + Self::F32Eq => Ident::Eq, + Self::F32NotEq => Ident::NotEq, + Self::F32Lt => Ident::Lt, + Self::F32NotLt => Ident::NotLt, + Self::F32Le => Ident::Le, + Self::F32NotLe => Ident::NotLe, + Self::F64Eq => Ident::Eq, + Self::F64NotEq => Ident::NotEq, + Self::F64Lt => Ident::Lt, + Self::F64NotLt => Ident::NotLt, + Self::F64Le => Ident::Le, + Self::F64NotLe => Ident::NotLe, + } + } +} + +#[derive(Copy, Clone)] +pub struct LoadOp { + /// The kind of the load operator. + kind: LoadOpKind, + /// The `ptr` field type. + ptr: Input, + /// True, if the operator is always operating on (`memory 0`). + mem0: bool, + /// True, if the operator uses a 16-bit offset field. + offset16: bool, +} + +#[derive(Copy, Clone)] +pub enum LoadOpKind { + I32Load, + S32Load8, + U32Load8, + S32Load16, + U32Load16, + I64Load, + S64Load8, + U64Load8, + S64Load16, + U64Load16, + S64Load32, + U64Load32, + F32Load, + F64Load, +} + +impl LoadOpKind { + pub fn ident(&self) -> Ident { + match self { + Self::I32Load => Ident::Load, + Self::S32Load8 => Ident::Load8, + Self::U32Load8 => Ident::Load8, + Self::S32Load16 => Ident::Load16, + Self::U32Load16 => Ident::Load16, + Self::I64Load => Ident::Load, + Self::S64Load8 => Ident::Load8, + Self::U64Load8 => Ident::Load8, + Self::S64Load16 => Ident::Load16, + Self::U64Load16 => Ident::Load16, + Self::S64Load32 => Ident::Load32, + Self::U64Load32 => Ident::Load32, + Self::F32Load => Ident::Load, + Self::F64Load => Ident::Load, + } + } + + pub fn result_ty(&self) -> Ty { + match self { + LoadOpKind::I32Load => Ty::I32, + LoadOpKind::S32Load8 => Ty::S32, + LoadOpKind::U32Load8 => Ty::U32, + LoadOpKind::S32Load16 => Ty::S32, + LoadOpKind::U32Load16 => Ty::U32, + LoadOpKind::I64Load => Ty::I64, + LoadOpKind::S64Load8 => Ty::S64, + LoadOpKind::U64Load8 => Ty::U64, + LoadOpKind::S64Load16 => Ty::S64, + LoadOpKind::U64Load16 => Ty::U64, + LoadOpKind::S64Load32 => Ty::S64, + LoadOpKind::U64Load32 => Ty::U64, + LoadOpKind::F32Load => Ty::F32, + LoadOpKind::F64Load => Ty::F64, + } + } +} + +#[derive(Copy, Clone)] +pub struct StoreOp { + /// The kind of the load operator. + kind: StoreOpKind, + /// The `ptr` input type. + ptr: Input, + /// The `value` input type. + value: Input, + /// True, if the operator is always operating on (`memory 0`). + mem0: bool, + /// True, if the operator uses a 16-bit offset field. + offset16: bool, +} + +#[derive(Copy, Clone)] +pub enum StoreOpKind { + I32Store, + I32Store8, + I32Store16, + I64Store, + I64Store8, + I64Store16, + I64Store32, + F32Store, + F64Store, +} + +impl StoreOpKind { + pub fn ident(&self) -> Ident { + match self { + Self::I32Store => Ident::Store, + Self::I32Store8 => Ident::Store8, + Self::I32Store16 => Ident::Store16, + Self::I64Store => Ident::Store, + Self::I64Store8 => Ident::Store8, + Self::I64Store16 => Ident::Store16, + Self::I64Store32 => Ident::Store32, + Self::F32Store => Ident::Store, + Self::F64Store => Ident::Store, + } + } + + pub fn value_ty(&self, input: Input) -> FieldTy { + match input { + Input::Stack => return FieldTy::Stack, + Input::Immediate => match self { + Self::I32Store => FieldTy::I32, + Self::I32Store8 => FieldTy::I8, + Self::I32Store16 => FieldTy::I16, + Self::I64Store => FieldTy::I64, + Self::I64Store8 => FieldTy::I8, + Self::I64Store16 => FieldTy::I16, + Self::I64Store32 => FieldTy::I32, + Self::F32Store => FieldTy::F32, + Self::F64Store => FieldTy::F64, + }, + } + } +} + +#[derive(Copy, Clone)] +pub enum Input { + Stack, + Immediate, +} + +impl Display for CamelCase { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s = match self.0 { + Input::Stack => "S", + Input::Immediate => "I", + }; + write!(f, "{s}") + } +} + +impl Display for SnakeCase { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s = match self.0 { + Input::Stack => "s", + Input::Immediate => "i", + }; + write!(f, "{s}") + } +} diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index d55d4fadab..4b6dc5b607 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -45,58 +45,42 @@ define_ident!( Sub: sub, Mul: mul, Div: div, - Sdiv: sdiv, - Udiv: udiv, - Srem: srem, - Urem: urem, + Rem: rem, Min: min, Max: max, Copysign: copysign, Shl: shl, - Sshr: sshr, - Ushr: ushr, + Shr: shr, Rotl: rotl, Rotr: rotr, Eq: eq, - Ne: ne, - Slt: slt, - Ult: ult, - Sle: sle, - Ule: ule, - Lt: lt, - Le: le, - NotLt: not_lt, - NotLe: not_le, - And: and, Or: or, + NotEq: ne, NotAnd: not_and, NotOr: not_or, + Lt: lt, + Le: le, + NotLt: not_lt, + NotLe: not_le, BitAnd: bit_and, BitOr: bit_or, BitXor: bit_xor, - Popcnt: popcnt, - Clz: clz, - Ctz: ctz, - - Not: not, - Abs: abs, - Neg: neg, - Ceil: ceil, - Floor: floor, - Trunc: trunc, - Nearest: nearest, - Sqrt: sqrt, - Return: r#return, Branch: branch, Select: select, Store: store, + Store8: store8, + Store16: store16, + Store32: store32, Load: load, + Load8: load8, + Load16: load16, + Load32: load32, Copy: copy, Fill: fill, @@ -108,6 +92,7 @@ define_ident!( Table: table, Memory: memory, Func: func, + FuncType: func_type, Global: global, Elem: elem, Data: data, @@ -118,9 +103,39 @@ define_ident!( ReturnCall: return_call, ReturnCallIndirect: return_call_indirect, + U8: r#u8, + U16: r#u16, + U32: r#u32, + U64: r#u64, + I8: r#i8, + I16: r#i16, I32: r#i32, I64: r#i64, + S8: s8, + S16: s16, + S32: s32, + S64: s64, F32: r#f32, F64: r#f64, Ref: r#ref, + + Not: not, + Clz: clz, + Ctz: ctz, + Popcnt: popcnt, + Wrap: wrap, + Sext8: sext8, + Sext16: sext16, + Sext32: sext32, + Abs: abs, + Neg: neg, + Ceil: ceil, + Floor: floor, + Trunc: trunc, + TruncSat: trunc_sat, + Nearest: nearest, + Sqrt: sqrt, + Demote: demote, + Promote: promote, + Convert: convert, ); diff --git a/crates/ir2/src/lib.rs b/crates/ir2/src/lib.rs index 8b13789179..2d714c61ae 100644 --- a/crates/ir2/src/lib.rs +++ b/crates/ir2/src/lib.rs @@ -1 +1,5 @@ +#![allow(warnings)] +mod ops; + +pub use self::ops::Instruction; diff --git a/crates/ir2/src/ops.rs b/crates/ir2/src/ops.rs new file mode 100644 index 0000000000..82cb78f5bc --- /dev/null +++ b/crates/ir2/src/ops.rs @@ -0,0 +1 @@ +include!(concat!(env!("OUT_DIR"), "/instruction.rs")); From 5fefcaedeb8ed3fb9671ccb793f5bb10c5630323 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 20 Aug 2025 18:34:39 +0200 Subject: [PATCH 004/186] fix codegen for unary ops --- crates/ir2/build/display.rs | 8 ++++---- crates/ir2/build/op.rs | 12 ++++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/crates/ir2/build/display.rs b/crates/ir2/build/display.rs index c2c055c583..24cf17c597 100644 --- a/crates/ir2/build/display.rs +++ b/crates/ir2/build/display.rs @@ -91,9 +91,9 @@ impl Display for DisplayEnum<&'_ Op> { impl Display for DisplayEnum<&'_ UnaryOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.val.kind.is_conversion() { - self.display_unary(f) - } else { self.display_conversion(f) + } else { + self.display_unary(f) } } } @@ -113,7 +113,7 @@ impl DisplayEnum<&'_ UnaryOp> { {indent0}{result_ident}{ident}_Ss {{\n\ {indent1}result: {result_field},\n\ {indent1}value: {value_field},\n\ - {indent0}}}\n\ + {indent0}}},\n\ ", ) } @@ -135,7 +135,7 @@ impl DisplayEnum<&'_ UnaryOp> { {indent0}{result_ident}{ident}{input_ident}_Ss {{\n\ {indent1}result: {result_field},\n\ {indent1}value: {value_field},\n\ - {indent0}}}\n\ + {indent0}}},\n\ ", ) } diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index bcdfef2863..9e13a7d81c 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -139,10 +139,14 @@ impl UnaryOpKind { | Self::S64TruncSatF32 | Self::U64TruncSatF32 => Ty::F32, | Self::S64TruncSatF64 | Self::U64TruncSatF64 | Self::F32DemoteF64 => Ty::F64, | Self::F64PromoteF32 => Ty::F32, - | Self::F32ConvertS32 | Self::F32ConvertU32 => Ty::I32, - | Self::F32ConvertS64 | Self::F32ConvertU64 => Ty::I64, - | Self::F64ConvertS32 | Self::F64ConvertU32 => Ty::I32, - | Self::F64ConvertS64 | Self::F64ConvertU64 => Ty::I64, + | Self::F32ConvertS32 => Ty::I32, + | Self::F32ConvertU32 => Ty::U32, + | Self::F32ConvertS64 => Ty::I64, + | Self::F32ConvertU64 => Ty::U64, + | Self::F64ConvertS32 => Ty::I32, + | Self::F64ConvertU32 => Ty::U32, + | Self::F64ConvertS64 => Ty::I64, + | Self::F64ConvertU64 => Ty::U64, } } From 56aa7083c15fcc6c3165e2b55fe0b98fed6b7543 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 20 Aug 2025 18:34:49 +0200 Subject: [PATCH 005/186] add wasmi_ir2 crate contents --- crates/ir2/src/error.rs | 27 +++ crates/ir2/src/index.rs | 105 +++++++++++ crates/ir2/src/lib.rs | 19 +- crates/ir2/src/ops.rs | 2 + crates/ir2/src/primitive.rs | 220 +++++++++++++++++++++++ crates/ir2/src/span.rs | 338 ++++++++++++++++++++++++++++++++++++ 6 files changed, 710 insertions(+), 1 deletion(-) create mode 100644 crates/ir2/src/error.rs create mode 100644 crates/ir2/src/index.rs create mode 100644 crates/ir2/src/primitive.rs create mode 100644 crates/ir2/src/span.rs diff --git a/crates/ir2/src/error.rs b/crates/ir2/src/error.rs new file mode 100644 index 0000000000..cb9062bbfc --- /dev/null +++ b/crates/ir2/src/error.rs @@ -0,0 +1,27 @@ +use core::fmt; + +/// An error that may be occurred when operating with some Wasmi IR primitives. +#[derive(Debug)] +pub enum Error { + /// Encountered when trying to create a [`Reg`](crate::Reg) from an out of bounds integer. + StackSlotOutOfBounds, + /// Encountered when trying to create a [`BranchOffset`](crate::BranchOffset) from an out of bounds integer. + BranchOffsetOutOfBounds, + /// Encountered when trying to create a [`Comparator`](crate::Comparator) from an out of bounds integer. + ComparatorOutOfBounds, + /// Encountered when trying to create a [`BlockFuel`](crate::BlockFuel) from an out of bounds integer. + BlockFuelOutOfBounds, +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::StackSlotOutOfBounds => write!(f, "stack slot out of bounds"), + Self::BranchOffsetOutOfBounds => write!(f, "branch offset out of bounds"), + Self::ComparatorOutOfBounds => write!(f, "comparator out of bounds"), + Self::BlockFuelOutOfBounds => write!(f, "block fuel out of bounds"), + } + } +} + +impl core::error::Error for Error {} diff --git a/crates/ir2/src/index.rs b/crates/ir2/src/index.rs new file mode 100644 index 0000000000..f996b6b941 --- /dev/null +++ b/crates/ir2/src/index.rs @@ -0,0 +1,105 @@ +//! Definitions for thin-wrapper index types. + +use crate::Error; + +macro_rules! for_each_index { + ($mac:ident) => { + $mac! { + /// A Wasmi stack slot. + Stack(pub(crate) u16); + /// A Wasm function index. + Func(pub(crate) u32); + /// A Wasm function type index. + FuncType(pub(crate) u32); + /// A Wasmi internal function index. + InternalFunc(pub(crate) u32); + /// A Wasm global variable index. + Global(pub(crate) u32); + /// A Wasm linear memory index. + Memory(pub(crate) u16); + /// A Wasm table index. + Table(pub(crate) u32); + /// A Wasm data segment index. + Data(pub(crate) u32); + /// A Wasm element segment index. + Elem(pub(crate) u32); + } + }; +} + +impl Memory { + /// Returns `true` if `self` refers to the default linear memory which always is at index 0. + pub fn is_default(&self) -> bool { + self.0 == 0 + } +} + +macro_rules! define_index { + ( + $( + $( #[$docs:meta] )* + $name:ident($vis:vis $ty:ty) + );* $(;)? + ) => { + $( + $( #[$docs] )* + #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct $name($vis $ty); + + impl From<$name> for $ty { + fn from(value: $name) -> $ty { + value.0 + } + } + + impl From<$ty> for $name { + fn from(value: $ty) -> Self { + Self(value) + } + } + )* + }; +} +for_each_index!(define_index); + +impl TryFrom for Stack { + type Error = Error; + + fn try_from(local_index: u32) -> Result { + u16::try_from(local_index) + .map_err(|_| Error::StackSlotOutOfBounds) + .map(Self::from) + } +} + +impl Stack { + /// Returns the n-th next [`Stack`] from `self` with contiguous index. + /// + /// # Note + /// + /// - Calling this with `n == 0` just returns `self`. + /// - This has wrapping semantics with respect to the underlying index. + pub fn next_n(self, n: u16) -> Self { + Self(self.0.wrapping_add(n)) + } + + /// Returns the n-th previous [`Stack`] from `self` with contiguous index. + /// + /// # Note + /// + /// - Calling this with `n == 0` just returns `self`. + /// - This has wrapping semantics with respect to the underlying index. + pub fn prev_n(self, n: u16) -> Self { + Self(self.0.wrapping_sub(n)) + } + + /// Returns the [`Stack`] with the next contiguous index. + pub fn next(self) -> Self { + self.next_n(1) + } + + /// Returns the [`Stack`] with the previous contiguous index. + pub fn prev(self) -> Self { + self.prev_n(1) + } +} diff --git a/crates/ir2/src/lib.rs b/crates/ir2/src/lib.rs index 2d714c61ae..4431ebe64a 100644 --- a/crates/ir2/src/lib.rs +++ b/crates/ir2/src/lib.rs @@ -1,5 +1,22 @@ #![allow(warnings)] +#![no_std] +extern crate alloc; +#[cfg(feature = "std")] +extern crate std; + +mod error; +mod index; mod ops; +mod primitive; +mod span; + +use wasmi_core as core; -pub use self::ops::Instruction; +pub use self::{ + error::Error, + index::Stack, + ops::Instruction, + primitive::{Address, BlockFuel, BranchOffset, Offset16, Sign}, + span::{BoundedStackSpan, FixedStackSpan, StackSpan}, +}; diff --git a/crates/ir2/src/ops.rs b/crates/ir2/src/ops.rs index 82cb78f5bc..306e710f8c 100644 --- a/crates/ir2/src/ops.rs +++ b/crates/ir2/src/ops.rs @@ -1 +1,3 @@ +use crate::Stack; + include!(concat!(env!("OUT_DIR"), "/instruction.rs")); diff --git a/crates/ir2/src/primitive.rs b/crates/ir2/src/primitive.rs new file mode 100644 index 0000000000..4736b35009 --- /dev/null +++ b/crates/ir2/src/primitive.rs @@ -0,0 +1,220 @@ +use crate::Error; +use core::marker::PhantomData; + +/// Error that may occur upon converting values to [`Const16`]. +#[derive(Debug, Copy, Clone)] +pub struct OutOfBoundsConst; + +/// The sign of a value. +#[derive(Debug)] +pub struct Sign { + /// Whether the sign value is positive. + is_positive: bool, + /// Required for the Rust compiler. + marker: PhantomData T>, +} + +impl Clone for Sign { + fn clone(&self) -> Self { + *self + } +} + +impl Copy for Sign {} + +impl PartialEq for Sign { + fn eq(&self, other: &Self) -> bool { + self.is_positive == other.is_positive + } +} + +impl Eq for Sign {} + +impl Sign { + /// Create a new typed [`Sign`] with the given value. + fn new(is_positive: bool) -> Self { + Self { + is_positive, + marker: PhantomData, + } + } + + /// Creates a new typed [`Sign`] that has positive polarity. + pub fn pos() -> Self { + Self::new(true) + } + + /// Creates a new typed [`Sign`] that has negative polarity. + pub fn neg() -> Self { + Self::new(false) + } +} + +macro_rules! impl_sign_for { + ( $($ty:ty),* $(,)? ) => { + $( + impl From<$ty> for Sign<$ty> { + fn from(value: $ty) -> Self { + Self::new(value.is_sign_positive()) + } + } + + impl From> for $ty { + fn from(sign: Sign<$ty>) -> Self { + match sign.is_positive { + true => 1.0, + false => -1.0, + } + } + } + )* + }; +} +impl_sign_for!(f32, f64); + +/// A signed offset for branch instructions. +/// +/// This defines how much the instruction pointer is offset +/// upon taking the respective branch. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct BranchOffset(i32); + +impl From for BranchOffset { + fn from(index: i32) -> Self { + Self(index) + } +} + +impl BranchOffset { + /// Creates an uninitialized [`BranchOffset`]. + pub fn uninit() -> Self { + Self(0) + } + + /// Creates an initialized [`BranchOffset`] from `src` to `dst`. + /// + /// # Errors + /// + /// If the resulting [`BranchOffset`] is out of bounds. + pub fn from_src_to_dst(src: u32, dst: u32) -> Result { + let src = i64::from(src); + let dst = i64::from(dst); + let Some(offset) = dst.checked_sub(src) else { + // Note: This never needs to be called on backwards branches since they are immediated resolved. + unreachable!( + "offset for forward branches must have `src` be smaller than or equal to `dst`" + ); + }; + let Ok(offset) = i32::try_from(offset) else { + return Err(Error::BranchOffsetOutOfBounds); + }; + Ok(Self(offset)) + } + + /// Returns `true` if the [`BranchOffset`] has been initialized. + pub fn is_init(self) -> bool { + self.to_i32() != 0 + } + + /// Initializes the [`BranchOffset`] with a proper value. + /// + /// # Panics + /// + /// - If the [`BranchOffset`] have already been initialized. + /// - If the given [`BranchOffset`] is not properly initialized. + pub fn init(&mut self, valid_offset: BranchOffset) { + assert!(valid_offset.is_init()); + assert!(!self.is_init()); + *self = valid_offset; + } + + /// Returns the `i32` representation of the [`BranchOffset`]. + pub fn to_i32(self) -> i32 { + self.0 + } +} + +/// The accumulated fuel to execute a block via [`Instruction::ConsumeFuel`]. +/// +/// [`Instruction::ConsumeFuel`]: [`super::Instruction::ConsumeFuel`] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[repr(transparent)] +pub struct BlockFuel(u64); + +impl From for BlockFuel { + fn from(value: u64) -> Self { + Self(value) + } +} + +impl From for u64 { + fn from(value: BlockFuel) -> Self { + value.0 + } +} + +impl BlockFuel { + /// Bump the fuel by `amount` if possible. + /// + /// # Errors + /// + /// If the new fuel amount after this operation is out of bounds. + pub fn bump_by(&mut self, amount: u64) -> Result<(), Error> { + self.0 = u64::from(*self) + .checked_add(amount) + .ok_or(Error::BlockFuelOutOfBounds)?; + Ok(()) + } +} + +/// A 64-bit memory address used for some load and store instructions. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[repr(transparent)] +pub struct Address(u64); + +impl TryFrom for Address { + type Error = OutOfBoundsConst; + + fn try_from(address: u64) -> Result { + if usize::try_from(address).is_err() { + return Err(OutOfBoundsConst); + }; + Ok(Self(address)) + } +} + +impl From
for usize { + fn from(address: Address) -> Self { + // Note: no checks are needed since we statically ensured that + // `Address32` can be safely and losslessly cast to `usize`. + debug_assert!(usize::try_from(address.0).is_ok()); + address.0 as usize + } +} + +impl From
for u64 { + fn from(address: Address) -> Self { + address.0 + } +} + +/// A 16-bit encoded load or store address offset. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[repr(transparent)] +pub struct Offset16(u16); + +impl TryFrom for Offset16 { + type Error = OutOfBoundsConst; + + fn try_from(address: u64) -> Result { + ::try_from(address) + .map(Self) + .map_err(|_| OutOfBoundsConst) + } +} + +impl From for u16 { + fn from(offset: Offset16) -> Self { + offset.0 + } +} diff --git a/crates/ir2/src/span.rs b/crates/ir2/src/span.rs new file mode 100644 index 0000000000..f510701157 --- /dev/null +++ b/crates/ir2/src/span.rs @@ -0,0 +1,338 @@ +use crate::{Error, Stack}; + +/// A [`StackSpan`] of contiguous [`Stack`] indices. +/// +/// # Note +/// +/// - Represents an amount of contiguous [`Stack`] indices. +/// - For the sake of space efficiency the actual number of [`Stack`] +/// of the [`StackSpan`] is stored externally and provided in +/// [`StackSpan::iter`] when there is a need to iterate over +/// the [`Stack`] of the [`StackSpan`]. +/// +/// The caller is responsible for providing the correct length. +/// Due to Wasm validation guided bytecode construction we assert +/// that the externally stored length is valid. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[repr(transparent)] +pub struct StackSpan(Stack); + +impl StackSpan { + /// Creates a new [`StackSpan`] starting with the given `start` [`Stack`]. + pub fn new(head: Stack) -> Self { + Self(head) + } + + /// Returns a [`StackSpanIter`] yielding `len` [`Stack`]s. + pub fn iter_sized(self, len: usize) -> StackSpanIter { + StackSpanIter::new(self.0, len) + } + + /// Returns a [`StackSpanIter`] yielding `len` [`Stack`]s. + pub fn iter(self, len: u16) -> StackSpanIter { + StackSpanIter::new_u16(self.0, len) + } + + /// Returns the head [`Stack`] of the [`StackSpan`]. + pub fn head(self) -> Stack { + self.0 + } + + /// Returns an exclusive reference to the head [`Stack`] of the [`StackSpan`]. + pub fn head_mut(&mut self) -> &mut Stack { + &mut self.0 + } + + /// Returns `true` if `copy_span results <- values` has overlapping copies. + /// + /// # Examples + /// + /// - `[ ]`: empty never overlaps + /// - `[ 1 <- 0 ]`: single element never overlaps + /// - `[ 0 <- 1, 1 <- 2, 2 <- 3 ]`: no overlap + /// - `[ 1 <- 0, 2 <- 1 ]`: overlaps! + pub fn has_overlapping_copies(results: Self, values: Self, len: u16) -> bool { + StackSpanIter::has_overlapping_copies(results.iter(len), values.iter(len)) + } +} + +/// A [`StackSpan`] with a statically known number of [`Stack`]. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[repr(transparent)] +pub struct FixedStackSpan { + /// The underlying [`StackSpan`] without the known length. + span: StackSpan, +} + +impl FixedStackSpan<2> { + /// Returns an array of the results represented by `self`. + pub fn to_array(self) -> [Stack; 2] { + let span = self.span(); + let fst = span.head(); + let snd = fst.next(); + [fst, snd] + } +} + +impl FixedStackSpan { + /// Creates a new [`StackSpan`] starting with the given `start` [`Stack`]. + pub fn new(span: StackSpan) -> Result { + let head = span.head(); + if head >= head.next_n(N) { + return Err(Error::StackSlotOutOfBounds); + } + Ok(Self { span }) + } + + /// Returns a [`StackSpanIter`] yielding `N` [`Stack`]s. + pub fn iter(&self) -> StackSpanIter { + self.span.iter(self.len()) + } + + /// Creates a new [`BoundedStackSpan`] from `self`. + pub fn bounded(self) -> BoundedStackSpan { + BoundedStackSpan { + span: self.span, + len: N, + } + } + + /// Returns the underlying [`StackSpan`] of `self`. + pub fn span(self) -> StackSpan { + self.span + } + + /// Returns an exclusive reference to the underlying [`StackSpan`] of `self`. + pub fn span_mut(&mut self) -> &mut StackSpan { + &mut self.span + } + + /// Returns `true` if the [`Stack`] is contained in `self`. + pub fn contains(self, reg: Stack) -> bool { + if self.is_empty() { + return false; + } + let min = self.span.head(); + let max = min.next_n(N); + min <= reg && reg < max + } + + /// Returns the number of [`Stack`]s in `self`. + pub fn len(self) -> u16 { + N + } + + /// Returns `true` if `self` is empty. + pub fn is_empty(self) -> bool { + N == 0 + } +} + +impl IntoIterator for &FixedStackSpan { + type Item = Stack; + type IntoIter = StackSpanIter; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl IntoIterator for FixedStackSpan { + type Item = Stack; + type IntoIter = StackSpanIter; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +/// A [`StackSpan`] with a known number of [`Stack`]. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct BoundedStackSpan { + /// The first [`Stack`] in `self`. + span: StackSpan, + /// The number of [`Stack`] in `self`. + len: u16, +} + +impl BoundedStackSpan { + /// Creates a new [`BoundedStackSpan`] from the given `span` and `len`. + pub fn new(span: StackSpan, len: u16) -> Self { + Self { span, len } + } + + /// Returns a [`StackSpanIter`] yielding `len` [`Stack`]s. + pub fn iter(&self) -> StackSpanIter { + self.span.iter(self.len()) + } + + /// Returns `self` as unbounded [`StackSpan`]. + pub fn span(&self) -> StackSpan { + self.span + } + + /// Returns a mutable reference to the underlying [`StackSpan`]. + pub fn span_mut(&mut self) -> &mut StackSpan { + &mut self.span + } + + /// Returns `true` if the [`Stack`] is contained in `self`. + pub fn contains(self, reg: Stack) -> bool { + if self.is_empty() { + return false; + } + let min = self.span.head(); + let max = min.next_n(self.len); + min <= reg && reg < max + } + + /// Returns the number of [`Stack`] in `self`. + pub fn len(&self) -> u16 { + self.len + } + + /// Returns `true` if `self` is empty. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } +} + +impl IntoIterator for &BoundedStackSpan { + type Item = Stack; + type IntoIter = StackSpanIter; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl IntoIterator for BoundedStackSpan { + type Item = Stack; + type IntoIter = StackSpanIter; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +/// A [`StackSpanIter`] iterator yielding contiguous [`Stack`]. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct StackSpanIter { + /// The next [`Stack`] in the [`StackSpanIter`]. + next: Stack, + /// The last [`Stack`] in the [`StackSpanIter`]. + last: Stack, +} + +impl StackSpanIter { + /// Creates a [`StackSpanIter`] from then given raw `start` and `end` [`Stack`]. + pub fn from_raw_parts(start: Stack, end: Stack) -> Self { + debug_assert!(u16::from(start) <= u16::from(end)); + Self { + next: start, + last: end, + } + } + + /// Creates a new [`StackSpanIter`] for the given `start` [`Stack`] and length `len`. + /// + /// # Panics + /// + /// If the `start..end` [`Stack`] span indices are out of bounds. + fn new(start: Stack, len: usize) -> Self { + let len = u16::try_from(len) + .unwrap_or_else(|_| panic!("out of bounds length for register span: {len}")); + Self::new_u16(start, len) + } + + /// Creates a new [`StackSpanIter`] for the given `start` [`Stack`] and length `len`. + /// + /// # Panics + /// + /// If the `start..end` [`Stack`] span indices are out of bounds. + fn new_u16(start: Stack, len: u16) -> Self { + let next = start; + let last = start + .0 + .checked_add(len) + .map(Stack) + .expect("overflowing register index for register span"); + Self::from_raw_parts(next, last) + } + + /// Creates a [`StackSpan`] from this [`StackSpanIter`]. + pub fn span(self) -> StackSpan { + StackSpan(self.next) + } + + /// Returns the remaining number of [`Stack`]s yielded by the [`StackSpanIter`]. + pub fn len_as_u16(&self) -> u16 { + self.last.0.abs_diff(self.next.0) + } + + /// Returns `true` if `self` yields no more [`Stack`]s. + pub fn is_empty(&self) -> bool { + self.len_as_u16() == 0 + } + + /// Returns `true` if `copy_span results <- values` has overlapping copies. + /// + /// # Examples + /// + /// - `[ ]`: empty never overlaps + /// - `[ 1 <- 0 ]`: single element never overlaps + /// - `[ 0 <- 1, 1 <- 2, 2 <- 3 ]`: no overlap + /// - `[ 1 <- 0, 2 <- 1 ]`: overlaps! + pub fn has_overlapping_copies(results: Self, values: Self) -> bool { + assert_eq!( + results.len(), + values.len(), + "cannot copy between different sized register spans" + ); + let len = results.len(); + if len <= 1 { + // Empty spans or single-element spans can never overlap. + return false; + } + let first_value = values.span().head(); + let first_result = results.span().head(); + if first_value >= first_result { + // This case can never result in overlapping copies. + return false; + } + let mut values = values; + let last_value = values + .next_back() + .expect("span is non empty and thus must return"); + last_value >= first_result + } +} + +impl Iterator for StackSpanIter { + type Item = Stack; + + fn next(&mut self) -> Option { + if self.next == self.last { + return None; + } + let reg = self.next; + self.next = self.next.next(); + Some(reg) + } +} + +impl DoubleEndedIterator for StackSpanIter { + fn next_back(&mut self) -> Option { + if self.next == self.last { + return None; + } + self.last = self.last.prev(); + Some(self.last) + } +} + +impl ExactSizeIterator for StackSpanIter { + fn len(&self) -> usize { + usize::from(StackSpanIter::len_as_u16(self)) + } +} From 541a258a53d7b1cec6e268aa608ad1f8df8430ac Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 20 Aug 2025 18:36:09 +0200 Subject: [PATCH 006/186] rename files and Instruction -> Op --- crates/ir2/build/display.rs | 2 +- crates/ir2/build/mod.rs | 5 +---- crates/ir2/src/lib.rs | 4 ++-- crates/ir2/src/op.rs | 3 +++ crates/ir2/src/ops.rs | 3 --- 5 files changed, 7 insertions(+), 10 deletions(-) create mode 100644 crates/ir2/src/op.rs delete mode 100644 crates/ir2/src/ops.rs diff --git a/crates/ir2/build/display.rs b/crates/ir2/build/display.rs index 24cf17c597..2324478d20 100644 --- a/crates/ir2/build/display.rs +++ b/crates/ir2/build/display.rs @@ -54,7 +54,7 @@ impl Display for DisplayEnum { write!( f, "\ - {indent}pub enum Instruction {{\n\ + {indent}pub enum Op {{\n\ " )?; for op in &self.val.ops { diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index d750c0137e..27260fea4a 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -49,9 +49,6 @@ pub fn generate_code(out_dir: &Path) -> Result<(), Error> { )?; std::println!("out_dir = {out_dir:?}"); fs::create_dir_all(out_dir)?; - fs::write(out_dir.join("instruction.rs"), contents)?; - // let mut ctx = Context::default(); - // define_ops(&mut ctx); - // generate_ops(&ctx)?; + fs::write(out_dir.join("op.rs"), contents)?; Ok(()) } diff --git a/crates/ir2/src/lib.rs b/crates/ir2/src/lib.rs index 4431ebe64a..35dded46de 100644 --- a/crates/ir2/src/lib.rs +++ b/crates/ir2/src/lib.rs @@ -7,7 +7,7 @@ extern crate std; mod error; mod index; -mod ops; +mod op; mod primitive; mod span; @@ -16,7 +16,7 @@ use wasmi_core as core; pub use self::{ error::Error, index::Stack, - ops::Instruction, + op::Op, primitive::{Address, BlockFuel, BranchOffset, Offset16, Sign}, span::{BoundedStackSpan, FixedStackSpan, StackSpan}, }; diff --git a/crates/ir2/src/op.rs b/crates/ir2/src/op.rs new file mode 100644 index 0000000000..eac9de5918 --- /dev/null +++ b/crates/ir2/src/op.rs @@ -0,0 +1,3 @@ +use crate::Stack; + +include!(concat!(env!("OUT_DIR"), "/op.rs")); diff --git a/crates/ir2/src/ops.rs b/crates/ir2/src/ops.rs deleted file mode 100644 index 306e710f8c..0000000000 --- a/crates/ir2/src/ops.rs +++ /dev/null @@ -1,3 +0,0 @@ -use crate::Stack; - -include!(concat!(env!("OUT_DIR"), "/instruction.rs")); From bf03002c83db4c57524f4fe6c8d0024950cc0221 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 20 Aug 2025 19:48:58 +0200 Subject: [PATCH 007/186] add codegen for binary ops --- crates/ir2/build/display.rs | 32 +++++++++++++++-- crates/ir2/build/isa.rs | 71 ++++++++++++++++++++++++++++++++++++- crates/ir2/build/op.rs | 18 +++++----- crates/ir2/src/op.rs | 3 +- 4 files changed, 110 insertions(+), 14 deletions(-) diff --git a/crates/ir2/build/display.rs b/crates/ir2/build/display.rs index 2324478d20..f691e4754e 100644 --- a/crates/ir2/build/display.rs +++ b/crates/ir2/build/display.rs @@ -1,6 +1,6 @@ use crate::build::{ isa::Isa, - op::{BinaryOp, FieldTy, Input, Op, Ty, UnaryOp}, + op::{BinaryOp, BinaryOpKind, FieldTy, Input, Op, Ty, UnaryOp, CmpOpKind}, token::{CamelCase, Ident, SnakeCase}, }; use core::fmt::{self, Display}; @@ -73,8 +73,8 @@ impl Display for DisplayEnum { impl Display for DisplayEnum<&'_ Op> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.val { - Op::Unary(op) => write!(f, "{}", self.map(op)), - Op::Binary(_op) => Ok(()), + Op::Unary(op) => self.map(op).fmt(f), + Op::Binary(op) => self.map(op).fmt(f), Op::CmpBranch(_op) => Ok(()), Op::CmpSelect(_op) => Ok(()), Op::Load(_op) => Ok(()), @@ -140,3 +140,29 @@ impl DisplayEnum<&'_ UnaryOp> { ) } } + +impl Display for DisplayEnum<&'_ BinaryOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let indent0 = self.indent; + let indent1 = indent0.inc(); + let kind = self.val.kind; + let ident = CamelCase(kind.ident()); + let result_ident = CamelCase(Ident::from(kind.result_ty())); + let result_ty = FieldTy::Stack; + let lhs_ty = kind.lhs_field(self.val.lhs); + let rhs_ty = kind.rhs_field(self.val.rhs); + let result_suffix = CamelCase(Input::Stack); + let lhs_suffix = SnakeCase(self.val.lhs); + let rhs_suffix = SnakeCase(self.val.rhs); + write!( + f, + "\ + {indent0}{result_ident}{ident}_S{lhs_suffix}{rhs_suffix} {{\n\ + {indent1}result: {result_ty},\n\ + {indent1}lhs: {lhs_ty},\n\ + {indent1}rhs: {rhs_ty},\n\ + {indent0}}},\n\ + ", + ) + } +} diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 7cac50d10f..2475ffc965 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -1,5 +1,5 @@ use crate::build::{ - op::{UnaryOp, UnaryOpKind}, + op::{BinaryOp, BinaryOpKind, Commutativity, Input, UnaryOp, UnaryOpKind}, Op, }; @@ -17,6 +17,7 @@ impl Isa { pub fn wasmi_isa() -> Isa { let mut isa = Isa::default(); add_unary_ops(&mut isa); + add_binary_ops(&mut isa); isa } @@ -67,3 +68,71 @@ fn add_unary_ops(isa: &mut Isa) { isa.push_op(Op::Unary(UnaryOp::new(op))); } } + +fn add_binary_ops(isa: &mut Isa) { + let ops = [ + // i32 + BinaryOpKind::I32Add, + BinaryOpKind::I32Sub, + BinaryOpKind::I32Mul, + BinaryOpKind::S32Div, + BinaryOpKind::U32Div, + BinaryOpKind::S32Rem, + BinaryOpKind::U32Rem, + BinaryOpKind::I32BitAnd, + BinaryOpKind::I32BitOr, + BinaryOpKind::I32BitXor, + BinaryOpKind::I32Shl, + BinaryOpKind::S32Shr, + BinaryOpKind::U32Shr, + BinaryOpKind::I32Rotl, + BinaryOpKind::I32Rotr, + // i64 + BinaryOpKind::I64Add, + BinaryOpKind::I64Sub, + BinaryOpKind::I64Mul, + BinaryOpKind::S64Div, + BinaryOpKind::U64Div, + BinaryOpKind::S64Rem, + BinaryOpKind::U64Rem, + BinaryOpKind::I64BitAnd, + BinaryOpKind::I64BitOr, + BinaryOpKind::I64BitXor, + BinaryOpKind::I64Shl, + BinaryOpKind::S64Shr, + BinaryOpKind::U64Shr, + BinaryOpKind::I64Rotl, + BinaryOpKind::I64Rotr, + // f32 + BinaryOpKind::F32Add, + BinaryOpKind::F32Sub, + BinaryOpKind::F32Mul, + BinaryOpKind::F32Div, + BinaryOpKind::F32Min, + BinaryOpKind::F32Max, + BinaryOpKind::F32Copysign, + // f64 + BinaryOpKind::F64Add, + BinaryOpKind::F64Sub, + BinaryOpKind::F64Mul, + BinaryOpKind::F64Div, + BinaryOpKind::F64Min, + BinaryOpKind::F64Max, + BinaryOpKind::F64Copysign, + ]; + for op in ops { + isa.push_op(Op::Binary(BinaryOp::new(op, Input::Stack, Input::Stack))); + isa.push_op(Op::Binary(BinaryOp::new( + op, + Input::Stack, + Input::Immediate, + ))); + if matches!(op.commutativity(), Commutativity::NonCommutative) { + isa.push_op(Op::Binary(BinaryOp::new( + op, + Input::Immediate, + Input::Stack, + ))); + } + } +} diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 9e13a7d81c..91ef5f6866 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -258,8 +258,8 @@ impl UnaryOpKind { #[derive(Copy, Clone)] pub struct BinaryOp { pub kind: BinaryOpKind, - pub lhs: FieldTy, - pub rhs: FieldTy, + pub lhs: Input, + pub rhs: Input, } #[derive(Copy, Clone)] @@ -470,32 +470,32 @@ impl BinaryOpKind { | Self::I32Sub | Self::I32Mul | Self::S32Div - | Self::U32Div | Self::S32Rem - | Self::U32Rem | Self::I32BitAnd | Self::I32BitOr | Self::I32BitXor | Self::I32Shl | Self::S32Shr - | Self::U32Shr | Self::I32Rotl | Self::I32Rotr => Ty::I32, + | Self::U32Div + | Self::U32Rem + | Self::U32Shr => Ty::U32, | Self::I64Add | Self::I64Sub | Self::I64Mul | Self::S64Div - | Self::U64Div | Self::S64Rem - | Self::U64Rem | Self::I64BitAnd | Self::I64BitOr | Self::I64BitXor | Self::I64Shl | Self::S64Shr - | Self::U64Shr | Self::I64Rotl | Self::I64Rotr => Ty::I64, + | Self::U64Div + | Self::U64Rem + | Self::U64Shr => Ty::U64, | Self::F32Add | Self::F32Sub | Self::F32Mul @@ -588,7 +588,7 @@ pub enum Commutativity { } impl BinaryOp { - pub fn new(kind: BinaryOpKind, lhs: FieldTy, rhs: FieldTy) -> Self { + pub fn new(kind: BinaryOpKind, lhs: Input, rhs: Input) -> Self { Self { kind, lhs, rhs } } } diff --git a/crates/ir2/src/op.rs b/crates/ir2/src/op.rs index eac9de5918..605573d896 100644 --- a/crates/ir2/src/op.rs +++ b/crates/ir2/src/op.rs @@ -1,3 +1,4 @@ -use crate::Stack; +use crate::{Stack, Sign}; +use core::num::NonZero; include!(concat!(env!("OUT_DIR"), "/op.rs")); From 4acf5259cff9228672d59895a583332ad740091f Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 20 Aug 2025 20:08:05 +0200 Subject: [PATCH 008/186] add cmp+branch ops codegen --- crates/ir2/build/display.rs | 30 ++++++++++++++-- crates/ir2/build/isa.rs | 72 ++++++++++++++++++++++++++++++++++++- crates/ir2/build/op.rs | 18 ++++------ crates/ir2/src/op.rs | 2 +- 4 files changed, 106 insertions(+), 16 deletions(-) diff --git a/crates/ir2/build/display.rs b/crates/ir2/build/display.rs index f691e4754e..b4ba89920e 100644 --- a/crates/ir2/build/display.rs +++ b/crates/ir2/build/display.rs @@ -1,6 +1,6 @@ use crate::build::{ isa::Isa, - op::{BinaryOp, BinaryOpKind, FieldTy, Input, Op, Ty, UnaryOp, CmpOpKind}, + op::{BinaryOp, BinaryOpKind, CmpBranchOp, CmpOpKind, FieldTy, Input, Op, Ty, UnaryOp}, token::{CamelCase, Ident, SnakeCase}, }; use core::fmt::{self, Display}; @@ -75,7 +75,7 @@ impl Display for DisplayEnum<&'_ Op> { match self.val { Op::Unary(op) => self.map(op).fmt(f), Op::Binary(op) => self.map(op).fmt(f), - Op::CmpBranch(_op) => Ok(()), + Op::CmpBranch(op) => self.map(op).fmt(f), Op::CmpSelect(_op) => Ok(()), Op::Load(_op) => Ok(()), Op::Store(_op) => Ok(()), @@ -166,3 +166,29 @@ impl Display for DisplayEnum<&'_ BinaryOp> { ) } } + +impl Display for DisplayEnum<&'_ CmpBranchOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let indent0 = self.indent; + let indent1 = indent0.inc(); + let cmp = self.val.cmp; + let ident = CamelCase(cmp.ident()); + let input_ident = CamelCase(Ident::from(cmp.input_ty())); + let result_ty = FieldTy::Stack; + let lhs_ty = cmp.input_field(self.val.lhs); + let rhs_ty = cmp.input_field(self.val.rhs); + let result_suffix = CamelCase(Input::Stack); + let lhs_suffix = SnakeCase(self.val.lhs); + let rhs_suffix = SnakeCase(self.val.rhs); + write!( + f, + "\ + {indent0}Branch{input_ident}{ident}_S{lhs_suffix}{rhs_suffix} {{\n\ + {indent1}offset: BranchOffset,\n\ + {indent1}lhs: {lhs_ty},\n\ + {indent1}rhs: {rhs_ty},\n\ + {indent0}}},\n\ + ", + ) + } +} diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 2475ffc965..db41d061c3 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -1,5 +1,14 @@ use crate::build::{ - op::{BinaryOp, BinaryOpKind, Commutativity, Input, UnaryOp, UnaryOpKind}, + op::{ + BinaryOp, + BinaryOpKind, + CmpBranchOp, + CmpOpKind, + Commutativity, + Input, + UnaryOp, + UnaryOpKind, + }, Op, }; @@ -18,6 +27,7 @@ pub fn wasmi_isa() -> Isa { let mut isa = Isa::default(); add_unary_ops(&mut isa); add_binary_ops(&mut isa); + add_cmp_branch_ops(&mut isa); isa } @@ -136,3 +146,63 @@ fn add_binary_ops(isa: &mut Isa) { } } } + +fn add_cmp_branch_ops(isa: &mut Isa) { + let ops = [ + // i32 + CmpOpKind::I32Eq, + CmpOpKind::I32NotEq, + CmpOpKind::I32And, + CmpOpKind::I32NotAnd, + CmpOpKind::I32Or, + CmpOpKind::I32NotOr, + CmpOpKind::S32Lt, + CmpOpKind::S32Le, + CmpOpKind::U32Lt, + CmpOpKind::U32Le, + // i64 + CmpOpKind::I64Eq, + CmpOpKind::I64NotEq, + CmpOpKind::I64And, + CmpOpKind::I64NotAnd, + CmpOpKind::I64Or, + CmpOpKind::I64NotOr, + CmpOpKind::S64Lt, + CmpOpKind::S64Le, + CmpOpKind::U64Lt, + CmpOpKind::U64Le, + // f32 + CmpOpKind::F32Eq, + CmpOpKind::F32NotEq, + CmpOpKind::F32Lt, + CmpOpKind::F32NotLt, + CmpOpKind::F32Le, + CmpOpKind::F32NotLe, + // f64 + CmpOpKind::F64Eq, + CmpOpKind::F64NotEq, + CmpOpKind::F64Lt, + CmpOpKind::F64NotLt, + CmpOpKind::F64Le, + CmpOpKind::F64NotLe, + ]; + for op in ops { + isa.push_op(Op::CmpBranch(CmpBranchOp::new( + op, + Input::Stack, + Input::Stack, + ))); + isa.push_op(Op::CmpBranch(CmpBranchOp::new( + op, + Input::Stack, + Input::Immediate, + ))); + if matches!(op.commutativity(), Commutativity::NonCommutative) { + isa.push_op(Op::CmpBranch(CmpBranchOp::new( + op, + Input::Immediate, + Input::Stack, + ))); + } + } +} diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 91ef5f6866..836e66e4b1 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -478,9 +478,7 @@ impl BinaryOpKind { | Self::S32Shr | Self::I32Rotl | Self::I32Rotr => Ty::I32, - | Self::U32Div - | Self::U32Rem - | Self::U32Shr => Ty::U32, + | Self::U32Div | Self::U32Rem | Self::U32Shr => Ty::U32, | Self::I64Add | Self::I64Sub | Self::I64Mul @@ -493,9 +491,7 @@ impl BinaryOpKind { | Self::S64Shr | Self::I64Rotl | Self::I64Rotr => Ty::I64, - | Self::U64Div - | Self::U64Rem - | Self::U64Shr => Ty::U64, + | Self::U64Div | Self::U64Rem | Self::U64Shr => Ty::U64, | Self::F32Add | Self::F32Sub | Self::F32Mul @@ -857,9 +853,8 @@ impl CmpOpKind { | Self::I32Or | Self::I32NotOr | Self::S32Lt - | Self::U32Lt - | Self::S32Le - | Self::U32Le => Ty::I32, + | Self::S32Le => Ty::I32, + | Self::U32Lt | Self::U32Le => Ty::U32, | Self::I64Eq | Self::I64NotEq | Self::I64And @@ -867,9 +862,8 @@ impl CmpOpKind { | Self::I64Or | Self::I64NotOr | Self::S64Lt - | Self::U64Lt - | Self::S64Le - | Self::U64Le => Ty::I64, + | Self::S64Le => Ty::I64, + | Self::U64Lt | Self::U64Le => Ty::U64, | Self::F32Eq | Self::F32NotEq | Self::F32Lt diff --git a/crates/ir2/src/op.rs b/crates/ir2/src/op.rs index 605573d896..31414116b8 100644 --- a/crates/ir2/src/op.rs +++ b/crates/ir2/src/op.rs @@ -1,4 +1,4 @@ -use crate::{Stack, Sign}; +use crate::{BranchOffset, Sign, Stack}; use core::num::NonZero; include!(concat!(env!("OUT_DIR"), "/op.rs")); From 5fab8a4bee9aa1332fa8f8ae8f33db0e39ef1817 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 20 Aug 2025 20:10:47 +0200 Subject: [PATCH 009/186] add Copy and Clone impls for Op --- crates/ir2/src/op.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/crates/ir2/src/op.rs b/crates/ir2/src/op.rs index 31414116b8..88a2c1f92e 100644 --- a/crates/ir2/src/op.rs +++ b/crates/ir2/src/op.rs @@ -2,3 +2,10 @@ use crate::{BranchOffset, Sign, Stack}; use core::num::NonZero; include!(concat!(env!("OUT_DIR"), "/op.rs")); + +impl Copy for Op {} +impl Clone for Op { + fn clone(&self) -> Self { + *self + } +} From 1505d45fbdbffba01f834765055aa6ad976b4d9b Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 20 Aug 2025 20:19:36 +0200 Subject: [PATCH 010/186] add cmp+select ops codegen --- crates/ir2/build/display.rs | 45 +++++++++++++++++++++++++++++++-- crates/ir2/build/isa.rs | 50 +++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 2 deletions(-) diff --git a/crates/ir2/build/display.rs b/crates/ir2/build/display.rs index b4ba89920e..93adf472e0 100644 --- a/crates/ir2/build/display.rs +++ b/crates/ir2/build/display.rs @@ -1,6 +1,17 @@ use crate::build::{ isa::Isa, - op::{BinaryOp, BinaryOpKind, CmpBranchOp, CmpOpKind, FieldTy, Input, Op, Ty, UnaryOp}, + op::{ + BinaryOp, + BinaryOpKind, + CmpBranchOp, + CmpOpKind, + CmpSelectOp, + FieldTy, + Input, + Op, + Ty, + UnaryOp, + }, token::{CamelCase, Ident, SnakeCase}, }; use core::fmt::{self, Display}; @@ -76,7 +87,7 @@ impl Display for DisplayEnum<&'_ Op> { Op::Unary(op) => self.map(op).fmt(f), Op::Binary(op) => self.map(op).fmt(f), Op::CmpBranch(op) => self.map(op).fmt(f), - Op::CmpSelect(_op) => Ok(()), + Op::CmpSelect(op) => self.map(op).fmt(f), Op::Load(_op) => Ok(()), Op::Store(_op) => Ok(()), Op::Generic0(_op) => Ok(()), @@ -192,3 +203,33 @@ impl Display for DisplayEnum<&'_ CmpBranchOp> { ) } } + +impl Display for DisplayEnum<&'_ CmpSelectOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let indent0 = self.indent; + let indent1 = indent0.inc(); + let cmp = self.val.cmp; + let ident = CamelCase(cmp.ident()); + let input_ident = CamelCase(Ident::from(cmp.input_ty())); + let result_ty = FieldTy::Stack; + let lhs_ty = cmp.input_field(self.val.lhs); + let rhs_ty = cmp.input_field(self.val.rhs); + let result_suffix = CamelCase(Input::Stack); + let lhs_suffix = SnakeCase(self.val.lhs); + let rhs_suffix = SnakeCase(self.val.rhs); + let val_true = FieldTy::Stack; + let val_false = FieldTy::Stack; + write!( + f, + "\ + {indent0}Select{input_ident}{ident}_S{lhs_suffix}{rhs_suffix} {{\n\ + {indent1}result: {result_ty},\n\ + {indent1}lhs: {lhs_ty},\n\ + {indent1}rhs: {rhs_ty},\n\ + {indent1}val_true: {val_true},\n\ + {indent1}val_false: {val_false},\n\ + {indent0}}},\n\ + ", + ) + } +} diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index db41d061c3..d3edf3f576 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -4,6 +4,7 @@ use crate::build::{ BinaryOpKind, CmpBranchOp, CmpOpKind, + CmpSelectOp, Commutativity, Input, UnaryOp, @@ -28,6 +29,7 @@ pub fn wasmi_isa() -> Isa { add_unary_ops(&mut isa); add_binary_ops(&mut isa); add_cmp_branch_ops(&mut isa); + add_cmp_select_ops(&mut isa); isa } @@ -206,3 +208,51 @@ fn add_cmp_branch_ops(isa: &mut Isa) { } } } + +fn add_cmp_select_ops(isa: &mut Isa) { + let ops = [ + // i32 + CmpOpKind::I32Eq, + CmpOpKind::I32And, + CmpOpKind::I32Or, + CmpOpKind::S32Lt, + CmpOpKind::S32Le, + CmpOpKind::U32Lt, + CmpOpKind::U32Le, + // i64 + CmpOpKind::I64Eq, + CmpOpKind::I64And, + CmpOpKind::I64Or, + CmpOpKind::S64Lt, + CmpOpKind::S64Le, + CmpOpKind::U64Lt, + CmpOpKind::U64Le, + // f32 + CmpOpKind::F32Eq, + CmpOpKind::F32Lt, + CmpOpKind::F32Le, + // f64 + CmpOpKind::F64Eq, + CmpOpKind::F64Lt, + CmpOpKind::F64Le, + ]; + for op in ops { + isa.push_op(Op::CmpSelect(CmpSelectOp::new( + op, + Input::Stack, + Input::Stack, + ))); + isa.push_op(Op::CmpSelect(CmpSelectOp::new( + op, + Input::Stack, + Input::Immediate, + ))); + if matches!(op.commutativity(), Commutativity::NonCommutative) { + isa.push_op(Op::CmpSelect(CmpSelectOp::new( + op, + Input::Immediate, + Input::Stack, + ))); + } + } +} From 5e1dfcf4f723fb841b19ed0070155c29748f00a1 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 20 Aug 2025 20:47:23 +0200 Subject: [PATCH 011/186] add load ops codegen --- crates/ir2/build/display.rs | 70 ++++++++++++++++++++++++++++++++++++- crates/ir2/build/isa.rs | 31 ++++++++++++++++ crates/ir2/build/op.rs | 19 +++++++--- crates/ir2/src/lib.rs | 2 +- crates/ir2/src/op.rs | 2 +- 5 files changed, 117 insertions(+), 7 deletions(-) diff --git a/crates/ir2/build/display.rs b/crates/ir2/build/display.rs index 93adf472e0..7aba2b5c90 100644 --- a/crates/ir2/build/display.rs +++ b/crates/ir2/build/display.rs @@ -8,6 +8,7 @@ use crate::build::{ CmpSelectOp, FieldTy, Input, + LoadOp, Op, Ty, UnaryOp, @@ -88,7 +89,7 @@ impl Display for DisplayEnum<&'_ Op> { Op::Binary(op) => self.map(op).fmt(f), Op::CmpBranch(op) => self.map(op).fmt(f), Op::CmpSelect(op) => self.map(op).fmt(f), - Op::Load(_op) => Ok(()), + Op::Load(op) => self.map(op).fmt(f), Op::Store(_op) => Ok(()), Op::Generic0(_op) => Ok(()), Op::Generic1(_op) => Ok(()), @@ -233,3 +234,70 @@ impl Display for DisplayEnum<&'_ CmpSelectOp> { ) } } + +impl Display for DisplayEnum<&'_ LoadOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let indent0 = self.indent; + let indent1 = indent0.inc(); + let kind = self.val.kind; + let ident = CamelCase(kind.ident()); + let result_ty = FieldTy::Stack; + let result_ident = CamelCase(Ident::from(kind.result_ty())); + let result_suffix = CamelCase(Input::Stack); + let ptr_suffix = SnakeCase(self.val.ptr); + let (ptr_ty, offset_ty) = match self.val.ptr { + Input::Stack => { + let ptr = FieldTy::Stack; + let offset = match self.val.offset16 { + true => FieldTy::Offset16, + false => FieldTy::U64, + }; + (ptr, Some(offset)) + } + Input::Immediate => (FieldTy::Address, None), + }; + let mem_ty = match self.val.mem0 { + false => Some(FieldTy::Memory), + true => None, + }; + let mem0_ident = match self.val.mem0 { + true => "Mem0", + false => "", + }; + let offset16_ident = match self.val.offset16 { + true => "Offset16", + false => "", + }; + write!( + f, + "\ + {indent0}{result_ident}{ident}{mem0_ident}{offset16_ident}_{result_suffix}{ptr_suffix} {{\n\ + {indent1}result: {result_ty},\n\ + {indent1}ptr: {ptr_ty},\n\ + ", + )?; + if let Some(offset) = offset_ty { + write!( + f, + "\ + {indent1}offset: {offset},\n\ + " + )?; + } + if let Some(mem) = mem_ty { + write!( + f, + "\ + {indent1}mem: {mem},\n\ + " + )?; + } + write!( + f, + "\ + {indent0}}},\n\ + ", + )?; + Ok(()) + } +} diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index d3edf3f576..64b957d6cf 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -7,6 +7,8 @@ use crate::build::{ CmpSelectOp, Commutativity, Input, + LoadOp, + LoadOpKind, UnaryOp, UnaryOpKind, }, @@ -30,6 +32,7 @@ pub fn wasmi_isa() -> Isa { add_binary_ops(&mut isa); add_cmp_branch_ops(&mut isa); add_cmp_select_ops(&mut isa); + add_load_ops(&mut isa); isa } @@ -256,3 +259,31 @@ fn add_cmp_select_ops(isa: &mut Isa) { } } } + +fn add_load_ops(isa: &mut Isa) { + let ops = [ + // i32 + LoadOpKind::I32Load, + LoadOpKind::S32Load8, + LoadOpKind::S32Load16, + LoadOpKind::U32Load8, + LoadOpKind::U32Load16, + // i64 + LoadOpKind::I64Load, + LoadOpKind::S64Load8, + LoadOpKind::S64Load16, + LoadOpKind::S64Load32, + LoadOpKind::U64Load8, + LoadOpKind::U64Load16, + LoadOpKind::U64Load32, + // f32 + LoadOpKind::F32Load, + // f64 + LoadOpKind::F64Load, + ]; + for op in ops { + isa.push_op(Op::Load(LoadOp::new(op, Input::Stack, false, false))); + isa.push_op(Op::Load(LoadOp::new(op, Input::Immediate, false, false))); + isa.push_op(Op::Load(LoadOp::new(op, Input::Stack, true, true))); + } +} diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 836e66e4b1..65424a0599 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -920,13 +920,24 @@ impl CmpOpKind { #[derive(Copy, Clone)] pub struct LoadOp { /// The kind of the load operator. - kind: LoadOpKind, + pub kind: LoadOpKind, /// The `ptr` field type. - ptr: Input, + pub ptr: Input, /// True, if the operator is always operating on (`memory 0`). - mem0: bool, + pub mem0: bool, /// True, if the operator uses a 16-bit offset field. - offset16: bool, + pub offset16: bool, +} + +impl LoadOp { + pub fn new(kind: LoadOpKind, ptr: Input, mem0: bool, offset16: bool) -> Self { + Self { + kind, + ptr, + mem0, + offset16, + } + } } #[derive(Copy, Clone)] diff --git a/crates/ir2/src/lib.rs b/crates/ir2/src/lib.rs index 35dded46de..3fbb371268 100644 --- a/crates/ir2/src/lib.rs +++ b/crates/ir2/src/lib.rs @@ -6,7 +6,7 @@ extern crate alloc; extern crate std; mod error; -mod index; +pub mod index; mod op; mod primitive; mod span; diff --git a/crates/ir2/src/op.rs b/crates/ir2/src/op.rs index 88a2c1f92e..2e672db222 100644 --- a/crates/ir2/src/op.rs +++ b/crates/ir2/src/op.rs @@ -1,4 +1,4 @@ -use crate::{BranchOffset, Sign, Stack}; +use crate::{index::Memory, Address, BranchOffset, Offset16, Sign, Stack}; use core::num::NonZero; include!(concat!(env!("OUT_DIR"), "/op.rs")); From c7187d8e554eb6cc8c17e3dc856e52717d4adbc5 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 20 Aug 2025 21:40:03 +0200 Subject: [PATCH 012/186] fix load ops codegen --- crates/ir2/build/display.rs | 18 +++++++++++++-- crates/ir2/build/isa.rs | 9 +++----- crates/ir2/build/op.rs | 45 +++++++++++++++++++++++-------------- crates/ir2/build/token.rs | 1 + 4 files changed, 48 insertions(+), 25 deletions(-) diff --git a/crates/ir2/build/display.rs b/crates/ir2/build/display.rs index 7aba2b5c90..4ee0564c4f 100644 --- a/crates/ir2/build/display.rs +++ b/crates/ir2/build/display.rs @@ -10,6 +10,7 @@ use crate::build::{ Input, LoadOp, Op, + StoreOp, Ty, UnaryOp, }, @@ -242,7 +243,7 @@ impl Display for DisplayEnum<&'_ LoadOp> { let kind = self.val.kind; let ident = CamelCase(kind.ident()); let result_ty = FieldTy::Stack; - let result_ident = CamelCase(Ident::from(kind.result_ty())); + let result_ident = kind.result_ident().map(CamelCase); let result_suffix = CamelCase(Input::Stack); let ptr_suffix = SnakeCase(self.val.ptr); let (ptr_ty, offset_ty) = match self.val.ptr { @@ -268,10 +269,23 @@ impl Display for DisplayEnum<&'_ LoadOp> { true => "Offset16", false => "", }; + match result_ident { + Some(result_ident) => { + write!( + f, + "{indent0}{result_ident}{ident}{mem0_ident}{offset16_ident}_{result_suffix}{ptr_suffix} {{\n", + )?; + } + None => { + write!( + f, + "{indent0}{ident}{mem0_ident}{offset16_ident}_{result_suffix}{ptr_suffix} {{\n", + )?; + } + } write!( f, "\ - {indent0}{result_ident}{ident}{mem0_ident}{offset16_ident}_{result_suffix}{ptr_suffix} {{\n\ {indent1}result: {result_ty},\n\ {indent1}ptr: {ptr_ty},\n\ ", diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 64b957d6cf..60dd6f046c 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -262,24 +262,21 @@ fn add_cmp_select_ops(isa: &mut Isa) { fn add_load_ops(isa: &mut Isa) { let ops = [ + // Generic + LoadOpKind::Load32, + LoadOpKind::Load64, // i32 - LoadOpKind::I32Load, LoadOpKind::S32Load8, LoadOpKind::S32Load16, LoadOpKind::U32Load8, LoadOpKind::U32Load16, // i64 - LoadOpKind::I64Load, LoadOpKind::S64Load8, LoadOpKind::S64Load16, LoadOpKind::S64Load32, LoadOpKind::U64Load8, LoadOpKind::U64Load16, LoadOpKind::U64Load32, - // f32 - LoadOpKind::F32Load, - // f64 - LoadOpKind::F64Load, ]; for op in ops { isa.push_op(Op::Load(LoadOp::new(op, Input::Stack, false, false))); diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 65424a0599..92c7a0f5bf 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -942,58 +942,69 @@ impl LoadOp { #[derive(Copy, Clone)] pub enum LoadOpKind { - I32Load, + Load32, + Load64, S32Load8, U32Load8, S32Load16, U32Load16, - I64Load, S64Load8, U64Load8, S64Load16, U64Load16, S64Load32, U64Load32, - F32Load, - F64Load, } impl LoadOpKind { pub fn ident(&self) -> Ident { match self { - Self::I32Load => Ident::Load, + Self::Load32 => Ident::Load32, + Self::Load64 => Ident::Load64, Self::S32Load8 => Ident::Load8, Self::U32Load8 => Ident::Load8, Self::S32Load16 => Ident::Load16, Self::U32Load16 => Ident::Load16, - Self::I64Load => Ident::Load, Self::S64Load8 => Ident::Load8, Self::U64Load8 => Ident::Load8, Self::S64Load16 => Ident::Load16, Self::U64Load16 => Ident::Load16, Self::S64Load32 => Ident::Load32, Self::U64Load32 => Ident::Load32, - Self::F32Load => Ident::Load, - Self::F64Load => Ident::Load, + } + } + + pub fn result_ident(&self) -> Option { + match self { + LoadOpKind::Load32 => None, + LoadOpKind::Load64 => None, + LoadOpKind::S32Load8 => Some(Ident::S32), + LoadOpKind::U32Load8 => Some(Ident::U32), + LoadOpKind::S32Load16 => Some(Ident::S32), + LoadOpKind::U32Load16 => Some(Ident::U32), + LoadOpKind::S64Load8 => Some(Ident::S64), + LoadOpKind::U64Load8 => Some(Ident::U64), + LoadOpKind::S64Load16 => Some(Ident::S64), + LoadOpKind::U64Load16 => Some(Ident::U64), + LoadOpKind::S64Load32 => Some(Ident::S64), + LoadOpKind::U64Load32 => Some(Ident::U64), } } pub fn result_ty(&self) -> Ty { match self { - LoadOpKind::I32Load => Ty::I32, + LoadOpKind::Load32 => Ty::U32, + LoadOpKind::Load64 => Ty::U64, LoadOpKind::S32Load8 => Ty::S32, LoadOpKind::U32Load8 => Ty::U32, LoadOpKind::S32Load16 => Ty::S32, LoadOpKind::U32Load16 => Ty::U32, - LoadOpKind::I64Load => Ty::I64, LoadOpKind::S64Load8 => Ty::S64, LoadOpKind::U64Load8 => Ty::U64, LoadOpKind::S64Load16 => Ty::S64, LoadOpKind::U64Load16 => Ty::U64, LoadOpKind::S64Load32 => Ty::S64, LoadOpKind::U64Load32 => Ty::U64, - LoadOpKind::F32Load => Ty::F32, - LoadOpKind::F64Load => Ty::F64, } } } @@ -1001,15 +1012,15 @@ impl LoadOpKind { #[derive(Copy, Clone)] pub struct StoreOp { /// The kind of the load operator. - kind: StoreOpKind, + pub kind: StoreOpKind, /// The `ptr` input type. - ptr: Input, + pub ptr: Input, /// The `value` input type. - value: Input, + pub value: Input, /// True, if the operator is always operating on (`memory 0`). - mem0: bool, + pub mem0: bool, /// True, if the operator uses a 16-bit offset field. - offset16: bool, + pub offset16: bool, } #[derive(Copy, Clone)] diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index 4b6dc5b607..bd6d75be04 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -81,6 +81,7 @@ define_ident!( Load8: load8, Load16: load16, Load32: load32, + Load64: load64, Copy: copy, Fill: fill, From 1bd29bc4df5c4c2aee781049a6360e98a6f2180f Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 20 Aug 2025 23:04:44 +0200 Subject: [PATCH 013/186] add DisplayIdent for LoadOp --- crates/ir2/build/display.rs | 39 ++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/crates/ir2/build/display.rs b/crates/ir2/build/display.rs index 4ee0564c4f..a2eb209533 100644 --- a/crates/ir2/build/display.rs +++ b/crates/ir2/build/display.rs @@ -15,6 +15,8 @@ use crate::build::{ UnaryOp, }, token::{CamelCase, Ident, SnakeCase}, + IntoMaybe as _, + Maybe, }; use core::fmt::{self, Display}; @@ -241,9 +243,9 @@ impl Display for DisplayEnum<&'_ LoadOp> { let indent0 = self.indent; let indent1 = indent0.inc(); let kind = self.val.kind; - let ident = CamelCase(kind.ident()); + let ident = DisplayIdent(self.val); let result_ty = FieldTy::Stack; - let result_ident = kind.result_ident().map(CamelCase); + let result_ident = kind.ident_prefix().map(CamelCase); let result_suffix = CamelCase(Input::Stack); let ptr_suffix = SnakeCase(self.val.ptr); let (ptr_ty, offset_ty) = match self.val.ptr { @@ -269,23 +271,10 @@ impl Display for DisplayEnum<&'_ LoadOp> { true => "Offset16", false => "", }; - match result_ident { - Some(result_ident) => { - write!( - f, - "{indent0}{result_ident}{ident}{mem0_ident}{offset16_ident}_{result_suffix}{ptr_suffix} {{\n", - )?; - } - None => { - write!( - f, - "{indent0}{ident}{mem0_ident}{offset16_ident}_{result_suffix}{ptr_suffix} {{\n", - )?; - } - } write!( f, "\ + {indent0}{ident} {{\n\ {indent1}result: {result_ty},\n\ {indent1}ptr: {ptr_ty},\n\ ", @@ -315,3 +304,21 @@ impl Display for DisplayEnum<&'_ LoadOp> { Ok(()) } } + +pub struct DisplayIdent(pub T); + +impl Display for DisplayIdent<&'_ LoadOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let kind = self.0.kind; + let ident = CamelCase(kind.ident()); + let result_suffix = CamelCase(Input::Stack); + let ptr_suffix = SnakeCase(self.0.ptr); + let ident_prefix = self.0.kind.ident_prefix().map(CamelCase).into_maybe(); + let mem0_ident = self.0.mem0.then(|| "Mem0").unwrap_or_default(); + let offset16_ident = self.0.offset16.then(|| "Offset16").unwrap_or_default(); + write!( + f, + "{ident_prefix}{ident}{mem0_ident}{offset16_ident}_{result_suffix}{ptr_suffix}", + ) + } +} From b9809fc81188662b8288cba9ac4c219ee05168b3 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 20 Aug 2025 23:05:12 +0200 Subject: [PATCH 014/186] add Maybe utility type --- crates/ir2/build/op.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 92c7a0f5bf..a887e3bef7 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -22,6 +22,47 @@ pub struct GenericOp { pub fields: [Field; N], } +pub enum Maybe { + Some(T), + None, +} + +impl Display for Maybe +where + T: Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Maybe::Some(field) = self { + field.fmt(f)?; + } + Ok(()) + } +} + +pub trait IntoMaybe { + fn into_maybe(self) -> Maybe; +} +impl IntoMaybe for Option { + fn into_maybe(self) -> Maybe { + Maybe::from(self) + } +} + +impl From for Maybe { + fn from(value: T) -> Self { + Maybe::Some(value) + } +} + +impl From> for Maybe { + fn from(value: Option) -> Self { + match value { + Some(value) => Self::Some(value), + None => Self::None, + } + } +} + #[derive(Copy, Clone)] pub struct Field { ident: Ident, From 7103acab5c853711f43529ed1b6a897503d2b229 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 20 Aug 2025 23:05:19 +0200 Subject: [PATCH 015/186] add Display for Field --- crates/ir2/build/op.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index a887e3bef7..c91177b28c 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -69,6 +69,14 @@ pub struct Field { ty: FieldTy, } +impl Display for Field { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let ident = SnakeCase(self.ident); + let ty = self.ty; + write!(f, "{ident}: {ty}") + } +} + #[derive(Copy, Clone)] pub struct UnaryOp { pub kind: UnaryOpKind, From 54a69021517b6dab3e8d340f1c5365e1094badee Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 20 Aug 2025 23:05:29 +0200 Subject: [PATCH 016/186] rename result_ident -> ident_prefix --- crates/ir2/build/op.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index c91177b28c..c40d948905 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -1023,7 +1023,7 @@ impl LoadOpKind { } } - pub fn result_ident(&self) -> Option { + pub fn ident_prefix(&self) -> Option { match self { LoadOpKind::Load32 => None, LoadOpKind::Load64 => None, From 26dcf94fc0bb0a851b00f8431eb0028dcf27d7ee Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 20 Aug 2025 23:30:38 +0200 Subject: [PATCH 017/186] add DisplayIndented utility type --- crates/ir2/build/display.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/crates/ir2/build/display.rs b/crates/ir2/build/display.rs index a2eb209533..314ebc9590 100644 --- a/crates/ir2/build/display.rs +++ b/crates/ir2/build/display.rs @@ -322,3 +322,25 @@ impl Display for DisplayIdent<&'_ LoadOp> { ) } } + +pub struct DisplayIndented { + val: T, + indent: Indent, +} + +impl DisplayIndented { + pub fn new(val: T, indent: Indent) -> Self { + Self { val, indent } + } +} + +impl Display for DisplayIndented +where + T: Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let indent = self.indent; + let val = &self.val; + write!(f, "{indent}{val}") + } +} From b2dbb1ce9fffaaad782fbfbc58f405981a64a896 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 20 Aug 2025 23:30:56 +0200 Subject: [PATCH 018/186] remove unused code --- crates/ir2/build/display.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/crates/ir2/build/display.rs b/crates/ir2/build/display.rs index 314ebc9590..b2fb07296d 100644 --- a/crates/ir2/build/display.rs +++ b/crates/ir2/build/display.rs @@ -263,14 +263,6 @@ impl Display for DisplayEnum<&'_ LoadOp> { false => Some(FieldTy::Memory), true => None, }; - let mem0_ident = match self.val.mem0 { - true => "Mem0", - false => "", - }; - let offset16_ident = match self.val.offset16 { - true => "Offset16", - false => "", - }; write!( f, "\ From 8fd2108666451543b829c2531b53dd4c8d9dc0da Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 20 Aug 2025 23:31:04 +0200 Subject: [PATCH 019/186] apply rustfmt --- crates/ir2/build/display.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/ir2/build/display.rs b/crates/ir2/build/display.rs index b2fb07296d..8e56436595 100644 --- a/crates/ir2/build/display.rs +++ b/crates/ir2/build/display.rs @@ -18,7 +18,10 @@ use crate::build::{ IntoMaybe as _, Maybe, }; -use core::fmt::{self, Display}; +use core::{ + fmt::{self, Display}, + ops::Not, +}; #[derive(Copy, Clone, Default)] pub struct Indent(usize); From ac26378484d5bf0f9419f65baa9d7b69a1e0ee7f Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 20 Aug 2025 23:31:36 +0200 Subject: [PATCH 020/186] add store ops codegen --- crates/ir2/build/display.rs | 58 +++++++++++++++++++++++++++++- crates/ir2/build/isa.rs | 55 ++++++++++++++++++++++++++++ crates/ir2/build/mod.rs | 2 +- crates/ir2/build/op.rs | 72 +++++++++++++++++++++++++++++-------- crates/ir2/build/token.rs | 3 ++ 5 files changed, 174 insertions(+), 16 deletions(-) diff --git a/crates/ir2/build/display.rs b/crates/ir2/build/display.rs index 8e56436595..6dc045d2b8 100644 --- a/crates/ir2/build/display.rs +++ b/crates/ir2/build/display.rs @@ -6,6 +6,7 @@ use crate::build::{ CmpBranchOp, CmpOpKind, CmpSelectOp, + Field, FieldTy, Input, LoadOp, @@ -96,7 +97,7 @@ impl Display for DisplayEnum<&'_ Op> { Op::CmpBranch(op) => self.map(op).fmt(f), Op::CmpSelect(op) => self.map(op).fmt(f), Op::Load(op) => self.map(op).fmt(f), - Op::Store(_op) => Ok(()), + Op::Store(op) => self.map(op).fmt(f), Op::Generic0(_op) => Ok(()), Op::Generic1(_op) => Ok(()), Op::Generic2(_op) => Ok(()), @@ -300,6 +301,45 @@ impl Display for DisplayEnum<&'_ LoadOp> { } } +impl Display for DisplayEnum<&'_ StoreOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let indent0 = self.indent; + let indent1 = indent0.inc(); + let kind = self.val.kind; + let ident = DisplayIdent(self.val); + let result_ty = FieldTy::Stack; + let result_suffix = CamelCase(Input::Stack); + let ptr_suffix = SnakeCase(self.val.ptr); + let ptr_ty = self.val.kind.ptr_ty(self.val.ptr); + let value_ty = self.val.kind.value_ty(self.val.value); + let offset_field = self + .val + .kind + .offset_ty(self.val.ptr, self.val.offset16) + .map(|offset| Field::new(Ident::Offset, offset)) + .map(|field| DisplayIndented::new(field, indent1)) + .into_maybe(); + let mem_field = self + .val + .mem0 + .not() + .then(|| Field::new(Ident::Memory, FieldTy::Memory)) + .map(|field| DisplayIndented::new(field, indent1)) + .into_maybe(); + write!( + f, + "\ + {indent0}{ident} {{\n\ + {indent1}ptr: {ptr_ty},\n\ + {offset_field}\n\ + {indent1}value: {value_ty},\n\ + {mem_field}\n\ + {indent0}}},\n\ + ", + ) + } +} + pub struct DisplayIdent(pub T); impl Display for DisplayIdent<&'_ LoadOp> { @@ -318,6 +358,22 @@ impl Display for DisplayIdent<&'_ LoadOp> { } } +impl Display for DisplayIdent<&'_ StoreOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let kind = self.0.kind; + let ident = CamelCase(kind.ident()); + let ptr_suffix = CamelCase(self.0.ptr); + let value_suffix = SnakeCase(self.0.value); + let ident_prefix = self.0.kind.ident_prefix().map(CamelCase).into_maybe(); + let mem0_ident = self.0.mem0.then(|| "Mem0").unwrap_or_default(); + let offset16_ident = self.0.offset16.then(|| "Offset16").unwrap_or_default(); + write!( + f, + "{ident_prefix}{ident}{mem0_ident}{offset16_ident}_{ptr_suffix}{value_suffix}", + ) + } +} + pub struct DisplayIndented { val: T, indent: Indent, diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 60dd6f046c..b0f52f865d 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -9,6 +9,8 @@ use crate::build::{ Input, LoadOp, LoadOpKind, + StoreOp, + StoreOpKind, UnaryOp, UnaryOpKind, }, @@ -33,6 +35,7 @@ pub fn wasmi_isa() -> Isa { add_cmp_branch_ops(&mut isa); add_cmp_select_ops(&mut isa); add_load_ops(&mut isa); + add_store_ops(&mut isa); isa } @@ -284,3 +287,55 @@ fn add_load_ops(isa: &mut Isa) { isa.push_op(Op::Load(LoadOp::new(op, Input::Stack, true, true))); } } + +fn add_store_ops(isa: &mut Isa) { + let ops = [ + // Generic + StoreOpKind::Store32, + StoreOpKind::Store64, + // i32 + StoreOpKind::I32Store8, + StoreOpKind::I32Store16, + // i64 + StoreOpKind::I64Store8, + StoreOpKind::I64Store16, + StoreOpKind::I64Store32, + ]; + for op in ops { + isa.push_op(Op::Store(StoreOp::new( + op, + Input::Stack, + Input::Stack, + false, + false, + ))); + isa.push_op(Op::Store(StoreOp::new( + op, + Input::Stack, + Input::Immediate, + false, + false, + ))); + isa.push_op(Op::Store(StoreOp::new( + op, + Input::Immediate, + Input::Stack, + false, + false, + ))); + isa.push_op(Op::Store(StoreOp::new( + op, + Input::Stack, + Input::Stack, + true, + true, + ))); + isa.push_op(Op::Store(StoreOp::new( + op, + Input::Stack, + Input::Immediate, + true, + true, + ))); + } +} diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index 27260fea4a..a5065c1951 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -6,7 +6,7 @@ pub mod token; use self::{ display::{DisplayEnum, Indent}, isa::Isa, - op::{BinaryOp, Op, UnaryOp}, + op::{BinaryOp, IntoMaybe, Maybe, Op, UnaryOp}, token::{CamelCase, Ident, SnakeCase}, }; use core::fmt::{self, Display, Error as FmtError, Write as _}; diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index c40d948905..151b3783cf 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -69,11 +69,17 @@ pub struct Field { ty: FieldTy, } +impl Field { + pub fn new(ident: Ident, ty: FieldTy) -> Self { + Self { ident, ty } + } +} + impl Display for Field { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let ident = SnakeCase(self.ident); let ty = self.ty; - write!(f, "{ident}: {ty}") + write!(f, "{ident}: {ty},") } } @@ -1072,47 +1078,85 @@ pub struct StoreOp { pub offset16: bool, } +impl StoreOp { + pub fn new(kind: StoreOpKind, ptr: Input, value: Input, mem0: bool, offset16: bool) -> Self { + Self { + kind, + ptr, + value, + mem0, + offset16, + } + } +} + #[derive(Copy, Clone)] pub enum StoreOpKind { - I32Store, + // Generic + Store32, + Store64, + // i32 I32Store8, I32Store16, - I64Store, + // i64 I64Store8, I64Store16, I64Store32, - F32Store, - F64Store, } impl StoreOpKind { pub fn ident(&self) -> Ident { match self { - Self::I32Store => Ident::Store, + Self::Store32 => Ident::Store32, + Self::Store64 => Ident::Store64, Self::I32Store8 => Ident::Store8, Self::I32Store16 => Ident::Store16, - Self::I64Store => Ident::Store, Self::I64Store8 => Ident::Store8, Self::I64Store16 => Ident::Store16, Self::I64Store32 => Ident::Store32, - Self::F32Store => Ident::Store, - Self::F64Store => Ident::Store, + } + } + + pub fn ident_prefix(&self) -> Option { + match self { + StoreOpKind::Store32 => None, + StoreOpKind::Store64 => None, + StoreOpKind::I32Store8 => Some(Ident::I32), + StoreOpKind::I32Store16 => Some(Ident::I32), + StoreOpKind::I64Store8 => Some(Ident::I64), + StoreOpKind::I64Store16 => Some(Ident::I64), + StoreOpKind::I64Store32 => Some(Ident::I64), + } + } + + pub fn ptr_ty(&self, ptr: Input) -> FieldTy { + match ptr { + Input::Stack => FieldTy::Stack, + Input::Immediate => FieldTy::Address, + } + } + + pub fn offset_ty(&self, ptr: Input, offset16: bool) -> Option { + match ptr { + Input::Stack => match offset16 { + true => Some(FieldTy::Offset16), + false => Some(FieldTy::U64), + }, + Input::Immediate => None, } } pub fn value_ty(&self, input: Input) -> FieldTy { match input { - Input::Stack => return FieldTy::Stack, + Input::Stack => FieldTy::Stack, Input::Immediate => match self { - Self::I32Store => FieldTy::I32, + Self::Store32 => FieldTy::U32, + Self::Store64 => FieldTy::U64, Self::I32Store8 => FieldTy::I8, Self::I32Store16 => FieldTy::I16, - Self::I64Store => FieldTy::I64, Self::I64Store8 => FieldTy::I8, Self::I64Store16 => FieldTy::I16, Self::I64Store32 => FieldTy::I32, - Self::F32Store => FieldTy::F32, - Self::F64Store => FieldTy::F64, }, } } diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index bd6d75be04..e591a98920 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -77,6 +77,7 @@ define_ident!( Store8: store8, Store16: store16, Store32: store32, + Store64: store64, Load: load, Load8: load8, Load16: load16, @@ -139,4 +140,6 @@ define_ident!( Demote: demote, Promote: promote, Convert: convert, + + Offset: offset, ); From 9eaf2dbc793c9117071b3c0a4ad0450dbf489849 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 00:00:50 +0200 Subject: [PATCH 021/186] add missing unary and binary ops --- crates/ir2/build/isa.rs | 49 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index b0f52f865d..d3a0c23655 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -81,6 +81,23 @@ fn add_unary_ops(isa: &mut Isa) { UnaryOpKind::F64ConvertS64, UnaryOpKind::F64ConvertU64, UnaryOpKind::F64PromoteF32, + // f2i conversions + UnaryOpKind::S32TruncF32, + UnaryOpKind::U32TruncF32, + UnaryOpKind::S32TruncF64, + UnaryOpKind::U32TruncF64, + UnaryOpKind::S64TruncF32, + UnaryOpKind::U64TruncF32, + UnaryOpKind::S64TruncF64, + UnaryOpKind::U64TruncF64, + UnaryOpKind::S32TruncSatF32, + UnaryOpKind::U32TruncSatF32, + UnaryOpKind::S32TruncSatF64, + UnaryOpKind::U32TruncSatF64, + UnaryOpKind::S64TruncSatF32, + UnaryOpKind::U64TruncSatF32, + UnaryOpKind::S64TruncSatF64, + UnaryOpKind::U64TruncSatF64, ]; for op in ops { isa.push_op(Op::Unary(UnaryOp::new(op))); @@ -89,6 +106,38 @@ fn add_unary_ops(isa: &mut Isa) { fn add_binary_ops(isa: &mut Isa) { let ops = [ + // comparisons: i32 + BinaryOpKind::Cmp(CmpOpKind::I32Eq), + BinaryOpKind::Cmp(CmpOpKind::I32NotEq), + BinaryOpKind::Cmp(CmpOpKind::I32And), + BinaryOpKind::Cmp(CmpOpKind::I32NotAnd), + BinaryOpKind::Cmp(CmpOpKind::I32Or), + BinaryOpKind::Cmp(CmpOpKind::I32NotOr), + BinaryOpKind::Cmp(CmpOpKind::S32Lt), + BinaryOpKind::Cmp(CmpOpKind::S32Le), + BinaryOpKind::Cmp(CmpOpKind::U32Lt), + BinaryOpKind::Cmp(CmpOpKind::U32Le), + // comparisons: i64 + BinaryOpKind::Cmp(CmpOpKind::I64Eq), + BinaryOpKind::Cmp(CmpOpKind::I64NotEq), + BinaryOpKind::Cmp(CmpOpKind::I64And), + BinaryOpKind::Cmp(CmpOpKind::I64NotAnd), + BinaryOpKind::Cmp(CmpOpKind::I64Or), + BinaryOpKind::Cmp(CmpOpKind::I64NotOr), + BinaryOpKind::Cmp(CmpOpKind::S64Lt), + BinaryOpKind::Cmp(CmpOpKind::S64Le), + BinaryOpKind::Cmp(CmpOpKind::U64Lt), + BinaryOpKind::Cmp(CmpOpKind::U64Le), + // comparisons: f32 + BinaryOpKind::Cmp(CmpOpKind::F32Eq), + BinaryOpKind::Cmp(CmpOpKind::F32NotEq), + BinaryOpKind::Cmp(CmpOpKind::F32Lt), + BinaryOpKind::Cmp(CmpOpKind::F32Le), + // comparisons: f64 + BinaryOpKind::Cmp(CmpOpKind::F64Eq), + BinaryOpKind::Cmp(CmpOpKind::F64NotEq), + BinaryOpKind::Cmp(CmpOpKind::F64Lt), + BinaryOpKind::Cmp(CmpOpKind::F64Le), // i32 BinaryOpKind::I32Add, BinaryOpKind::I32Sub, From fa61ce8dcf6626b315b8d2a82d863bc92758978a Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 00:01:53 +0200 Subject: [PATCH 022/186] fix codegen --- crates/ir2/build/display.rs | 4 ++-- crates/ir2/build/op.rs | 40 ++++++++++++++++++------------------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/crates/ir2/build/display.rs b/crates/ir2/build/display.rs index 6dc045d2b8..1652d03e90 100644 --- a/crates/ir2/build/display.rs +++ b/crates/ir2/build/display.rs @@ -166,7 +166,7 @@ impl Display for DisplayEnum<&'_ BinaryOp> { let indent1 = indent0.inc(); let kind = self.val.kind; let ident = CamelCase(kind.ident()); - let result_ident = CamelCase(Ident::from(kind.result_ty())); + let ident_prefix = CamelCase(kind.ident_prefix()); let result_ty = FieldTy::Stack; let lhs_ty = kind.lhs_field(self.val.lhs); let rhs_ty = kind.rhs_field(self.val.rhs); @@ -176,7 +176,7 @@ impl Display for DisplayEnum<&'_ BinaryOp> { write!( f, "\ - {indent0}{result_ident}{ident}_S{lhs_suffix}{rhs_suffix} {{\n\ + {indent0}{ident_prefix}{ident}_{result_suffix}{lhs_suffix}{rhs_suffix} {{\n\ {indent1}result: {result_ty},\n\ {indent1}lhs: {lhs_ty},\n\ {indent1}rhs: {rhs_ty},\n\ diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 151b3783cf..4a900c1908 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -225,20 +225,14 @@ impl UnaryOpKind { | Self::F64Trunc | Self::F64Nearest | Self::F64Sqrt => Ty::F64, - | Self::S32TruncF32 | Self::U32TruncF32 | Self::S32TruncF64 | Self::U32TruncF64 => { - Ty::I32 - } - | Self::S64TruncF32 | Self::U64TruncF32 | Self::S64TruncF64 | Self::U64TruncF64 => { - Ty::I64 - } - | Self::S32TruncSatF32 - | Self::U32TruncSatF32 - | Self::S32TruncSatF64 - | Self::U32TruncSatF64 => Ty::I32, - | Self::S64TruncSatF32 - | Self::U64TruncSatF32 - | Self::S64TruncSatF64 - | Self::U64TruncSatF64 => Ty::I64, + | Self::S32TruncF32 | Self::S32TruncF64 => Ty::I32, + | Self::U32TruncF32 | Self::U32TruncF64 => Ty::U32, + | Self::S64TruncF32 | Self::S64TruncF64 => Ty::I64, + | Self::U64TruncF32 | Self::U64TruncF64 => Ty::U64, + | Self::S32TruncSatF32 | Self::S32TruncSatF64 => Ty::I32, + | Self::U32TruncSatF32 | Self::U32TruncSatF64 => Ty::U32, + | Self::S64TruncSatF32 | Self::S64TruncSatF64 => Ty::I64, + | Self::U64TruncSatF32 | Self::U64TruncSatF64 => Ty::U64, | Self::F32DemoteF64 => Ty::F32, | Self::F64PromoteF32 => Ty::F64, | Self::F32ConvertS32 @@ -422,6 +416,14 @@ impl BinaryOpKind { } } + pub fn ident_prefix(&self) -> Ident { + let ty = match self { + BinaryOpKind::Cmp(op) => op.input_ty(), + _ => self.result_ty(), + }; + Ident::from(ty) + } + pub fn lhs_field(&self, input: Input) -> FieldTy { match input { Input::Stack => return FieldTy::Stack, @@ -906,18 +908,16 @@ impl CmpOpKind { | Self::I32And | Self::I32NotAnd | Self::I32Or - | Self::I32NotOr - | Self::S32Lt - | Self::S32Le => Ty::I32, + | Self::I32NotOr => Ty::I32, + | Self::S32Lt | Self::S32Le => Ty::S32, | Self::U32Lt | Self::U32Le => Ty::U32, | Self::I64Eq | Self::I64NotEq | Self::I64And | Self::I64NotAnd | Self::I64Or - | Self::I64NotOr - | Self::S64Lt - | Self::S64Le => Ty::I64, + | Self::I64NotOr => Ty::I64, + | Self::S64Lt | Self::S64Le => Ty::S64, | Self::U64Lt | Self::U64Le => Ty::U64, | Self::F32Eq | Self::F32NotEq From 1a1e0d79c8846077c9bd8112b7506d6603ce4f71 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 00:02:31 +0200 Subject: [PATCH 023/186] remove lots of unused code and imports --- crates/ir2/build.rs | 2 -- crates/ir2/build/display.rs | 25 +------------------------ crates/ir2/build/mod.rs | 2 ++ crates/ir2/build/op.rs | 21 --------------------- crates/ir2/build/token.rs | 3 --- 5 files changed, 3 insertions(+), 50 deletions(-) diff --git a/crates/ir2/build.rs b/crates/ir2/build.rs index e17bbad8da..09cf03d8d0 100644 --- a/crates/ir2/build.rs +++ b/crates/ir2/build.rs @@ -1,5 +1,3 @@ -#![allow(warnings)] - use std::{ env, fs, diff --git a/crates/ir2/build/display.rs b/crates/ir2/build/display.rs index 1652d03e90..820b20c533 100644 --- a/crates/ir2/build/display.rs +++ b/crates/ir2/build/display.rs @@ -1,23 +1,8 @@ use crate::build::{ isa::Isa, - op::{ - BinaryOp, - BinaryOpKind, - CmpBranchOp, - CmpOpKind, - CmpSelectOp, - Field, - FieldTy, - Input, - LoadOp, - Op, - StoreOp, - Ty, - UnaryOp, - }, + op::{BinaryOp, CmpBranchOp, CmpSelectOp, Field, FieldTy, Input, LoadOp, Op, StoreOp, UnaryOp}, token::{CamelCase, Ident, SnakeCase}, IntoMaybe as _, - Maybe, }; use core::{ fmt::{self, Display}, @@ -246,12 +231,8 @@ impl Display for DisplayEnum<&'_ LoadOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent0 = self.indent; let indent1 = indent0.inc(); - let kind = self.val.kind; let ident = DisplayIdent(self.val); let result_ty = FieldTy::Stack; - let result_ident = kind.ident_prefix().map(CamelCase); - let result_suffix = CamelCase(Input::Stack); - let ptr_suffix = SnakeCase(self.val.ptr); let (ptr_ty, offset_ty) = match self.val.ptr { Input::Stack => { let ptr = FieldTy::Stack; @@ -305,11 +286,7 @@ impl Display for DisplayEnum<&'_ StoreOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent0 = self.indent; let indent1 = indent0.inc(); - let kind = self.val.kind; let ident = DisplayIdent(self.val); - let result_ty = FieldTy::Stack; - let result_suffix = CamelCase(Input::Stack); - let ptr_suffix = SnakeCase(self.val.ptr); let ptr_ty = self.val.kind.ptr_ty(self.val.ptr); let value_ty = self.val.kind.value_ty(self.val.value); let offset_field = self diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index a5065c1951..39a0874df6 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -1,3 +1,5 @@ +#![allow(unused_imports, dead_code)] + mod display; mod isa; mod op; diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 4a900c1908..5de07aa3d2 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -743,8 +743,6 @@ pub enum FieldTy { F64, NonZeroU32, NonZeroU64, - NonZeroI32, - NonZeroI64, SignF32, SignF64, Address, @@ -779,8 +777,6 @@ impl Display for FieldTy { Self::F64 => "f64", Self::NonZeroU32 => "NonZero", Self::NonZeroU64 => "NonZero", - Self::NonZeroI32 => "NonZero", - Self::NonZeroI64 => "NonZero", Self::SignF32 => "Sign", Self::SignF64 => "Sign", Self::Address => "Address", @@ -1045,23 +1041,6 @@ impl LoadOpKind { LoadOpKind::U64Load32 => Some(Ident::U64), } } - - pub fn result_ty(&self) -> Ty { - match self { - LoadOpKind::Load32 => Ty::U32, - LoadOpKind::Load64 => Ty::U64, - LoadOpKind::S32Load8 => Ty::S32, - LoadOpKind::U32Load8 => Ty::U32, - LoadOpKind::S32Load16 => Ty::S32, - LoadOpKind::U32Load16 => Ty::U32, - LoadOpKind::S64Load8 => Ty::S64, - LoadOpKind::U64Load8 => Ty::U64, - LoadOpKind::S64Load16 => Ty::S64, - LoadOpKind::U64Load16 => Ty::U64, - LoadOpKind::S64Load32 => Ty::S64, - LoadOpKind::U64Load32 => Ty::U64, - } - } } #[derive(Copy, Clone)] diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index e591a98920..80187aecf8 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -70,15 +70,12 @@ define_ident!( BitOr: bit_or, BitXor: bit_xor, - Return: r#return, Branch: branch, Select: select, - Store: store, Store8: store8, Store16: store16, Store32: store32, Store64: store64, - Load: load, Load8: load8, Load16: load16, Load32: load32, From 2c2690158d000f59acf72a8b76db5c7a1a555550 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 00:02:41 +0200 Subject: [PATCH 024/186] clean-up codegen a bit --- crates/ir2/build/display.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/crates/ir2/build/display.rs b/crates/ir2/build/display.rs index 820b20c533..883e9c1fe4 100644 --- a/crates/ir2/build/display.rs +++ b/crates/ir2/build/display.rs @@ -107,6 +107,8 @@ impl DisplayEnum<&'_ UnaryOp> { let kind = self.val.kind; let ident = CamelCase(kind.ident()); let result_ident = CamelCase(Ident::from(kind.result_ty())); + let result_suffix = CamelCase(Input::Stack); + let value_suffix = SnakeCase(Input::Stack); let result_field = FieldTy::Stack; let value_field = FieldTy::Stack; let indent0 = self.indent; @@ -114,7 +116,7 @@ impl DisplayEnum<&'_ UnaryOp> { write!( f, "\ - {indent0}{result_ident}{ident}_Ss {{\n\ + {indent0}{result_ident}{ident}_{result_suffix}{value_suffix} {{\n\ {indent1}result: {result_field},\n\ {indent1}value: {value_field},\n\ {indent0}}},\n\ @@ -127,8 +129,8 @@ impl DisplayEnum<&'_ UnaryOp> { let ident = CamelCase(kind.ident()); let result_ident = CamelCase(Ident::from(kind.result_ty())); let input_ident = CamelCase(Ident::from(kind.input_ty())); - let result_id = CamelCase(Input::Stack); - let value_id = CamelCase(Input::Stack); + let result_suffix = CamelCase(Input::Stack); + let value_suffix = SnakeCase(Input::Stack); let result_field = FieldTy::Stack; let value_field = FieldTy::Stack; let indent0 = self.indent; @@ -136,7 +138,7 @@ impl DisplayEnum<&'_ UnaryOp> { write!( f, "\ - {indent0}{result_ident}{ident}{input_ident}_Ss {{\n\ + {indent0}{result_ident}{ident}{input_ident}_{result_suffix}{value_suffix} {{\n\ {indent1}result: {result_field},\n\ {indent1}value: {value_field},\n\ {indent0}}},\n\ @@ -178,17 +180,17 @@ impl Display for DisplayEnum<&'_ CmpBranchOp> { let cmp = self.val.cmp; let ident = CamelCase(cmp.ident()); let input_ident = CamelCase(Ident::from(cmp.input_ty())); - let result_ty = FieldTy::Stack; let lhs_ty = cmp.input_field(self.val.lhs); let rhs_ty = cmp.input_field(self.val.rhs); + let offset_ty = FieldTy::BranchOffset; let result_suffix = CamelCase(Input::Stack); let lhs_suffix = SnakeCase(self.val.lhs); let rhs_suffix = SnakeCase(self.val.rhs); write!( f, "\ - {indent0}Branch{input_ident}{ident}_S{lhs_suffix}{rhs_suffix} {{\n\ - {indent1}offset: BranchOffset,\n\ + {indent0}Branch{input_ident}{ident}_{result_suffix}{lhs_suffix}{rhs_suffix} {{\n\ + {indent1}offset: {offset_ty},\n\ {indent1}lhs: {lhs_ty},\n\ {indent1}rhs: {rhs_ty},\n\ {indent0}}},\n\ @@ -215,7 +217,7 @@ impl Display for DisplayEnum<&'_ CmpSelectOp> { write!( f, "\ - {indent0}Select{input_ident}{ident}_S{lhs_suffix}{rhs_suffix} {{\n\ + {indent0}Select{input_ident}{ident}_{result_suffix}{lhs_suffix}{rhs_suffix} {{\n\ {indent1}result: {result_ty},\n\ {indent1}lhs: {lhs_ty},\n\ {indent1}rhs: {rhs_ty},\n\ From 39ecb3109cb90e7229a3ac314fd8a476163de0a6 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 00:34:12 +0200 Subject: [PATCH 025/186] add reserve to Isa --- crates/ir2/build/isa.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index d3a0c23655..29b0b8d7f7 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -30,6 +30,7 @@ impl Isa { pub fn wasmi_isa() -> Isa { let mut isa = Isa::default(); + isa.ops.reserve(500); add_unary_ops(&mut isa); add_binary_ops(&mut isa); add_cmp_branch_ops(&mut isa); From ea69a0db7dc62727f41f9be55694dc21a4e388de Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 02:46:19 +0200 Subject: [PATCH 026/186] generalize DisplayIndented -> DisplayPair --- crates/ir2/build/display.rs | 40 ++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/crates/ir2/build/display.rs b/crates/ir2/build/display.rs index 883e9c1fe4..65acb86738 100644 --- a/crates/ir2/build/display.rs +++ b/crates/ir2/build/display.rs @@ -1,6 +1,18 @@ use crate::build::{ isa::Isa, - op::{BinaryOp, CmpBranchOp, CmpSelectOp, Field, FieldTy, Input, LoadOp, Op, StoreOp, UnaryOp}, + op::{ + BinaryOp, + CmpBranchOp, + CmpSelectOp, + Field, + FieldTy, + GenericOp, + Input, + LoadOp, + Op, + StoreOp, + UnaryOp, + }, token::{CamelCase, Ident, SnakeCase}, IntoMaybe as _, }; @@ -296,14 +308,14 @@ impl Display for DisplayEnum<&'_ StoreOp> { .kind .offset_ty(self.val.ptr, self.val.offset16) .map(|offset| Field::new(Ident::Offset, offset)) - .map(|field| DisplayIndented::new(field, indent1)) + .map(|field| DisplayPair(indent1, field)) .into_maybe(); let mem_field = self .val .mem0 .not() .then(|| Field::new(Ident::Memory, FieldTy::Memory)) - .map(|field| DisplayIndented::new(field, indent1)) + .map(|field| DisplayPair(indent1, field)) .into_maybe(); write!( f, @@ -353,24 +365,16 @@ impl Display for DisplayIdent<&'_ StoreOp> { } } -pub struct DisplayIndented { - val: T, - indent: Indent, -} +pub struct DisplayPair(pub T0, pub T1); -impl DisplayIndented { - pub fn new(val: T, indent: Indent) -> Self { - Self { val, indent } - } -} - -impl Display for DisplayIndented +impl Display for DisplayPair where - T: Display, + T0: Display, + T1: Display, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let indent = self.indent; - let val = &self.val; - write!(f, "{indent}{val}") + let t0 = &self.0; + let t1 = &self.1; + write!(f, "{t0}{t1}") } } From f10dbcfe59c2124f1e11024fc7fe4dba8ae5518c Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 02:46:36 +0200 Subject: [PATCH 027/186] add GenericOp::new --- crates/ir2/build/op.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 5de07aa3d2..71cb7af002 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -22,6 +22,12 @@ pub struct GenericOp { pub fields: [Field; N], } +impl GenericOp { + pub fn new(ident: Ident, fields: [Field; N]) -> Self { + Self { ident, fields } + } +} + pub enum Maybe { Some(T), None, @@ -733,6 +739,7 @@ pub enum FieldTy { StackSpan, BoundedStackSpan, U8, + U16, U32, U64, I8, @@ -767,6 +774,7 @@ impl Display for FieldTy { Self::StackSpan => "StackSpan", Self::BoundedStackSpan => "BoundedStackSpan", Self::U8 => "u8", + Self::U16 => "u16", Self::U32 => "u32", Self::U64 => "u64", Self::I8 => "i8", From 7e5704a34355f88b761b2e3db846458592f7ff8d Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 02:46:59 +0200 Subject: [PATCH 028/186] add control and copy ops to ISA --- crates/ir2/build/isa.rs | 68 +++++++++++++++++++++++++++++++++++++++ crates/ir2/build/token.rs | 13 ++++++++ 2 files changed, 81 insertions(+) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 29b0b8d7f7..93a209e072 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -6,6 +6,9 @@ use crate::build::{ CmpOpKind, CmpSelectOp, Commutativity, + Field, + FieldTy, + GenericOp, Input, LoadOp, LoadOpKind, @@ -14,6 +17,7 @@ use crate::build::{ UnaryOp, UnaryOpKind, }, + token::Ident, Op, }; @@ -37,6 +41,8 @@ pub fn wasmi_isa() -> Isa { add_cmp_select_ops(&mut isa); add_load_ops(&mut isa); add_store_ops(&mut isa); + add_control_ops(&mut isa); + add_copy_ops(&mut isa); isa } @@ -389,3 +395,65 @@ fn add_store_ops(isa: &mut Isa) { ))); } } + +fn add_control_ops(isa: &mut Isa) { + let ops = [ + Op::Generic1(GenericOp::new( + Ident::Trap, + [Field::new(Ident::TrapCode, FieldTy::TrapCode)], + )), + Op::Generic1(GenericOp::new( + Ident::ConsumeFuel, + [Field::new(Ident::Fuel, FieldTy::BlockFuel)], + )), + Op::Generic0(GenericOp::new(Ident::Return, [])), + Op::Generic1(GenericOp::new( + Ident::ReturnSpan, + [Field::new(Ident::Fuel, FieldTy::BlockFuel)], + )), + Op::Generic1(GenericOp::new( + Ident::Branch, + [Field::new(Ident::Values, FieldTy::StackSpan)], + )), + ]; + for op in ops { + isa.push_op(op); + } +} + +fn add_copy_ops(isa: &mut Isa) { + let ops = [ + Op::Generic2(GenericOp::new( + Ident::Copy, + [ + Field::new(Ident::Result, FieldTy::Stack), + Field::new(Ident::Value, FieldTy::Stack), + ], + )), + Op::Generic2(GenericOp::new( + Ident::Copy32, + [ + Field::new(Ident::Result, FieldTy::Stack), + Field::new(Ident::Value, FieldTy::U32), + ], + )), + Op::Generic2(GenericOp::new( + Ident::Copy64, + [ + Field::new(Ident::Result, FieldTy::Stack), + Field::new(Ident::Value, FieldTy::U64), + ], + )), + Op::Generic3(GenericOp::new( + Ident::CopySpan, + [ + Field::new(Ident::Results, FieldTy::StackSpan), + Field::new(Ident::Values, FieldTy::StackSpan), + Field::new(Ident::Len, FieldTy::U16), + ], + )), + ]; + for op in ops { + isa.push_op(op); + } +} diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index 80187aecf8..066627ed38 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -82,6 +82,9 @@ define_ident!( Load64: load64, Copy: copy, + Copy32: copy32, + Copy64: copy64, + CopySpan: copy_span, Fill: fill, Init: init, Grow: grow, @@ -139,4 +142,14 @@ define_ident!( Convert: convert, Offset: offset, + TrapCode: trap_code, + ConsumeFuel: consume_fuel, + Fuel: fuel, + Return: r#return, + ReturnSpan: return_span, + Values: values, + Value: value, + Result: result, + Results: results, + Len: len, ); From f5446d87a2b183a1e77fd1d5c0f3722349edd3cb Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 03:04:19 +0200 Subject: [PATCH 029/186] add DisplaySequence utility --- crates/ir2/build/display.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/crates/ir2/build/display.rs b/crates/ir2/build/display.rs index 65acb86738..493976a4b8 100644 --- a/crates/ir2/build/display.rs +++ b/crates/ir2/build/display.rs @@ -378,3 +378,17 @@ where write!(f, "{t0}{t1}") } } + +pub struct DisplaySequence(pub T); + +impl Display for DisplaySequence +where + T: IntoIterator + Clone, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for item in self.0.clone() { + write!(f, "{item}")?; + } + Ok(()) + } +} From 496cfc8aa79e6e39d6905f60bdac533265af725b Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 03:04:33 +0200 Subject: [PATCH 030/186] add control and copy ops codegen --- crates/ir2/build/display.rs | 32 +++++++++++++++++++++++++++----- crates/ir2/src/op.rs | 12 +++++++++++- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/crates/ir2/build/display.rs b/crates/ir2/build/display.rs index 493976a4b8..abc93f239b 100644 --- a/crates/ir2/build/display.rs +++ b/crates/ir2/build/display.rs @@ -95,11 +95,11 @@ impl Display for DisplayEnum<&'_ Op> { Op::CmpSelect(op) => self.map(op).fmt(f), Op::Load(op) => self.map(op).fmt(f), Op::Store(op) => self.map(op).fmt(f), - Op::Generic0(_op) => Ok(()), - Op::Generic1(_op) => Ok(()), - Op::Generic2(_op) => Ok(()), - Op::Generic3(_op) => Ok(()), - Op::Generic4(_op) => Ok(()), + Op::Generic0(op) => self.map(op).fmt(f), + Op::Generic1(op) => self.map(op).fmt(f), + Op::Generic2(op) => self.map(op).fmt(f), + Op::Generic3(op) => self.map(op).fmt(f), + Op::Generic4(op) => self.map(op).fmt(f), } } } @@ -331,6 +331,28 @@ impl Display for DisplayEnum<&'_ StoreOp> { } } +impl Display for DisplayEnum<&'_ GenericOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let indent0 = self.indent; + let indent1 = indent0.inc(); + let ident = CamelCase(self.val.ident); + let fields = DisplaySequence( + self.val + .fields + .into_iter() + .map(move |field| DisplayPair(indent1, DisplayPair(field, "\n"))), + ); + write!( + f, + "\ + {indent0}{ident} {{\n\ + {fields} + {indent0}}},\n\ + ", + ) + } +} + pub struct DisplayIdent(pub T); impl Display for DisplayIdent<&'_ LoadOp> { diff --git a/crates/ir2/src/op.rs b/crates/ir2/src/op.rs index 2e672db222..716cf7f7df 100644 --- a/crates/ir2/src/op.rs +++ b/crates/ir2/src/op.rs @@ -1,4 +1,14 @@ -use crate::{index::Memory, Address, BranchOffset, Offset16, Sign, Stack}; +use crate::{ + core::TrapCode, + index::Memory, + Address, + BlockFuel, + BranchOffset, + Offset16, + Sign, + Stack, + StackSpan, +}; use core::num::NonZero; include!(concat!(env!("OUT_DIR"), "/op.rs")); From 51e238dbfb03b7925ccb5311865be16c0bf1da3a Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 03:05:36 +0200 Subject: [PATCH 031/186] add GenericOp with 5 fields --- crates/ir2/build/display.rs | 1 + crates/ir2/build/op.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/crates/ir2/build/display.rs b/crates/ir2/build/display.rs index abc93f239b..16f9c1aedc 100644 --- a/crates/ir2/build/display.rs +++ b/crates/ir2/build/display.rs @@ -100,6 +100,7 @@ impl Display for DisplayEnum<&'_ Op> { Op::Generic2(op) => self.map(op).fmt(f), Op::Generic3(op) => self.map(op).fmt(f), Op::Generic4(op) => self.map(op).fmt(f), + Op::Generic5(op) => self.map(op).fmt(f), } } } diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 71cb7af002..0488bc2188 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -14,6 +14,7 @@ pub enum Op { Generic2(GenericOp<2>), Generic3(GenericOp<3>), Generic4(GenericOp<4>), + Generic5(GenericOp<5>), } #[derive(Copy, Clone)] From 80291b70e38990237c3b2020f643fc29fd6e4744 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 12:43:44 +0200 Subject: [PATCH 032/186] add some table ops codegen --- crates/ir2/build/display.rs | 59 +++++++++++++++++++++++++++++++++++++ crates/ir2/build/isa.rs | 17 +++++++++++ crates/ir2/build/op.rs | 28 ++++++++++++++++++ crates/ir2/build/token.rs | 2 ++ crates/ir2/src/op.rs | 2 +- 5 files changed, 107 insertions(+), 1 deletion(-) diff --git a/crates/ir2/build/display.rs b/crates/ir2/build/display.rs index 16f9c1aedc..74caae19be 100644 --- a/crates/ir2/build/display.rs +++ b/crates/ir2/build/display.rs @@ -11,6 +11,8 @@ use crate::build::{ LoadOp, Op, StoreOp, + TableGetOp, + TableSetOp, UnaryOp, }, token::{CamelCase, Ident, SnakeCase}, @@ -95,6 +97,8 @@ impl Display for DisplayEnum<&'_ Op> { Op::CmpSelect(op) => self.map(op).fmt(f), Op::Load(op) => self.map(op).fmt(f), Op::Store(op) => self.map(op).fmt(f), + Op::TableGet(op) => self.map(op).fmt(f), + Op::TableSet(op) => self.map(op).fmt(f), Op::Generic0(op) => self.map(op).fmt(f), Op::Generic1(op) => self.map(op).fmt(f), Op::Generic2(op) => self.map(op).fmt(f), @@ -354,6 +358,61 @@ impl Display for DisplayEnum<&'_ GenericOp> { } } +impl Display for DisplayEnum<&'_ TableGetOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let indent0 = self.indent; + let indent1 = indent0.inc(); + let ident = CamelCase(Ident::TableGet); + let result_ty = FieldTy::Stack; + let index_ty = match self.val.index { + Input::Stack => FieldTy::Stack, + Input::Immediate => FieldTy::U64, + }; + let table_ty = FieldTy::Table; + let result_suffix = CamelCase(Input::Stack); + let index_suffix = SnakeCase(self.val.index); + write!( + f, + "\ + {indent0}{ident}_{result_suffix}{index_suffix} {{\n\ + {indent1}result: {result_ty},\n\ + {indent1}index: {index_ty},\n\ + {indent1}table: {table_ty},\n\ + {indent0}}},\n\ + ", + ) + } +} + +impl Display for DisplayEnum<&'_ TableSetOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let indent0 = self.indent; + let indent1 = indent0.inc(); + let ident = CamelCase(Ident::TableSet); + let index_ty = match self.val.index { + Input::Stack => FieldTy::Stack, + Input::Immediate => FieldTy::U64, + }; + let value_ty = match self.val.value { + Input::Stack => FieldTy::Stack, + Input::Immediate => FieldTy::U64, + }; + let table_ty = FieldTy::Table; + let index_suffix = CamelCase(self.val.index); + let value_suffix = SnakeCase(self.val.value); + write!( + f, + "\ + {indent0}{ident}_{index_suffix}{value_suffix} {{\n\ + {indent1}table: {table_ty},\n\ + {indent1}index: {index_ty},\n\ + {indent1}value: {value_ty},\n\ + {indent0}}},\n\ + ", + ) + } +} + pub struct DisplayIdent(pub T); impl Display for DisplayIdent<&'_ LoadOp> { diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 93a209e072..b0f5bd149e 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -14,6 +14,8 @@ use crate::build::{ LoadOpKind, StoreOp, StoreOpKind, + TableGetOp, + TableSetOp, UnaryOp, UnaryOpKind, }, @@ -43,6 +45,7 @@ pub fn wasmi_isa() -> Isa { add_store_ops(&mut isa); add_control_ops(&mut isa); add_copy_ops(&mut isa); + add_table_ops(&mut isa); isa } @@ -457,3 +460,17 @@ fn add_copy_ops(isa: &mut Isa) { isa.push_op(op); } } + +fn add_table_ops(isa: &mut Isa) { + let ops = [ + Op::TableGet(TableGetOp::new(Input::Stack)), + Op::TableGet(TableGetOp::new(Input::Immediate)), + Op::TableSet(TableSetOp::new(Input::Stack, Input::Stack)), + Op::TableSet(TableSetOp::new(Input::Stack, Input::Immediate)), + Op::TableSet(TableSetOp::new(Input::Immediate, Input::Stack)), + Op::TableSet(TableSetOp::new(Input::Immediate, Input::Immediate)), + ]; + for op in ops { + isa.push_op(op); + } +} diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 0488bc2188..792dad3531 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -9,6 +9,8 @@ pub enum Op { CmpSelect(CmpSelectOp), Load(LoadOp), Store(StoreOp), + TableGet(TableGetOp), + TableSet(TableSetOp), Generic0(GenericOp<0>), Generic1(GenericOp<1>), Generic2(GenericOp<2>), @@ -1150,6 +1152,32 @@ impl StoreOpKind { } } +#[derive(Copy, Clone)] +pub struct TableGetOp { + /// The `index` type. + pub index: Input, +} + +impl TableGetOp { + pub fn new(index: Input) -> Self { + Self { index } + } +} + +#[derive(Copy, Clone)] +pub struct TableSetOp { + /// The `index` input. + pub index: Input, + /// The `value` input. + pub value: Input, +} + +impl TableSetOp { + pub fn new(index: Input, value: Input) -> Self { + Self { index, value } + } +} + #[derive(Copy, Clone)] pub enum Input { Stack, diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index 066627ed38..33583a19f9 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -152,4 +152,6 @@ define_ident!( Result: result, Results: results, Len: len, + TableGet: table_get, + TableSet: table_set, ); diff --git a/crates/ir2/src/op.rs b/crates/ir2/src/op.rs index 716cf7f7df..5a294c9f2b 100644 --- a/crates/ir2/src/op.rs +++ b/crates/ir2/src/op.rs @@ -1,6 +1,6 @@ use crate::{ core::TrapCode, - index::Memory, + index::{Memory, Table}, Address, BlockFuel, BranchOffset, From 8253a22d9c26c74233dfb649dbb7586e43f4c3aa Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 12:57:52 +0200 Subject: [PATCH 033/186] add From> for Op impls --- crates/ir2/build/op.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 792dad3531..ebc4e88730 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -19,6 +19,26 @@ pub enum Op { Generic5(GenericOp<5>), } +macro_rules! impl_from_generic_op { + ( $($op:ident < $n:literal >),* $(,)? ) => { + $( + impl From> for Op { + fn from(op: GenericOp<$n>) -> Self { + Op::$op(op) + } + } + )* + }; +} +impl_from_generic_op! { + Generic0<0>, + Generic1<1>, + Generic2<2>, + Generic3<3>, + Generic4<4>, + Generic5<5>, +} + #[derive(Copy, Clone)] pub struct GenericOp { pub ident: Ident, From af243ba3531b2569e1b89026408a4f701eaef443 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 12:58:06 +0200 Subject: [PATCH 034/186] use new generic from impls --- crates/ir2/build/isa.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index b0f5bd149e..7feb0fb455 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -401,20 +401,20 @@ fn add_store_ops(isa: &mut Isa) { fn add_control_ops(isa: &mut Isa) { let ops = [ - Op::Generic1(GenericOp::new( + Op::from(GenericOp::new( Ident::Trap, [Field::new(Ident::TrapCode, FieldTy::TrapCode)], )), - Op::Generic1(GenericOp::new( + Op::from(GenericOp::new( Ident::ConsumeFuel, [Field::new(Ident::Fuel, FieldTy::BlockFuel)], )), - Op::Generic0(GenericOp::new(Ident::Return, [])), - Op::Generic1(GenericOp::new( + Op::from(GenericOp::new(Ident::Return, [])), + Op::from(GenericOp::new( Ident::ReturnSpan, [Field::new(Ident::Fuel, FieldTy::BlockFuel)], )), - Op::Generic1(GenericOp::new( + Op::from(GenericOp::new( Ident::Branch, [Field::new(Ident::Values, FieldTy::StackSpan)], )), @@ -426,28 +426,28 @@ fn add_control_ops(isa: &mut Isa) { fn add_copy_ops(isa: &mut Isa) { let ops = [ - Op::Generic2(GenericOp::new( + Op::from(GenericOp::new( Ident::Copy, [ Field::new(Ident::Result, FieldTy::Stack), Field::new(Ident::Value, FieldTy::Stack), ], )), - Op::Generic2(GenericOp::new( + Op::from(GenericOp::new( Ident::Copy32, [ Field::new(Ident::Result, FieldTy::Stack), Field::new(Ident::Value, FieldTy::U32), ], )), - Op::Generic2(GenericOp::new( + Op::from(GenericOp::new( Ident::Copy64, [ Field::new(Ident::Result, FieldTy::Stack), Field::new(Ident::Value, FieldTy::U64), ], )), - Op::Generic3(GenericOp::new( + Op::from(GenericOp::new( Ident::CopySpan, [ Field::new(Ident::Results, FieldTy::StackSpan), From 2937694aaa65890e32c000dd1a86e4cb8cf77025 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 13:04:25 +0200 Subject: [PATCH 035/186] change immediate index type of Table{Get,Set} to u32 --- crates/ir2/build/display.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ir2/build/display.rs b/crates/ir2/build/display.rs index 74caae19be..94f3c3d9c3 100644 --- a/crates/ir2/build/display.rs +++ b/crates/ir2/build/display.rs @@ -366,7 +366,7 @@ impl Display for DisplayEnum<&'_ TableGetOp> { let result_ty = FieldTy::Stack; let index_ty = match self.val.index { Input::Stack => FieldTy::Stack, - Input::Immediate => FieldTy::U64, + Input::Immediate => FieldTy::U32, }; let table_ty = FieldTy::Table; let result_suffix = CamelCase(Input::Stack); @@ -391,7 +391,7 @@ impl Display for DisplayEnum<&'_ TableSetOp> { let ident = CamelCase(Ident::TableSet); let index_ty = match self.val.index { Input::Stack => FieldTy::Stack, - Input::Immediate => FieldTy::U64, + Input::Immediate => FieldTy::U32, }; let value_ty = match self.val.value { Input::Stack => FieldTy::Stack, From 6f329ee958c5ce045fb77f034a699b5b97f2f414 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 13:04:35 +0200 Subject: [PATCH 036/186] add remaining table ops codegen --- crates/ir2/build/isa.rs | 49 +++++++++++++++++++++++++++++++++++++++ crates/ir2/build/token.rs | 11 +++++++++ crates/ir2/src/op.rs | 2 +- 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 7feb0fb455..34ca03c59b 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -469,6 +469,55 @@ fn add_table_ops(isa: &mut Isa) { Op::TableSet(TableSetOp::new(Input::Stack, Input::Immediate)), Op::TableSet(TableSetOp::new(Input::Immediate, Input::Stack)), Op::TableSet(TableSetOp::new(Input::Immediate, Input::Immediate)), + Op::from(GenericOp::new( + Ident::TableSize, + [ + Field::new(Ident::Result, FieldTy::Stack), + Field::new(Ident::Table, FieldTy::Table), + ], + )), + Op::from(GenericOp::new( + Ident::TableGrow, + [ + Field::new(Ident::Result, FieldTy::Stack), + Field::new(Ident::Delta, FieldTy::Stack), + Field::new(Ident::Value, FieldTy::Stack), + Field::new(Ident::Table, FieldTy::Table), + ], + )), + Op::from(GenericOp::new( + Ident::TableCopy, + [ + Field::new(Ident::DstTable, FieldTy::Table), + Field::new(Ident::SrcTable, FieldTy::Table), + Field::new(Ident::Dst, FieldTy::Stack), + Field::new(Ident::Src, FieldTy::Stack), + Field::new(Ident::Len, FieldTy::Stack), + ], + )), + Op::from(GenericOp::new( + Ident::TableFill, + [ + Field::new(Ident::Table, FieldTy::Table), + Field::new(Ident::Dst, FieldTy::Stack), + Field::new(Ident::Len, FieldTy::Stack), + Field::new(Ident::Value, FieldTy::Stack), + ], + )), + Op::from(GenericOp::new( + Ident::TableInit, + [ + Field::new(Ident::Table, FieldTy::Table), + Field::new(Ident::Elem, FieldTy::Elem), + Field::new(Ident::Dst, FieldTy::Stack), + Field::new(Ident::Src, FieldTy::Stack), + Field::new(Ident::Len, FieldTy::Stack), + ], + )), + Op::from(GenericOp::new( + Ident::ElemDrop, + [Field::new(Ident::Elem, FieldTy::Elem)], + )), ]; for op in ops { isa.push_op(op); diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index 33583a19f9..60d69f540f 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -152,6 +152,17 @@ define_ident!( Result: result, Results: results, Len: len, + Delta: delta, + Dst: dst, + Src: src, + DstTable: dst_table, + SrcTable: src_table, TableGet: table_get, TableSet: table_set, + TableSize: table_size, + TableGrow: table_grow, + TableCopy: table_copy, + TableFill: table_fill, + TableInit: table_init, + ElemDrop: elem_drop, ); diff --git a/crates/ir2/src/op.rs b/crates/ir2/src/op.rs index 5a294c9f2b..6bc87546d8 100644 --- a/crates/ir2/src/op.rs +++ b/crates/ir2/src/op.rs @@ -1,6 +1,6 @@ use crate::{ core::TrapCode, - index::{Memory, Table}, + index::{Elem, Memory, Table}, Address, BlockFuel, BranchOffset, From 8a8748090f4845f936afb95e26f56305b02d3d77 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 13:07:26 +0200 Subject: [PATCH 037/186] add more from impls for Op --- crates/ir2/build/op.rs | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index ebc4e88730..89354b240f 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -19,24 +19,32 @@ pub enum Op { Generic5(GenericOp<5>), } -macro_rules! impl_from_generic_op { - ( $($op:ident < $n:literal >),* $(,)? ) => { +macro_rules! impl_from_for_op { + ( $($op_ty:ty: $variant:ident),* $(,)? ) => { $( - impl From> for Op { - fn from(op: GenericOp<$n>) -> Self { - Op::$op(op) + impl From<$op_ty> for Op { + fn from(op: $op_ty) -> Self { + Op::$variant(op) } } )* }; } -impl_from_generic_op! { - Generic0<0>, - Generic1<1>, - Generic2<2>, - Generic3<3>, - Generic4<4>, - Generic5<5>, +impl_from_for_op! { + UnaryOp: Unary, + BinaryOp: Binary, + CmpBranchOp: CmpBranch, + CmpSelectOp: CmpSelect, + LoadOp: Load, + StoreOp: Store, + TableGetOp: TableGet, + TableSetOp: TableSet, + GenericOp<0>: Generic0, + GenericOp<1>: Generic1, + GenericOp<2>: Generic2, + GenericOp<3>: Generic3, + GenericOp<4>: Generic4, + GenericOp<5>: Generic5, } #[derive(Copy, Clone)] From 1d9c6efb116bd7efb27cc573359f7613aaa99ec9 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 13:11:16 +0200 Subject: [PATCH 038/186] define Op via macro --- crates/ir2/build/op.rs | 63 ++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 33 deletions(-) diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 89354b240f..b3c3cdea07 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -1,26 +1,20 @@ use crate::build::{CamelCase, Ident, SnakeCase}; use core::fmt::{self, Display}; -#[derive(Copy, Clone)] -pub enum Op { - Unary(UnaryOp), - Binary(BinaryOp), - CmpBranch(CmpBranchOp), - CmpSelect(CmpSelectOp), - Load(LoadOp), - Store(StoreOp), - TableGet(TableGetOp), - TableSet(TableSetOp), - Generic0(GenericOp<0>), - Generic1(GenericOp<1>), - Generic2(GenericOp<2>), - Generic3(GenericOp<3>), - Generic4(GenericOp<4>), - Generic5(GenericOp<5>), -} - macro_rules! impl_from_for_op { - ( $($op_ty:ty: $variant:ident),* $(,)? ) => { + ( + $( #[$attr:meta] )* + pub enum Op { + $($variant:ident($op_ty:ty)),* $(,)? + } + ) => { + $( #[$attr] )* + pub enum Op { + $( + $variant($op_ty), + )* + } + $( impl From<$op_ty> for Op { fn from(op: $op_ty) -> Self { @@ -31,20 +25,23 @@ macro_rules! impl_from_for_op { }; } impl_from_for_op! { - UnaryOp: Unary, - BinaryOp: Binary, - CmpBranchOp: CmpBranch, - CmpSelectOp: CmpSelect, - LoadOp: Load, - StoreOp: Store, - TableGetOp: TableGet, - TableSetOp: TableSet, - GenericOp<0>: Generic0, - GenericOp<1>: Generic1, - GenericOp<2>: Generic2, - GenericOp<3>: Generic3, - GenericOp<4>: Generic4, - GenericOp<5>: Generic5, + #[derive(Copy, Clone)] + pub enum Op { + Unary(UnaryOp), + Binary(BinaryOp), + CmpBranch(CmpBranchOp), + CmpSelect(CmpSelectOp), + Load(LoadOp), + Store(StoreOp), + TableGet(TableGetOp), + TableSet(TableSetOp), + Generic0(GenericOp<0>), + Generic1(GenericOp<1>), + Generic2(GenericOp<2>), + Generic3(GenericOp<3>), + Generic4(GenericOp<4>), + Generic5(GenericOp<5>), + } } #[derive(Copy, Clone)] From a204dc3ef4d1abd4198cdf36430e4d801845942d Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 13:19:43 +0200 Subject: [PATCH 039/186] add memory ops codegen --- crates/ir2/build/isa.rs | 57 +++++++++++++++++++++++++++++++++++++++ crates/ir2/build/token.rs | 8 ++++++ crates/ir2/src/op.rs | 2 +- 3 files changed, 66 insertions(+), 1 deletion(-) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 34ca03c59b..9d058c8047 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -45,6 +45,7 @@ pub fn wasmi_isa() -> Isa { add_store_ops(&mut isa); add_control_ops(&mut isa); add_copy_ops(&mut isa); + add_memory_ops(&mut isa); add_table_ops(&mut isa); isa } @@ -523,3 +524,59 @@ fn add_table_ops(isa: &mut Isa) { isa.push_op(op); } } + +fn add_memory_ops(isa: &mut Isa) { + let ops = [ + Op::from(GenericOp::new( + Ident::DataDrop, + [Field::new(Ident::Data, FieldTy::Data)], + )), + Op::from(GenericOp::new( + Ident::MemorySize, + [ + Field::new(Ident::Result, FieldTy::Stack), + Field::new(Ident::Memory, FieldTy::Memory), + ], + )), + Op::from(GenericOp::new( + Ident::MemoryGrow, + [ + Field::new(Ident::Result, FieldTy::Stack), + Field::new(Ident::Delta, FieldTy::Stack), + Field::new(Ident::Memory, FieldTy::Memory), + ], + )), + Op::from(GenericOp::new( + Ident::MemoryCopy, + [ + Field::new(Ident::DstMemory, FieldTy::Memory), + Field::new(Ident::SrcMemory, FieldTy::Memory), + Field::new(Ident::Dst, FieldTy::Stack), + Field::new(Ident::Src, FieldTy::Stack), + Field::new(Ident::Len, FieldTy::Stack), + ], + )), + Op::from(GenericOp::new( + Ident::MemoryFill, + [ + Field::new(Ident::Memory, FieldTy::Memory), + Field::new(Ident::Dst, FieldTy::Stack), + Field::new(Ident::Len, FieldTy::Stack), + Field::new(Ident::Value, FieldTy::Stack), + ], + )), + Op::from(GenericOp::new( + Ident::MemoryInit, + [ + Field::new(Ident::Memory, FieldTy::Memory), + Field::new(Ident::Data, FieldTy::Data), + Field::new(Ident::Dst, FieldTy::Stack), + Field::new(Ident::Src, FieldTy::Stack), + Field::new(Ident::Len, FieldTy::Stack), + ], + )), + ]; + for op in ops { + isa.push_op(op); + } +} diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index 60d69f540f..97da39cebf 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -155,6 +155,8 @@ define_ident!( Delta: delta, Dst: dst, Src: src, + DstMemory: dst_memory, + SrcMemory: src_memory, DstTable: dst_table, SrcTable: src_table, TableGet: table_get, @@ -165,4 +167,10 @@ define_ident!( TableFill: table_fill, TableInit: table_init, ElemDrop: elem_drop, + DataDrop: data_drop, + MemoryGrow: memory_grow, + MemorySize: memory_size, + MemoryCopy: memory_copy, + MemoryFill: memory_fill, + MemoryInit: memory_init, ); diff --git a/crates/ir2/src/op.rs b/crates/ir2/src/op.rs index 6bc87546d8..790b0bee3b 100644 --- a/crates/ir2/src/op.rs +++ b/crates/ir2/src/op.rs @@ -1,6 +1,6 @@ use crate::{ core::TrapCode, - index::{Elem, Memory, Table}, + index::{Data, Elem, Memory, Table}, Address, BlockFuel, BranchOffset, From 3e8b85cb01550d7b451615952c7c39a4dec6a7a1 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 13:19:51 +0200 Subject: [PATCH 040/186] add size_of and align_of test for Op --- crates/ir2/src/op.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/crates/ir2/src/op.rs b/crates/ir2/src/op.rs index 790b0bee3b..647b4c9beb 100644 --- a/crates/ir2/src/op.rs +++ b/crates/ir2/src/op.rs @@ -19,3 +19,9 @@ impl Clone for Op { *self } } + +#[test] +fn op_size_of_and_alignment() { + assert_eq!(core::mem::size_of::(), 24); + assert_eq!(core::mem::align_of::(), 8); +} From 329cc956dcf0c99b1f6efe13c274ad23226c1e47 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 13:25:07 +0200 Subject: [PATCH 041/186] use DisplaySequence in DisplayEnum impl --- crates/ir2/build/display.rs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/crates/ir2/build/display.rs b/crates/ir2/build/display.rs index 94f3c3d9c3..e0ddcfe7a0 100644 --- a/crates/ir2/build/display.rs +++ b/crates/ir2/build/display.rs @@ -69,22 +69,15 @@ impl DisplayEnum { impl Display for DisplayEnum { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent = self.indent; + let variants = DisplaySequence(self.val.ops.iter().map(|op| self.scoped(op))); write!( f, "\ {indent}pub enum Op {{\n\ - " - )?; - for op in &self.val.ops { - write!(f, "{}", self.scoped(op))?; - } - write!( - f, - "\ + {variants} {indent}}}\n\ " - )?; - Ok(()) + ) } } From e766d5affa3f81603d23d1966b0c8c362ae713ac Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 13:27:57 +0200 Subject: [PATCH 042/186] fix formatting issues in generated code --- crates/ir2/build/display.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ir2/build/display.rs b/crates/ir2/build/display.rs index e0ddcfe7a0..0da55e78c1 100644 --- a/crates/ir2/build/display.rs +++ b/crates/ir2/build/display.rs @@ -74,7 +74,7 @@ impl Display for DisplayEnum { f, "\ {indent}pub enum Op {{\n\ - {variants} + {variants}\ {indent}}}\n\ " ) @@ -344,7 +344,7 @@ impl Display for DisplayEnum<&'_ GenericOp> { f, "\ {indent0}{ident} {{\n\ - {fields} + {fields}\ {indent0}}},\n\ ", ) From 2425d43f1f9b242f876edcd13dad64e23011063b Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 15:16:40 +0200 Subject: [PATCH 043/186] add call ops codegen --- crates/ir2/build/isa.rs | 48 +++++++++++++++++++++++++++++++++++++++ crates/ir2/build/token.rs | 5 ++++ crates/ir2/src/op.rs | 2 +- 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 9d058c8047..2ef4c88efc 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -45,6 +45,7 @@ pub fn wasmi_isa() -> Isa { add_store_ops(&mut isa); add_control_ops(&mut isa); add_copy_ops(&mut isa); + add_call_ops(&mut isa); add_memory_ops(&mut isa); add_table_ops(&mut isa); isa @@ -462,6 +463,53 @@ fn add_copy_ops(isa: &mut Isa) { } } +fn add_call_ops(isa: &mut Isa) { + let ops = [ + Op::from(GenericOp::new( + Ident::CallInternal, + [ + Field::new(Ident::Results, FieldTy::StackSpan), + Field::new(Ident::Func, FieldTy::InternalFunc), + ], + )), + Op::from(GenericOp::new( + Ident::CallImported, + [ + Field::new(Ident::Results, FieldTy::StackSpan), + Field::new(Ident::Func, FieldTy::Func), + ], + )), + Op::from(GenericOp::new( + Ident::CallIndirect, + [ + Field::new(Ident::Results, FieldTy::StackSpan), + Field::new(Ident::Index, FieldTy::Stack), + Field::new(Ident::FuncType, FieldTy::FuncType), + Field::new(Ident::Table, FieldTy::Table), + ], + )), + Op::from(GenericOp::new( + Ident::ReturnCallInternal, + [Field::new(Ident::Func, FieldTy::InternalFunc)], + )), + Op::from(GenericOp::new( + Ident::ReturnCallImported, + [Field::new(Ident::Func, FieldTy::Func)], + )), + Op::from(GenericOp::new( + Ident::ReturnCallIndirect, + [ + Field::new(Ident::Index, FieldTy::Stack), + Field::new(Ident::FuncType, FieldTy::FuncType), + Field::new(Ident::Table, FieldTy::Table), + ], + )), + ]; + for op in ops { + isa.push_op(op); + } +} + fn add_table_ops(isa: &mut Isa) { let ops = [ Op::TableGet(TableGetOp::new(Input::Stack)), diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index 97da39cebf..a2b6727652 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -101,8 +101,12 @@ define_ident!( Trap: trap, Call: call, + CallInternal: call_internal, + CallImported: call_imported, CallIndirect: call_indirect, ReturnCall: return_call, + ReturnCallInternal: return_call_internal, + ReturnCallImported: return_call_imported, ReturnCallIndirect: return_call_indirect, U8: r#u8, @@ -155,6 +159,7 @@ define_ident!( Delta: delta, Dst: dst, Src: src, + Index: index, DstMemory: dst_memory, SrcMemory: src_memory, DstTable: dst_table, diff --git a/crates/ir2/src/op.rs b/crates/ir2/src/op.rs index 647b4c9beb..8abf7d0982 100644 --- a/crates/ir2/src/op.rs +++ b/crates/ir2/src/op.rs @@ -1,6 +1,6 @@ use crate::{ core::TrapCode, - index::{Data, Elem, Memory, Table}, + index::{Data, Elem, Func, FuncType, InternalFunc, Memory, Table}, Address, BlockFuel, BranchOffset, From fd96631b767da83bfc2e9ff6ebce96170fda3656 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 15:21:35 +0200 Subject: [PATCH 044/186] unsilence warnings and fix lots of warnings --- crates/ir2/build/display.rs | 6 ++++-- crates/ir2/build/mod.rs | 4 +--- crates/ir2/build/op.rs | 4 +--- crates/ir2/build/token.rs | 14 -------------- 4 files changed, 6 insertions(+), 22 deletions(-) diff --git a/crates/ir2/build/display.rs b/crates/ir2/build/display.rs index 0da55e78c1..cba24d2131 100644 --- a/crates/ir2/build/display.rs +++ b/crates/ir2/build/display.rs @@ -188,6 +188,7 @@ impl Display for DisplayEnum<&'_ CmpBranchOp> { let indent0 = self.indent; let indent1 = indent0.inc(); let cmp = self.val.cmp; + let branch = CamelCase(Ident::Branch); let ident = CamelCase(cmp.ident()); let input_ident = CamelCase(Ident::from(cmp.input_ty())); let lhs_ty = cmp.input_field(self.val.lhs); @@ -199,7 +200,7 @@ impl Display for DisplayEnum<&'_ CmpBranchOp> { write!( f, "\ - {indent0}Branch{input_ident}{ident}_{result_suffix}{lhs_suffix}{rhs_suffix} {{\n\ + {indent0}{branch}{input_ident}{ident}_{result_suffix}{lhs_suffix}{rhs_suffix} {{\n\ {indent1}offset: {offset_ty},\n\ {indent1}lhs: {lhs_ty},\n\ {indent1}rhs: {rhs_ty},\n\ @@ -214,6 +215,7 @@ impl Display for DisplayEnum<&'_ CmpSelectOp> { let indent0 = self.indent; let indent1 = indent0.inc(); let cmp = self.val.cmp; + let select = CamelCase(Ident::Select); let ident = CamelCase(cmp.ident()); let input_ident = CamelCase(Ident::from(cmp.input_ty())); let result_ty = FieldTy::Stack; @@ -227,7 +229,7 @@ impl Display for DisplayEnum<&'_ CmpSelectOp> { write!( f, "\ - {indent0}Select{input_ident}{ident}_{result_suffix}{lhs_suffix}{rhs_suffix} {{\n\ + {indent0}{select}{input_ident}{ident}_{result_suffix}{lhs_suffix}{rhs_suffix} {{\n\ {indent1}result: {result_ty},\n\ {indent1}lhs: {lhs_ty},\n\ {indent1}rhs: {rhs_ty},\n\ diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index 39a0874df6..461b60e431 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -1,5 +1,3 @@ -#![allow(unused_imports, dead_code)] - mod display; mod isa; mod op; @@ -8,7 +6,7 @@ pub mod token; use self::{ display::{DisplayEnum, Indent}, isa::Isa, - op::{BinaryOp, IntoMaybe, Maybe, Op, UnaryOp}, + op::{IntoMaybe, Op}, token::{CamelCase, Ident, SnakeCase}, }; use core::fmt::{self, Display, Error as FmtError, Write as _}; diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index b3c3cdea07..604bf35c98 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -460,7 +460,7 @@ impl BinaryOpKind { pub fn lhs_field(&self, input: Input) -> FieldTy { match input { - Input::Stack => return FieldTy::Stack, + Input::Stack => FieldTy::Stack, Input::Immediate => match self { | Self::Cmp(cmp) => cmp.input_field(input), | Self::I32Add @@ -765,7 +765,6 @@ impl From for Ident { pub enum FieldTy { Stack, StackSpan, - BoundedStackSpan, U8, U16, U32, @@ -800,7 +799,6 @@ impl Display for FieldTy { let s = match self { Self::Stack => "Stack", Self::StackSpan => "StackSpan", - Self::BoundedStackSpan => "BoundedStackSpan", Self::U8 => "u8", Self::U16 => "u16", Self::U32 => "u32", diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index a2b6727652..c167648438 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -85,11 +85,6 @@ define_ident!( Copy32: copy32, Copy64: copy64, CopySpan: copy_span, - Fill: fill, - Init: init, - Grow: grow, - Get: get, - Set: set, Table: table, Memory: memory, @@ -100,32 +95,23 @@ define_ident!( Data: data, Trap: trap, - Call: call, CallInternal: call_internal, CallImported: call_imported, CallIndirect: call_indirect, - ReturnCall: return_call, ReturnCallInternal: return_call_internal, ReturnCallImported: return_call_imported, ReturnCallIndirect: return_call_indirect, - U8: r#u8, - U16: r#u16, U32: r#u32, U64: r#u64, - I8: r#i8, - I16: r#i16, I32: r#i32, I64: r#i64, - S8: s8, - S16: s16, S32: s32, S64: s64, F32: r#f32, F64: r#f64, Ref: r#ref, - Not: not, Clz: clz, Ctz: ctz, Popcnt: popcnt, From 83ec4b26c86895ff0bfa7eb3911b8532c2c42fd9 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 15:24:07 +0200 Subject: [PATCH 045/186] add global ops codegen --- crates/ir2/build/isa.rs | 37 +++++++++++++++++++++++++++++++++++++ crates/ir2/build/token.rs | 4 ++++ crates/ir2/src/op.rs | 2 +- 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 2ef4c88efc..0d8437a3a4 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -46,6 +46,7 @@ pub fn wasmi_isa() -> Isa { add_control_ops(&mut isa); add_copy_ops(&mut isa); add_call_ops(&mut isa); + add_global_ops(&mut isa); add_memory_ops(&mut isa); add_table_ops(&mut isa); isa @@ -510,6 +511,42 @@ fn add_call_ops(isa: &mut Isa) { } } +fn add_global_ops(isa: &mut Isa) { + let ops = [ + Op::from(GenericOp::new( + Ident::GlobalGet, + [ + Field::new(Ident::Result, FieldTy::Stack), + Field::new(Ident::Global, FieldTy::Global), + ], + )), + Op::from(GenericOp::new( + Ident::GlobalSet, + [ + Field::new(Ident::Result, FieldTy::Stack), + Field::new(Ident::Global, FieldTy::Global), + ], + )), + Op::from(GenericOp::new( + Ident::GlobalSet32, + [ + Field::new(Ident::Result, FieldTy::U32), + Field::new(Ident::Global, FieldTy::Global), + ], + )), + Op::from(GenericOp::new( + Ident::GlobalSet64, + [ + Field::new(Ident::Result, FieldTy::U64), + Field::new(Ident::Global, FieldTy::Global), + ], + )), + ]; + for op in ops { + isa.push_op(op); + } +} + fn add_table_ops(isa: &mut Isa) { let ops = [ Op::TableGet(TableGetOp::new(Input::Stack)), diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index c167648438..c3e19dcd90 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -164,4 +164,8 @@ define_ident!( MemoryCopy: memory_copy, MemoryFill: memory_fill, MemoryInit: memory_init, + GlobalGet: global_get, + GlobalSet: global_set, + GlobalSet32: global_set32, + GlobalSet64: global_set64, ); diff --git a/crates/ir2/src/op.rs b/crates/ir2/src/op.rs index 8abf7d0982..c26baac9a7 100644 --- a/crates/ir2/src/op.rs +++ b/crates/ir2/src/op.rs @@ -1,6 +1,6 @@ use crate::{ core::TrapCode, - index::{Data, Elem, Func, FuncType, InternalFunc, Memory, Table}, + index::{Data, Elem, Func, FuncType, Global, InternalFunc, Memory, Table}, Address, BlockFuel, BranchOffset, From fb4390cd00d7ef05f33b6692978b95327f5bc11f Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 15:28:05 +0200 Subject: [PATCH 046/186] add ref.func op codegen --- crates/ir2/build/isa.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 0d8437a3a4..0ced99170a 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -466,6 +466,13 @@ fn add_copy_ops(isa: &mut Isa) { fn add_call_ops(isa: &mut Isa) { let ops = [ + Op::from(GenericOp::new( + Ident::RefFunc, + [ + Field::new(Ident::Result, FieldTy::Stack), + Field::new(Ident::Func, FieldTy::Func), + ], + )), Op::from(GenericOp::new( Ident::CallInternal, [ From 926bac194359a402f2a3054dd449fcaa1723541c Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 15:28:10 +0200 Subject: [PATCH 047/186] remove more unused code --- crates/ir2/build/op.rs | 4 ---- crates/ir2/build/token.rs | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 604bf35c98..fd020a9b20 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -724,8 +724,6 @@ pub enum Ty { F32, /// A 64-bit float type. F64, - /// A general reference type. - Ref, } impl Display for Ty { @@ -739,7 +737,6 @@ impl Display for Ty { Ty::U64 => "u64", Ty::F32 => "f32", Ty::F64 => "f64", - Ty::Ref => "ref", }; write!(f, "{s}") } @@ -756,7 +753,6 @@ impl From for Ident { Ty::U64 => Self::U64, Ty::F32 => Self::F32, Ty::F64 => Self::F64, - Ty::Ref => Self::Ref, } } } diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index c3e19dcd90..3e5aecae1d 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -110,7 +110,6 @@ define_ident!( S64: s64, F32: r#f32, F64: r#f64, - Ref: r#ref, Clz: clz, Ctz: ctz, @@ -168,4 +167,5 @@ define_ident!( GlobalSet: global_set, GlobalSet32: global_set32, GlobalSet64: global_set64, + RefFunc: ref_func, ); From 0fbfa18223613df6d3781e8cff6647d474429463 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 15:30:24 +0200 Subject: [PATCH 048/186] remove unused input_ty method --- crates/ir2/build/op.rs | 50 ------------------------------------------ 1 file changed, 50 deletions(-) diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index fd020a9b20..b59ab63a15 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -600,56 +600,6 @@ impl BinaryOpKind { } } - pub fn input_ty(&self) -> Ty { - match self { - | Self::Cmp(cmp) => cmp.input_ty(), - | Self::I32Add - | Self::I32Sub - | Self::I32Mul - | Self::S32Div - | Self::U32Div - | Self::S32Rem - | Self::U32Rem - | Self::I32BitAnd - | Self::I32BitOr - | Self::I32BitXor - | Self::I32Shl - | Self::S32Shr - | Self::U32Shr - | Self::I32Rotl - | Self::I32Rotr => Ty::I32, - | Self::I64Add - | Self::I64Sub - | Self::I64Mul - | Self::S64Div - | Self::U64Div - | Self::S64Rem - | Self::U64Rem - | Self::I64BitAnd - | Self::I64BitOr - | Self::I64BitXor - | Self::I64Shl - | Self::S64Shr - | Self::U64Shr - | Self::I64Rotl - | Self::I64Rotr => Ty::I64, - | Self::F32Add - | Self::F32Sub - | Self::F32Mul - | Self::F32Div - | Self::F32Min - | Self::F32Max - | Self::F32Copysign => Ty::F32, - | Self::F64Add - | Self::F64Sub - | Self::F64Mul - | Self::F64Div - | Self::F64Min - | Self::F64Max - | Self::F64Copysign => Ty::F64, - } - } - pub fn commutativity(&self) -> Commutativity { match self { | Self::Cmp(cmp) => cmp.commutativity(), From c6a97aff44d8dc7ef542588fbd64483fd92306ba Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 15:32:45 +0200 Subject: [PATCH 049/186] apply some clippy suggestions --- crates/ir2/build/display.rs | 8 ++++---- crates/ir2/build/op.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/ir2/build/display.rs b/crates/ir2/build/display.rs index cba24d2131..b0a8bc9f39 100644 --- a/crates/ir2/build/display.rs +++ b/crates/ir2/build/display.rs @@ -417,8 +417,8 @@ impl Display for DisplayIdent<&'_ LoadOp> { let result_suffix = CamelCase(Input::Stack); let ptr_suffix = SnakeCase(self.0.ptr); let ident_prefix = self.0.kind.ident_prefix().map(CamelCase).into_maybe(); - let mem0_ident = self.0.mem0.then(|| "Mem0").unwrap_or_default(); - let offset16_ident = self.0.offset16.then(|| "Offset16").unwrap_or_default(); + let mem0_ident = self.0.mem0.then_some("Mem0").unwrap_or_default(); + let offset16_ident = self.0.offset16.then_some("Offset16").unwrap_or_default(); write!( f, "{ident_prefix}{ident}{mem0_ident}{offset16_ident}_{result_suffix}{ptr_suffix}", @@ -433,8 +433,8 @@ impl Display for DisplayIdent<&'_ StoreOp> { let ptr_suffix = CamelCase(self.0.ptr); let value_suffix = SnakeCase(self.0.value); let ident_prefix = self.0.kind.ident_prefix().map(CamelCase).into_maybe(); - let mem0_ident = self.0.mem0.then(|| "Mem0").unwrap_or_default(); - let offset16_ident = self.0.offset16.then(|| "Offset16").unwrap_or_default(); + let mem0_ident = self.0.mem0.then_some("Mem0").unwrap_or_default(); + let offset16_ident = self.0.offset16.then_some("Offset16").unwrap_or_default(); write!( f, "{ident_prefix}{ident}{mem0_ident}{offset16_ident}_{ptr_suffix}{value_suffix}", diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index b59ab63a15..8f2f16806f 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -513,7 +513,7 @@ impl BinaryOpKind { pub fn rhs_field(&self, input: Input) -> FieldTy { match input { - Input::Stack => return FieldTy::Stack, + Input::Stack => FieldTy::Stack, Input::Immediate => match self { | Self::Cmp(cmp) => cmp.input_field(input), | Self::I32Add From a35345970ddad89ff8f7785d8ac50b855adb8c19 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 15:36:30 +0200 Subject: [PATCH 050/186] use into_maybe where applicable --- crates/ir2/build/display.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/ir2/build/display.rs b/crates/ir2/build/display.rs index b0a8bc9f39..859608bad5 100644 --- a/crates/ir2/build/display.rs +++ b/crates/ir2/build/display.rs @@ -417,8 +417,8 @@ impl Display for DisplayIdent<&'_ LoadOp> { let result_suffix = CamelCase(Input::Stack); let ptr_suffix = SnakeCase(self.0.ptr); let ident_prefix = self.0.kind.ident_prefix().map(CamelCase).into_maybe(); - let mem0_ident = self.0.mem0.then_some("Mem0").unwrap_or_default(); - let offset16_ident = self.0.offset16.then_some("Offset16").unwrap_or_default(); + let mem0_ident = self.0.mem0.then_some("Mem0").into_maybe(); + let offset16_ident = self.0.offset16.then_some("Offset16").into_maybe(); write!( f, "{ident_prefix}{ident}{mem0_ident}{offset16_ident}_{result_suffix}{ptr_suffix}", @@ -433,8 +433,8 @@ impl Display for DisplayIdent<&'_ StoreOp> { let ptr_suffix = CamelCase(self.0.ptr); let value_suffix = SnakeCase(self.0.value); let ident_prefix = self.0.kind.ident_prefix().map(CamelCase).into_maybe(); - let mem0_ident = self.0.mem0.then_some("Mem0").unwrap_or_default(); - let offset16_ident = self.0.offset16.then_some("Offset16").unwrap_or_default(); + let mem0_ident = self.0.mem0.then_some("Mem0").into_maybe(); + let offset16_ident = self.0.offset16.then_some("Offset16").into_maybe(); write!( f, "{ident_prefix}{ident}{mem0_ident}{offset16_ident}_{ptr_suffix}{value_suffix}", From 2c93265a03e6e9573cc47e3649b914d200e789b3 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 15:42:06 +0200 Subject: [PATCH 051/186] refactor Maybe -> DisplayMaybe and put into display module --- crates/ir2/build/display.rs | 58 +++++++++++++++++++++++++++++++------ crates/ir2/build/mod.rs | 2 +- crates/ir2/build/op.rs | 41 -------------------------- 3 files changed, 50 insertions(+), 51 deletions(-) diff --git a/crates/ir2/build/display.rs b/crates/ir2/build/display.rs index 859608bad5..2d91e9de4f 100644 --- a/crates/ir2/build/display.rs +++ b/crates/ir2/build/display.rs @@ -16,7 +16,6 @@ use crate::build::{ UnaryOp, }, token::{CamelCase, Ident, SnakeCase}, - IntoMaybe as _, }; use core::{ fmt::{self, Display}, @@ -309,14 +308,14 @@ impl Display for DisplayEnum<&'_ StoreOp> { .offset_ty(self.val.ptr, self.val.offset16) .map(|offset| Field::new(Ident::Offset, offset)) .map(|field| DisplayPair(indent1, field)) - .into_maybe(); + .display_maybe(); let mem_field = self .val .mem0 .not() .then(|| Field::new(Ident::Memory, FieldTy::Memory)) .map(|field| DisplayPair(indent1, field)) - .into_maybe(); + .display_maybe(); write!( f, "\ @@ -416,9 +415,9 @@ impl Display for DisplayIdent<&'_ LoadOp> { let ident = CamelCase(kind.ident()); let result_suffix = CamelCase(Input::Stack); let ptr_suffix = SnakeCase(self.0.ptr); - let ident_prefix = self.0.kind.ident_prefix().map(CamelCase).into_maybe(); - let mem0_ident = self.0.mem0.then_some("Mem0").into_maybe(); - let offset16_ident = self.0.offset16.then_some("Offset16").into_maybe(); + let ident_prefix = self.0.kind.ident_prefix().map(CamelCase).display_maybe(); + let mem0_ident = self.0.mem0.then_some("Mem0").display_maybe(); + let offset16_ident = self.0.offset16.then_some("Offset16").display_maybe(); write!( f, "{ident_prefix}{ident}{mem0_ident}{offset16_ident}_{result_suffix}{ptr_suffix}", @@ -432,9 +431,9 @@ impl Display for DisplayIdent<&'_ StoreOp> { let ident = CamelCase(kind.ident()); let ptr_suffix = CamelCase(self.0.ptr); let value_suffix = SnakeCase(self.0.value); - let ident_prefix = self.0.kind.ident_prefix().map(CamelCase).into_maybe(); - let mem0_ident = self.0.mem0.then_some("Mem0").into_maybe(); - let offset16_ident = self.0.offset16.then_some("Offset16").into_maybe(); + let ident_prefix = self.0.kind.ident_prefix().map(CamelCase).display_maybe(); + let mem0_ident = self.0.mem0.then_some("Mem0").display_maybe(); + let offset16_ident = self.0.offset16.then_some("Offset16").display_maybe(); write!( f, "{ident_prefix}{ident}{mem0_ident}{offset16_ident}_{ptr_suffix}{value_suffix}", @@ -469,3 +468,44 @@ where Ok(()) } } + +pub enum DisplayMaybe { + Some(T), + None, +} + +impl Display for DisplayMaybe +where + T: Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let DisplayMaybe::Some(field) = self { + field.fmt(f)?; + } + Ok(()) + } +} + +pub trait IntoDisplayMaybe { + fn display_maybe(self) -> DisplayMaybe; +} +impl IntoDisplayMaybe for Option { + fn display_maybe(self) -> DisplayMaybe { + DisplayMaybe::from(self) + } +} + +impl From for DisplayMaybe { + fn from(value: T) -> Self { + DisplayMaybe::Some(value) + } +} + +impl From> for DisplayMaybe { + fn from(value: Option) -> Self { + match value { + Some(value) => Self::Some(value), + None => Self::None, + } + } +} diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index 461b60e431..9f768626ed 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -6,7 +6,7 @@ pub mod token; use self::{ display::{DisplayEnum, Indent}, isa::Isa, - op::{IntoMaybe, Op}, + op::Op, token::{CamelCase, Ident, SnakeCase}, }; use core::fmt::{self, Display, Error as FmtError, Write as _}; diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 8f2f16806f..c7917b1e15 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -56,47 +56,6 @@ impl GenericOp { } } -pub enum Maybe { - Some(T), - None, -} - -impl Display for Maybe -where - T: Display, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Maybe::Some(field) = self { - field.fmt(f)?; - } - Ok(()) - } -} - -pub trait IntoMaybe { - fn into_maybe(self) -> Maybe; -} -impl IntoMaybe for Option { - fn into_maybe(self) -> Maybe { - Maybe::from(self) - } -} - -impl From for Maybe { - fn from(value: T) -> Self { - Maybe::Some(value) - } -} - -impl From> for Maybe { - fn from(value: Option) -> Self { - match value { - Some(value) => Self::Some(value), - None => Self::None, - } - } -} - #[derive(Copy, Clone)] pub struct Field { ident: Ident, From 3f59b39bc6665c60fc44f2431fb9fbc22dcf38aa Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 15:53:15 +0200 Subject: [PATCH 052/186] replace DisplayPair with the more generic DisplayConcat --- crates/ir2/build/display.rs | 40 ++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/crates/ir2/build/display.rs b/crates/ir2/build/display.rs index 2d91e9de4f..ea2ec2ecd6 100644 --- a/crates/ir2/build/display.rs +++ b/crates/ir2/build/display.rs @@ -307,14 +307,16 @@ impl Display for DisplayEnum<&'_ StoreOp> { .kind .offset_ty(self.val.ptr, self.val.offset16) .map(|offset| Field::new(Ident::Offset, offset)) - .map(|field| DisplayPair(indent1, field)) + .map(|field| (indent1, field)) + .map(DisplayConcat::from) .display_maybe(); let mem_field = self .val .mem0 .not() .then(|| Field::new(Ident::Memory, FieldTy::Memory)) - .map(|field| DisplayPair(indent1, field)) + .map(|field| (indent1, field)) + .map(DisplayConcat::from) .display_maybe(); write!( f, @@ -339,7 +341,8 @@ impl Display for DisplayEnum<&'_ GenericOp> { self.val .fields .into_iter() - .map(move |field| DisplayPair(indent1, DisplayPair(field, "\n"))), + .map(move |field| (indent1, field, "\n")) + .map(DisplayConcat::from), ); write!( f, @@ -441,20 +444,43 @@ impl Display for DisplayIdent<&'_ StoreOp> { } } -pub struct DisplayPair(pub T0, pub T1); +pub struct DisplayConcat(pub T); -impl Display for DisplayPair +impl From<(T0, T1)> for DisplayConcat<(T0, T1)> { + fn from(value: (T0, T1)) -> Self { + Self(value) + } +} + +impl From<(T0, T1, T2)> for DisplayConcat<(T0, T1, T2)> { + fn from(value: (T0, T1, T2)) -> Self { + Self(value) + } +} + +impl Display for DisplayConcat<(T0, T1)> where T0: Display, T1: Display, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let t0 = &self.0; - let t1 = &self.1; + let (t0, t1) = &self.0; write!(f, "{t0}{t1}") } } +impl Display for DisplayConcat<(T0, T1, T2)> +where + T0: Display, + T1: Display, + T2: Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let (t0, t1, t2) = &self.0; + write!(f, "{t0}{t1}{t2}") + } +} + pub struct DisplaySequence(pub T); impl Display for DisplaySequence From f807a9d60d5a89f1e8bc36e4ecadf62beab6a75d Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 15:55:15 +0200 Subject: [PATCH 053/186] move display.rs -> display/mod.rs --- crates/ir2/build/{display.rs => display/mod.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename crates/ir2/build/{display.rs => display/mod.rs} (100%) diff --git a/crates/ir2/build/display.rs b/crates/ir2/build/display/mod.rs similarity index 100% rename from crates/ir2/build/display.rs rename to crates/ir2/build/display/mod.rs From cea6041a8fa2fefdb44a572fbd72012bab3ef37a Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 15:56:43 +0200 Subject: [PATCH 054/186] move Display utils into utils sub-module --- crates/ir2/build/display/mod.rs | 95 +------------------------------ crates/ir2/build/display/utils.rs | 93 ++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 92 deletions(-) create mode 100644 crates/ir2/build/display/utils.rs diff --git a/crates/ir2/build/display/mod.rs b/crates/ir2/build/display/mod.rs index ea2ec2ecd6..444d27bd0e 100644 --- a/crates/ir2/build/display/mod.rs +++ b/crates/ir2/build/display/mod.rs @@ -1,3 +1,6 @@ +mod utils; + +use self::utils::{DisplayConcat, DisplaySequence, IntoDisplayMaybe as _}; use crate::build::{ isa::Isa, op::{ @@ -443,95 +446,3 @@ impl Display for DisplayIdent<&'_ StoreOp> { ) } } - -pub struct DisplayConcat(pub T); - -impl From<(T0, T1)> for DisplayConcat<(T0, T1)> { - fn from(value: (T0, T1)) -> Self { - Self(value) - } -} - -impl From<(T0, T1, T2)> for DisplayConcat<(T0, T1, T2)> { - fn from(value: (T0, T1, T2)) -> Self { - Self(value) - } -} - -impl Display for DisplayConcat<(T0, T1)> -where - T0: Display, - T1: Display, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let (t0, t1) = &self.0; - write!(f, "{t0}{t1}") - } -} - -impl Display for DisplayConcat<(T0, T1, T2)> -where - T0: Display, - T1: Display, - T2: Display, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let (t0, t1, t2) = &self.0; - write!(f, "{t0}{t1}{t2}") - } -} - -pub struct DisplaySequence(pub T); - -impl Display for DisplaySequence -where - T: IntoIterator + Clone, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for item in self.0.clone() { - write!(f, "{item}")?; - } - Ok(()) - } -} - -pub enum DisplayMaybe { - Some(T), - None, -} - -impl Display for DisplayMaybe -where - T: Display, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let DisplayMaybe::Some(field) = self { - field.fmt(f)?; - } - Ok(()) - } -} - -pub trait IntoDisplayMaybe { - fn display_maybe(self) -> DisplayMaybe; -} -impl IntoDisplayMaybe for Option { - fn display_maybe(self) -> DisplayMaybe { - DisplayMaybe::from(self) - } -} - -impl From for DisplayMaybe { - fn from(value: T) -> Self { - DisplayMaybe::Some(value) - } -} - -impl From> for DisplayMaybe { - fn from(value: Option) -> Self { - match value { - Some(value) => Self::Some(value), - None => Self::None, - } - } -} diff --git a/crates/ir2/build/display/utils.rs b/crates/ir2/build/display/utils.rs new file mode 100644 index 0000000000..d28c19c247 --- /dev/null +++ b/crates/ir2/build/display/utils.rs @@ -0,0 +1,93 @@ +use core::fmt::{self, Display}; + +pub struct DisplayConcat(pub T); + +impl From<(T0, T1)> for DisplayConcat<(T0, T1)> { + fn from(value: (T0, T1)) -> Self { + Self(value) + } +} + +impl From<(T0, T1, T2)> for DisplayConcat<(T0, T1, T2)> { + fn from(value: (T0, T1, T2)) -> Self { + Self(value) + } +} + +impl Display for DisplayConcat<(T0, T1)> +where + T0: Display, + T1: Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let (t0, t1) = &self.0; + write!(f, "{t0}{t1}") + } +} + +impl Display for DisplayConcat<(T0, T1, T2)> +where + T0: Display, + T1: Display, + T2: Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let (t0, t1, t2) = &self.0; + write!(f, "{t0}{t1}{t2}") + } +} + +pub struct DisplaySequence(pub T); + +impl Display for DisplaySequence +where + T: IntoIterator + Clone, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for item in self.0.clone() { + write!(f, "{item}")?; + } + Ok(()) + } +} + +pub enum DisplayMaybe { + Some(T), + None, +} + +impl Display for DisplayMaybe +where + T: Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let DisplayMaybe::Some(field) = self { + field.fmt(f)?; + } + Ok(()) + } +} + +pub trait IntoDisplayMaybe { + fn display_maybe(self) -> DisplayMaybe; +} +impl IntoDisplayMaybe for Option { + fn display_maybe(self) -> DisplayMaybe { + DisplayMaybe::from(self) + } +} + +impl From for DisplayMaybe { + fn from(value: T) -> Self { + DisplayMaybe::Some(value) + } +} + +impl From> for DisplayMaybe { + fn from(value: Option) -> Self { + match value { + Some(value) => Self::Some(value), + None => Self::None, + } + } +} From 74566620859d2c6b17c2720c295788d2b5c55cfd Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 16:07:25 +0200 Subject: [PATCH 055/186] fix superflous newlines in codegen --- crates/ir2/build/display/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/ir2/build/display/mod.rs b/crates/ir2/build/display/mod.rs index 444d27bd0e..2aeb4f9c81 100644 --- a/crates/ir2/build/display/mod.rs +++ b/crates/ir2/build/display/mod.rs @@ -310,7 +310,7 @@ impl Display for DisplayEnum<&'_ StoreOp> { .kind .offset_ty(self.val.ptr, self.val.offset16) .map(|offset| Field::new(Ident::Offset, offset)) - .map(|field| (indent1, field)) + .map(|field| (indent1, field, "\n")) .map(DisplayConcat::from) .display_maybe(); let mem_field = self @@ -318,7 +318,7 @@ impl Display for DisplayEnum<&'_ StoreOp> { .mem0 .not() .then(|| Field::new(Ident::Memory, FieldTy::Memory)) - .map(|field| (indent1, field)) + .map(|field| (indent1, field, "\n")) .map(DisplayConcat::from) .display_maybe(); write!( @@ -326,9 +326,9 @@ impl Display for DisplayEnum<&'_ StoreOp> { "\ {indent0}{ident} {{\n\ {indent1}ptr: {ptr_ty},\n\ - {offset_field}\n\ + {offset_field}\ {indent1}value: {value_ty},\n\ - {mem_field}\n\ + {mem_field}\ {indent0}}},\n\ ", ) From cc5bc1d646160b4fa13fe24af77ad3f94d7b9622 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 16:17:54 +0200 Subject: [PATCH 056/186] clean-up DisplayEnum impl --- crates/ir2/build/display/mod.rs | 43 ++++++++++++--------------------- 1 file changed, 16 insertions(+), 27 deletions(-) diff --git a/crates/ir2/build/display/mod.rs b/crates/ir2/build/display/mod.rs index 2aeb4f9c81..7eb0ba0675 100644 --- a/crates/ir2/build/display/mod.rs +++ b/crates/ir2/build/display/mod.rs @@ -260,41 +260,30 @@ impl Display for DisplayEnum<&'_ LoadOp> { } Input::Immediate => (FieldTy::Address, None), }; - let mem_ty = match self.val.mem0 { - false => Some(FieldTy::Memory), - true => None, - }; + let offset_field = offset_ty + .map(|ty| Field::new(Ident::Offset, ty)) + .map(|field| (indent1, field, "\n")) + .map(DisplayConcat::from) + .display_maybe(); + let memory_field = self + .val + .mem0 + .then_some(FieldTy::Memory) + .map(|ty| Field::new(Ident::Memory, ty)) + .map(|field| (indent1, field, "\n")) + .map(DisplayConcat::from) + .display_maybe(); write!( f, "\ {indent0}{ident} {{\n\ {indent1}result: {result_ty},\n\ {indent1}ptr: {ptr_ty},\n\ - ", - )?; - if let Some(offset) = offset_ty { - write!( - f, - "\ - {indent1}offset: {offset},\n\ - " - )?; - } - if let Some(mem) = mem_ty { - write!( - f, - "\ - {indent1}mem: {mem},\n\ - " - )?; - } - write!( - f, - "\ + {offset_field}\ + {memory_field}\ {indent0}}},\n\ ", - )?; - Ok(()) + ) } } From fafbb692f9d2cda1e6bfd250b7869e1728c17a7f Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 16:20:20 +0200 Subject: [PATCH 057/186] remove , from Field Display impl --- crates/ir2/build/display/mod.rs | 10 +++++----- crates/ir2/build/op.rs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/ir2/build/display/mod.rs b/crates/ir2/build/display/mod.rs index 7eb0ba0675..8c758aa47d 100644 --- a/crates/ir2/build/display/mod.rs +++ b/crates/ir2/build/display/mod.rs @@ -262,7 +262,7 @@ impl Display for DisplayEnum<&'_ LoadOp> { }; let offset_field = offset_ty .map(|ty| Field::new(Ident::Offset, ty)) - .map(|field| (indent1, field, "\n")) + .map(|field| (indent1, field, ",\n")) .map(DisplayConcat::from) .display_maybe(); let memory_field = self @@ -270,7 +270,7 @@ impl Display for DisplayEnum<&'_ LoadOp> { .mem0 .then_some(FieldTy::Memory) .map(|ty| Field::new(Ident::Memory, ty)) - .map(|field| (indent1, field, "\n")) + .map(|field| (indent1, field, ",\n")) .map(DisplayConcat::from) .display_maybe(); write!( @@ -299,7 +299,7 @@ impl Display for DisplayEnum<&'_ StoreOp> { .kind .offset_ty(self.val.ptr, self.val.offset16) .map(|offset| Field::new(Ident::Offset, offset)) - .map(|field| (indent1, field, "\n")) + .map(|field| (indent1, field, ",\n")) .map(DisplayConcat::from) .display_maybe(); let mem_field = self @@ -307,7 +307,7 @@ impl Display for DisplayEnum<&'_ StoreOp> { .mem0 .not() .then(|| Field::new(Ident::Memory, FieldTy::Memory)) - .map(|field| (indent1, field, "\n")) + .map(|field| (indent1, field, ",\n")) .map(DisplayConcat::from) .display_maybe(); write!( @@ -333,7 +333,7 @@ impl Display for DisplayEnum<&'_ GenericOp> { self.val .fields .into_iter() - .map(move |field| (indent1, field, "\n")) + .map(move |field| (indent1, field, ",\n")) .map(DisplayConcat::from), ); write!( diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index c7917b1e15..72353f4402 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -72,7 +72,7 @@ impl Display for Field { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let ident = SnakeCase(self.ident); let ty = self.ty; - write!(f, "{ident}: {ty},") + write!(f, "{ident}: {ty}") } } From cb22a02303324a8d758b405975254ecd198bf8c6 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 16:24:54 +0200 Subject: [PATCH 058/186] improve DisplayIdent impls --- crates/ir2/build/display/mod.rs | 28 ++++++++++++++++++++++++---- crates/ir2/build/token.rs | 2 ++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/crates/ir2/build/display/mod.rs b/crates/ir2/build/display/mod.rs index 8c758aa47d..4348a4bd8d 100644 --- a/crates/ir2/build/display/mod.rs +++ b/crates/ir2/build/display/mod.rs @@ -411,8 +411,18 @@ impl Display for DisplayIdent<&'_ LoadOp> { let result_suffix = CamelCase(Input::Stack); let ptr_suffix = SnakeCase(self.0.ptr); let ident_prefix = self.0.kind.ident_prefix().map(CamelCase).display_maybe(); - let mem0_ident = self.0.mem0.then_some("Mem0").display_maybe(); - let offset16_ident = self.0.offset16.then_some("Offset16").display_maybe(); + let mem0_ident = self + .0 + .mem0 + .then_some(Ident::Mem0) + .map(CamelCase) + .display_maybe(); + let offset16_ident = self + .0 + .offset16 + .then_some(Ident::Offset16) + .map(CamelCase) + .display_maybe(); write!( f, "{ident_prefix}{ident}{mem0_ident}{offset16_ident}_{result_suffix}{ptr_suffix}", @@ -427,8 +437,18 @@ impl Display for DisplayIdent<&'_ StoreOp> { let ptr_suffix = CamelCase(self.0.ptr); let value_suffix = SnakeCase(self.0.value); let ident_prefix = self.0.kind.ident_prefix().map(CamelCase).display_maybe(); - let mem0_ident = self.0.mem0.then_some("Mem0").display_maybe(); - let offset16_ident = self.0.offset16.then_some("Offset16").display_maybe(); + let mem0_ident = self + .0 + .mem0 + .then_some(Ident::Mem0) + .map(CamelCase) + .display_maybe(); + let offset16_ident = self + .0 + .offset16 + .then_some(Ident::Offset16) + .map(CamelCase) + .display_maybe(); write!( f, "{ident_prefix}{ident}{mem0_ident}{offset16_ident}_{ptr_suffix}{value_suffix}", diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index 3e5aecae1d..ffa8d02183 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -168,4 +168,6 @@ define_ident!( GlobalSet32: global_set32, GlobalSet64: global_set64, RefFunc: ref_func, + Mem0: mem0, + Offset16: offset16, ); From 85414fdc75d245d8e5c79a39e628622d4bf314d9 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 16:56:19 +0200 Subject: [PATCH 059/186] make DisplayIdent case aware --- crates/ir2/build/display/mod.rs | 76 +++++++++++++++++++++++---------- crates/ir2/build/token.rs | 35 +++++++++++++++ 2 files changed, 89 insertions(+), 22 deletions(-) diff --git a/crates/ir2/build/display/mod.rs b/crates/ir2/build/display/mod.rs index 4348a4bd8d..a096c780a1 100644 --- a/crates/ir2/build/display/mod.rs +++ b/crates/ir2/build/display/mod.rs @@ -18,7 +18,7 @@ use crate::build::{ TableSetOp, UnaryOp, }, - token::{CamelCase, Ident, SnakeCase}, + token::{CamelCase, Case, Ident, SnakeCase}, }; use core::{ fmt::{self, Display}, @@ -247,7 +247,7 @@ impl Display for DisplayEnum<&'_ LoadOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent0 = self.indent; let indent1 = indent0.inc(); - let ident = DisplayIdent(self.val); + let ident = DisplayIdent::camel(self.val); let result_ty = FieldTy::Stack; let (ptr_ty, offset_ty) = match self.val.ptr { Input::Stack => { @@ -291,7 +291,7 @@ impl Display for DisplayEnum<&'_ StoreOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent0 = self.indent; let indent1 = indent0.inc(); - let ident = DisplayIdent(self.val); + let ident = DisplayIdent::camel(self.val); let ptr_ty = self.val.kind.ptr_ty(self.val.ptr); let value_ty = self.val.kind.value_ty(self.val.value); let offset_field = self @@ -402,26 +402,52 @@ impl Display for DisplayEnum<&'_ TableSetOp> { } } -pub struct DisplayIdent(pub T); +pub struct DisplayIdent { + value: T, + case: Case, +} + +impl DisplayIdent { + pub fn camel(value: T) -> Self { + Self { + value, + case: Case::Camel, + } + } + + #[expect(dead_code)] + pub fn snake(value: T) -> Self { + Self { + value, + case: Case::Snake, + } + } +} impl Display for DisplayIdent<&'_ LoadOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let kind = self.0.kind; - let ident = CamelCase(kind.ident()); - let result_suffix = CamelCase(Input::Stack); - let ptr_suffix = SnakeCase(self.0.ptr); - let ident_prefix = self.0.kind.ident_prefix().map(CamelCase).display_maybe(); + let case = self.case; + let kind = self.value.kind; + let ident = case.wrap(kind.ident()); + let result_suffix = case.wrap(Input::Stack); + let ptr_suffix = SnakeCase(self.value.ptr); + let ident_prefix = self + .value + .kind + .ident_prefix() + .map(|v| case.wrap(v)) + .display_maybe(); let mem0_ident = self - .0 + .value .mem0 .then_some(Ident::Mem0) - .map(CamelCase) + .map(|v| case.wrap(v)) .display_maybe(); let offset16_ident = self - .0 + .value .offset16 .then_some(Ident::Offset16) - .map(CamelCase) + .map(|v| case.wrap(v)) .display_maybe(); write!( f, @@ -432,22 +458,28 @@ impl Display for DisplayIdent<&'_ LoadOp> { impl Display for DisplayIdent<&'_ StoreOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let kind = self.0.kind; - let ident = CamelCase(kind.ident()); - let ptr_suffix = CamelCase(self.0.ptr); - let value_suffix = SnakeCase(self.0.value); - let ident_prefix = self.0.kind.ident_prefix().map(CamelCase).display_maybe(); + let case = self.case; + let kind = self.value.kind; + let ident = case.wrap(kind.ident()); + let ptr_suffix = case.wrap(self.value.ptr); + let value_suffix = SnakeCase(self.value.value); + let ident_prefix = self + .value + .kind + .ident_prefix() + .map(|v| case.wrap(v)) + .display_maybe(); let mem0_ident = self - .0 + .value .mem0 .then_some(Ident::Mem0) - .map(CamelCase) + .map(|v| case.wrap(v)) .display_maybe(); let offset16_ident = self - .0 + .value .offset16 .then_some(Ident::Offset16) - .map(CamelCase) + .map(|v| case.wrap(v)) .display_maybe(); write!( f, diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index ffa8d02183..adae9e376c 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -1,5 +1,40 @@ use core::fmt::{self, Display}; +#[derive(Copy, Clone)] +pub enum Case { + Camel, + Snake, +} + +impl Case { + pub fn wrap(self, value: T) -> ChosenCase { + match self { + Self::Camel => ChosenCase::Camel(value), + Self::Snake => ChosenCase::Snake(value), + } + } +} + +/// Runtime selected casing, either [`CamelCase`] or [`SnakeCase`]. +pub enum ChosenCase { + Camel(T), + Snake(T), +} + +impl Display for ChosenCase +where + CamelCase: Display, + SnakeCase: Display, + T: Clone, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Camel(value) => write!(f, "{}", CamelCase(value.clone())), + Self::Snake(value) => write!(f, "{}", SnakeCase(value.clone())), + } + } +} + /// Camel-case tokens, e.g. `HelloWorld`. pub struct CamelCase(pub T); From 8fbb8fd24d83adcd30f9e24cdd3c1ba8e9d05fad Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 21 Aug 2025 17:07:12 +0200 Subject: [PATCH 060/186] move DisplayIdent into ident submodule --- crates/ir2/build/display/ident.rs | 92 ++++++++++++++++++++++++++++++ crates/ir2/build/display/mod.rs | 94 ++----------------------------- 2 files changed, 98 insertions(+), 88 deletions(-) create mode 100644 crates/ir2/build/display/ident.rs diff --git a/crates/ir2/build/display/ident.rs b/crates/ir2/build/display/ident.rs new file mode 100644 index 0000000000..266fcc0b1d --- /dev/null +++ b/crates/ir2/build/display/ident.rs @@ -0,0 +1,92 @@ +use crate::build::{ + display::utils::IntoDisplayMaybe as _, + op::{Input, LoadOp, StoreOp}, + token::{Case, Ident, SnakeCase}, +}; +use core::fmt::{self, Display}; + +pub struct DisplayIdent { + value: T, + case: Case, +} + +impl DisplayIdent { + pub fn camel(value: T) -> Self { + Self { + value, + case: Case::Camel, + } + } + + #[expect(dead_code)] + pub fn snake(value: T) -> Self { + Self { + value, + case: Case::Snake, + } + } +} + +impl Display for DisplayIdent<&'_ LoadOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let case = self.case; + let kind = self.value.kind; + let ident = case.wrap(kind.ident()); + let result_suffix = case.wrap(Input::Stack); + let ptr_suffix = SnakeCase(self.value.ptr); + let ident_prefix = self + .value + .kind + .ident_prefix() + .map(|v| case.wrap(v)) + .display_maybe(); + let mem0_ident = self + .value + .mem0 + .then_some(Ident::Mem0) + .map(|v| case.wrap(v)) + .display_maybe(); + let offset16_ident = self + .value + .offset16 + .then_some(Ident::Offset16) + .map(|v| case.wrap(v)) + .display_maybe(); + write!( + f, + "{ident_prefix}{ident}{mem0_ident}{offset16_ident}_{result_suffix}{ptr_suffix}", + ) + } +} + +impl Display for DisplayIdent<&'_ StoreOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let case = self.case; + let kind = self.value.kind; + let ident = case.wrap(kind.ident()); + let ptr_suffix = case.wrap(self.value.ptr); + let value_suffix = SnakeCase(self.value.value); + let ident_prefix = self + .value + .kind + .ident_prefix() + .map(|v| case.wrap(v)) + .display_maybe(); + let mem0_ident = self + .value + .mem0 + .then_some(Ident::Mem0) + .map(|v| case.wrap(v)) + .display_maybe(); + let offset16_ident = self + .value + .offset16 + .then_some(Ident::Offset16) + .map(|v| case.wrap(v)) + .display_maybe(); + write!( + f, + "{ident_prefix}{ident}{mem0_ident}{offset16_ident}_{ptr_suffix}{value_suffix}", + ) + } +} diff --git a/crates/ir2/build/display/mod.rs b/crates/ir2/build/display/mod.rs index a096c780a1..c27f5cba21 100644 --- a/crates/ir2/build/display/mod.rs +++ b/crates/ir2/build/display/mod.rs @@ -1,6 +1,10 @@ +mod ident; mod utils; -use self::utils::{DisplayConcat, DisplaySequence, IntoDisplayMaybe as _}; +use self::{ + ident::DisplayIdent, + utils::{DisplayConcat, DisplaySequence, IntoDisplayMaybe as _}, +}; use crate::build::{ isa::Isa, op::{ @@ -18,7 +22,7 @@ use crate::build::{ TableSetOp, UnaryOp, }, - token::{CamelCase, Case, Ident, SnakeCase}, + token::{CamelCase, Ident, SnakeCase}, }; use core::{ fmt::{self, Display}, @@ -401,89 +405,3 @@ impl Display for DisplayEnum<&'_ TableSetOp> { ) } } - -pub struct DisplayIdent { - value: T, - case: Case, -} - -impl DisplayIdent { - pub fn camel(value: T) -> Self { - Self { - value, - case: Case::Camel, - } - } - - #[expect(dead_code)] - pub fn snake(value: T) -> Self { - Self { - value, - case: Case::Snake, - } - } -} - -impl Display for DisplayIdent<&'_ LoadOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let case = self.case; - let kind = self.value.kind; - let ident = case.wrap(kind.ident()); - let result_suffix = case.wrap(Input::Stack); - let ptr_suffix = SnakeCase(self.value.ptr); - let ident_prefix = self - .value - .kind - .ident_prefix() - .map(|v| case.wrap(v)) - .display_maybe(); - let mem0_ident = self - .value - .mem0 - .then_some(Ident::Mem0) - .map(|v| case.wrap(v)) - .display_maybe(); - let offset16_ident = self - .value - .offset16 - .then_some(Ident::Offset16) - .map(|v| case.wrap(v)) - .display_maybe(); - write!( - f, - "{ident_prefix}{ident}{mem0_ident}{offset16_ident}_{result_suffix}{ptr_suffix}", - ) - } -} - -impl Display for DisplayIdent<&'_ StoreOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let case = self.case; - let kind = self.value.kind; - let ident = case.wrap(kind.ident()); - let ptr_suffix = case.wrap(self.value.ptr); - let value_suffix = SnakeCase(self.value.value); - let ident_prefix = self - .value - .kind - .ident_prefix() - .map(|v| case.wrap(v)) - .display_maybe(); - let mem0_ident = self - .value - .mem0 - .then_some(Ident::Mem0) - .map(|v| case.wrap(v)) - .display_maybe(); - let offset16_ident = self - .value - .offset16 - .then_some(Ident::Offset16) - .map(|v| case.wrap(v)) - .display_maybe(); - write!( - f, - "{ident_prefix}{ident}{mem0_ident}{offset16_ident}_{ptr_suffix}{value_suffix}", - ) - } -} From f6662d064a20f1bafaf3f8a580f7bc590ec9518f Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Fri, 22 Aug 2025 13:05:04 +0200 Subject: [PATCH 061/186] add cased Sep (separator) display utility --- crates/ir2/build/token.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index adae9e376c..7888e04952 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -16,6 +16,7 @@ impl Case { } /// Runtime selected casing, either [`CamelCase`] or [`SnakeCase`]. +#[derive(Copy, Clone)] pub enum ChosenCase { Camel(T), Snake(T), @@ -41,6 +42,22 @@ pub struct CamelCase(pub T); /// Snake-case tokens, e.g. `hello_world`. pub struct SnakeCase(pub T); +/// A word separator as required by some casings, e.g. snake case uses `_`. +#[derive(Copy, Clone)] +pub struct Sep; + +impl Display for CamelCase { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + Ok(()) + } +} + +impl Display for SnakeCase { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "_") + } +} + macro_rules! define_ident { ( $( From 6c5cd0af5e2ad00402d053d7df0cf304d7d36317 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Fri, 22 Aug 2025 13:06:31 +0200 Subject: [PATCH 062/186] use new cased separator utilit in DisplayIdent --- crates/ir2/build/display/ident.rs | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/crates/ir2/build/display/ident.rs b/crates/ir2/build/display/ident.rs index 266fcc0b1d..14971f547d 100644 --- a/crates/ir2/build/display/ident.rs +++ b/crates/ir2/build/display/ident.rs @@ -1,7 +1,7 @@ use crate::build::{ - display::utils::IntoDisplayMaybe as _, + display::utils::{DisplayConcat, IntoDisplayMaybe as _}, op::{Input, LoadOp, StoreOp}, - token::{Case, Ident, SnakeCase}, + token::{Case, Ident, Sep, SnakeCase}, }; use core::fmt::{self, Display}; @@ -34,23 +34,27 @@ impl Display for DisplayIdent<&'_ LoadOp> { let ident = case.wrap(kind.ident()); let result_suffix = case.wrap(Input::Stack); let ptr_suffix = SnakeCase(self.value.ptr); + let sep = case.wrap(Sep); let ident_prefix = self .value .kind .ident_prefix() - .map(|v| case.wrap(v)) + .map(|v| (case.wrap(v), sep)) + .map(DisplayConcat::from) .display_maybe(); let mem0_ident = self .value .mem0 .then_some(Ident::Mem0) - .map(|v| case.wrap(v)) + .map(|v| (sep, case.wrap(v))) + .map(DisplayConcat::from) .display_maybe(); let offset16_ident = self .value .offset16 .then_some(Ident::Offset16) - .map(|v| case.wrap(v)) + .map(|v| (sep, case.wrap(v))) + .map(DisplayConcat::from) .display_maybe(); write!( f, @@ -66,23 +70,27 @@ impl Display for DisplayIdent<&'_ StoreOp> { let ident = case.wrap(kind.ident()); let ptr_suffix = case.wrap(self.value.ptr); let value_suffix = SnakeCase(self.value.value); + let sep = case.wrap(Sep); let ident_prefix = self .value .kind .ident_prefix() - .map(|v| case.wrap(v)) + .map(|v| (case.wrap(v), sep)) + .map(DisplayConcat::from) .display_maybe(); let mem0_ident = self .value .mem0 .then_some(Ident::Mem0) - .map(|v| case.wrap(v)) + .map(|v| (sep, case.wrap(v))) + .map(DisplayConcat::from) .display_maybe(); let offset16_ident = self .value .offset16 .then_some(Ident::Offset16) - .map(|v| case.wrap(v)) + .map(|v| (sep, case.wrap(v))) + .map(DisplayConcat::from) .display_maybe(); write!( f, From b235651182e9c1d59d3c3aeb96722a049528c556 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Fri, 22 Aug 2025 13:19:30 +0200 Subject: [PATCH 063/186] add more return ops for returning single values --- crates/ir2/build/isa.rs | 12 ++++++++++++ crates/ir2/build/token.rs | 3 +++ 2 files changed, 15 insertions(+) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 0ced99170a..2fceede9cc 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -413,6 +413,18 @@ fn add_control_ops(isa: &mut Isa) { [Field::new(Ident::Fuel, FieldTy::BlockFuel)], )), Op::from(GenericOp::new(Ident::Return, [])), + Op::from(GenericOp::new( + Ident::ReturnStack, + [Field::new(Ident::Value, FieldTy::Stack)], + )), + Op::from(GenericOp::new( + Ident::Return32, + [Field::new(Ident::Value, FieldTy::U32)], + )), + Op::from(GenericOp::new( + Ident::Return64, + [Field::new(Ident::Value, FieldTy::U64)], + )), Op::from(GenericOp::new( Ident::ReturnSpan, [Field::new(Ident::Fuel, FieldTy::BlockFuel)], diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index 7888e04952..1a631e0cc9 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -187,6 +187,9 @@ define_ident!( ConsumeFuel: consume_fuel, Fuel: fuel, Return: r#return, + Return32: return32, + Return64: return64, + ReturnStack: return_stack, ReturnSpan: return_span, Values: values, Value: value, From ce3e07f5556d56beac506b53a054c42dc1193f30 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Fri, 22 Aug 2025 14:33:56 +0200 Subject: [PATCH 064/186] unsilence more warnings --- crates/ir2/build/display/mod.rs | 1 + crates/ir2/src/lib.rs | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ir2/build/display/mod.rs b/crates/ir2/build/display/mod.rs index c27f5cba21..f8b383f895 100644 --- a/crates/ir2/build/display/mod.rs +++ b/crates/ir2/build/display/mod.rs @@ -79,6 +79,7 @@ impl Display for DisplayEnum { write!( f, "\ + {indent}#[allow(non_camel_case_types)] {indent}pub enum Op {{\n\ {variants}\ {indent}}}\n\ diff --git a/crates/ir2/src/lib.rs b/crates/ir2/src/lib.rs index 3fbb371268..0afe35454b 100644 --- a/crates/ir2/src/lib.rs +++ b/crates/ir2/src/lib.rs @@ -1,4 +1,3 @@ -#![allow(warnings)] #![no_std] extern crate alloc; From 4671a8b69ce527d541d444cfc742aaec9627471e Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Fri, 22 Aug 2025 14:34:10 +0200 Subject: [PATCH 065/186] simplify DisplayEnum impl for UnaryOp --- crates/ir2/build/display/mod.rs | 39 ++++++--------------------------- 1 file changed, 7 insertions(+), 32 deletions(-) diff --git a/crates/ir2/build/display/mod.rs b/crates/ir2/build/display/mod.rs index f8b383f895..7deacc3fc5 100644 --- a/crates/ir2/build/display/mod.rs +++ b/crates/ir2/build/display/mod.rs @@ -111,41 +111,16 @@ impl Display for DisplayEnum<&'_ Op> { impl Display for DisplayEnum<&'_ UnaryOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.val.kind.is_conversion() { - self.display_conversion(f) - } else { - self.display_unary(f) - } - } -} - -impl DisplayEnum<&'_ UnaryOp> { - fn display_unary(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let kind = self.val.kind; - let ident = CamelCase(kind.ident()); - let result_ident = CamelCase(Ident::from(kind.result_ty())); - let result_suffix = CamelCase(Input::Stack); - let value_suffix = SnakeCase(Input::Stack); - let result_field = FieldTy::Stack; - let value_field = FieldTy::Stack; - let indent0 = self.indent; - let indent1 = indent0.inc(); - write!( - f, - "\ - {indent0}{result_ident}{ident}_{result_suffix}{value_suffix} {{\n\ - {indent1}result: {result_field},\n\ - {indent1}value: {value_field},\n\ - {indent0}}},\n\ - ", - ) - } - - fn display_conversion(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let kind = self.val.kind; let ident = CamelCase(kind.ident()); let result_ident = CamelCase(Ident::from(kind.result_ty())); - let input_ident = CamelCase(Ident::from(kind.input_ty())); + let input_ident = self + .val + .kind + .is_conversion() + .then_some(Ident::from(kind.input_ty())) + .map(CamelCase) + .display_maybe(); let result_suffix = CamelCase(Input::Stack); let value_suffix = SnakeCase(Input::Stack); let result_field = FieldTy::Stack; From bd318441ddffbffe92ab963c3b1f2abbe7091027 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Fri, 22 Aug 2025 15:53:26 +0200 Subject: [PATCH 066/186] remove From impls from DisplayConcat --- crates/ir2/build/display/ident.rs | 12 ++++++------ crates/ir2/build/display/mod.rs | 10 +++++----- crates/ir2/build/display/utils.rs | 12 ------------ 3 files changed, 11 insertions(+), 23 deletions(-) diff --git a/crates/ir2/build/display/ident.rs b/crates/ir2/build/display/ident.rs index 14971f547d..66df8d6180 100644 --- a/crates/ir2/build/display/ident.rs +++ b/crates/ir2/build/display/ident.rs @@ -40,21 +40,21 @@ impl Display for DisplayIdent<&'_ LoadOp> { .kind .ident_prefix() .map(|v| (case.wrap(v), sep)) - .map(DisplayConcat::from) + .map(DisplayConcat) .display_maybe(); let mem0_ident = self .value .mem0 .then_some(Ident::Mem0) .map(|v| (sep, case.wrap(v))) - .map(DisplayConcat::from) + .map(DisplayConcat) .display_maybe(); let offset16_ident = self .value .offset16 .then_some(Ident::Offset16) .map(|v| (sep, case.wrap(v))) - .map(DisplayConcat::from) + .map(DisplayConcat) .display_maybe(); write!( f, @@ -76,21 +76,21 @@ impl Display for DisplayIdent<&'_ StoreOp> { .kind .ident_prefix() .map(|v| (case.wrap(v), sep)) - .map(DisplayConcat::from) + .map(DisplayConcat) .display_maybe(); let mem0_ident = self .value .mem0 .then_some(Ident::Mem0) .map(|v| (sep, case.wrap(v))) - .map(DisplayConcat::from) + .map(DisplayConcat) .display_maybe(); let offset16_ident = self .value .offset16 .then_some(Ident::Offset16) .map(|v| (sep, case.wrap(v))) - .map(DisplayConcat::from) + .map(DisplayConcat) .display_maybe(); write!( f, diff --git a/crates/ir2/build/display/mod.rs b/crates/ir2/build/display/mod.rs index 7deacc3fc5..930f2c4d6e 100644 --- a/crates/ir2/build/display/mod.rs +++ b/crates/ir2/build/display/mod.rs @@ -243,7 +243,7 @@ impl Display for DisplayEnum<&'_ LoadOp> { let offset_field = offset_ty .map(|ty| Field::new(Ident::Offset, ty)) .map(|field| (indent1, field, ",\n")) - .map(DisplayConcat::from) + .map(DisplayConcat) .display_maybe(); let memory_field = self .val @@ -251,7 +251,7 @@ impl Display for DisplayEnum<&'_ LoadOp> { .then_some(FieldTy::Memory) .map(|ty| Field::new(Ident::Memory, ty)) .map(|field| (indent1, field, ",\n")) - .map(DisplayConcat::from) + .map(DisplayConcat) .display_maybe(); write!( f, @@ -280,7 +280,7 @@ impl Display for DisplayEnum<&'_ StoreOp> { .offset_ty(self.val.ptr, self.val.offset16) .map(|offset| Field::new(Ident::Offset, offset)) .map(|field| (indent1, field, ",\n")) - .map(DisplayConcat::from) + .map(DisplayConcat) .display_maybe(); let mem_field = self .val @@ -288,7 +288,7 @@ impl Display for DisplayEnum<&'_ StoreOp> { .not() .then(|| Field::new(Ident::Memory, FieldTy::Memory)) .map(|field| (indent1, field, ",\n")) - .map(DisplayConcat::from) + .map(DisplayConcat) .display_maybe(); write!( f, @@ -314,7 +314,7 @@ impl Display for DisplayEnum<&'_ GenericOp> { .fields .into_iter() .map(move |field| (indent1, field, ",\n")) - .map(DisplayConcat::from), + .map(DisplayConcat), ); write!( f, diff --git a/crates/ir2/build/display/utils.rs b/crates/ir2/build/display/utils.rs index d28c19c247..c9c9e48629 100644 --- a/crates/ir2/build/display/utils.rs +++ b/crates/ir2/build/display/utils.rs @@ -2,18 +2,6 @@ use core::fmt::{self, Display}; pub struct DisplayConcat(pub T); -impl From<(T0, T1)> for DisplayConcat<(T0, T1)> { - fn from(value: (T0, T1)) -> Self { - Self(value) - } -} - -impl From<(T0, T1, T2)> for DisplayConcat<(T0, T1, T2)> { - fn from(value: (T0, T1, T2)) -> Self { - Self(value) - } -} - impl Display for DisplayConcat<(T0, T1)> where T0: Display, From 088246f9011e42315c429580d798496a7e465723 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Fri, 22 Aug 2025 15:53:44 +0200 Subject: [PATCH 067/186] no longer use raw identifiers in define_ident macro --- crates/ir2/build/token.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index 1a631e0cc9..6f7f25ed83 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -154,14 +154,14 @@ define_ident!( ReturnCallImported: return_call_imported, ReturnCallIndirect: return_call_indirect, - U32: r#u32, - U64: r#u64, - I32: r#i32, - I64: r#i64, + U32: u32, + U64: u64, + I32: i32, + I64: i64, S32: s32, S64: s64, - F32: r#f32, - F64: r#f64, + F32: f32, + F64: f64, Clz: clz, Ctz: ctz, @@ -186,7 +186,7 @@ define_ident!( TrapCode: trap_code, ConsumeFuel: consume_fuel, Fuel: fuel, - Return: r#return, + Return: return, Return32: return32, Return64: return64, ReturnStack: return_stack, From 2dbcee05e503f3024b9c7651019380d62e550368 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Fri, 22 Aug 2025 15:54:01 +0200 Subject: [PATCH 068/186] add DisplayIdent impl and use it --- crates/ir2/build/display/ident.rs | 26 +++++++++++++++++++++++++- crates/ir2/build/display/mod.rs | 15 ++------------- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/crates/ir2/build/display/ident.rs b/crates/ir2/build/display/ident.rs index 66df8d6180..9772b3a09a 100644 --- a/crates/ir2/build/display/ident.rs +++ b/crates/ir2/build/display/ident.rs @@ -1,6 +1,6 @@ use crate::build::{ display::utils::{DisplayConcat, IntoDisplayMaybe as _}, - op::{Input, LoadOp, StoreOp}, + op::{Input, LoadOp, StoreOp, UnaryOp}, token::{Case, Ident, Sep, SnakeCase}, }; use core::fmt::{self, Display}; @@ -27,6 +27,30 @@ impl DisplayIdent { } } +impl Display for DisplayIdent<&'_ UnaryOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let case = self.case; + let kind = self.value.kind; + let ident = case.wrap(kind.ident()); + let sep = case.wrap(Sep); + let ident_prefix = DisplayConcat((case.wrap(Ident::from(kind.result_ty())), sep)); + let ident_suffix = self + .value + .kind + .is_conversion() + .then_some(Ident::from(kind.input_ty())) + .map(|i| (sep, case.wrap(i))) + .map(DisplayConcat) + .display_maybe(); + let result_suffix = case.wrap(Input::Stack); + let value_suffix = SnakeCase(Input::Stack); + write!( + f, + "{ident_prefix}{ident}{ident_suffix}_{result_suffix}{value_suffix}" + ) + } +} + impl Display for DisplayIdent<&'_ LoadOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let case = self.case; diff --git a/crates/ir2/build/display/mod.rs b/crates/ir2/build/display/mod.rs index 930f2c4d6e..c0ce5cc65d 100644 --- a/crates/ir2/build/display/mod.rs +++ b/crates/ir2/build/display/mod.rs @@ -111,18 +111,7 @@ impl Display for DisplayEnum<&'_ Op> { impl Display for DisplayEnum<&'_ UnaryOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let kind = self.val.kind; - let ident = CamelCase(kind.ident()); - let result_ident = CamelCase(Ident::from(kind.result_ty())); - let input_ident = self - .val - .kind - .is_conversion() - .then_some(Ident::from(kind.input_ty())) - .map(CamelCase) - .display_maybe(); - let result_suffix = CamelCase(Input::Stack); - let value_suffix = SnakeCase(Input::Stack); + let ident = DisplayIdent::camel(self.val); let result_field = FieldTy::Stack; let value_field = FieldTy::Stack; let indent0 = self.indent; @@ -130,7 +119,7 @@ impl Display for DisplayEnum<&'_ UnaryOp> { write!( f, "\ - {indent0}{result_ident}{ident}{input_ident}_{result_suffix}{value_suffix} {{\n\ + {indent0}{ident} {{\n\ {indent1}result: {result_field},\n\ {indent1}value: {value_field},\n\ {indent0}}},\n\ From f895a800607d5cbfb0425ba29323d6cc585dc6b3 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Fri, 22 Aug 2025 15:54:49 +0200 Subject: [PATCH 069/186] fix warnings in wasmi_ir2 --- crates/ir2/src/error.rs | 5 +---- crates/ir2/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/crates/ir2/src/error.rs b/crates/ir2/src/error.rs index cb9062bbfc..4b56657145 100644 --- a/crates/ir2/src/error.rs +++ b/crates/ir2/src/error.rs @@ -3,12 +3,10 @@ use core::fmt; /// An error that may be occurred when operating with some Wasmi IR primitives. #[derive(Debug)] pub enum Error { - /// Encountered when trying to create a [`Reg`](crate::Reg) from an out of bounds integer. + /// Encountered when trying to create a [`Stack`](crate::Stack) from an out of bounds integer. StackSlotOutOfBounds, /// Encountered when trying to create a [`BranchOffset`](crate::BranchOffset) from an out of bounds integer. BranchOffsetOutOfBounds, - /// Encountered when trying to create a [`Comparator`](crate::Comparator) from an out of bounds integer. - ComparatorOutOfBounds, /// Encountered when trying to create a [`BlockFuel`](crate::BlockFuel) from an out of bounds integer. BlockFuelOutOfBounds, } @@ -18,7 +16,6 @@ impl fmt::Display for Error { match self { Self::StackSlotOutOfBounds => write!(f, "stack slot out of bounds"), Self::BranchOffsetOutOfBounds => write!(f, "branch offset out of bounds"), - Self::ComparatorOutOfBounds => write!(f, "comparator out of bounds"), Self::BlockFuelOutOfBounds => write!(f, "block fuel out of bounds"), } } diff --git a/crates/ir2/src/lib.rs b/crates/ir2/src/lib.rs index 0afe35454b..c1c75d827c 100644 --- a/crates/ir2/src/lib.rs +++ b/crates/ir2/src/lib.rs @@ -17,5 +17,5 @@ pub use self::{ index::Stack, op::Op, primitive::{Address, BlockFuel, BranchOffset, Offset16, Sign}, - span::{BoundedStackSpan, FixedStackSpan, StackSpan}, + span::{BoundedStackSpan, FixedStackSpan, StackSpan, StackSpanIter}, }; From 1f16271fcd651228a31a3cd374f2b16886619cee Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Fri, 22 Aug 2025 16:26:52 +0200 Subject: [PATCH 070/186] impl Display for DisplayIdent and use it --- crates/ir2/build/display/ident.rs | 19 ++++++++++++++++++- crates/ir2/build/display/mod.rs | 8 ++------ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/crates/ir2/build/display/ident.rs b/crates/ir2/build/display/ident.rs index 9772b3a09a..5d259b26a2 100644 --- a/crates/ir2/build/display/ident.rs +++ b/crates/ir2/build/display/ident.rs @@ -1,6 +1,6 @@ use crate::build::{ display::utils::{DisplayConcat, IntoDisplayMaybe as _}, - op::{Input, LoadOp, StoreOp, UnaryOp}, + op::{BinaryOp, Input, LoadOp, StoreOp, UnaryOp}, token::{Case, Ident, Sep, SnakeCase}, }; use core::fmt::{self, Display}; @@ -51,6 +51,23 @@ impl Display for DisplayIdent<&'_ UnaryOp> { } } +impl Display for DisplayIdent<&'_ BinaryOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let case = self.case; + let sep = case.wrap(Sep); + let kind = self.value.kind; + let ident = case.wrap(kind.ident()); + let ident_prefix = case.wrap(kind.ident_prefix()); + let result_suffix = case.wrap(Input::Stack); + let lhs_suffix = SnakeCase(self.value.lhs); + let rhs_suffix = SnakeCase(self.value.rhs); + write!( + f, + "{ident_prefix}{sep}{ident}_{result_suffix}{lhs_suffix}{rhs_suffix}" + ) + } +} + impl Display for DisplayIdent<&'_ LoadOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let case = self.case; diff --git a/crates/ir2/build/display/mod.rs b/crates/ir2/build/display/mod.rs index c0ce5cc65d..76e5cab06a 100644 --- a/crates/ir2/build/display/mod.rs +++ b/crates/ir2/build/display/mod.rs @@ -132,19 +132,15 @@ impl Display for DisplayEnum<&'_ BinaryOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent0 = self.indent; let indent1 = indent0.inc(); + let ident = DisplayIdent::camel(self.val); let kind = self.val.kind; - let ident = CamelCase(kind.ident()); - let ident_prefix = CamelCase(kind.ident_prefix()); let result_ty = FieldTy::Stack; let lhs_ty = kind.lhs_field(self.val.lhs); let rhs_ty = kind.rhs_field(self.val.rhs); - let result_suffix = CamelCase(Input::Stack); - let lhs_suffix = SnakeCase(self.val.lhs); - let rhs_suffix = SnakeCase(self.val.rhs); write!( f, "\ - {indent0}{ident_prefix}{ident}_{result_suffix}{lhs_suffix}{rhs_suffix} {{\n\ + {indent0}{ident} {{\n\ {indent1}result: {result_ty},\n\ {indent1}lhs: {lhs_ty},\n\ {indent1}rhs: {rhs_ty},\n\ From 070e0ab05215d44d5845d4760766ab49f04edc98 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Fri, 22 Aug 2025 17:27:52 +0200 Subject: [PATCH 071/186] add Display impl for DisplayIdent --- crates/ir2/build/display/ident.rs | 19 ++++++++++++++++++- crates/ir2/build/display/mod.rs | 9 ++------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/crates/ir2/build/display/ident.rs b/crates/ir2/build/display/ident.rs index 5d259b26a2..9749ecb3d8 100644 --- a/crates/ir2/build/display/ident.rs +++ b/crates/ir2/build/display/ident.rs @@ -1,6 +1,6 @@ use crate::build::{ display::utils::{DisplayConcat, IntoDisplayMaybe as _}, - op::{BinaryOp, Input, LoadOp, StoreOp, UnaryOp}, + op::{BinaryOp, CmpBranchOp, Input, LoadOp, StoreOp, UnaryOp}, token::{Case, Ident, Sep, SnakeCase}, }; use core::fmt::{self, Display}; @@ -68,6 +68,23 @@ impl Display for DisplayIdent<&'_ BinaryOp> { } } +impl Display for DisplayIdent<&'_ CmpBranchOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let case = self.case; + let sep = case.wrap(Sep); + let cmp = self.value.cmp; + let branch = case.wrap(Ident::Branch); + let ident = case.wrap(cmp.ident()); + let input_ident = case.wrap(Ident::from(cmp.input_ty())); + let lhs_suffix = case.wrap(self.value.lhs); + let rhs_suffix = SnakeCase(self.value.rhs); + write!( + f, + "{branch}{sep}{input_ident}{sep}{ident}_{lhs_suffix}{rhs_suffix}" + ) + } +} + impl Display for DisplayIdent<&'_ LoadOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let case = self.case; diff --git a/crates/ir2/build/display/mod.rs b/crates/ir2/build/display/mod.rs index 76e5cab06a..3bc1437eb9 100644 --- a/crates/ir2/build/display/mod.rs +++ b/crates/ir2/build/display/mod.rs @@ -155,19 +155,14 @@ impl Display for DisplayEnum<&'_ CmpBranchOp> { let indent0 = self.indent; let indent1 = indent0.inc(); let cmp = self.val.cmp; - let branch = CamelCase(Ident::Branch); - let ident = CamelCase(cmp.ident()); - let input_ident = CamelCase(Ident::from(cmp.input_ty())); + let ident = DisplayIdent::camel(self.val); let lhs_ty = cmp.input_field(self.val.lhs); let rhs_ty = cmp.input_field(self.val.rhs); let offset_ty = FieldTy::BranchOffset; - let result_suffix = CamelCase(Input::Stack); - let lhs_suffix = SnakeCase(self.val.lhs); - let rhs_suffix = SnakeCase(self.val.rhs); write!( f, "\ - {indent0}{branch}{input_ident}{ident}_{result_suffix}{lhs_suffix}{rhs_suffix} {{\n\ + {indent0}{ident} {{\n\ {indent1}offset: {offset_ty},\n\ {indent1}lhs: {lhs_ty},\n\ {indent1}rhs: {rhs_ty},\n\ From 6cc3bd564e93398b7d061b28a69ba955b81ba713 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Fri, 22 Aug 2025 20:09:07 +0200 Subject: [PATCH 072/186] impl Display for DisplayIdent --- crates/ir2/build/display/ident.rs | 19 ++++++++++++++++++- crates/ir2/build/display/mod.rs | 9 ++------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/crates/ir2/build/display/ident.rs b/crates/ir2/build/display/ident.rs index 9749ecb3d8..4eb9f9185e 100644 --- a/crates/ir2/build/display/ident.rs +++ b/crates/ir2/build/display/ident.rs @@ -1,6 +1,6 @@ use crate::build::{ display::utils::{DisplayConcat, IntoDisplayMaybe as _}, - op::{BinaryOp, CmpBranchOp, Input, LoadOp, StoreOp, UnaryOp}, + op::{BinaryOp, CmpBranchOp, CmpSelectOp, Input, LoadOp, StoreOp, UnaryOp}, token::{Case, Ident, Sep, SnakeCase}, }; use core::fmt::{self, Display}; @@ -85,6 +85,23 @@ impl Display for DisplayIdent<&'_ CmpBranchOp> { } } +impl Display for DisplayIdent<&'_ CmpSelectOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let case = self.case; + let cmp = self.value.cmp; + let select = case.wrap(Ident::Select); + let ident = case.wrap(cmp.ident()); + let input_ident = case.wrap(Ident::from(cmp.input_ty())); + let result_suffix = case.wrap(Input::Stack); + let lhs_suffix = SnakeCase(self.value.lhs); + let rhs_suffix = SnakeCase(self.value.rhs); + write!( + f, + "{select}{input_ident}{ident}_{result_suffix}{lhs_suffix}{rhs_suffix}" + ) + } +} + impl Display for DisplayIdent<&'_ LoadOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let case = self.case; diff --git a/crates/ir2/build/display/mod.rs b/crates/ir2/build/display/mod.rs index 3bc1437eb9..69e545afcf 100644 --- a/crates/ir2/build/display/mod.rs +++ b/crates/ir2/build/display/mod.rs @@ -177,21 +177,16 @@ impl Display for DisplayEnum<&'_ CmpSelectOp> { let indent0 = self.indent; let indent1 = indent0.inc(); let cmp = self.val.cmp; - let select = CamelCase(Ident::Select); - let ident = CamelCase(cmp.ident()); - let input_ident = CamelCase(Ident::from(cmp.input_ty())); + let ident = DisplayIdent::camel(self.val); let result_ty = FieldTy::Stack; let lhs_ty = cmp.input_field(self.val.lhs); let rhs_ty = cmp.input_field(self.val.rhs); - let result_suffix = CamelCase(Input::Stack); - let lhs_suffix = SnakeCase(self.val.lhs); - let rhs_suffix = SnakeCase(self.val.rhs); let val_true = FieldTy::Stack; let val_false = FieldTy::Stack; write!( f, "\ - {indent0}{select}{input_ident}{ident}_{result_suffix}{lhs_suffix}{rhs_suffix} {{\n\ + {indent0}{ident} {{\n\ {indent1}result: {result_ty},\n\ {indent1}lhs: {lhs_ty},\n\ {indent1}rhs: {rhs_ty},\n\ From bb29969c2e9789c21a10e5e5535a6c7a028e5ef7 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Sat, 23 Aug 2025 08:53:21 +0200 Subject: [PATCH 073/186] implement DisplayIdent for the remaining ops --- crates/ir2/build/display/ident.rs | 69 ++++++++++++++++++++++++++++++- crates/ir2/build/display/mod.rs | 16 +++---- crates/ir2/build/token.rs | 2 +- 3 files changed, 75 insertions(+), 12 deletions(-) diff --git a/crates/ir2/build/display/ident.rs b/crates/ir2/build/display/ident.rs index 4eb9f9185e..e4c071e0d5 100644 --- a/crates/ir2/build/display/ident.rs +++ b/crates/ir2/build/display/ident.rs @@ -1,6 +1,18 @@ use crate::build::{ display::utils::{DisplayConcat, IntoDisplayMaybe as _}, - op::{BinaryOp, CmpBranchOp, CmpSelectOp, Input, LoadOp, StoreOp, UnaryOp}, + op::{ + BinaryOp, + CmpBranchOp, + CmpSelectOp, + GenericOp, + Input, + LoadOp, + Op, + StoreOp, + TableGetOp, + TableSetOp, + UnaryOp, + }, token::{Case, Ident, Sep, SnakeCase}, }; use core::fmt::{self, Display}; @@ -25,6 +37,34 @@ impl DisplayIdent { case: Case::Snake, } } + + pub fn map(&self, value: V) -> DisplayIdent { + DisplayIdent { + value, + case: self.case, + } + } +} + +impl Display for DisplayIdent<&'_ Op> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.value { + Op::Unary(op) => self.map(op).fmt(f), + Op::Binary(op) => self.map(op).fmt(f), + Op::CmpBranch(op) => self.map(op).fmt(f), + Op::CmpSelect(op) => self.map(op).fmt(f), + Op::Load(op) => self.map(op).fmt(f), + Op::Store(op) => self.map(op).fmt(f), + Op::TableGet(op) => self.map(op).fmt(f), + Op::TableSet(op) => self.map(op).fmt(f), + Op::Generic0(op) => self.map(op).fmt(f), + Op::Generic1(op) => self.map(op).fmt(f), + Op::Generic2(op) => self.map(op).fmt(f), + Op::Generic3(op) => self.map(op).fmt(f), + Op::Generic4(op) => self.map(op).fmt(f), + Op::Generic5(op) => self.map(op).fmt(f), + } + } } impl Display for DisplayIdent<&'_ UnaryOp> { @@ -173,3 +213,30 @@ impl Display for DisplayIdent<&'_ StoreOp> { ) } } + +impl Display for DisplayIdent<&'_ GenericOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let ident = self.case.wrap(self.value.ident); + write!(f, "{ident}") + } +} + +impl Display for DisplayIdent<&'_ TableGetOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let case = self.case; + let ident = case.wrap(Ident::TableGet); + let result_suffix = case.wrap(Input::Stack); + let index_suffix = SnakeCase(self.value.index); + write!(f, "{ident}_{result_suffix}{index_suffix}") + } +} + +impl Display for DisplayIdent<&'_ TableSetOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let case = self.case; + let ident = case.wrap(Ident::TableSet); + let index_suffix = case.wrap(self.value.index); + let value_suffix = SnakeCase(self.value.value); + write!(f, "{ident}_{index_suffix}{value_suffix}") + } +} diff --git a/crates/ir2/build/display/mod.rs b/crates/ir2/build/display/mod.rs index 69e545afcf..8acbab258c 100644 --- a/crates/ir2/build/display/mod.rs +++ b/crates/ir2/build/display/mod.rs @@ -22,7 +22,7 @@ use crate::build::{ TableSetOp, UnaryOp, }, - token::{CamelCase, Ident, SnakeCase}, + token::Ident, }; use core::{ fmt::{self, Display}, @@ -283,7 +283,7 @@ impl Display for DisplayEnum<&'_ GenericOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent0 = self.indent; let indent1 = indent0.inc(); - let ident = CamelCase(self.val.ident); + let ident = DisplayIdent::camel(self.val); let fields = DisplaySequence( self.val .fields @@ -306,19 +306,17 @@ impl Display for DisplayEnum<&'_ TableGetOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent0 = self.indent; let indent1 = indent0.inc(); - let ident = CamelCase(Ident::TableGet); + let ident = DisplayIdent::camel(self.val); let result_ty = FieldTy::Stack; let index_ty = match self.val.index { Input::Stack => FieldTy::Stack, Input::Immediate => FieldTy::U32, }; let table_ty = FieldTy::Table; - let result_suffix = CamelCase(Input::Stack); - let index_suffix = SnakeCase(self.val.index); write!( f, "\ - {indent0}{ident}_{result_suffix}{index_suffix} {{\n\ + {indent0}{ident} {{\n\ {indent1}result: {result_ty},\n\ {indent1}index: {index_ty},\n\ {indent1}table: {table_ty},\n\ @@ -332,7 +330,7 @@ impl Display for DisplayEnum<&'_ TableSetOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent0 = self.indent; let indent1 = indent0.inc(); - let ident = CamelCase(Ident::TableSet); + let ident = DisplayIdent::camel(self.val); let index_ty = match self.val.index { Input::Stack => FieldTy::Stack, Input::Immediate => FieldTy::U32, @@ -342,12 +340,10 @@ impl Display for DisplayEnum<&'_ TableSetOp> { Input::Immediate => FieldTy::U64, }; let table_ty = FieldTy::Table; - let index_suffix = CamelCase(self.val.index); - let value_suffix = SnakeCase(self.val.value); write!( f, "\ - {indent0}{ident}_{index_suffix}{value_suffix} {{\n\ + {indent0}{ident} {{\n\ {indent1}table: {table_ty},\n\ {indent1}index: {index_ty},\n\ {indent1}value: {value_ty},\n\ diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index 6f7f25ed83..32f1a4e8fd 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -186,7 +186,7 @@ define_ident!( TrapCode: trap_code, ConsumeFuel: consume_fuel, Fuel: fuel, - Return: return, + Return: r#return, Return32: return32, Return64: return64, ReturnStack: return_stack, From 4220e219ffd175403c50dcf75febbb5a568d4aa8 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Sat, 23 Aug 2025 08:57:55 +0200 Subject: [PATCH 074/186] add BranchTable[Span] ops --- crates/ir2/build/isa.rs | 16 ++++++++++++++++ crates/ir2/build/token.rs | 4 ++++ 2 files changed, 20 insertions(+) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 2fceede9cc..38e4223267 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -433,6 +433,22 @@ fn add_control_ops(isa: &mut Isa) { Ident::Branch, [Field::new(Ident::Values, FieldTy::StackSpan)], )), + Op::from(GenericOp::new( + Ident::BranchTable, + [ + Field::new(Ident::Index, FieldTy::Stack), + Field::new(Ident::Len, FieldTy::U16), + ], + )), + Op::from(GenericOp::new( + Ident::BranchTableSpan, + [ + Field::new(Ident::Index, FieldTy::Stack), + Field::new(Ident::LenTargets, FieldTy::U16), + Field::new(Ident::Values, FieldTy::StackSpan), + Field::new(Ident::LenValues, FieldTy::U16), + ], + )), ]; for op in ops { isa.push_op(op); diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index 32f1a4e8fd..e7bd666053 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -123,6 +123,8 @@ define_ident!( BitXor: bit_xor, Branch: branch, + BranchTable: branch_table, + BranchTableSpan: branch_table_span, Select: select, Store8: store8, Store16: store16, @@ -196,6 +198,8 @@ define_ident!( Result: result, Results: results, Len: len, + LenTargets: len_targets, + LenValues: len_values, Delta: delta, Dst: dst, Src: src, From ecfe12c484ddd9cdc5f02b4d566bcede170f339b Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Sat, 23 Aug 2025 08:58:29 +0200 Subject: [PATCH 075/186] rename len -> len_targets --- crates/ir2/build/isa.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 38e4223267..39a0eb3ce6 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -437,7 +437,7 @@ fn add_control_ops(isa: &mut Isa) { Ident::BranchTable, [ Field::new(Ident::Index, FieldTy::Stack), - Field::new(Ident::Len, FieldTy::U16), + Field::new(Ident::LenTargets, FieldTy::U16), ], )), Op::from(GenericOp::new( From 66213308f8ddf06eb1232ea7059901c00a13b09c Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Sat, 23 Aug 2025 11:43:16 +0200 Subject: [PATCH 076/186] add wide-arithmetic ops codegen --- crates/ir2/build/isa.rs | 45 +++++++++++++++++++++++++++++++++++++++ crates/ir2/build/op.rs | 2 ++ crates/ir2/build/token.rs | 12 +++++++++++ crates/ir2/src/op.rs | 1 + 4 files changed, 60 insertions(+) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 39a0eb3ce6..7f28ee8e2f 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -49,6 +49,7 @@ pub fn wasmi_isa() -> Isa { add_global_ops(&mut isa); add_memory_ops(&mut isa); add_table_ops(&mut isa); + add_wide_arithmetic(&mut isa); isa } @@ -700,3 +701,47 @@ fn add_memory_ops(isa: &mut Isa) { isa.push_op(op); } } + +fn add_wide_arithmetic(isa: &mut Isa) { + let ops = [ + Op::from(GenericOp::new( + Ident::I64Add128, + [ + Field::new(Ident::Results, FieldTy::FixedStackSpan2), + Field::new(Ident::LhsLo, FieldTy::Stack), + Field::new(Ident::LhsHi, FieldTy::Stack), + Field::new(Ident::RhsLo, FieldTy::Stack), + Field::new(Ident::RhsHi, FieldTy::Stack), + ], + )), + Op::from(GenericOp::new( + Ident::I64Sub128, + [ + Field::new(Ident::Results, FieldTy::FixedStackSpan2), + Field::new(Ident::LhsLo, FieldTy::Stack), + Field::new(Ident::LhsHi, FieldTy::Stack), + Field::new(Ident::RhsLo, FieldTy::Stack), + Field::new(Ident::RhsHi, FieldTy::Stack), + ], + )), + Op::from(GenericOp::new( + Ident::S64MulWide, + [ + Field::new(Ident::Results, FieldTy::FixedStackSpan2), + Field::new(Ident::Lhs, FieldTy::Stack), + Field::new(Ident::Rhs, FieldTy::Stack), + ], + )), + Op::from(GenericOp::new( + Ident::U64MulWide, + [ + Field::new(Ident::Results, FieldTy::FixedStackSpan2), + Field::new(Ident::Lhs, FieldTy::Stack), + Field::new(Ident::Rhs, FieldTy::Stack), + ], + )), + ]; + for op in ops { + isa.push_op(op); + } +} diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 72353f4402..ab14d93b8c 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -670,6 +670,7 @@ impl From for Ident { pub enum FieldTy { Stack, StackSpan, + FixedStackSpan2, U8, U16, U32, @@ -704,6 +705,7 @@ impl Display for FieldTy { let s = match self { Self::Stack => "Stack", Self::StackSpan => "StackSpan", + Self::FixedStackSpan2 => "FixedStackSpan<2>", Self::U8 => "u8", Self::U16 => "u16", Self::U32 => "u32", diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index e7bd666053..bbe709580f 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -229,4 +229,16 @@ define_ident!( RefFunc: ref_func, Mem0: mem0, Offset16: offset16, + + I64Add128: i64_add128, + I64Sub128: i64_sub128, + S64MulWide: s64_mul_wide, + U64MulWide: u64_mul_wide, + + Lhs: lhs, + Rhs: rhs, + LhsLo: lhs_lo, + LhsHi: lhs_hi, + RhsLo: rhs_lo, + RhsHi: rhs_hi, ); diff --git a/crates/ir2/src/op.rs b/crates/ir2/src/op.rs index c26baac9a7..9456ea223a 100644 --- a/crates/ir2/src/op.rs +++ b/crates/ir2/src/op.rs @@ -4,6 +4,7 @@ use crate::{ Address, BlockFuel, BranchOffset, + FixedStackSpan, Offset16, Sign, Stack, From 1da211849b39636dcfe41ab8424bac3e270f853a Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Sat, 23 Aug 2025 11:43:29 +0200 Subject: [PATCH 077/186] allocate just once for contents --- crates/ir2/build/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index 9f768626ed..539013384a 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -41,6 +41,7 @@ impl Display for Error { pub fn generate_code(out_dir: &Path) -> Result<(), Error> { let mut contents = String::new(); + contents.reserve_exact(50_000); let isa = isa::wasmi_isa(); write!( &mut contents, From 5b9991c73f9818bd67bc9ba33c79618c02a2eb01 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Sat, 23 Aug 2025 11:44:58 +0200 Subject: [PATCH 078/186] use reserve_exact (since we know exactly how many ops) --- crates/ir2/build/isa.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 7f28ee8e2f..f4fc07393d 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -36,7 +36,7 @@ impl Isa { pub fn wasmi_isa() -> Isa { let mut isa = Isa::default(); - isa.ops.reserve(500); + isa.ops.reserve_exact(500); add_unary_ops(&mut isa); add_binary_ops(&mut isa); add_cmp_branch_ops(&mut isa); From 1dc8d66c842bfcdf92d477f205c4b96d3e38da40 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Mon, 25 Aug 2025 13:22:13 +0200 Subject: [PATCH 079/186] make Field fields pub --- crates/ir2/build/op.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index ab14d93b8c..1405ee9d7c 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -58,8 +58,8 @@ impl GenericOp { #[derive(Copy, Clone)] pub struct Field { - ident: Ident, - ty: FieldTy, + pub ident: Ident, + pub ty: FieldTy, } impl Field { From 153aadde914e4b2fbe2c5f5b010f2305315573e8 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Mon, 25 Aug 2025 13:22:27 +0200 Subject: [PATCH 080/186] move Field defs more to top --- crates/ir2/build/op.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 1405ee9d7c..c13783cb88 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -44,18 +44,6 @@ impl_from_for_op! { } } -#[derive(Copy, Clone)] -pub struct GenericOp { - pub ident: Ident, - pub fields: [Field; N], -} - -impl GenericOp { - pub fn new(ident: Ident, fields: [Field; N]) -> Self { - Self { ident, fields } - } -} - #[derive(Copy, Clone)] pub struct Field { pub ident: Ident, @@ -76,6 +64,18 @@ impl Display for Field { } } +#[derive(Copy, Clone)] +pub struct GenericOp { + pub ident: Ident, + pub fields: [Field; N], +} + +impl GenericOp { + pub fn new(ident: Ident, fields: [Field; N]) -> Self { + Self { ident, fields } + } +} + #[derive(Copy, Clone)] pub struct UnaryOp { pub kind: UnaryOpKind, From 5bb614d360c663c1eb67ca648438ee5218c148b3 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Mon, 25 Aug 2025 14:40:34 +0200 Subject: [PATCH 081/186] add field getters to all op types --- crates/ir2/build/display/mod.rs | 169 ++++++++++++----------------- crates/ir2/build/op.rs | 182 +++++++++++++++++++++++++++----- crates/ir2/build/token.rs | 3 + 3 files changed, 228 insertions(+), 126 deletions(-) diff --git a/crates/ir2/build/display/mod.rs b/crates/ir2/build/display/mod.rs index 8acbab258c..9e2d6de1c3 100644 --- a/crates/ir2/build/display/mod.rs +++ b/crates/ir2/build/display/mod.rs @@ -11,10 +11,8 @@ use crate::build::{ BinaryOp, CmpBranchOp, CmpSelectOp, - Field, FieldTy, GenericOp, - Input, LoadOp, Op, StoreOp, @@ -22,12 +20,8 @@ use crate::build::{ TableSetOp, UnaryOp, }, - token::Ident, -}; -use core::{ - fmt::{self, Display}, - ops::Not, }; +use core::fmt::{self, Display}; #[derive(Copy, Clone, Default)] pub struct Indent(usize); @@ -111,17 +105,18 @@ impl Display for DisplayEnum<&'_ Op> { impl Display for DisplayEnum<&'_ UnaryOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let ident = DisplayIdent::camel(self.val); - let result_field = FieldTy::Stack; - let value_field = FieldTy::Stack; let indent0 = self.indent; let indent1 = indent0.inc(); + let op = self.val; + let ident = DisplayIdent::camel(op); + let result_field = op.result_field(); + let value_field = op.value_field(); write!( f, "\ {indent0}{ident} {{\n\ - {indent1}result: {result_field},\n\ - {indent1}value: {value_field},\n\ + {indent1}{result_field},\n\ + {indent1}{value_field},\n\ {indent0}}},\n\ ", ) @@ -132,18 +127,18 @@ impl Display for DisplayEnum<&'_ BinaryOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent0 = self.indent; let indent1 = indent0.inc(); - let ident = DisplayIdent::camel(self.val); - let kind = self.val.kind; - let result_ty = FieldTy::Stack; - let lhs_ty = kind.lhs_field(self.val.lhs); - let rhs_ty = kind.rhs_field(self.val.rhs); + let op = self.val; + let ident = DisplayIdent::camel(op); + let result_field = op.result_field(); + let lhs_field = op.lhs_field(); + let rhs_field = op.rhs_field(); write!( f, "\ {indent0}{ident} {{\n\ - {indent1}result: {result_ty},\n\ - {indent1}lhs: {lhs_ty},\n\ - {indent1}rhs: {rhs_ty},\n\ + {indent1}{result_field},\n\ + {indent1}{lhs_field},\n\ + {indent1}{rhs_field},\n\ {indent0}}},\n\ ", ) @@ -154,18 +149,18 @@ impl Display for DisplayEnum<&'_ CmpBranchOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent0 = self.indent; let indent1 = indent0.inc(); - let cmp = self.val.cmp; - let ident = DisplayIdent::camel(self.val); - let lhs_ty = cmp.input_field(self.val.lhs); - let rhs_ty = cmp.input_field(self.val.rhs); + let op = self.val; + let ident = DisplayIdent::camel(op); + let lhs_field = op.lhs_field(); + let rhs_field = op.rhs_field(); let offset_ty = FieldTy::BranchOffset; write!( f, "\ {indent0}{ident} {{\n\ {indent1}offset: {offset_ty},\n\ - {indent1}lhs: {lhs_ty},\n\ - {indent1}rhs: {rhs_ty},\n\ + {indent1}{lhs_field},\n\ + {indent1}{rhs_field},\n\ {indent0}}},\n\ ", ) @@ -176,22 +171,22 @@ impl Display for DisplayEnum<&'_ CmpSelectOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent0 = self.indent; let indent1 = indent0.inc(); - let cmp = self.val.cmp; - let ident = DisplayIdent::camel(self.val); - let result_ty = FieldTy::Stack; - let lhs_ty = cmp.input_field(self.val.lhs); - let rhs_ty = cmp.input_field(self.val.rhs); - let val_true = FieldTy::Stack; - let val_false = FieldTy::Stack; + let op = self.val; + let ident = DisplayIdent::camel(op); + let result_field = op.result_field(); + let lhs_field = op.lhs_field(); + let rhs_field = op.rhs_field(); + let val_true_field = op.val_true_field(); + let val_false_field = op.val_false_field(); write!( f, "\ {indent0}{ident} {{\n\ - {indent1}result: {result_ty},\n\ - {indent1}lhs: {lhs_ty},\n\ - {indent1}rhs: {rhs_ty},\n\ - {indent1}val_true: {val_true},\n\ - {indent1}val_false: {val_false},\n\ + {indent1}{result_field},\n\ + {indent1}{lhs_field},\n\ + {indent1}{rhs_field},\n\ + {indent1}{val_true_field},\n\ + {indent1}{val_false_field},\n\ {indent0}}},\n\ ", ) @@ -202,29 +197,17 @@ impl Display for DisplayEnum<&'_ LoadOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent0 = self.indent; let indent1 = indent0.inc(); - let ident = DisplayIdent::camel(self.val); - let result_ty = FieldTy::Stack; - let (ptr_ty, offset_ty) = match self.val.ptr { - Input::Stack => { - let ptr = FieldTy::Stack; - let offset = match self.val.offset16 { - true => FieldTy::Offset16, - false => FieldTy::U64, - }; - (ptr, Some(offset)) - } - Input::Immediate => (FieldTy::Address, None), - }; - let offset_field = offset_ty - .map(|ty| Field::new(Ident::Offset, ty)) + let op = self.val; + let ident = DisplayIdent::camel(op); + let result_field = op.result_field(); + let ptr_field = op.ptr_field(); + let offset_field = op + .offset_field() .map(|field| (indent1, field, ",\n")) .map(DisplayConcat) .display_maybe(); - let memory_field = self - .val - .mem0 - .then_some(FieldTy::Memory) - .map(|ty| Field::new(Ident::Memory, ty)) + let memory_field = op + .memory_field() .map(|field| (indent1, field, ",\n")) .map(DisplayConcat) .display_maybe(); @@ -232,8 +215,8 @@ impl Display for DisplayEnum<&'_ LoadOp> { f, "\ {indent0}{ident} {{\n\ - {indent1}result: {result_ty},\n\ - {indent1}ptr: {ptr_ty},\n\ + {indent1}{result_field},\n\ + {indent1}{ptr_field},\n\ {offset_field}\ {memory_field}\ {indent0}}},\n\ @@ -246,22 +229,17 @@ impl Display for DisplayEnum<&'_ StoreOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent0 = self.indent; let indent1 = indent0.inc(); - let ident = DisplayIdent::camel(self.val); - let ptr_ty = self.val.kind.ptr_ty(self.val.ptr); - let value_ty = self.val.kind.value_ty(self.val.value); - let offset_field = self - .val - .kind - .offset_ty(self.val.ptr, self.val.offset16) - .map(|offset| Field::new(Ident::Offset, offset)) + let op = self.val; + let ident = DisplayIdent::camel(op); + let ptr_field = op.ptr_field(); + let offset_field = op + .offset_field() .map(|field| (indent1, field, ",\n")) .map(DisplayConcat) .display_maybe(); - let mem_field = self - .val - .mem0 - .not() - .then(|| Field::new(Ident::Memory, FieldTy::Memory)) + let value_field = op.value_field(); + let memory_field = op + .memory_field() .map(|field| (indent1, field, ",\n")) .map(DisplayConcat) .display_maybe(); @@ -269,10 +247,10 @@ impl Display for DisplayEnum<&'_ StoreOp> { f, "\ {indent0}{ident} {{\n\ - {indent1}ptr: {ptr_ty},\n\ + {indent1}{ptr_field},\n\ {offset_field}\ - {indent1}value: {value_ty},\n\ - {mem_field}\ + {indent1}{value_field},\n\ + {memory_field}\ {indent0}}},\n\ ", ) @@ -306,20 +284,18 @@ impl Display for DisplayEnum<&'_ TableGetOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent0 = self.indent; let indent1 = indent0.inc(); - let ident = DisplayIdent::camel(self.val); - let result_ty = FieldTy::Stack; - let index_ty = match self.val.index { - Input::Stack => FieldTy::Stack, - Input::Immediate => FieldTy::U32, - }; - let table_ty = FieldTy::Table; + let op = self.val; + let ident = DisplayIdent::camel(op); + let result_field = op.result_field(); + let index_field = op.index_field(); + let table_field = op.table_field(); write!( f, "\ {indent0}{ident} {{\n\ - {indent1}result: {result_ty},\n\ - {indent1}index: {index_ty},\n\ - {indent1}table: {table_ty},\n\ + {indent1}{result_field},\n\ + {indent1}{index_field},\n\ + {indent1}{table_field},\n\ {indent0}}},\n\ ", ) @@ -330,23 +306,18 @@ impl Display for DisplayEnum<&'_ TableSetOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent0 = self.indent; let indent1 = indent0.inc(); - let ident = DisplayIdent::camel(self.val); - let index_ty = match self.val.index { - Input::Stack => FieldTy::Stack, - Input::Immediate => FieldTy::U32, - }; - let value_ty = match self.val.value { - Input::Stack => FieldTy::Stack, - Input::Immediate => FieldTy::U64, - }; - let table_ty = FieldTy::Table; + let op = self.val; + let ident = DisplayIdent::camel(op); + let index_field = op.index_field(); + let value_field = op.value_field(); + let table_field = op.table_field(); write!( f, "\ {indent0}{ident} {{\n\ - {indent1}table: {table_ty},\n\ - {indent1}index: {index_ty},\n\ - {indent1}value: {value_ty},\n\ + {indent1}{table_field},\n\ + {indent1}{index_field},\n\ + {indent1}{value_field},\n\ {indent0}}},\n\ ", ) diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index c13783cb88..559373ded5 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -85,6 +85,14 @@ impl UnaryOp { pub fn new(kind: UnaryOpKind) -> Self { Self { kind } } + + pub fn result_field(&self) -> Field { + Field::new(Ident::Result, FieldTy::Stack) + } + + pub fn value_field(&self) -> Field { + Field::new(Ident::Value, FieldTy::Stack) + } } #[derive(Copy, Clone)] @@ -304,6 +312,24 @@ pub struct BinaryOp { pub rhs: Input, } +impl BinaryOp { + pub fn new(kind: BinaryOpKind, lhs: Input, rhs: Input) -> Self { + Self { kind, lhs, rhs } + } + + pub fn result_field(&self) -> Field { + Field::new(Ident::Result, FieldTy::Stack) + } + + pub fn lhs_field(&self) -> Field { + Field::new(Ident::Lhs, self.kind.lhs_field(self.lhs)) + } + + pub fn rhs_field(&self) -> Field { + Field::new(Ident::Rhs, self.kind.rhs_field(self.rhs)) + } +} + #[derive(Copy, Clone)] pub enum BinaryOpKind { // Compare operators. @@ -417,7 +443,7 @@ impl BinaryOpKind { Ident::from(ty) } - pub fn lhs_field(&self, input: Input) -> FieldTy { + fn lhs_field(&self, input: Input) -> FieldTy { match input { Input::Stack => FieldTy::Stack, Input::Immediate => match self { @@ -470,7 +496,7 @@ impl BinaryOpKind { } } - pub fn rhs_field(&self, input: Input) -> FieldTy { + fn rhs_field(&self, input: Input) -> FieldTy { match input { Input::Stack => FieldTy::Stack, Input::Immediate => match self { @@ -583,12 +609,6 @@ pub enum Commutativity { NonCommutative, } -impl BinaryOp { - pub fn new(kind: BinaryOpKind, lhs: Input, rhs: Input) -> Self { - Self { kind, lhs, rhs } - } -} - #[derive(Copy, Clone)] pub struct CmpBranchOp { pub cmp: CmpOpKind, @@ -600,6 +620,14 @@ impl CmpBranchOp { pub fn new(cmp: CmpOpKind, lhs: Input, rhs: Input) -> Self { Self { cmp, lhs, rhs } } + + pub fn lhs_field(&self) -> Field { + Field::new(Ident::Lhs, self.cmp.input_field(self.lhs)) + } + + pub fn rhs_field(&self) -> Field { + Field::new(Ident::Rhs, self.cmp.input_field(self.rhs)) + } } #[derive(Copy, Clone)] @@ -613,6 +641,26 @@ impl CmpSelectOp { pub fn new(cmp: CmpOpKind, lhs: Input, rhs: Input) -> Self { Self { cmp, lhs, rhs } } + + pub fn result_field(&self) -> Field { + Field::new(Ident::Result, FieldTy::Stack) + } + + pub fn lhs_field(&self) -> Field { + Field::new(Ident::Lhs, self.cmp.input_field(self.lhs)) + } + + pub fn rhs_field(&self) -> Field { + Field::new(Ident::Rhs, self.cmp.input_field(self.rhs)) + } + + pub fn val_true_field(&self) -> Field { + Field::new(Ident::ValTrue, FieldTy::Stack) + } + + pub fn val_false_field(&self) -> Field { + Field::new(Ident::ValFalse, FieldTy::Stack) + } } #[derive(Copy, Clone, PartialEq, Eq)] @@ -800,7 +848,7 @@ impl CmpOpKind { } } - pub fn input_field(&self, input: Input) -> FieldTy { + fn input_field(&self, input: Input) -> FieldTy { match input { Input::Stack => FieldTy::Stack, Input::Immediate => match self { @@ -930,6 +978,36 @@ impl LoadOp { offset16, } } + + pub fn result_field(&self) -> Field { + Field::new(Ident::Result, FieldTy::Stack) + } + + pub fn ptr_field(&self) -> Field { + let ptr_ty = match self.ptr { + Input::Stack => FieldTy::Stack, + Input::Immediate => FieldTy::Address, + }; + Field::new(Ident::Ptr, ptr_ty) + } + + pub fn offset_field(&self) -> Option { + let offset_ty = match self.ptr { + Input::Stack => match self.offset16 { + true => FieldTy::Offset16, + false => FieldTy::U64, + }, + Input::Immediate => return None, + }; + Some(Field::new(Ident::Offset, offset_ty)) + } + + pub fn memory_field(&self) -> Option { + if self.mem0 { + return None; + } + Some(Field::new(Ident::Memory, FieldTy::Memory)) + } } #[derive(Copy, Clone)] @@ -1008,6 +1086,37 @@ impl StoreOp { offset16, } } + + pub fn ptr_field(&self) -> Field { + let ptr_ty = match self.ptr { + Input::Stack => FieldTy::Stack, + Input::Immediate => FieldTy::Address, + }; + Field::new(Ident::Ptr, ptr_ty) + } + + pub fn offset_field(&self) -> Option { + let offset_ty = match self.ptr { + Input::Stack => match self.offset16 { + true => FieldTy::Offset16, + false => FieldTy::U64, + }, + Input::Immediate => return None, + }; + Some(Field::new(Ident::Offset, offset_ty)) + } + + pub fn value_field(&self) -> Field { + let value_ty = self.kind.value_ty(self.value); + Field::new(Ident::Value, value_ty) + } + + pub fn memory_field(&self) -> Option { + if self.mem0 { + return None; + } + Some(Field::new(Ident::Memory, FieldTy::Memory)) + } } #[derive(Copy, Clone)] @@ -1049,24 +1158,7 @@ impl StoreOpKind { } } - pub fn ptr_ty(&self, ptr: Input) -> FieldTy { - match ptr { - Input::Stack => FieldTy::Stack, - Input::Immediate => FieldTy::Address, - } - } - - pub fn offset_ty(&self, ptr: Input, offset16: bool) -> Option { - match ptr { - Input::Stack => match offset16 { - true => Some(FieldTy::Offset16), - false => Some(FieldTy::U64), - }, - Input::Immediate => None, - } - } - - pub fn value_ty(&self, input: Input) -> FieldTy { + fn value_ty(&self, input: Input) -> FieldTy { match input { Input::Stack => FieldTy::Stack, Input::Immediate => match self { @@ -1092,6 +1184,22 @@ impl TableGetOp { pub fn new(index: Input) -> Self { Self { index } } + + pub fn result_field(&self) -> Field { + Field::new(Ident::Result, FieldTy::Stack) + } + + pub fn index_field(&self) -> Field { + let index_ty = match self.index { + Input::Stack => FieldTy::Stack, + Input::Immediate => FieldTy::U32, + }; + Field::new(Ident::Index, index_ty) + } + + pub fn table_field(&self) -> Field { + Field::new(Ident::Table, FieldTy::Table) + } } #[derive(Copy, Clone)] @@ -1106,6 +1214,26 @@ impl TableSetOp { pub fn new(index: Input, value: Input) -> Self { Self { index, value } } + + pub fn index_field(&self) -> Field { + let index_ty = match self.index { + Input::Stack => FieldTy::Stack, + Input::Immediate => FieldTy::U32, + }; + Field::new(Ident::Index, index_ty) + } + + pub fn value_field(&self) -> Field { + let value_ty = match self.value { + Input::Stack => FieldTy::Stack, + Input::Immediate => FieldTy::U64, + }; + Field::new(Ident::Value, value_ty) + } + + pub fn table_field(&self) -> Field { + Field::new(Ident::Table, FieldTy::Table) + } } #[derive(Copy, Clone)] diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index bbe709580f..e2668a4c72 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -241,4 +241,7 @@ define_ident!( LhsHi: lhs_hi, RhsLo: rhs_lo, RhsHi: rhs_hi, + Ptr: ptr, + ValTrue: val_true, + ValFalse: val_false, ); From 8a1f73a2eae8bfb7e81c5ebb10efdca4bd3fc5c8 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Mon, 25 Aug 2025 14:54:27 +0200 Subject: [PATCH 082/186] move Indent to utils submodule --- crates/ir2/build/display/mod.rs | 19 +------------------ crates/ir2/build/display/utils.rs | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/crates/ir2/build/display/mod.rs b/crates/ir2/build/display/mod.rs index 9e2d6de1c3..355c131b07 100644 --- a/crates/ir2/build/display/mod.rs +++ b/crates/ir2/build/display/mod.rs @@ -1,6 +1,7 @@ mod ident; mod utils; +pub use self::utils::Indent; use self::{ ident::DisplayIdent, utils::{DisplayConcat, DisplaySequence, IntoDisplayMaybe as _}, @@ -23,24 +24,6 @@ use crate::build::{ }; use core::fmt::{self, Display}; -#[derive(Copy, Clone, Default)] -pub struct Indent(usize); - -impl Indent { - pub fn inc(self) -> Self { - Self(self.0 + 1) - } -} - -impl Display for Indent { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for _ in 0..self.0 { - write!(f, " ")?; - } - Ok(()) - } -} - pub struct DisplayEnum { pub val: T, pub indent: Indent, diff --git a/crates/ir2/build/display/utils.rs b/crates/ir2/build/display/utils.rs index c9c9e48629..9c5bf350f2 100644 --- a/crates/ir2/build/display/utils.rs +++ b/crates/ir2/build/display/utils.rs @@ -1,5 +1,23 @@ use core::fmt::{self, Display}; +#[derive(Copy, Clone, Default)] +pub struct Indent(usize); + +impl Indent { + pub fn inc(self) -> Self { + Self(self.0 + 1) + } +} + +impl Display for Indent { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for _ in 0..self.0 { + write!(f, " ")?; + } + Ok(()) + } +} + pub struct DisplayConcat(pub T); impl Display for DisplayConcat<(T0, T1)> From baa1cec56429d8787e8343092ec18c920d99be3a Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Mon, 25 Aug 2025 20:26:02 +0200 Subject: [PATCH 083/186] rename DisplayEnum -> DisplayOp --- crates/ir2/build/display/mod.rs | 34 ++++++++++++++++----------------- crates/ir2/build/mod.rs | 4 ++-- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/crates/ir2/build/display/mod.rs b/crates/ir2/build/display/mod.rs index 355c131b07..e9ccf4e8be 100644 --- a/crates/ir2/build/display/mod.rs +++ b/crates/ir2/build/display/mod.rs @@ -24,32 +24,32 @@ use crate::build::{ }; use core::fmt::{self, Display}; -pub struct DisplayEnum { +pub struct DisplayOp { pub val: T, pub indent: Indent, } -impl DisplayEnum { +impl DisplayOp { pub fn new(val: T, indent: Indent) -> Self { Self { val, indent } } - pub fn scoped(&self, val: V) -> DisplayEnum { - DisplayEnum { + pub fn scoped(&self, val: V) -> DisplayOp { + DisplayOp { val, indent: self.indent.inc(), } } - pub fn map(&self, val: V) -> DisplayEnum { - DisplayEnum { + pub fn map(&self, val: V) -> DisplayOp { + DisplayOp { val, indent: self.indent, } } } -impl Display for DisplayEnum { +impl Display for DisplayOp { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent = self.indent; let variants = DisplaySequence(self.val.ops.iter().map(|op| self.scoped(op))); @@ -65,7 +65,7 @@ impl Display for DisplayEnum { } } -impl Display for DisplayEnum<&'_ Op> { +impl Display for DisplayOp<&'_ Op> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.val { Op::Unary(op) => self.map(op).fmt(f), @@ -86,7 +86,7 @@ impl Display for DisplayEnum<&'_ Op> { } } -impl Display for DisplayEnum<&'_ UnaryOp> { +impl Display for DisplayOp<&'_ UnaryOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent0 = self.indent; let indent1 = indent0.inc(); @@ -106,7 +106,7 @@ impl Display for DisplayEnum<&'_ UnaryOp> { } } -impl Display for DisplayEnum<&'_ BinaryOp> { +impl Display for DisplayOp<&'_ BinaryOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent0 = self.indent; let indent1 = indent0.inc(); @@ -128,7 +128,7 @@ impl Display for DisplayEnum<&'_ BinaryOp> { } } -impl Display for DisplayEnum<&'_ CmpBranchOp> { +impl Display for DisplayOp<&'_ CmpBranchOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent0 = self.indent; let indent1 = indent0.inc(); @@ -150,7 +150,7 @@ impl Display for DisplayEnum<&'_ CmpBranchOp> { } } -impl Display for DisplayEnum<&'_ CmpSelectOp> { +impl Display for DisplayOp<&'_ CmpSelectOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent0 = self.indent; let indent1 = indent0.inc(); @@ -176,7 +176,7 @@ impl Display for DisplayEnum<&'_ CmpSelectOp> { } } -impl Display for DisplayEnum<&'_ LoadOp> { +impl Display for DisplayOp<&'_ LoadOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent0 = self.indent; let indent1 = indent0.inc(); @@ -208,7 +208,7 @@ impl Display for DisplayEnum<&'_ LoadOp> { } } -impl Display for DisplayEnum<&'_ StoreOp> { +impl Display for DisplayOp<&'_ StoreOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent0 = self.indent; let indent1 = indent0.inc(); @@ -240,7 +240,7 @@ impl Display for DisplayEnum<&'_ StoreOp> { } } -impl Display for DisplayEnum<&'_ GenericOp> { +impl Display for DisplayOp<&'_ GenericOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent0 = self.indent; let indent1 = indent0.inc(); @@ -263,7 +263,7 @@ impl Display for DisplayEnum<&'_ GenericOp> { } } -impl Display for DisplayEnum<&'_ TableGetOp> { +impl Display for DisplayOp<&'_ TableGetOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent0 = self.indent; let indent1 = indent0.inc(); @@ -285,7 +285,7 @@ impl Display for DisplayEnum<&'_ TableGetOp> { } } -impl Display for DisplayEnum<&'_ TableSetOp> { +impl Display for DisplayOp<&'_ TableSetOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent0 = self.indent; let indent1 = indent0.inc(); diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index 539013384a..93b54e19b5 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -4,7 +4,7 @@ mod op; pub mod token; use self::{ - display::{DisplayEnum, Indent}, + display::{DisplayOp, Indent}, isa::Isa, op::Op, token::{CamelCase, Ident, SnakeCase}, @@ -46,7 +46,7 @@ pub fn generate_code(out_dir: &Path) -> Result<(), Error> { write!( &mut contents, "{}", - >::new(isa, Indent::default()) + >::new(isa, Indent::default()) )?; std::println!("out_dir = {out_dir:?}"); fs::create_dir_all(out_dir)?; From 3f6cb21bea69c6da61450d8000d3889758300f8e Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Mon, 25 Aug 2025 20:28:02 +0200 Subject: [PATCH 084/186] move DisplayOp impls into its own submodule --- crates/ir2/build/display/mod.rs | 307 +------------------------------- crates/ir2/build/display/op.rs | 305 +++++++++++++++++++++++++++++++ 2 files changed, 307 insertions(+), 305 deletions(-) create mode 100644 crates/ir2/build/display/op.rs diff --git a/crates/ir2/build/display/mod.rs b/crates/ir2/build/display/mod.rs index e9ccf4e8be..b53a984d38 100644 --- a/crates/ir2/build/display/mod.rs +++ b/crates/ir2/build/display/mod.rs @@ -1,308 +1,5 @@ mod ident; +mod op; mod utils; -pub use self::utils::Indent; -use self::{ - ident::DisplayIdent, - utils::{DisplayConcat, DisplaySequence, IntoDisplayMaybe as _}, -}; -use crate::build::{ - isa::Isa, - op::{ - BinaryOp, - CmpBranchOp, - CmpSelectOp, - FieldTy, - GenericOp, - LoadOp, - Op, - StoreOp, - TableGetOp, - TableSetOp, - UnaryOp, - }, -}; -use core::fmt::{self, Display}; - -pub struct DisplayOp { - pub val: T, - pub indent: Indent, -} - -impl DisplayOp { - pub fn new(val: T, indent: Indent) -> Self { - Self { val, indent } - } - - pub fn scoped(&self, val: V) -> DisplayOp { - DisplayOp { - val, - indent: self.indent.inc(), - } - } - - pub fn map(&self, val: V) -> DisplayOp { - DisplayOp { - val, - indent: self.indent, - } - } -} - -impl Display for DisplayOp { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let indent = self.indent; - let variants = DisplaySequence(self.val.ops.iter().map(|op| self.scoped(op))); - write!( - f, - "\ - {indent}#[allow(non_camel_case_types)] - {indent}pub enum Op {{\n\ - {variants}\ - {indent}}}\n\ - " - ) - } -} - -impl Display for DisplayOp<&'_ Op> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.val { - Op::Unary(op) => self.map(op).fmt(f), - Op::Binary(op) => self.map(op).fmt(f), - Op::CmpBranch(op) => self.map(op).fmt(f), - Op::CmpSelect(op) => self.map(op).fmt(f), - Op::Load(op) => self.map(op).fmt(f), - Op::Store(op) => self.map(op).fmt(f), - Op::TableGet(op) => self.map(op).fmt(f), - Op::TableSet(op) => self.map(op).fmt(f), - Op::Generic0(op) => self.map(op).fmt(f), - Op::Generic1(op) => self.map(op).fmt(f), - Op::Generic2(op) => self.map(op).fmt(f), - Op::Generic3(op) => self.map(op).fmt(f), - Op::Generic4(op) => self.map(op).fmt(f), - Op::Generic5(op) => self.map(op).fmt(f), - } - } -} - -impl Display for DisplayOp<&'_ UnaryOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let indent0 = self.indent; - let indent1 = indent0.inc(); - let op = self.val; - let ident = DisplayIdent::camel(op); - let result_field = op.result_field(); - let value_field = op.value_field(); - write!( - f, - "\ - {indent0}{ident} {{\n\ - {indent1}{result_field},\n\ - {indent1}{value_field},\n\ - {indent0}}},\n\ - ", - ) - } -} - -impl Display for DisplayOp<&'_ BinaryOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let indent0 = self.indent; - let indent1 = indent0.inc(); - let op = self.val; - let ident = DisplayIdent::camel(op); - let result_field = op.result_field(); - let lhs_field = op.lhs_field(); - let rhs_field = op.rhs_field(); - write!( - f, - "\ - {indent0}{ident} {{\n\ - {indent1}{result_field},\n\ - {indent1}{lhs_field},\n\ - {indent1}{rhs_field},\n\ - {indent0}}},\n\ - ", - ) - } -} - -impl Display for DisplayOp<&'_ CmpBranchOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let indent0 = self.indent; - let indent1 = indent0.inc(); - let op = self.val; - let ident = DisplayIdent::camel(op); - let lhs_field = op.lhs_field(); - let rhs_field = op.rhs_field(); - let offset_ty = FieldTy::BranchOffset; - write!( - f, - "\ - {indent0}{ident} {{\n\ - {indent1}offset: {offset_ty},\n\ - {indent1}{lhs_field},\n\ - {indent1}{rhs_field},\n\ - {indent0}}},\n\ - ", - ) - } -} - -impl Display for DisplayOp<&'_ CmpSelectOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let indent0 = self.indent; - let indent1 = indent0.inc(); - let op = self.val; - let ident = DisplayIdent::camel(op); - let result_field = op.result_field(); - let lhs_field = op.lhs_field(); - let rhs_field = op.rhs_field(); - let val_true_field = op.val_true_field(); - let val_false_field = op.val_false_field(); - write!( - f, - "\ - {indent0}{ident} {{\n\ - {indent1}{result_field},\n\ - {indent1}{lhs_field},\n\ - {indent1}{rhs_field},\n\ - {indent1}{val_true_field},\n\ - {indent1}{val_false_field},\n\ - {indent0}}},\n\ - ", - ) - } -} - -impl Display for DisplayOp<&'_ LoadOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let indent0 = self.indent; - let indent1 = indent0.inc(); - let op = self.val; - let ident = DisplayIdent::camel(op); - let result_field = op.result_field(); - let ptr_field = op.ptr_field(); - let offset_field = op - .offset_field() - .map(|field| (indent1, field, ",\n")) - .map(DisplayConcat) - .display_maybe(); - let memory_field = op - .memory_field() - .map(|field| (indent1, field, ",\n")) - .map(DisplayConcat) - .display_maybe(); - write!( - f, - "\ - {indent0}{ident} {{\n\ - {indent1}{result_field},\n\ - {indent1}{ptr_field},\n\ - {offset_field}\ - {memory_field}\ - {indent0}}},\n\ - ", - ) - } -} - -impl Display for DisplayOp<&'_ StoreOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let indent0 = self.indent; - let indent1 = indent0.inc(); - let op = self.val; - let ident = DisplayIdent::camel(op); - let ptr_field = op.ptr_field(); - let offset_field = op - .offset_field() - .map(|field| (indent1, field, ",\n")) - .map(DisplayConcat) - .display_maybe(); - let value_field = op.value_field(); - let memory_field = op - .memory_field() - .map(|field| (indent1, field, ",\n")) - .map(DisplayConcat) - .display_maybe(); - write!( - f, - "\ - {indent0}{ident} {{\n\ - {indent1}{ptr_field},\n\ - {offset_field}\ - {indent1}{value_field},\n\ - {memory_field}\ - {indent0}}},\n\ - ", - ) - } -} - -impl Display for DisplayOp<&'_ GenericOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let indent0 = self.indent; - let indent1 = indent0.inc(); - let ident = DisplayIdent::camel(self.val); - let fields = DisplaySequence( - self.val - .fields - .into_iter() - .map(move |field| (indent1, field, ",\n")) - .map(DisplayConcat), - ); - write!( - f, - "\ - {indent0}{ident} {{\n\ - {fields}\ - {indent0}}},\n\ - ", - ) - } -} - -impl Display for DisplayOp<&'_ TableGetOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let indent0 = self.indent; - let indent1 = indent0.inc(); - let op = self.val; - let ident = DisplayIdent::camel(op); - let result_field = op.result_field(); - let index_field = op.index_field(); - let table_field = op.table_field(); - write!( - f, - "\ - {indent0}{ident} {{\n\ - {indent1}{result_field},\n\ - {indent1}{index_field},\n\ - {indent1}{table_field},\n\ - {indent0}}},\n\ - ", - ) - } -} - -impl Display for DisplayOp<&'_ TableSetOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let indent0 = self.indent; - let indent1 = indent0.inc(); - let op = self.val; - let ident = DisplayIdent::camel(op); - let index_field = op.index_field(); - let value_field = op.value_field(); - let table_field = op.table_field(); - write!( - f, - "\ - {indent0}{ident} {{\n\ - {indent1}{table_field},\n\ - {indent1}{index_field},\n\ - {indent1}{value_field},\n\ - {indent0}}},\n\ - ", - ) - } -} +pub use self::{op::DisplayOp, utils::Indent}; diff --git a/crates/ir2/build/display/op.rs b/crates/ir2/build/display/op.rs new file mode 100644 index 0000000000..741d38eb55 --- /dev/null +++ b/crates/ir2/build/display/op.rs @@ -0,0 +1,305 @@ +use crate::build::{ + display::{ + ident::DisplayIdent, + utils::{DisplayConcat, DisplaySequence, IntoDisplayMaybe as _}, + Indent, + }, + isa::Isa, + op::{ + BinaryOp, + CmpBranchOp, + CmpSelectOp, + FieldTy, + GenericOp, + LoadOp, + Op, + StoreOp, + TableGetOp, + TableSetOp, + UnaryOp, + }, +}; +use core::fmt::{self, Display}; + +pub struct DisplayOp { + pub val: T, + pub indent: Indent, +} + +impl DisplayOp { + pub fn new(val: T, indent: Indent) -> Self { + Self { val, indent } + } + + pub fn scoped(&self, val: V) -> DisplayOp { + DisplayOp { + val, + indent: self.indent.inc(), + } + } + + pub fn map(&self, val: V) -> DisplayOp { + DisplayOp { + val, + indent: self.indent, + } + } +} + +impl Display for DisplayOp { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let indent = self.indent; + let variants = DisplaySequence(self.val.ops.iter().map(|op| self.scoped(op))); + write!( + f, + "\ + {indent}#[allow(non_camel_case_types)] + {indent}pub enum Op {{\n\ + {variants}\ + {indent}}}\n\ + " + ) + } +} + +impl Display for DisplayOp<&'_ Op> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.val { + Op::Unary(op) => self.map(op).fmt(f), + Op::Binary(op) => self.map(op).fmt(f), + Op::CmpBranch(op) => self.map(op).fmt(f), + Op::CmpSelect(op) => self.map(op).fmt(f), + Op::Load(op) => self.map(op).fmt(f), + Op::Store(op) => self.map(op).fmt(f), + Op::TableGet(op) => self.map(op).fmt(f), + Op::TableSet(op) => self.map(op).fmt(f), + Op::Generic0(op) => self.map(op).fmt(f), + Op::Generic1(op) => self.map(op).fmt(f), + Op::Generic2(op) => self.map(op).fmt(f), + Op::Generic3(op) => self.map(op).fmt(f), + Op::Generic4(op) => self.map(op).fmt(f), + Op::Generic5(op) => self.map(op).fmt(f), + } + } +} + +impl Display for DisplayOp<&'_ UnaryOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let indent0 = self.indent; + let indent1 = indent0.inc(); + let op = self.val; + let ident = DisplayIdent::camel(op); + let result_field = op.result_field(); + let value_field = op.value_field(); + write!( + f, + "\ + {indent0}{ident} {{\n\ + {indent1}{result_field},\n\ + {indent1}{value_field},\n\ + {indent0}}},\n\ + ", + ) + } +} + +impl Display for DisplayOp<&'_ BinaryOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let indent0 = self.indent; + let indent1 = indent0.inc(); + let op = self.val; + let ident = DisplayIdent::camel(op); + let result_field = op.result_field(); + let lhs_field = op.lhs_field(); + let rhs_field = op.rhs_field(); + write!( + f, + "\ + {indent0}{ident} {{\n\ + {indent1}{result_field},\n\ + {indent1}{lhs_field},\n\ + {indent1}{rhs_field},\n\ + {indent0}}},\n\ + ", + ) + } +} + +impl Display for DisplayOp<&'_ CmpBranchOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let indent0 = self.indent; + let indent1 = indent0.inc(); + let op = self.val; + let ident = DisplayIdent::camel(op); + let lhs_field = op.lhs_field(); + let rhs_field = op.rhs_field(); + let offset_ty = FieldTy::BranchOffset; + write!( + f, + "\ + {indent0}{ident} {{\n\ + {indent1}offset: {offset_ty},\n\ + {indent1}{lhs_field},\n\ + {indent1}{rhs_field},\n\ + {indent0}}},\n\ + ", + ) + } +} + +impl Display for DisplayOp<&'_ CmpSelectOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let indent0 = self.indent; + let indent1 = indent0.inc(); + let op = self.val; + let ident = DisplayIdent::camel(op); + let result_field = op.result_field(); + let lhs_field = op.lhs_field(); + let rhs_field = op.rhs_field(); + let val_true_field = op.val_true_field(); + let val_false_field = op.val_false_field(); + write!( + f, + "\ + {indent0}{ident} {{\n\ + {indent1}{result_field},\n\ + {indent1}{lhs_field},\n\ + {indent1}{rhs_field},\n\ + {indent1}{val_true_field},\n\ + {indent1}{val_false_field},\n\ + {indent0}}},\n\ + ", + ) + } +} + +impl Display for DisplayOp<&'_ LoadOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let indent0 = self.indent; + let indent1 = indent0.inc(); + let op = self.val; + let ident = DisplayIdent::camel(op); + let result_field = op.result_field(); + let ptr_field = op.ptr_field(); + let offset_field = op + .offset_field() + .map(|field| (indent1, field, ",\n")) + .map(DisplayConcat) + .display_maybe(); + let memory_field = op + .memory_field() + .map(|field| (indent1, field, ",\n")) + .map(DisplayConcat) + .display_maybe(); + write!( + f, + "\ + {indent0}{ident} {{\n\ + {indent1}{result_field},\n\ + {indent1}{ptr_field},\n\ + {offset_field}\ + {memory_field}\ + {indent0}}},\n\ + ", + ) + } +} + +impl Display for DisplayOp<&'_ StoreOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let indent0 = self.indent; + let indent1 = indent0.inc(); + let op = self.val; + let ident = DisplayIdent::camel(op); + let ptr_field = op.ptr_field(); + let offset_field = op + .offset_field() + .map(|field| (indent1, field, ",\n")) + .map(DisplayConcat) + .display_maybe(); + let value_field = op.value_field(); + let memory_field = op + .memory_field() + .map(|field| (indent1, field, ",\n")) + .map(DisplayConcat) + .display_maybe(); + write!( + f, + "\ + {indent0}{ident} {{\n\ + {indent1}{ptr_field},\n\ + {offset_field}\ + {indent1}{value_field},\n\ + {memory_field}\ + {indent0}}},\n\ + ", + ) + } +} + +impl Display for DisplayOp<&'_ GenericOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let indent0 = self.indent; + let indent1 = indent0.inc(); + let ident = DisplayIdent::camel(self.val); + let fields = DisplaySequence( + self.val + .fields + .into_iter() + .map(move |field| (indent1, field, ",\n")) + .map(DisplayConcat), + ); + write!( + f, + "\ + {indent0}{ident} {{\n\ + {fields}\ + {indent0}}},\n\ + ", + ) + } +} + +impl Display for DisplayOp<&'_ TableGetOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let indent0 = self.indent; + let indent1 = indent0.inc(); + let op = self.val; + let ident = DisplayIdent::camel(op); + let result_field = op.result_field(); + let index_field = op.index_field(); + let table_field = op.table_field(); + write!( + f, + "\ + {indent0}{ident} {{\n\ + {indent1}{result_field},\n\ + {indent1}{index_field},\n\ + {indent1}{table_field},\n\ + {indent0}}},\n\ + ", + ) + } +} + +impl Display for DisplayOp<&'_ TableSetOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let indent0 = self.indent; + let indent1 = indent0.inc(); + let op = self.val; + let ident = DisplayIdent::camel(op); + let index_field = op.index_field(); + let value_field = op.value_field(); + let table_field = op.table_field(); + write!( + f, + "\ + {indent0}{ident} {{\n\ + {indent1}{table_field},\n\ + {indent1}{index_field},\n\ + {indent1}{value_field},\n\ + {indent0}}},\n\ + ", + ) + } +} From 62c0c4387488c7c1da6786f7e047cb45119b48ef Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Mon, 25 Aug 2025 21:18:43 +0200 Subject: [PATCH 085/186] fix GlobalSet ops fields --- crates/ir2/build/isa.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index f4fc07393d..f2b29fa97f 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -559,22 +559,22 @@ fn add_global_ops(isa: &mut Isa) { Op::from(GenericOp::new( Ident::GlobalSet, [ - Field::new(Ident::Result, FieldTy::Stack), Field::new(Ident::Global, FieldTy::Global), + Field::new(Ident::Value, FieldTy::Stack), ], )), Op::from(GenericOp::new( Ident::GlobalSet32, [ - Field::new(Ident::Result, FieldTy::U32), Field::new(Ident::Global, FieldTy::Global), + Field::new(Ident::Value, FieldTy::U32), ], )), Op::from(GenericOp::new( Ident::GlobalSet64, [ - Field::new(Ident::Result, FieldTy::U64), Field::new(Ident::Global, FieldTy::Global), + Field::new(Ident::Value, FieldTy::U64), ], )), ]; From 01140edc5832e0304999768ec1dd60450b6ea73e Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Mon, 25 Aug 2025 21:19:38 +0200 Subject: [PATCH 086/186] take reference for DisplayOp --- crates/ir2/build/display/op.rs | 2 +- crates/ir2/build/mod.rs | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/crates/ir2/build/display/op.rs b/crates/ir2/build/display/op.rs index 741d38eb55..e99e581dda 100644 --- a/crates/ir2/build/display/op.rs +++ b/crates/ir2/build/display/op.rs @@ -46,7 +46,7 @@ impl DisplayOp { } } -impl Display for DisplayOp { +impl Display for DisplayOp<&'_ Isa> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent = self.indent; let variants = DisplaySequence(self.val.ops.iter().map(|op| self.scoped(op))); diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index 93b54e19b5..5a77320973 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -45,8 +45,10 @@ pub fn generate_code(out_dir: &Path) -> Result<(), Error> { let isa = isa::wasmi_isa(); write!( &mut contents, - "{}", - >::new(isa, Indent::default()) + "\ + {}\n\ + ", + DisplayOp::new(&isa, Indent::default()), )?; std::println!("out_dir = {out_dir:?}"); fs::create_dir_all(out_dir)?; From eacc2ba6800c5c20cf1936a07aeb52795ac85410 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Mon, 25 Aug 2025 21:19:49 +0200 Subject: [PATCH 087/186] remove unused import --- crates/ir2/build/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index 5a77320973..d16c508be2 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -5,7 +5,6 @@ pub mod token; use self::{ display::{DisplayOp, Indent}, - isa::Isa, op::Op, token::{CamelCase, Ident, SnakeCase}, }; From dc46fcab3ebac90ec4aa1a37a9f1463bedb70b6d Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Mon, 25 Aug 2025 21:19:59 +0200 Subject: [PATCH 088/186] add DisplayResultMut codegen --- crates/ir2/build/display/mod.rs | 3 +- crates/ir2/build/display/result_mut.rs | 150 +++++++++++++++++++++++++ crates/ir2/build/display/utils.rs | 4 + crates/ir2/build/mod.rs | 3 + crates/ir2/build/op.rs | 6 + 5 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 crates/ir2/build/display/result_mut.rs diff --git a/crates/ir2/build/display/mod.rs b/crates/ir2/build/display/mod.rs index b53a984d38..ac01bfa0e2 100644 --- a/crates/ir2/build/display/mod.rs +++ b/crates/ir2/build/display/mod.rs @@ -1,5 +1,6 @@ mod ident; mod op; +mod result_mut; mod utils; -pub use self::{op::DisplayOp, utils::Indent}; +pub use self::{op::DisplayOp, result_mut::DisplayResultMut, utils::Indent}; diff --git a/crates/ir2/build/display/result_mut.rs b/crates/ir2/build/display/result_mut.rs new file mode 100644 index 0000000000..9f84670b63 --- /dev/null +++ b/crates/ir2/build/display/result_mut.rs @@ -0,0 +1,150 @@ +use crate::build::{ + display::{ident::DisplayIdent, utils::DisplaySequence, Indent}, + isa::Isa, + op::{ + BinaryOp, + CmpBranchOp, + CmpSelectOp, + GenericOp, + LoadOp, + Op, + StoreOp, + TableGetOp, + TableSetOp, + UnaryOp, + }, +}; +use core::fmt::{self, Display}; + +pub struct DisplayResultMut { + pub value: T, + pub indent: Indent, +} + +impl DisplayResultMut { + pub fn new(value: T, indent: Indent) -> Self { + Self { value, indent } + } + + pub fn map(&self, value: V) -> DisplayResultMut { + DisplayResultMut { + value, + indent: self.indent, + } + } +} + +impl<'a, T> DisplayResultMut<&'a T> { + fn display_match_arm(&self, f: &mut fmt::Formatter) -> fmt::Result + where + DisplayIdent<&'a T>: Display, + { + let indent = self.indent; + let ident = DisplayIdent::camel(self.value); + writeln!(f, "{indent}Self::{ident} {{ result, .. }} => result,") + } +} + +impl Display for DisplayResultMut<&'_ Isa> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let indent = self.indent; + let variants = DisplaySequence( + self.value + .ops + .iter() + .map(|op| DisplayResultMut::new(op, indent.inc_by(3))), + ); + write!( + f, + "\ + {indent}impl Op {{\n\ + {indent} pub fn result_mut(&mut self) -> Option<&mut Stack> {{\n\ + {indent} let res = match self {{\n\ + {variants}\ + {indent} _ => return None,\n\ + {indent} }};\n\ + {indent} Some(res)\n\ + {indent} }}\n\ + {indent}}}\n\ + " + ) + } +} + +impl Display for DisplayResultMut<&'_ Op> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.value { + Op::Unary(op) => self.map(op).fmt(f), + Op::Binary(op) => self.map(op).fmt(f), + Op::CmpBranch(op) => self.map(op).fmt(f), + Op::CmpSelect(op) => self.map(op).fmt(f), + Op::Load(op) => self.map(op).fmt(f), + Op::Store(op) => self.map(op).fmt(f), + Op::TableGet(op) => self.map(op).fmt(f), + Op::TableSet(op) => self.map(op).fmt(f), + Op::Generic0(op) => self.map(op).fmt(f), + Op::Generic1(op) => self.map(op).fmt(f), + Op::Generic2(op) => self.map(op).fmt(f), + Op::Generic3(op) => self.map(op).fmt(f), + Op::Generic4(op) => self.map(op).fmt(f), + Op::Generic5(op) => self.map(op).fmt(f), + } + } +} + +impl Display for DisplayResultMut<&'_ UnaryOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.display_match_arm(f) + } +} + +impl Display for DisplayResultMut<&'_ BinaryOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.display_match_arm(f) + } +} + +impl Display for DisplayResultMut<&'_ CmpBranchOp> { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + Ok(()) + } +} + +impl Display for DisplayResultMut<&'_ CmpSelectOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.display_match_arm(f) + } +} + +impl Display for DisplayResultMut<&'_ LoadOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.display_match_arm(f) + } +} + +impl Display for DisplayResultMut<&'_ StoreOp> { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + Ok(()) + } +} + +impl Display for DisplayResultMut<&'_ TableGetOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.display_match_arm(f) + } +} + +impl Display for DisplayResultMut<&'_ TableSetOp> { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + Ok(()) + } +} + +impl Display for DisplayResultMut<&'_ GenericOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if !self.value.has_result() { + return Ok(()); + } + self.display_match_arm(f) + } +} diff --git a/crates/ir2/build/display/utils.rs b/crates/ir2/build/display/utils.rs index 9c5bf350f2..875a262882 100644 --- a/crates/ir2/build/display/utils.rs +++ b/crates/ir2/build/display/utils.rs @@ -7,6 +7,10 @@ impl Indent { pub fn inc(self) -> Self { Self(self.0 + 1) } + + pub fn inc_by(self, delta: usize) -> Self { + Self(self.0 + delta) + } } impl Display for Indent { diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index d16c508be2..d80bb70622 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -8,6 +8,7 @@ use self::{ op::Op, token::{CamelCase, Ident, SnakeCase}, }; +use crate::build::display::DisplayResultMut; use core::fmt::{self, Display, Error as FmtError, Write as _}; use std::{fs, io::Error as IoError, path::Path}; @@ -46,8 +47,10 @@ pub fn generate_code(out_dir: &Path) -> Result<(), Error> { &mut contents, "\ {}\n\ + {}\n\ ", DisplayOp::new(&isa, Indent::default()), + DisplayResultMut::new(&isa, Indent::default()), )?; std::println!("out_dir = {out_dir:?}"); fs::create_dir_all(out_dir)?; diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 559373ded5..83393af893 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -74,6 +74,12 @@ impl GenericOp { pub fn new(ident: Ident, fields: [Field; N]) -> Self { Self { ident, fields } } + + pub fn has_result(&self) -> bool { + self.fields + .iter() + .any(|field| matches!(field.ident, Ident::Result)) + } } #[derive(Copy, Clone)] From 869a90df411e6d25cace66b441fab70bd1312742 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Tue, 26 Aug 2025 09:51:39 +0200 Subject: [PATCH 089/186] add fields methods to all ops --- crates/ir2/build/op.rs | 52 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 83393af893..08c53980fa 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -99,6 +99,10 @@ impl UnaryOp { pub fn value_field(&self) -> Field { Field::new(Ident::Value, FieldTy::Stack) } + + pub fn fields(&self) -> [Field; 2] { + [self.result_field(), self.value_field()] + } } #[derive(Copy, Clone)] @@ -334,6 +338,10 @@ impl BinaryOp { pub fn rhs_field(&self) -> Field { Field::new(Ident::Rhs, self.kind.rhs_field(self.rhs)) } + + pub fn fields(&self) -> [Field; 3] { + [self.result_field(), self.lhs_field(), self.rhs_field()] + } } #[derive(Copy, Clone)] @@ -634,6 +642,14 @@ impl CmpBranchOp { pub fn rhs_field(&self) -> Field { Field::new(Ident::Rhs, self.cmp.input_field(self.rhs)) } + + pub fn offset_field(&self) -> Field { + Field::new(Ident::Offset, FieldTy::BranchOffset) + } + + pub fn fields(&self) -> [Field; 3] { + [self.lhs_field(), self.rhs_field(), self.offset_field()] + } } #[derive(Copy, Clone)] @@ -667,6 +683,16 @@ impl CmpSelectOp { pub fn val_false_field(&self) -> Field { Field::new(Ident::ValFalse, FieldTy::Stack) } + + pub fn fields(&self) -> [Field; 5] { + [ + self.result_field(), + self.lhs_field(), + self.rhs_field(), + self.val_true_field(), + self.val_false_field(), + ] + } } #[derive(Copy, Clone, PartialEq, Eq)] @@ -1014,6 +1040,15 @@ impl LoadOp { } Some(Field::new(Ident::Memory, FieldTy::Memory)) } + + pub fn fields(&self) -> [Option; 4] { + [ + Some(self.result_field()), + Some(self.ptr_field()), + self.offset_field(), + self.memory_field(), + ] + } } #[derive(Copy, Clone)] @@ -1123,6 +1158,15 @@ impl StoreOp { } Some(Field::new(Ident::Memory, FieldTy::Memory)) } + + pub fn fields(&self) -> [Option; 4] { + [ + Some(self.ptr_field()), + self.offset_field(), + Some(self.value_field()), + self.memory_field(), + ] + } } #[derive(Copy, Clone)] @@ -1206,6 +1250,10 @@ impl TableGetOp { pub fn table_field(&self) -> Field { Field::new(Ident::Table, FieldTy::Table) } + + pub fn fields(&self) -> [Field; 3] { + [self.result_field(), self.index_field(), self.table_field()] + } } #[derive(Copy, Clone)] @@ -1240,6 +1288,10 @@ impl TableSetOp { pub fn table_field(&self) -> Field { Field::new(Ident::Table, FieldTy::Table) } + + pub fn fields(&self) -> [Field; 3] { + [self.index_field(), self.value_field(), self.table_field()] + } } #[derive(Copy, Clone)] From e278bdbab10a83d38ec2d0dc722fd04af75958ea Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Tue, 26 Aug 2025 09:52:10 +0200 Subject: [PATCH 090/186] use offset_field in DisplayOp --- crates/ir2/build/display/op.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/ir2/build/display/op.rs b/crates/ir2/build/display/op.rs index e99e581dda..a68f060d1f 100644 --- a/crates/ir2/build/display/op.rs +++ b/crates/ir2/build/display/op.rs @@ -9,7 +9,6 @@ use crate::build::{ BinaryOp, CmpBranchOp, CmpSelectOp, - FieldTy, GenericOp, LoadOp, Op, @@ -133,14 +132,14 @@ impl Display for DisplayOp<&'_ CmpBranchOp> { let ident = DisplayIdent::camel(op); let lhs_field = op.lhs_field(); let rhs_field = op.rhs_field(); - let offset_ty = FieldTy::BranchOffset; + let offset_field = op.offset_field(); write!( f, "\ {indent0}{ident} {{\n\ - {indent1}offset: {offset_ty},\n\ {indent1}{lhs_field},\n\ {indent1}{rhs_field},\n\ + {indent1}{offset_field},\n\ {indent0}}},\n\ ", ) From 4ca1e27cc8473d957217618305afb2896d9d287d Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Tue, 26 Aug 2025 09:52:27 +0200 Subject: [PATCH 091/186] add Op constructor codegen --- crates/ir2/build/display/constructors.rs | 178 +++++++++++++++++++++++ crates/ir2/build/display/ident.rs | 1 - crates/ir2/build/display/mod.rs | 8 +- crates/ir2/build/mod.rs | 4 +- 4 files changed, 188 insertions(+), 3 deletions(-) create mode 100644 crates/ir2/build/display/constructors.rs diff --git a/crates/ir2/build/display/constructors.rs b/crates/ir2/build/display/constructors.rs new file mode 100644 index 0000000000..0930550cd7 --- /dev/null +++ b/crates/ir2/build/display/constructors.rs @@ -0,0 +1,178 @@ +use crate::build::{ + display::{ + ident::DisplayIdent, + utils::{DisplayConcat, DisplaySequence}, + Indent, + }, + isa::Isa, + op::{ + BinaryOp, + CmpBranchOp, + CmpSelectOp, + Field, + GenericOp, + LoadOp, + Op, + StoreOp, + TableGetOp, + TableSetOp, + UnaryOp, + }, + token::SnakeCase, +}; +use core::fmt::{self, Display}; + +pub struct DisplayConstructor { + pub value: T, + pub indent: Indent, +} + +impl DisplayConstructor { + pub fn new(value: T, indent: Indent) -> Self { + Self { value, indent } + } + + pub fn map(&self, value: V) -> DisplayConstructor { + DisplayConstructor { + value, + indent: self.indent, + } + } +} + +impl<'a, T> DisplayConstructor<&'a T> { + fn display_constructor(&self, f: &mut fmt::Formatter, fields: &[Option]) -> fmt::Result + where + DisplayIdent<&'a T>: Display, + { + let indent = self.indent; + let snake_ident = DisplayIdent::snake(self.value); + let camel_ident = DisplayIdent::camel(self.value); + let fn_params = DisplaySequence( + fields + .iter() + .filter_map(Option::as_ref) + .map(|param| (param, ", ")) + .map(DisplayConcat), + ); + let struct_params = DisplaySequence( + fields + .iter() + .filter_map(Option::as_ref) + .map(|param| (SnakeCase(param.ident), ", ")) + .map(DisplayConcat), + ); + write!( + f, + "\ + {indent}pub fn {snake_ident}({fn_params}) -> Self {{\n\ + {indent} Self::{camel_ident} {{ {struct_params} }}\n\ + {indent}}}\n\ + " + ) + } +} + +impl Display for DisplayConstructor<&'_ Isa> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let indent = self.indent; + let variants = DisplaySequence( + self.value + .ops + .iter() + .map(|op| DisplayConstructor::new(op, indent.inc_by(3))), + ); + write!( + f, + "\ + {indent}impl Op {{\n\ + {variants}\ + {indent}}}\n\ + " + ) + } +} + +impl Display for DisplayConstructor<&'_ Op> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.value { + Op::Unary(op) => self.map(op).fmt(f), + Op::Binary(op) => self.map(op).fmt(f), + Op::CmpBranch(op) => self.map(op).fmt(f), + Op::CmpSelect(op) => self.map(op).fmt(f), + Op::Load(op) => self.map(op).fmt(f), + Op::Store(op) => self.map(op).fmt(f), + Op::TableGet(op) => self.map(op).fmt(f), + Op::TableSet(op) => self.map(op).fmt(f), + Op::Generic0(op) => self.map(op).fmt(f), + Op::Generic1(op) => self.map(op).fmt(f), + Op::Generic2(op) => self.map(op).fmt(f), + Op::Generic3(op) => self.map(op).fmt(f), + Op::Generic4(op) => self.map(op).fmt(f), + Op::Generic5(op) => self.map(op).fmt(f), + } + } +} + +impl Display for DisplayConstructor<&'_ UnaryOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fields = self.value.fields().map(Option::from); + self.display_constructor(f, &fields) + } +} + +impl Display for DisplayConstructor<&'_ BinaryOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fields = self.value.fields().map(Option::from); + self.display_constructor(f, &fields) + } +} + +impl Display for DisplayConstructor<&'_ CmpBranchOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fields = self.value.fields().map(Option::from); + self.display_constructor(f, &fields) + } +} + +impl Display for DisplayConstructor<&'_ CmpSelectOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fields = self.value.fields().map(Option::from); + self.display_constructor(f, &fields) + } +} + +impl Display for DisplayConstructor<&'_ LoadOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fields = self.value.fields(); + self.display_constructor(f, &fields) + } +} + +impl Display for DisplayConstructor<&'_ StoreOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fields = self.value.fields(); + self.display_constructor(f, &fields) + } +} + +impl Display for DisplayConstructor<&'_ TableGetOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fields = self.value.fields().map(Option::from); + self.display_constructor(f, &fields) + } +} + +impl Display for DisplayConstructor<&'_ TableSetOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fields = self.value.fields().map(Option::from); + self.display_constructor(f, &fields) + } +} + +impl Display for DisplayConstructor<&'_ GenericOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fields = self.value.fields.map(Option::from); + self.display_constructor(f, &fields) + } +} diff --git a/crates/ir2/build/display/ident.rs b/crates/ir2/build/display/ident.rs index e4c071e0d5..41574d9f09 100644 --- a/crates/ir2/build/display/ident.rs +++ b/crates/ir2/build/display/ident.rs @@ -30,7 +30,6 @@ impl DisplayIdent { } } - #[expect(dead_code)] pub fn snake(value: T) -> Self { Self { value, diff --git a/crates/ir2/build/display/mod.rs b/crates/ir2/build/display/mod.rs index ac01bfa0e2..83bc6b2e1e 100644 --- a/crates/ir2/build/display/mod.rs +++ b/crates/ir2/build/display/mod.rs @@ -1,6 +1,12 @@ +mod constructors; mod ident; mod op; mod result_mut; mod utils; -pub use self::{op::DisplayOp, result_mut::DisplayResultMut, utils::Indent}; +pub use self::{ + constructors::DisplayConstructor, + op::DisplayOp, + result_mut::DisplayResultMut, + utils::Indent, +}; diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index d80bb70622..e4c32970bc 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -8,7 +8,7 @@ use self::{ op::Op, token::{CamelCase, Ident, SnakeCase}, }; -use crate::build::display::DisplayResultMut; +use crate::build::display::{DisplayConstructor, DisplayResultMut}; use core::fmt::{self, Display, Error as FmtError, Write as _}; use std::{fs, io::Error as IoError, path::Path}; @@ -48,9 +48,11 @@ pub fn generate_code(out_dir: &Path) -> Result<(), Error> { "\ {}\n\ {}\n\ + {}\n\ ", DisplayOp::new(&isa, Indent::default()), DisplayResultMut::new(&isa, Indent::default()), + DisplayConstructor::new(&isa, Indent::default()), )?; std::println!("out_dir = {out_dir:?}"); fs::create_dir_all(out_dir)?; From 773ddd56453efe967efa8dd14f3b7e66170a35db Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Tue, 26 Aug 2025 09:59:31 +0200 Subject: [PATCH 092/186] add indent to DisplayOp codegen --- crates/ir2/build/display/op.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ir2/build/display/op.rs b/crates/ir2/build/display/op.rs index a68f060d1f..db60c69c20 100644 --- a/crates/ir2/build/display/op.rs +++ b/crates/ir2/build/display/op.rs @@ -54,7 +54,7 @@ impl Display for DisplayOp<&'_ Isa> { "\ {indent}#[allow(non_camel_case_types)] {indent}pub enum Op {{\n\ - {variants}\ + {variants}\ {indent}}}\n\ " ) From 6e2650f4d5a2ac2156a3548ded5c7a9c9d68ede8 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Tue, 26 Aug 2025 10:11:32 +0200 Subject: [PATCH 093/186] simplify DisplayOp via fields methods --- crates/ir2/build/display/op.rs | 222 +++++++-------------------------- 1 file changed, 45 insertions(+), 177 deletions(-) diff --git a/crates/ir2/build/display/op.rs b/crates/ir2/build/display/op.rs index db60c69c20..a422490469 100644 --- a/crates/ir2/build/display/op.rs +++ b/crates/ir2/build/display/op.rs @@ -1,7 +1,7 @@ use crate::build::{ display::{ ident::DisplayIdent, - utils::{DisplayConcat, DisplaySequence, IntoDisplayMaybe as _}, + utils::{DisplayConcat, DisplaySequence}, Indent, }, isa::Isa, @@ -9,6 +9,7 @@ use crate::build::{ BinaryOp, CmpBranchOp, CmpSelectOp, + Field, GenericOp, LoadOp, Op, @@ -45,6 +46,31 @@ impl DisplayOp { } } +impl<'a, T> DisplayOp<&'a T> +where + DisplayIdent<&'a T>: Display, +{ + fn display_variant(&self, f: &mut fmt::Formatter<'_>, fields: &[Option]) -> fmt::Result { + let indent = self.indent; + let ident = DisplayIdent::camel(self.val); + let fields = DisplaySequence( + fields + .iter() + .filter_map(Option::as_ref) + .map(|field| (indent.inc(), field, ",\n")) + .map(DisplayConcat), + ); + write!( + f, + "\ + {indent}{ident} {{\n\ + {fields}\ + {indent}}},\n\ + ", + ) + } +} + impl Display for DisplayOp<&'_ Isa> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent = self.indent; @@ -84,221 +110,63 @@ impl Display for DisplayOp<&'_ Op> { impl Display for DisplayOp<&'_ UnaryOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let indent0 = self.indent; - let indent1 = indent0.inc(); - let op = self.val; - let ident = DisplayIdent::camel(op); - let result_field = op.result_field(); - let value_field = op.value_field(); - write!( - f, - "\ - {indent0}{ident} {{\n\ - {indent1}{result_field},\n\ - {indent1}{value_field},\n\ - {indent0}}},\n\ - ", - ) + let fields = self.val.fields().map(Option::from); + self.display_variant(f, &fields) } } impl Display for DisplayOp<&'_ BinaryOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let indent0 = self.indent; - let indent1 = indent0.inc(); - let op = self.val; - let ident = DisplayIdent::camel(op); - let result_field = op.result_field(); - let lhs_field = op.lhs_field(); - let rhs_field = op.rhs_field(); - write!( - f, - "\ - {indent0}{ident} {{\n\ - {indent1}{result_field},\n\ - {indent1}{lhs_field},\n\ - {indent1}{rhs_field},\n\ - {indent0}}},\n\ - ", - ) + let fields = self.val.fields().map(Option::from); + self.display_variant(f, &fields) } } impl Display for DisplayOp<&'_ CmpBranchOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let indent0 = self.indent; - let indent1 = indent0.inc(); - let op = self.val; - let ident = DisplayIdent::camel(op); - let lhs_field = op.lhs_field(); - let rhs_field = op.rhs_field(); - let offset_field = op.offset_field(); - write!( - f, - "\ - {indent0}{ident} {{\n\ - {indent1}{lhs_field},\n\ - {indent1}{rhs_field},\n\ - {indent1}{offset_field},\n\ - {indent0}}},\n\ - ", - ) + let fields = self.val.fields().map(Option::from); + self.display_variant(f, &fields) } } impl Display for DisplayOp<&'_ CmpSelectOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let indent0 = self.indent; - let indent1 = indent0.inc(); - let op = self.val; - let ident = DisplayIdent::camel(op); - let result_field = op.result_field(); - let lhs_field = op.lhs_field(); - let rhs_field = op.rhs_field(); - let val_true_field = op.val_true_field(); - let val_false_field = op.val_false_field(); - write!( - f, - "\ - {indent0}{ident} {{\n\ - {indent1}{result_field},\n\ - {indent1}{lhs_field},\n\ - {indent1}{rhs_field},\n\ - {indent1}{val_true_field},\n\ - {indent1}{val_false_field},\n\ - {indent0}}},\n\ - ", - ) + let fields = self.val.fields().map(Option::from); + self.display_variant(f, &fields) } } impl Display for DisplayOp<&'_ LoadOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let indent0 = self.indent; - let indent1 = indent0.inc(); - let op = self.val; - let ident = DisplayIdent::camel(op); - let result_field = op.result_field(); - let ptr_field = op.ptr_field(); - let offset_field = op - .offset_field() - .map(|field| (indent1, field, ",\n")) - .map(DisplayConcat) - .display_maybe(); - let memory_field = op - .memory_field() - .map(|field| (indent1, field, ",\n")) - .map(DisplayConcat) - .display_maybe(); - write!( - f, - "\ - {indent0}{ident} {{\n\ - {indent1}{result_field},\n\ - {indent1}{ptr_field},\n\ - {offset_field}\ - {memory_field}\ - {indent0}}},\n\ - ", - ) + let fields = self.val.fields(); + self.display_variant(f, &fields) } } impl Display for DisplayOp<&'_ StoreOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let indent0 = self.indent; - let indent1 = indent0.inc(); - let op = self.val; - let ident = DisplayIdent::camel(op); - let ptr_field = op.ptr_field(); - let offset_field = op - .offset_field() - .map(|field| (indent1, field, ",\n")) - .map(DisplayConcat) - .display_maybe(); - let value_field = op.value_field(); - let memory_field = op - .memory_field() - .map(|field| (indent1, field, ",\n")) - .map(DisplayConcat) - .display_maybe(); - write!( - f, - "\ - {indent0}{ident} {{\n\ - {indent1}{ptr_field},\n\ - {offset_field}\ - {indent1}{value_field},\n\ - {memory_field}\ - {indent0}}},\n\ - ", - ) + let fields = self.val.fields().map(Option::from); + self.display_variant(f, &fields) } } impl Display for DisplayOp<&'_ GenericOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let indent0 = self.indent; - let indent1 = indent0.inc(); - let ident = DisplayIdent::camel(self.val); - let fields = DisplaySequence( - self.val - .fields - .into_iter() - .map(move |field| (indent1, field, ",\n")) - .map(DisplayConcat), - ); - write!( - f, - "\ - {indent0}{ident} {{\n\ - {fields}\ - {indent0}}},\n\ - ", - ) + let fields = self.val.fields.map(Option::from); + self.display_variant(f, &fields) } } impl Display for DisplayOp<&'_ TableGetOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let indent0 = self.indent; - let indent1 = indent0.inc(); - let op = self.val; - let ident = DisplayIdent::camel(op); - let result_field = op.result_field(); - let index_field = op.index_field(); - let table_field = op.table_field(); - write!( - f, - "\ - {indent0}{ident} {{\n\ - {indent1}{result_field},\n\ - {indent1}{index_field},\n\ - {indent1}{table_field},\n\ - {indent0}}},\n\ - ", - ) + let fields = self.val.fields().map(Option::from); + self.display_variant(f, &fields) } } impl Display for DisplayOp<&'_ TableSetOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let indent0 = self.indent; - let indent1 = indent0.inc(); - let op = self.val; - let ident = DisplayIdent::camel(op); - let index_field = op.index_field(); - let value_field = op.value_field(); - let table_field = op.table_field(); - write!( - f, - "\ - {indent0}{ident} {{\n\ - {indent1}{table_field},\n\ - {indent1}{index_field},\n\ - {indent1}{value_field},\n\ - {indent0}}},\n\ - ", - ) + let fields = self.val.fields().map(Option::from); + self.display_variant(f, &fields) } } From de136b65ecd984908830b6de0825ef995094d17c Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Tue, 26 Aug 2025 10:16:25 +0200 Subject: [PATCH 094/186] remove DisplayOp::scoped utility --- crates/ir2/build/display/op.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/crates/ir2/build/display/op.rs b/crates/ir2/build/display/op.rs index a422490469..2017b71e44 100644 --- a/crates/ir2/build/display/op.rs +++ b/crates/ir2/build/display/op.rs @@ -31,13 +31,6 @@ impl DisplayOp { Self { val, indent } } - pub fn scoped(&self, val: V) -> DisplayOp { - DisplayOp { - val, - indent: self.indent.inc(), - } - } - pub fn map(&self, val: V) -> DisplayOp { DisplayOp { val, @@ -74,7 +67,12 @@ where impl Display for DisplayOp<&'_ Isa> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent = self.indent; - let variants = DisplaySequence(self.val.ops.iter().map(|op| self.scoped(op))); + let variants = DisplaySequence( + self.val + .ops + .iter() + .map(|op| DisplayOp::new(op, indent.inc())), + ); write!( f, "\ From f16feca9cf4640bc98f51948afbfe06510e03083 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Tue, 26 Aug 2025 14:02:43 +0200 Subject: [PATCH 095/186] add separator field to DisplaySequence --- crates/ir2/build/display/constructors.rs | 9 +++++--- crates/ir2/build/display/op.rs | 6 ++++-- crates/ir2/build/display/result_mut.rs | 3 ++- crates/ir2/build/display/utils.rs | 26 +++++++++++++++++++----- 4 files changed, 33 insertions(+), 11 deletions(-) diff --git a/crates/ir2/build/display/constructors.rs b/crates/ir2/build/display/constructors.rs index 0930550cd7..ae9ccc7859 100644 --- a/crates/ir2/build/display/constructors.rs +++ b/crates/ir2/build/display/constructors.rs @@ -48,14 +48,16 @@ impl<'a, T> DisplayConstructor<&'a T> { let indent = self.indent; let snake_ident = DisplayIdent::snake(self.value); let camel_ident = DisplayIdent::camel(self.value); - let fn_params = DisplaySequence( + let fn_params = DisplaySequence::new( + "", fields .iter() .filter_map(Option::as_ref) .map(|param| (param, ", ")) .map(DisplayConcat), ); - let struct_params = DisplaySequence( + let struct_params = DisplaySequence::new( + "", fields .iter() .filter_map(Option::as_ref) @@ -76,7 +78,8 @@ impl<'a, T> DisplayConstructor<&'a T> { impl Display for DisplayConstructor<&'_ Isa> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent = self.indent; - let variants = DisplaySequence( + let variants = DisplaySequence::new( + "", self.value .ops .iter() diff --git a/crates/ir2/build/display/op.rs b/crates/ir2/build/display/op.rs index 2017b71e44..fada3ca64a 100644 --- a/crates/ir2/build/display/op.rs +++ b/crates/ir2/build/display/op.rs @@ -46,7 +46,8 @@ where fn display_variant(&self, f: &mut fmt::Formatter<'_>, fields: &[Option]) -> fmt::Result { let indent = self.indent; let ident = DisplayIdent::camel(self.val); - let fields = DisplaySequence( + let fields = DisplaySequence::new( + "", fields .iter() .filter_map(Option::as_ref) @@ -67,7 +68,8 @@ where impl Display for DisplayOp<&'_ Isa> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent = self.indent; - let variants = DisplaySequence( + let variants = DisplaySequence::new( + "", self.val .ops .iter() diff --git a/crates/ir2/build/display/result_mut.rs b/crates/ir2/build/display/result_mut.rs index 9f84670b63..f1e869f8bd 100644 --- a/crates/ir2/build/display/result_mut.rs +++ b/crates/ir2/build/display/result_mut.rs @@ -48,7 +48,8 @@ impl<'a, T> DisplayResultMut<&'a T> { impl Display for DisplayResultMut<&'_ Isa> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent = self.indent; - let variants = DisplaySequence( + let variants = DisplaySequence::new( + "", self.value .ops .iter() diff --git a/crates/ir2/build/display/utils.rs b/crates/ir2/build/display/utils.rs index 875a262882..c10da573da 100644 --- a/crates/ir2/build/display/utils.rs +++ b/crates/ir2/build/display/utils.rs @@ -47,15 +47,31 @@ where } } -pub struct DisplaySequence(pub T); +pub struct DisplaySequence { + iter: I, + sep: S, +} + +impl DisplaySequence { + pub fn new(sep: S, iter: I) -> Self { + Self { sep, iter } + } +} -impl Display for DisplaySequence +impl Display for DisplaySequence where - T: IntoIterator + Clone, + I: IntoIterator + Clone, + S: Display, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for item in self.0.clone() { - write!(f, "{item}")?; + let mut iter = self.iter.clone().into_iter(); + let Some(first) = iter.next() else { + return Ok(()); + }; + write!(f, "{}", first)?; + let sep = &self.sep; + for item in iter { + write!(f, "{sep}{item}")?; } Ok(()) } From 9ac2e0a17e85fa89ad9f002a661dc3724d90d61e Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Tue, 26 Aug 2025 14:14:27 +0200 Subject: [PATCH 096/186] use new DisplaySequence separator --- crates/ir2/build/display/constructors.rs | 23 ++++++----------------- crates/ir2/build/display/op.rs | 12 ++++++------ 2 files changed, 12 insertions(+), 23 deletions(-) diff --git a/crates/ir2/build/display/constructors.rs b/crates/ir2/build/display/constructors.rs index ae9ccc7859..d49f8923d7 100644 --- a/crates/ir2/build/display/constructors.rs +++ b/crates/ir2/build/display/constructors.rs @@ -1,9 +1,5 @@ use crate::build::{ - display::{ - ident::DisplayIdent, - utils::{DisplayConcat, DisplaySequence}, - Indent, - }, + display::{ident::DisplayIdent, utils::DisplaySequence, Indent}, isa::Isa, op::{ BinaryOp, @@ -48,21 +44,14 @@ impl<'a, T> DisplayConstructor<&'a T> { let indent = self.indent; let snake_ident = DisplayIdent::snake(self.value); let camel_ident = DisplayIdent::camel(self.value); - let fn_params = DisplaySequence::new( - "", - fields - .iter() - .filter_map(Option::as_ref) - .map(|param| (param, ", ")) - .map(DisplayConcat), - ); + let fn_params = DisplaySequence::new(", ", fields.iter().filter_map(Option::as_ref)); let struct_params = DisplaySequence::new( - "", + ", ", fields .iter() .filter_map(Option::as_ref) - .map(|param| (SnakeCase(param.ident), ", ")) - .map(DisplayConcat), + .map(|param| param.ident) + .map(SnakeCase), ); write!( f, @@ -83,7 +72,7 @@ impl Display for DisplayConstructor<&'_ Isa> { self.value .ops .iter() - .map(|op| DisplayConstructor::new(op, indent.inc_by(3))), + .map(|op| DisplayConstructor::new(op, indent.inc_by(1))), ); write!( f, diff --git a/crates/ir2/build/display/op.rs b/crates/ir2/build/display/op.rs index fada3ca64a..b803091901 100644 --- a/crates/ir2/build/display/op.rs +++ b/crates/ir2/build/display/op.rs @@ -47,19 +47,19 @@ where let indent = self.indent; let ident = DisplayIdent::camel(self.val); let fields = DisplaySequence::new( - "", + ",\n", fields .iter() .filter_map(Option::as_ref) - .map(|field| (indent.inc(), field, ",\n")) + .map(|field| (indent.inc(), field)) .map(DisplayConcat), ); write!( f, "\ {indent}{ident} {{\n\ - {fields}\ - {indent}}},\n\ + {fields}\n\ + {indent}}}\ ", ) } @@ -69,7 +69,7 @@ impl Display for DisplayOp<&'_ Isa> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let indent = self.indent; let variants = DisplaySequence::new( - "", + ",\n", self.val .ops .iter() @@ -80,7 +80,7 @@ impl Display for DisplayOp<&'_ Isa> { "\ {indent}#[allow(non_camel_case_types)] {indent}pub enum Op {{\n\ - {variants}\ + {variants}\n\ {indent}}}\n\ " ) From ce7b350a4fadf22357894bf6cee6ddd06e696c6a Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Tue, 26 Aug 2025 14:15:30 +0200 Subject: [PATCH 097/186] fix intendation for Op type in codegen --- crates/ir2/build/display/op.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ir2/build/display/op.rs b/crates/ir2/build/display/op.rs index b803091901..938b851194 100644 --- a/crates/ir2/build/display/op.rs +++ b/crates/ir2/build/display/op.rs @@ -78,7 +78,7 @@ impl Display for DisplayOp<&'_ Isa> { write!( f, "\ - {indent}#[allow(non_camel_case_types)] + {indent}#[allow(non_camel_case_types)]\n\ {indent}pub enum Op {{\n\ {variants}\n\ {indent}}}\n\ From db1f11678435dc18eb6003087498b9cfe2a38cdc Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Tue, 26 Aug 2025 17:45:18 +0200 Subject: [PATCH 098/186] add wasmi_ir2::{Encoder, Encode} traits and impls --- crates/ir2/src/encode.rs | 128 ++++++++++++++++++++++++++++++++++++ crates/ir2/src/lib.rs | 2 + crates/ir2/src/primitive.rs | 7 +- 3 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 crates/ir2/src/encode.rs diff --git a/crates/ir2/src/encode.rs b/crates/ir2/src/encode.rs new file mode 100644 index 0000000000..d31bf16c95 --- /dev/null +++ b/crates/ir2/src/encode.rs @@ -0,0 +1,128 @@ +use crate::{ + core::TrapCode, + index::{Data, Elem, Func, FuncType, Global, InternalFunc, Memory, Table}, + Address, + BlockFuel, + BoundedStackSpan, + BranchOffset, + FixedStackSpan, + Offset16, + Sign, + Stack, + StackSpan, +}; + +/// Types that can encode types that implement [`Encode`]. +pub trait Encoder { + /// Position of encoded items. + type Pos: Copy; + /// Errors that may be returned during encoding. + type Error; + + /// Writes `bytes` to the encoder. + /// + /// # Errors + /// + /// If the encoder cannot encode more `bytes`. + fn write_bytes(&mut self, bytes: &[u8]) -> Result; + + /// Registers an encoded [`BranchOffset`] to the encoder. + /// + /// # Errors + /// + /// If the encoder cannot register the `branch_offset`. + fn branch_offset( + &mut self, + pos: Self::Pos, + branch_offset: BranchOffset, + ) -> Result<(), Self::Error>; +} + +/// Types that can be encoded by types that implement [`Encoder`]. +pub trait Encode { + /// Encode `self` to `encoder` and return its position within the `encoder`. + fn encode(&self, encoder: &mut E) -> Result + where + E: Encoder; +} + +impl Encode for BranchOffset { + fn encode(&self, encoder: &mut E) -> Result + where + E: Encoder, + { + let pos = self.to_i32().encode(encoder)?; + encoder.branch_offset(pos, *self)?; + Ok(pos) + } +} + +macro_rules! impl_encode_for_primitive { + ( $($ty:ty),* $(,)? ) => { + $( + impl Encode for $ty { + fn encode(&self, encoder: &mut E) -> Result + where + E: Encoder, + { + encoder.write_bytes(&self.to_ne_bytes()) + } + } + )* + }; +} +impl_encode_for_primitive!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize,); + +macro_rules! impl_encode_using { + ( $($ty:ty as $prim:ty = $e:expr),* $(,)? ) => { + $( + impl Encode for $ty { + fn encode(&self, encoder: &mut E) -> Result + where + E: Encoder, + { + let conv = |value: &Self| -> $prim { $e(*value) }; + conv(self).encode(encoder) + } + } + )* + }; +} +impl_encode_using! { + bool as u8 = Into::into, + Offset16 as u16 = Into::into, + BlockFuel as u64 = Into::into, + Address as u64 = Into::into, + Sign as bool = Sign::is_positive, + Sign as bool = Sign::is_positive, + + Stack as u16 = Into::into, + Func as u32 = Into::into, + FuncType as u32 = Into::into, + InternalFunc as u32 = Into::into, + Global as u32 = Into::into, + Memory as u16 = Into::into, + Table as u32 = Into::into, + Data as u32 = Into::into, + Elem as u32 = Into::into, + + StackSpan as Stack = StackSpan::head, + FixedStackSpan<2> as StackSpan = >::span, + BoundedStackSpan as StackSpan = |bounded: BoundedStackSpan| { bounded.span() }, + + TrapCode as u8 = |code: TrapCode| -> u8 { + match code { + TrapCode::UnreachableCodeReached => 0, + TrapCode::MemoryOutOfBounds => 1, + TrapCode::TableOutOfBounds => 2, + TrapCode::IndirectCallToNull => 3, + TrapCode::IntegerDivisionByZero => 4, + TrapCode::IntegerOverflow => 5, + TrapCode::BadConversionToInteger => 6, + TrapCode::StackOverflow => 7, + TrapCode::BadSignature => 8, + TrapCode::OutOfFuel => 9, + TrapCode::GrowthOperationLimited => 10, + } + }, +} diff --git a/crates/ir2/src/lib.rs b/crates/ir2/src/lib.rs index c1c75d827c..861e0c5578 100644 --- a/crates/ir2/src/lib.rs +++ b/crates/ir2/src/lib.rs @@ -4,6 +4,7 @@ extern crate alloc; #[cfg(feature = "std")] extern crate std; +mod encode; mod error; pub mod index; mod op; @@ -13,6 +14,7 @@ mod span; use wasmi_core as core; pub use self::{ + encode::{Encode, Encoder}, error::Error, index::Stack, op::Op, diff --git a/crates/ir2/src/primitive.rs b/crates/ir2/src/primitive.rs index 4736b35009..9782d463e3 100644 --- a/crates/ir2/src/primitive.rs +++ b/crates/ir2/src/primitive.rs @@ -9,7 +9,7 @@ pub struct OutOfBoundsConst; #[derive(Debug)] pub struct Sign { /// Whether the sign value is positive. - is_positive: bool, + pub(crate) is_positive: bool, /// Required for the Rust compiler. marker: PhantomData T>, } @@ -48,6 +48,11 @@ impl Sign { pub fn neg() -> Self { Self::new(false) } + + /// Returns `true` if [`Sign`] is positive. + pub(crate) fn is_positive(self) -> bool { + self.is_positive + } } macro_rules! impl_sign_for { From 382998adf7a5f0b5ccc163544b76bf36edea49f8 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Tue, 26 Aug 2025 18:21:18 +0200 Subject: [PATCH 099/186] add OpCode enum codegen --- crates/ir2/build/display/mod.rs | 2 + crates/ir2/build/display/op_code.rs | 68 +++++++++++++++++++++++++++++ crates/ir2/build/mod.rs | 4 +- crates/ir2/src/lib.rs | 2 +- crates/ir2/src/op.rs | 7 +++ 5 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 crates/ir2/build/display/op_code.rs diff --git a/crates/ir2/build/display/mod.rs b/crates/ir2/build/display/mod.rs index 83bc6b2e1e..7c3dc4589d 100644 --- a/crates/ir2/build/display/mod.rs +++ b/crates/ir2/build/display/mod.rs @@ -1,12 +1,14 @@ mod constructors; mod ident; mod op; +mod op_code; mod result_mut; mod utils; pub use self::{ constructors::DisplayConstructor, op::DisplayOp, + op_code::DisplayOpCode, result_mut::DisplayResultMut, utils::Indent, }; diff --git a/crates/ir2/build/display/op_code.rs b/crates/ir2/build/display/op_code.rs new file mode 100644 index 0000000000..56e452779c --- /dev/null +++ b/crates/ir2/build/display/op_code.rs @@ -0,0 +1,68 @@ +use crate::build::{ + display::{ + ident::DisplayIdent, + utils::{DisplayConcat, DisplaySequence}, + Indent, + }, + isa::Isa, + op::Op, +}; +use core::fmt::{self, Display}; + +pub struct DisplayOpCode { + pub value: T, + pub indent: Indent, +} + +impl DisplayOpCode { + pub fn new(value: T, indent: Indent) -> Self { + Self { value, indent } + } +} + +impl Display for DisplayOpCode<&'_ Isa> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let indent = self.indent; + let variants = DisplaySequence::new( + ",\n", + self.value + .ops + .iter() + .map(|op| (indent.inc(), DisplayIdent::camel(op))) + .map(DisplayConcat), + ); + let match_arms = DisplaySequence::new( + ",\n", + self.value + .ops + .iter() + .map(|op| DisplayOpCode::new(op, indent.inc_by(3))), + ); + write!( + f, + "\ + {indent}#[allow(non_camel_case_types)]\n\ + {indent}#[repr(u16)] + {indent}pub enum OpCode {{\n\ + {variants}\n\ + {indent}}}\n\ + \n\ + {indent}impl Op {{\n\ + {indent} pub fn code(&self) -> OpCode {{\n\ + {indent} match self {{\n\ + {match_arms}\n\ + {indent} }}\n\ + {indent} }}\n\ + {indent}}}\n\ + " + ) + } +} + +impl Display for DisplayOpCode<&'_ Op> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let indent = self.indent; + let ident = DisplayIdent::camel(self.value); + write!(f, "{indent}Self::{ident} {{ .. }} => OpCode::{ident}") + } +} diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index e4c32970bc..eb39d4b2a0 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -8,7 +8,7 @@ use self::{ op::Op, token::{CamelCase, Ident, SnakeCase}, }; -use crate::build::display::{DisplayConstructor, DisplayResultMut}; +use crate::build::display::{DisplayConstructor, DisplayOpCode, DisplayResultMut}; use core::fmt::{self, Display, Error as FmtError, Write as _}; use std::{fs, io::Error as IoError, path::Path}; @@ -49,10 +49,12 @@ pub fn generate_code(out_dir: &Path) -> Result<(), Error> { {}\n\ {}\n\ {}\n\ + {}\n\ ", DisplayOp::new(&isa, Indent::default()), DisplayResultMut::new(&isa, Indent::default()), DisplayConstructor::new(&isa, Indent::default()), + DisplayOpCode::new(&isa, Indent::default()), )?; std::println!("out_dir = {out_dir:?}"); fs::create_dir_all(out_dir)?; diff --git a/crates/ir2/src/lib.rs b/crates/ir2/src/lib.rs index 861e0c5578..02cb7fd1f5 100644 --- a/crates/ir2/src/lib.rs +++ b/crates/ir2/src/lib.rs @@ -17,7 +17,7 @@ pub use self::{ encode::{Encode, Encoder}, error::Error, index::Stack, - op::Op, + op::{Op, OpCode}, primitive::{Address, BlockFuel, BranchOffset, Offset16, Sign}, span::{BoundedStackSpan, FixedStackSpan, StackSpan, StackSpanIter}, }; diff --git a/crates/ir2/src/op.rs b/crates/ir2/src/op.rs index 9456ea223a..2e1ea6b9a4 100644 --- a/crates/ir2/src/op.rs +++ b/crates/ir2/src/op.rs @@ -21,6 +21,13 @@ impl Clone for Op { } } +impl Copy for OpCode {} +impl Clone for OpCode { + fn clone(&self) -> Self { + *self + } +} + #[test] fn op_size_of_and_alignment() { assert_eq!(core::mem::size_of::(), 24); From eb1acd08eb0eba0e0669d149a2de281ba5021a1c Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Tue, 26 Aug 2025 18:24:01 +0200 Subject: [PATCH 100/186] add Encoder::encode_op_code and Encode impl for OpCode --- crates/ir2/src/encode.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/crates/ir2/src/encode.rs b/crates/ir2/src/encode.rs index d31bf16c95..b9daf96b2e 100644 --- a/crates/ir2/src/encode.rs +++ b/crates/ir2/src/encode.rs @@ -7,6 +7,7 @@ use crate::{ BranchOffset, FixedStackSpan, Offset16, + OpCode, Sign, Stack, StackSpan, @@ -26,6 +27,14 @@ pub trait Encoder { /// If the encoder cannot encode more `bytes`. fn write_bytes(&mut self, bytes: &[u8]) -> Result; + /// Encodes the [`OpCode`] to `self`. + /// + /// # Note + /// This API allows the encoder to customize encoding of [`OpCode`], e.g. to + /// allow for direct or indirect threading encodings where the [`OpCode`] is + /// either encoded as function pointer or as `u16` value respectively. + fn encode_op_code(&mut self, code: OpCode) -> Result; + /// Registers an encoded [`BranchOffset`] to the encoder. /// /// # Errors @@ -46,6 +55,15 @@ pub trait Encode { E: Encoder; } +impl Encode for OpCode { + fn encode(&self, encoder: &mut E) -> Result + where + E: Encoder, + { + encoder.encode_op_code(*self) + } +} + impl Encode for BranchOffset { fn encode(&self, encoder: &mut E) -> Result where From 193f063f8bd2f25acd22e391d42576a7c7fc8b30 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Tue, 26 Aug 2025 18:27:26 +0200 Subject: [PATCH 101/186] add From for u16 impl --- crates/ir2/src/op.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/crates/ir2/src/op.rs b/crates/ir2/src/op.rs index 2e1ea6b9a4..1fc6bb17e4 100644 --- a/crates/ir2/src/op.rs +++ b/crates/ir2/src/op.rs @@ -27,6 +27,11 @@ impl Clone for OpCode { *self } } +impl From for u16 { + fn from(code: OpCode) -> Self { + code as u16 + } +} #[test] fn op_size_of_and_alignment() { From 780aa207d53d44986b84038d92cf96b2c2877d88 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Tue, 26 Aug 2025 21:03:08 +0200 Subject: [PATCH 102/186] add Encode impls for f{32,64} and NonZero<{u32,64}> --- crates/ir2/src/encode.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/ir2/src/encode.rs b/crates/ir2/src/encode.rs index b9daf96b2e..80414865ed 100644 --- a/crates/ir2/src/encode.rs +++ b/crates/ir2/src/encode.rs @@ -12,6 +12,7 @@ use crate::{ Stack, StackSpan, }; +use core::num::NonZero; /// Types that can encode types that implement [`Encode`]. pub trait Encoder { @@ -89,7 +90,7 @@ macro_rules! impl_encode_for_primitive { )* }; } -impl_encode_for_primitive!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize,); +impl_encode_for_primitive!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize, f32, f64); macro_rules! impl_encode_using { ( $($ty:ty as $prim:ty = $e:expr),* $(,)? ) => { @@ -128,6 +129,9 @@ impl_encode_using! { FixedStackSpan<2> as StackSpan = >::span, BoundedStackSpan as StackSpan = |bounded: BoundedStackSpan| { bounded.span() }, + NonZero as u32 = NonZero::get, + NonZero as u64 = NonZero::get, + TrapCode as u8 = |code: TrapCode| -> u8 { match code { TrapCode::UnreachableCodeReached => 0, From b885522f739b8f8262a7191d6bf57dcf7c6e17da Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Tue, 26 Aug 2025 21:03:30 +0200 Subject: [PATCH 103/186] add impl Encode for Op codegen --- crates/ir2/build/display/encode.rs | 191 +++++++++++++++++++++++++++++ crates/ir2/build/display/mod.rs | 2 + crates/ir2/build/mod.rs | 12 +- crates/ir2/src/op.rs | 2 + 4 files changed, 205 insertions(+), 2 deletions(-) create mode 100644 crates/ir2/build/display/encode.rs diff --git a/crates/ir2/build/display/encode.rs b/crates/ir2/build/display/encode.rs new file mode 100644 index 0000000000..54f865dac2 --- /dev/null +++ b/crates/ir2/build/display/encode.rs @@ -0,0 +1,191 @@ +use crate::build::{ + display::{ + ident::DisplayIdent, + utils::{DisplayConcat, DisplaySequence}, + Indent, + }, + isa::Isa, + op::{ + BinaryOp, + CmpBranchOp, + CmpSelectOp, + Field, + GenericOp, + LoadOp, + Op, + StoreOp, + TableGetOp, + TableSetOp, + UnaryOp, + }, + token::SnakeCase, +}; +use core::fmt::{self, Display}; + +pub struct DisplayEncode { + pub value: T, + pub indent: Indent, +} + +impl DisplayEncode { + pub fn new(value: T, indent: Indent) -> Self { + Self { value, indent } + } + + pub fn map(&self, value: V) -> DisplayEncode { + DisplayEncode { + value, + indent: self.indent, + } + } +} + +impl<'a, T> DisplayEncode<&'a T> { + fn display_encode(&self, f: &mut fmt::Formatter, fields: &[Option]) -> fmt::Result + where + DisplayIdent<&'a T>: Display, + { + let indent = self.indent; + let camel_ident = DisplayIdent::camel(self.value); + let match_params = DisplaySequence::new( + ", ", + fields + .iter() + .filter_map(Option::as_ref) + .map(|field| field.ident) + .map(SnakeCase), + ); + let encode_params = DisplaySequence::new( + "", + fields + .iter() + .filter_map(Option::as_ref) + .map(|field| field.ident) + .map(SnakeCase) + .map(|param| (indent.inc(), param, ".encode(encoder)?;\n")) + .map(DisplayConcat), + ); + write!( + f, + "\ + {indent}Self::{camel_ident} {{ {match_params} }} => {{\n\ + {indent} let pos = OpCode::{camel_ident}.encode(encoder)?;\n\ + {encode_params}\ + {indent} Ok(pos)\n\ + {indent}}}\n\ + " + ) + } +} + +impl Display for DisplayEncode<&'_ Isa> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let indent = self.indent; + let impls = DisplaySequence::new( + "", + self.value + .ops + .iter() + .map(|op| DisplayEncode::new(op, indent.inc_by(3))), + ); + write!( + f, + "\ + {indent}impl Encode for Op {{\n\ + {indent} fn encode(&self, encoder: &mut E) -> Result\n\ + {indent} where\n\ + {indent} E: Encoder,\n\ + {indent} {{\n\ + {indent} match self {{\n\ + {impls}\n\ + {indent} }}\n\ + {indent} }}\n\ + {indent}}}\n\ + " + ) + } +} + +impl Display for DisplayEncode<&'_ Op> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.value { + Op::Unary(op) => self.map(op).fmt(f), + Op::Binary(op) => self.map(op).fmt(f), + Op::CmpBranch(op) => self.map(op).fmt(f), + Op::CmpSelect(op) => self.map(op).fmt(f), + Op::Load(op) => self.map(op).fmt(f), + Op::Store(op) => self.map(op).fmt(f), + Op::TableGet(op) => self.map(op).fmt(f), + Op::TableSet(op) => self.map(op).fmt(f), + Op::Generic0(op) => self.map(op).fmt(f), + Op::Generic1(op) => self.map(op).fmt(f), + Op::Generic2(op) => self.map(op).fmt(f), + Op::Generic3(op) => self.map(op).fmt(f), + Op::Generic4(op) => self.map(op).fmt(f), + Op::Generic5(op) => self.map(op).fmt(f), + } + } +} + +impl Display for DisplayEncode<&'_ UnaryOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fields = self.value.fields().map(Option::from); + self.display_encode(f, &fields) + } +} + +impl Display for DisplayEncode<&'_ BinaryOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fields = self.value.fields().map(Option::from); + self.display_encode(f, &fields) + } +} + +impl Display for DisplayEncode<&'_ CmpBranchOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fields = self.value.fields().map(Option::from); + self.display_encode(f, &fields) + } +} + +impl Display for DisplayEncode<&'_ CmpSelectOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fields = self.value.fields().map(Option::from); + self.display_encode(f, &fields) + } +} + +impl Display for DisplayEncode<&'_ LoadOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fields = self.value.fields(); + self.display_encode(f, &fields) + } +} + +impl Display for DisplayEncode<&'_ StoreOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fields = self.value.fields(); + self.display_encode(f, &fields) + } +} + +impl Display for DisplayEncode<&'_ TableGetOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fields = self.value.fields().map(Option::from); + self.display_encode(f, &fields) + } +} + +impl Display for DisplayEncode<&'_ TableSetOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fields = self.value.fields().map(Option::from); + self.display_encode(f, &fields) + } +} + +impl Display for DisplayEncode<&'_ GenericOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fields = self.value.fields.map(Option::from); + self.display_encode(f, &fields) + } +} diff --git a/crates/ir2/build/display/mod.rs b/crates/ir2/build/display/mod.rs index 7c3dc4589d..3227ad3900 100644 --- a/crates/ir2/build/display/mod.rs +++ b/crates/ir2/build/display/mod.rs @@ -1,4 +1,5 @@ mod constructors; +mod encode; mod ident; mod op; mod op_code; @@ -7,6 +8,7 @@ mod utils; pub use self::{ constructors::DisplayConstructor, + encode::DisplayEncode, op::DisplayOp, op_code::DisplayOpCode, result_mut::DisplayResultMut, diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index eb39d4b2a0..cfb92ce9c9 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -4,11 +4,17 @@ mod op; pub mod token; use self::{ - display::{DisplayOp, Indent}, + display::{ + DisplayConstructor, + DisplayEncode, + DisplayOp, + DisplayOpCode, + DisplayResultMut, + Indent, + }, op::Op, token::{CamelCase, Ident, SnakeCase}, }; -use crate::build::display::{DisplayConstructor, DisplayOpCode, DisplayResultMut}; use core::fmt::{self, Display, Error as FmtError, Write as _}; use std::{fs, io::Error as IoError, path::Path}; @@ -50,11 +56,13 @@ pub fn generate_code(out_dir: &Path) -> Result<(), Error> { {}\n\ {}\n\ {}\n\ + {}\n\ ", DisplayOp::new(&isa, Indent::default()), DisplayResultMut::new(&isa, Indent::default()), DisplayConstructor::new(&isa, Indent::default()), DisplayOpCode::new(&isa, Indent::default()), + DisplayEncode::new(&isa, Indent::default()), )?; std::println!("out_dir = {out_dir:?}"); fs::create_dir_all(out_dir)?; diff --git a/crates/ir2/src/op.rs b/crates/ir2/src/op.rs index 1fc6bb17e4..84ce1452ca 100644 --- a/crates/ir2/src/op.rs +++ b/crates/ir2/src/op.rs @@ -4,6 +4,8 @@ use crate::{ Address, BlockFuel, BranchOffset, + Encode, + Encoder, FixedStackSpan, Offset16, Sign, From 7d320e901477c23637fe478a41001c60992d619f Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Tue, 26 Aug 2025 21:26:29 +0200 Subject: [PATCH 104/186] reserve proper amount for contents --- crates/ir2/build/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index cfb92ce9c9..5c73c94fb4 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -47,7 +47,7 @@ impl Display for Error { pub fn generate_code(out_dir: &Path) -> Result<(), Error> { let mut contents = String::new(); - contents.reserve_exact(50_000); + contents.reserve(350_000); let isa = isa::wasmi_isa(); write!( &mut contents, From 987b2a38186234da20822a6af1e5b8a37874c704 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 27 Aug 2025 08:35:01 +0200 Subject: [PATCH 105/186] generate encode.rs in its own file --- crates/ir2/build/mod.rs | 47 ++++++++++++++++++++++++++++++---------- crates/ir2/src/encode.rs | 3 +++ crates/ir2/src/op.rs | 2 -- 3 files changed, 39 insertions(+), 13 deletions(-) diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index 5c73c94fb4..05d565a315 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -12,6 +12,7 @@ use self::{ DisplayResultMut, Indent, }, + isa::Isa, op::Op, token::{CamelCase, Ident, SnakeCase}, }; @@ -46,26 +47,50 @@ impl Display for Error { } pub fn generate_code(out_dir: &Path) -> Result<(), Error> { - let mut contents = String::new(); - contents.reserve(350_000); + fs::create_dir_all(out_dir)?; let isa = isa::wasmi_isa(); + let mut buffer = String::new(); + generate_op_rs(out_dir, &isa, &mut buffer)?; + generate_encode_rs(out_dir, &isa, &mut buffer)?; + Ok(()) +} + +fn generate_op_rs(out_dir: &Path, isa: &Isa, contents: &mut String) -> Result<(), Error> { + const EXPECTED_SIZE: usize = 180_000; + contents.clear(); + contents.reserve_exact(EXPECTED_SIZE); write!( - &mut contents, + contents, "\ {}\n\ {}\n\ {}\n\ {}\n\ - {}\n\ ", - DisplayOp::new(&isa, Indent::default()), - DisplayResultMut::new(&isa, Indent::default()), - DisplayConstructor::new(&isa, Indent::default()), - DisplayOpCode::new(&isa, Indent::default()), - DisplayEncode::new(&isa, Indent::default()), + DisplayOp::new(isa, Indent::default()), + DisplayResultMut::new(isa, Indent::default()), + DisplayConstructor::new(isa, Indent::default()), + DisplayOpCode::new(isa, Indent::default()), )?; - std::println!("out_dir = {out_dir:?}"); - fs::create_dir_all(out_dir)?; + let len_contents = contents.len(); + assert!( + len_contents <= EXPECTED_SIZE, + "reserved bytes: {EXPECTED_SIZE}, contents.len() = {len_contents}", + ); fs::write(out_dir.join("op.rs"), contents)?; Ok(()) } + +fn generate_encode_rs(out_dir: &Path, isa: &Isa, contents: &mut String) -> Result<(), Error> { + const EXPECTED_SIZE: usize = 150_000; + contents.clear(); + contents.reserve_exact(EXPECTED_SIZE); + write!(contents, "{}", DisplayEncode::new(isa, Indent::default()),)?; + let len_contents = contents.len(); + assert!( + len_contents <= EXPECTED_SIZE, + "reserved bytes: {EXPECTED_SIZE}, contents.len() = {len_contents}", + ); + fs::write(out_dir.join("encode.rs"), contents)?; + Ok(()) +} diff --git a/crates/ir2/src/encode.rs b/crates/ir2/src/encode.rs index 80414865ed..331fceff91 100644 --- a/crates/ir2/src/encode.rs +++ b/crates/ir2/src/encode.rs @@ -7,6 +7,7 @@ use crate::{ BranchOffset, FixedStackSpan, Offset16, + Op, OpCode, Sign, Stack, @@ -148,3 +149,5 @@ impl_encode_using! { } }, } + +include!(concat!(env!("OUT_DIR"), "/encode.rs")); diff --git a/crates/ir2/src/op.rs b/crates/ir2/src/op.rs index 84ce1452ca..1fc6bb17e4 100644 --- a/crates/ir2/src/op.rs +++ b/crates/ir2/src/op.rs @@ -4,8 +4,6 @@ use crate::{ Address, BlockFuel, BranchOffset, - Encode, - Encoder, FixedStackSpan, Offset16, Sign, From 6a6a455da7f0034c20d62889f42634824c8e7d3c Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 27 Aug 2025 08:45:15 +0200 Subject: [PATCH 106/186] use Config instead of &Path --- crates/ir2/build.rs | 11 ++++------- crates/ir2/build/mod.rs | 30 +++++++++++++++++++++--------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/crates/ir2/build.rs b/crates/ir2/build.rs index 09cf03d8d0..8bd945b85c 100644 --- a/crates/ir2/build.rs +++ b/crates/ir2/build.rs @@ -1,16 +1,13 @@ -use std::{ - env, - fs, - path::{Path, PathBuf}, -}; +use self::build::Config; +use std::{fs, path::Path}; #[path = "build/mod.rs"] mod build; fn main() { watch_dir_recursively(Path::new("build")); - let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); - build::generate_code(&out_dir).unwrap() + let config = Config::default(); + build::generate_code(&config).unwrap() } fn watch_dir_recursively(path: &Path) { diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index 05d565a315..f6214f275f 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -17,7 +17,7 @@ use self::{ token::{CamelCase, Ident, SnakeCase}, }; use core::fmt::{self, Display, Error as FmtError, Write as _}; -use std::{fs, io::Error as IoError, path::Path}; +use std::{env, fs, io::Error as IoError, path::PathBuf}; #[derive(Debug)] pub enum Error { @@ -46,16 +46,28 @@ impl Display for Error { } } -pub fn generate_code(out_dir: &Path) -> Result<(), Error> { - fs::create_dir_all(out_dir)?; +pub struct Config { + out_dir: PathBuf, +} + +impl Default for Config { + fn default() -> Self { + Self { + out_dir: PathBuf::from(env::var("OUT_DIR").unwrap()), + } + } +} + +pub fn generate_code(config: &Config) -> Result<(), Error> { + fs::create_dir_all(&config.out_dir)?; let isa = isa::wasmi_isa(); let mut buffer = String::new(); - generate_op_rs(out_dir, &isa, &mut buffer)?; - generate_encode_rs(out_dir, &isa, &mut buffer)?; + generate_op_rs(&config, &isa, &mut buffer)?; + generate_encode_rs(&config, &isa, &mut buffer)?; Ok(()) } -fn generate_op_rs(out_dir: &Path, isa: &Isa, contents: &mut String) -> Result<(), Error> { +fn generate_op_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<(), Error> { const EXPECTED_SIZE: usize = 180_000; contents.clear(); contents.reserve_exact(EXPECTED_SIZE); @@ -77,11 +89,11 @@ fn generate_op_rs(out_dir: &Path, isa: &Isa, contents: &mut String) -> Result<() len_contents <= EXPECTED_SIZE, "reserved bytes: {EXPECTED_SIZE}, contents.len() = {len_contents}", ); - fs::write(out_dir.join("op.rs"), contents)?; + fs::write(config.out_dir.join("op.rs"), contents)?; Ok(()) } -fn generate_encode_rs(out_dir: &Path, isa: &Isa, contents: &mut String) -> Result<(), Error> { +fn generate_encode_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<(), Error> { const EXPECTED_SIZE: usize = 150_000; contents.clear(); contents.reserve_exact(EXPECTED_SIZE); @@ -91,6 +103,6 @@ fn generate_encode_rs(out_dir: &Path, isa: &Isa, contents: &mut String) -> Resul len_contents <= EXPECTED_SIZE, "reserved bytes: {EXPECTED_SIZE}, contents.len() = {len_contents}", ); - fs::write(out_dir.join("encode.rs"), contents)?; + fs::write(config.out_dir.join("encode.rs"), contents)?; Ok(()) } From f4dd76914e2cd78cd9a31f526b43f9e4b2f36721 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 27 Aug 2025 08:51:39 +0200 Subject: [PATCH 107/186] add `simd` feature support and a demo simd copy128 op --- crates/ir2/build/isa.rs | 25 ++++++++++++++++++++++--- crates/ir2/build/mod.rs | 4 +++- crates/ir2/build/token.rs | 4 ++++ 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index f2b29fa97f..8a514b3de9 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -20,6 +20,7 @@ use crate::build::{ UnaryOpKind, }, token::Ident, + Config, Op, }; @@ -34,7 +35,7 @@ impl Isa { } } -pub fn wasmi_isa() -> Isa { +pub fn wasmi_isa(config: &Config) -> Isa { let mut isa = Isa::default(); isa.ops.reserve_exact(500); add_unary_ops(&mut isa); @@ -49,7 +50,8 @@ pub fn wasmi_isa() -> Isa { add_global_ops(&mut isa); add_memory_ops(&mut isa); add_table_ops(&mut isa); - add_wide_arithmetic(&mut isa); + add_wide_arithmetic_ops(&mut isa); + add_simd_ops(&mut isa, config); isa } @@ -702,7 +704,7 @@ fn add_memory_ops(isa: &mut Isa) { } } -fn add_wide_arithmetic(isa: &mut Isa) { +fn add_wide_arithmetic_ops(isa: &mut Isa) { let ops = [ Op::from(GenericOp::new( Ident::I64Add128, @@ -745,3 +747,20 @@ fn add_wide_arithmetic(isa: &mut Isa) { isa.push_op(op); } } + +fn add_simd_ops(isa: &mut Isa, config: &Config) { + if !config.simd { + return; + } + let ops = [Op::from(GenericOp::new( + Ident::Copy128, + [ + Field::new(Ident::Result, FieldTy::Stack), + Field::new(Ident::ValueLo, FieldTy::U64), + Field::new(Ident::ValueHi, FieldTy::U64), + ], + ))]; + for op in ops { + isa.push_op(op); + } +} diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index f6214f275f..96409b7b95 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -48,19 +48,21 @@ impl Display for Error { pub struct Config { out_dir: PathBuf, + simd: bool, } impl Default for Config { fn default() -> Self { Self { out_dir: PathBuf::from(env::var("OUT_DIR").unwrap()), + simd: env::var("CARGO_FEATURE_SIMD").is_ok(), } } } pub fn generate_code(config: &Config) -> Result<(), Error> { fs::create_dir_all(&config.out_dir)?; - let isa = isa::wasmi_isa(); + let isa = isa::wasmi_isa(&config); let mut buffer = String::new(); generate_op_rs(&config, &isa, &mut buffer)?; generate_encode_rs(&config, &isa, &mut buffer)?; diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index e2668a4c72..8c80121b22 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -244,4 +244,8 @@ define_ident!( Ptr: ptr, ValTrue: val_true, ValFalse: val_false, + + Copy128: copy128, + ValueLo: value_lo, + ValueHi: value_hi, ); From 9d723ea4ba864d94bcaa15e8ca11beb61df58bf5 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 27 Aug 2025 09:35:00 +0200 Subject: [PATCH 108/186] reduce amount of code generated for Encode impls --- crates/ir2/build/display/encode.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/crates/ir2/build/display/encode.rs b/crates/ir2/build/display/encode.rs index 54f865dac2..6010efb9cd 100644 --- a/crates/ir2/build/display/encode.rs +++ b/crates/ir2/build/display/encode.rs @@ -92,10 +92,7 @@ impl Display for DisplayEncode<&'_ Isa> { f, "\ {indent}impl Encode for Op {{\n\ - {indent} fn encode(&self, encoder: &mut E) -> Result\n\ - {indent} where\n\ - {indent} E: Encoder,\n\ - {indent} {{\n\ + {indent} fn encode(&self, encoder: &mut E) -> Result {{\n\ {indent} match self {{\n\ {impls}\n\ {indent} }}\n\ From 28ed682c11136654e5a37066dfbccf5043946d63 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 27 Aug 2025 09:35:19 +0200 Subject: [PATCH 109/186] add u128 and i128 Encode impls --- crates/ir2/src/encode.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/ir2/src/encode.rs b/crates/ir2/src/encode.rs index 331fceff91..55d24dafe9 100644 --- a/crates/ir2/src/encode.rs +++ b/crates/ir2/src/encode.rs @@ -91,7 +91,9 @@ macro_rules! impl_encode_for_primitive { )* }; } -impl_encode_for_primitive!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize, f32, f64); +impl_encode_for_primitive!( + u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64 +); macro_rules! impl_encode_using { ( $($ty:ty as $prim:ty = $e:expr),* $(,)? ) => { From 3940455ba9d6d1b131c89b3f7555972716618b9a Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 27 Aug 2025 10:21:54 +0200 Subject: [PATCH 110/186] apply clippy suggestions --- crates/ir2/build/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index 96409b7b95..0f414cc4c9 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -62,10 +62,10 @@ impl Default for Config { pub fn generate_code(config: &Config) -> Result<(), Error> { fs::create_dir_all(&config.out_dir)?; - let isa = isa::wasmi_isa(&config); + let isa = isa::wasmi_isa(config); let mut buffer = String::new(); - generate_op_rs(&config, &isa, &mut buffer)?; - generate_encode_rs(&config, &isa, &mut buffer)?; + generate_op_rs(config, &isa, &mut buffer)?; + generate_encode_rs(config, &isa, &mut buffer)?; Ok(()) } From e9603b09b04bfd09d90f9f4d355b8dc360ad826c Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 27 Aug 2025 10:22:13 +0200 Subject: [PATCH 111/186] change/fix Encode impl for BoundedStackSpan --- crates/ir2/src/encode.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/crates/ir2/src/encode.rs b/crates/ir2/src/encode.rs index 55d24dafe9..61c076b1be 100644 --- a/crates/ir2/src/encode.rs +++ b/crates/ir2/src/encode.rs @@ -77,6 +77,17 @@ impl Encode for BranchOffset { } } +impl Encode for BoundedStackSpan { + fn encode(&self, encoder: &mut E) -> Result + where + E: Encoder, + { + let pos = self.span().encode(encoder)?; + self.len().encode(encoder)?; + Ok(pos) + } +} + macro_rules! impl_encode_for_primitive { ( $($ty:ty),* $(,)? ) => { $( @@ -130,7 +141,6 @@ impl_encode_using! { StackSpan as Stack = StackSpan::head, FixedStackSpan<2> as StackSpan = >::span, - BoundedStackSpan as StackSpan = |bounded: BoundedStackSpan| { bounded.span() }, NonZero as u32 = NonZero::get, NonZero as u64 = NonZero::get, From 7b5c26bac1792107ea8b5db901e369a46b7d2b70 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 27 Aug 2025 10:22:44 +0200 Subject: [PATCH 112/186] add trivial Offset16 from impl --- crates/ir2/src/primitive.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/crates/ir2/src/primitive.rs b/crates/ir2/src/primitive.rs index 9782d463e3..c5428b49f9 100644 --- a/crates/ir2/src/primitive.rs +++ b/crates/ir2/src/primitive.rs @@ -218,6 +218,12 @@ impl TryFrom for Offset16 { } } +impl From for Offset16 { + fn from(offset: u16) -> Self { + Self(offset) + } +} + impl From for u16 { fn from(offset: Offset16) -> Self { offset.0 From 98a2ea11f0588b37f72a8dc8e8cb1ef9fa7a5bac Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 27 Aug 2025 10:22:50 +0200 Subject: [PATCH 113/186] make Sign::new crate public --- crates/ir2/src/primitive.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ir2/src/primitive.rs b/crates/ir2/src/primitive.rs index c5428b49f9..b35379e777 100644 --- a/crates/ir2/src/primitive.rs +++ b/crates/ir2/src/primitive.rs @@ -32,7 +32,7 @@ impl Eq for Sign {} impl Sign { /// Create a new typed [`Sign`] with the given value. - fn new(is_positive: bool) -> Self { + pub(crate) fn new(is_positive: bool) -> Self { Self { is_positive, marker: PhantomData, From 6086daba861f7cce64a29c31c06ee8b27ba974b4 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 27 Aug 2025 10:23:07 +0200 Subject: [PATCH 114/186] add FixedStackSpan::new_unchecked constructor --- crates/ir2/src/span.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/crates/ir2/src/span.rs b/crates/ir2/src/span.rs index f510701157..a8c5dc1f41 100644 --- a/crates/ir2/src/span.rs +++ b/crates/ir2/src/span.rs @@ -84,6 +84,15 @@ impl FixedStackSpan { Ok(Self { span }) } + /// Creates a new [`StackSpan`] starting with the given `start` [`Stack`]. + /// + /// # Safety + /// + /// The caller is responsible for making sure that `span` is valid for a length of `N`. + pub unsafe fn new_unchecked(span: StackSpan) -> Self { + Self { span } + } + /// Returns a [`StackSpanIter`] yielding `N` [`Stack`]s. pub fn iter(&self) -> StackSpanIter { self.span.iter(self.len()) From 9ae79577aae6d3e5166699d00b5d7137763070a0 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 27 Aug 2025 10:23:18 +0200 Subject: [PATCH 115/186] add Decode and Decoder traits and impls --- crates/ir2/src/decode.rs | 110 +++++++++++++++++++++++++++++++++++++++ crates/ir2/src/lib.rs | 2 + 2 files changed, 112 insertions(+) create mode 100644 crates/ir2/src/decode.rs diff --git a/crates/ir2/src/decode.rs b/crates/ir2/src/decode.rs new file mode 100644 index 0000000000..005c033cba --- /dev/null +++ b/crates/ir2/src/decode.rs @@ -0,0 +1,110 @@ +use crate::{ + core::TrapCode, + index::{Data, Elem, Func, FuncType, Global, InternalFunc, Memory, Table}, + Address, + BlockFuel, + BoundedStackSpan, + BranchOffset, + FixedStackSpan, + Offset16, + Sign, + Stack, + StackSpan, +}; +use core::{mem, num::NonZero}; + +/// Types that can be used to decode types implementing [`Decode`]. +pub trait Decoder { + /// Reads enough bytes from `self` to populate `buffer`. + fn read_bytes(&mut self, buffer: &mut [u8]); +} + +/// Types that can be decoded using a type that implements [`Decoder`]. +pub trait Decode { + /// Decodes `Self` via `decoder`. + /// + /// # Safety + /// + /// It is the callers responsibility to ensure that the decoder + /// decodes items in the order they have been encoded and on valid + /// positions within the decode stream. + unsafe fn decode(decoder: &mut D) -> Self; +} + +impl Decode for BoundedStackSpan { + unsafe fn decode(decoder: &mut D) -> Self { + let span = ::decode(decoder); + let len = u16::decode(decoder); + Self::new(span, len) + } +} + +macro_rules! impl_decode_for_primitive { + ( $($ty:ty),* $(,)? ) => { + $( + impl Decode for $ty { + unsafe fn decode(decoder: &mut D) -> Self { + let mut bytes = [0_u8; mem::size_of::<$ty>()]; + decoder.read_bytes(&mut bytes); + Self::from_ne_bytes(bytes) + } + } + )* + }; +} +impl_decode_for_primitive!( + u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64 +); + +macro_rules! impl_decode_using { + ( $($ty:ty as $as:ty = $e:expr),* $(,)? ) => { + $( + impl Decode for $ty { + unsafe fn decode(decoder: &mut D) -> Self { + $e(<$as as Decode>::decode(decoder)) + } + } + )* + }; +} +impl_decode_using! { + bool as u8 = |value| value != 0, + Offset16 as u16 = Into::into, + BranchOffset as i32 = Into::into, + BlockFuel as u64 = Into::into, + Address as u64 = |address| unsafe { Address::try_from(address).unwrap_unchecked() }, + Sign as bool = Sign::new, + Sign as bool = Sign::new, + + Stack as u16 = Into::into, + Func as u32 = Into::into, + FuncType as u32 = Into::into, + InternalFunc as u32 = Into::into, + Global as u32 = Into::into, + Memory as u16 = Into::into, + Table as u32 = Into::into, + Data as u32 = Into::into, + Elem as u32 = Into::into, + + StackSpan as Stack = StackSpan::new, + FixedStackSpan<2> as StackSpan = |span| unsafe { >::new_unchecked(span) }, + + NonZero as u32 = |value| unsafe { NonZero::new_unchecked(value) }, + NonZero as u64 = |value| unsafe { NonZero::new_unchecked(value) }, + + TrapCode as u8 = |code: u8| -> TrapCode { + match code { + 0 => TrapCode::UnreachableCodeReached, + 1 => TrapCode::MemoryOutOfBounds, + 2 => TrapCode::TableOutOfBounds, + 3 => TrapCode::IndirectCallToNull, + 4 => TrapCode::IntegerDivisionByZero, + 5 => TrapCode::IntegerOverflow, + 6 => TrapCode::BadConversionToInteger, + 7 => TrapCode::StackOverflow, + 8 => TrapCode::BadSignature, + 9 => TrapCode::OutOfFuel, + _ => TrapCode::GrowthOperationLimited, + } + }, +} diff --git a/crates/ir2/src/lib.rs b/crates/ir2/src/lib.rs index 02cb7fd1f5..fc608dd27d 100644 --- a/crates/ir2/src/lib.rs +++ b/crates/ir2/src/lib.rs @@ -4,6 +4,7 @@ extern crate alloc; #[cfg(feature = "std")] extern crate std; +mod decode; mod encode; mod error; pub mod index; @@ -14,6 +15,7 @@ mod span; use wasmi_core as core; pub use self::{ + decode::{Decode, Decoder}, encode::{Encode, Encoder}, error::Error, index::Stack, From a0f513736983300eae6b0ff7a1db25f47092699f Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 27 Aug 2025 13:01:22 +0200 Subject: [PATCH 116/186] use Self where applicate in matchers --- crates/ir2/build/op.rs | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 08c53980fa..16ca505154 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -1087,18 +1087,18 @@ impl LoadOpKind { pub fn ident_prefix(&self) -> Option { match self { - LoadOpKind::Load32 => None, - LoadOpKind::Load64 => None, - LoadOpKind::S32Load8 => Some(Ident::S32), - LoadOpKind::U32Load8 => Some(Ident::U32), - LoadOpKind::S32Load16 => Some(Ident::S32), - LoadOpKind::U32Load16 => Some(Ident::U32), - LoadOpKind::S64Load8 => Some(Ident::S64), - LoadOpKind::U64Load8 => Some(Ident::U64), - LoadOpKind::S64Load16 => Some(Ident::S64), - LoadOpKind::U64Load16 => Some(Ident::U64), - LoadOpKind::S64Load32 => Some(Ident::S64), - LoadOpKind::U64Load32 => Some(Ident::U64), + Self::Load32 => None, + Self::Load64 => None, + Self::S32Load8 => Some(Ident::S32), + Self::U32Load8 => Some(Ident::U32), + Self::S32Load16 => Some(Ident::S32), + Self::U32Load16 => Some(Ident::U32), + Self::S64Load8 => Some(Ident::S64), + Self::U64Load8 => Some(Ident::U64), + Self::S64Load16 => Some(Ident::S64), + Self::U64Load16 => Some(Ident::U64), + Self::S64Load32 => Some(Ident::S64), + Self::U64Load32 => Some(Ident::U64), } } } @@ -1198,13 +1198,13 @@ impl StoreOpKind { pub fn ident_prefix(&self) -> Option { match self { - StoreOpKind::Store32 => None, - StoreOpKind::Store64 => None, - StoreOpKind::I32Store8 => Some(Ident::I32), - StoreOpKind::I32Store16 => Some(Ident::I32), - StoreOpKind::I64Store8 => Some(Ident::I64), - StoreOpKind::I64Store16 => Some(Ident::I64), - StoreOpKind::I64Store32 => Some(Ident::I64), + Self::Store32 => None, + Self::Store64 => None, + Self::I32Store8 => Some(Ident::I32), + Self::I32Store16 => Some(Ident::I32), + Self::I64Store8 => Some(Ident::I64), + Self::I64Store16 => Some(Ident::I64), + Self::I64Store32 => Some(Ident::I64), } } From 8bc4db6ba3599bfc0e1d259b4ea1500ea4b065f1 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 28 Aug 2025 11:29:42 +0200 Subject: [PATCH 117/186] add decode codegen --- crates/ir2/build/display/decode.rs | 210 ++++++++++++++++++ crates/ir2/build/display/mod.rs | 2 + crates/ir2/build/mod.rs | 18 +- crates/ir2/src/{decode.rs => decode/mod.rs} | 20 ++ crates/ir2/src/decode/op.rs | 231 ++++++++++++++++++++ crates/ir2/src/lib.rs | 2 +- 6 files changed, 481 insertions(+), 2 deletions(-) create mode 100644 crates/ir2/build/display/decode.rs rename crates/ir2/src/{decode.rs => decode/mod.rs} (91%) create mode 100644 crates/ir2/src/decode/op.rs diff --git a/crates/ir2/build/display/decode.rs b/crates/ir2/build/display/decode.rs new file mode 100644 index 0000000000..633f08bbbc --- /dev/null +++ b/crates/ir2/build/display/decode.rs @@ -0,0 +1,210 @@ +use crate::build::{ + display::{ + ident::DisplayIdent, + utils::{DisplayConcat, DisplaySequence, IntoDisplayMaybe as _}, + Indent, + }, + op::{ + BinaryOp, + CmpBranchOp, + CmpSelectOp, + GenericOp, + Input, + LoadOp, + Op, + StoreOp, + TableGetOp, + TableSetOp, + UnaryOp, + }, + token::{CamelCase, SnakeCase}, + Isa, +}; +use core::fmt::{self, Display}; + +pub struct DisplayDecode { + pub value: T, + pub indent: Indent, +} + +impl DisplayDecode { + pub fn new(value: T, indent: Indent) -> Self { + Self { value, indent } + } + + pub fn map(&self, value: V) -> DisplayDecode { + DisplayDecode { + value, + indent: self.indent, + } + } +} + +impl Display for DisplayDecode<&'_ Isa> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let indent = self.indent; + let impls = DisplaySequence::new( + "", + self.value + .ops + .iter() + .map(|op| DisplayDecode::new(op, indent)), + ); + write!(f, "{impls}") + } +} + +impl Display for DisplayDecode<&'_ Op> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.value { + Op::Unary(op) => self.map(op).fmt(f), + Op::Binary(op) => self.map(op).fmt(f), + Op::CmpBranch(op) => self.map(op).fmt(f), + Op::CmpSelect(op) => self.map(op).fmt(f), + Op::Load(op) => self.map(op).fmt(f), + Op::Store(op) => self.map(op).fmt(f), + Op::TableGet(op) => self.map(op).fmt(f), + Op::TableSet(op) => self.map(op).fmt(f), + Op::Generic0(op) => self.map(op).fmt(f), + Op::Generic1(op) => self.map(op).fmt(f), + Op::Generic2(op) => self.map(op).fmt(f), + Op::Generic3(op) => self.map(op).fmt(f), + Op::Generic4(op) => self.map(op).fmt(f), + Op::Generic5(op) => self.map(op).fmt(f), + } + } +} + +impl Display for DisplayDecode<&'_ UnaryOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let camel_ident = DisplayIdent::camel(self.value); + writeln!(f, "pub type {camel_ident} = UnaryOp;") + } +} + +impl Display for DisplayDecode<&'_ BinaryOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let op = self.value; + let camel_ident = DisplayIdent::camel(op); + let lhs = op.lhs_field().ty; + let rhs = op.rhs_field().ty; + writeln!(f, "pub type {camel_ident} = BinaryOp<{lhs}, {rhs}>;") + } +} + +impl Display for DisplayDecode<&'_ CmpBranchOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let op = self.value; + let camel_ident = DisplayIdent::camel(op); + let lhs = op.lhs_field().ty; + let rhs = op.rhs_field().ty; + writeln!(f, "pub type {camel_ident} = CmpBranchOp<{lhs}, {rhs}>;") + } +} + +impl Display for DisplayDecode<&'_ CmpSelectOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let op = self.value; + let camel_ident = DisplayIdent::camel(op); + let lhs = op.lhs_field().ty; + let rhs = op.rhs_field().ty; + writeln!(f, "pub type {camel_ident} = CmpSelectOp<{lhs}, {rhs}>;") + } +} + +impl Display for DisplayDecode<&'_ LoadOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let op = self.value; + let camel_ident = DisplayIdent::camel(op); + let mem0_offset16 = (op.mem0 && op.offset16) + .then_some("Mem0Offset16") + .display_maybe(); + let result_suffix = CamelCase(Input::Stack); + let ptr_suffix = SnakeCase(op.ptr); + writeln!( + f, + "pub type {camel_ident} = LoadOp{mem0_offset16}_{result_suffix}{ptr_suffix};" + ) + } +} + +impl Display for DisplayDecode<&'_ StoreOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let op = self.value; + let camel_ident = DisplayIdent::camel(op); + let mem0_offset16 = (op.mem0 && op.offset16) + .then_some("Mem0Offset16") + .display_maybe(); + let ptr_suffix = CamelCase(op.ptr); + let value_ty = op.value_field().ty; + writeln!( + f, + "pub type {camel_ident} = StoreOp{mem0_offset16}_{ptr_suffix}<{value_ty}>;" + ) + } +} + +impl Display for DisplayDecode<&'_ TableGetOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let op = self.value; + let camel_ident = DisplayIdent::camel(op); + let index_ty = op.index_field().ty; + writeln!(f, "pub type {camel_ident} = TableGet<{index_ty}>;") + } +} + +impl Display for DisplayDecode<&'_ TableSetOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let op = self.value; + let camel_ident = DisplayIdent::camel(op); + let index_ty = op.index_field().ty; + let value_ty = op.value_field().ty; + writeln!( + f, + "pub type {camel_ident} = TableSet<{index_ty}, {value_ty}>;" + ) + } +} + +impl Display for DisplayDecode<&'_ GenericOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let indent = self.indent; + let op = self.value; + if op.fields.is_empty() { + // No need to decode type with no operands (a.k.a. fields). + return Ok(()); + } + let camel_ident = DisplayIdent::camel(self.value); + let fields = DisplaySequence::new( + ",\n", + op.fields + .iter() + .map(|field| (indent.inc(), "pub ", field)) + .map(DisplayConcat), + ); + let constructors = DisplaySequence::new( + ",\n", + op.fields + .iter() + .map(|field| field.ident) + .map(SnakeCase) + .map(|ident| (indent.inc_by(3), ident, ": Decode::decode(decoder)")) + .map(DisplayConcat), + ); + write!( + f, + "\ + {indent}pub struct {camel_ident} {{\n\ + {fields}\n\ + {indent}}}\n\ + {indent}impl Decode for {camel_ident} {{\n\ + {indent} unsafe fn decode(decoder: &mut D) -> Self {{\n\ + {indent} Self {{\n\ + {constructors}\n\ + {indent} }}\n\ + {indent} }}\n\ + {indent}}}\n\ + " + ) + } +} diff --git a/crates/ir2/build/display/mod.rs b/crates/ir2/build/display/mod.rs index 3227ad3900..6362dcc3c9 100644 --- a/crates/ir2/build/display/mod.rs +++ b/crates/ir2/build/display/mod.rs @@ -1,4 +1,5 @@ mod constructors; +mod decode; mod encode; mod ident; mod op; @@ -8,6 +9,7 @@ mod utils; pub use self::{ constructors::DisplayConstructor, + decode::DisplayDecode, encode::DisplayEncode, op::DisplayOp, op_code::DisplayOpCode, diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index 0f414cc4c9..ef9d90685f 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -6,6 +6,7 @@ pub mod token; use self::{ display::{ DisplayConstructor, + DisplayDecode, DisplayEncode, DisplayOp, DisplayOpCode, @@ -66,6 +67,7 @@ pub fn generate_code(config: &Config) -> Result<(), Error> { let mut buffer = String::new(); generate_op_rs(config, &isa, &mut buffer)?; generate_encode_rs(config, &isa, &mut buffer)?; + generate_decode_rs(config, &isa, &mut buffer)?; Ok(()) } @@ -99,7 +101,7 @@ fn generate_encode_rs(config: &Config, isa: &Isa, contents: &mut String) -> Resu const EXPECTED_SIZE: usize = 150_000; contents.clear(); contents.reserve_exact(EXPECTED_SIZE); - write!(contents, "{}", DisplayEncode::new(isa, Indent::default()),)?; + write!(contents, "{}", DisplayEncode::new(isa, Indent::default()))?; let len_contents = contents.len(); assert!( len_contents <= EXPECTED_SIZE, @@ -108,3 +110,17 @@ fn generate_encode_rs(config: &Config, isa: &Isa, contents: &mut String) -> Resu fs::write(config.out_dir.join("encode.rs"), contents)?; Ok(()) } + +fn generate_decode_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<(), Error> { + const EXPECTED_SIZE: usize = 35_000; + contents.clear(); + contents.reserve_exact(EXPECTED_SIZE); + write!(contents, "{}", DisplayDecode::new(isa, Indent::default()))?; + let len_contents = contents.len(); + assert!( + len_contents <= EXPECTED_SIZE, + "reserved bytes: {EXPECTED_SIZE}, contents.len() = {len_contents}", + ); + fs::write(config.out_dir.join("decode.rs"), contents)?; + Ok(()) +} diff --git a/crates/ir2/src/decode.rs b/crates/ir2/src/decode/mod.rs similarity index 91% rename from crates/ir2/src/decode.rs rename to crates/ir2/src/decode/mod.rs index 005c033cba..e5efeaea3d 100644 --- a/crates/ir2/src/decode.rs +++ b/crates/ir2/src/decode/mod.rs @@ -1,3 +1,21 @@ +#![allow(non_camel_case_types)] + +mod op; + +use self::op::{ + BinaryOp, + CmpBranchOp, + CmpSelectOp, + LoadOpMem0Offset16_Ss, + LoadOp_Si, + LoadOp_Ss, + StoreOpMem0Offset16_S, + StoreOp_I, + StoreOp_S, + TableGet, + TableSet, + UnaryOp, +}; use crate::{ core::TrapCode, index::{Data, Elem, Func, FuncType, Global, InternalFunc, Memory, Table}, @@ -108,3 +126,5 @@ impl_decode_using! { } }, } + +include!(concat!(env!("OUT_DIR"), "/decode.rs")); diff --git a/crates/ir2/src/decode/op.rs b/crates/ir2/src/decode/op.rs new file mode 100644 index 0000000000..52c1cd13ba --- /dev/null +++ b/crates/ir2/src/decode/op.rs @@ -0,0 +1,231 @@ +use crate::{ + index::{Memory, Table}, + Address, + BranchOffset, + Decode, + Decoder, + Offset16, + Stack, +}; + +#[derive(Copy, Clone)] +pub struct UnaryOp { + pub result: Stack, + pub value: Stack, +} + +impl Decode for UnaryOp { + unsafe fn decode(decoder: &mut D) -> Self { + Self { + result: Decode::decode(decoder), + value: Decode::decode(decoder), + } + } +} + +#[derive(Copy, Clone)] +pub struct BinaryOp { + pub result: Stack, + pub lhs: Lhs, + pub rhs: Rhs, +} + +impl Decode for BinaryOp +where + Lhs: Decode, + Rhs: Decode, +{ + unsafe fn decode(decoder: &mut D) -> Self { + Self { + result: Decode::decode(decoder), + lhs: Decode::decode(decoder), + rhs: Decode::decode(decoder), + } + } +} + +#[derive(Copy, Clone)] +pub struct CmpBranchOp { + pub lhs: Lhs, + pub rhs: Rhs, + pub offset: BranchOffset, +} + +impl Decode for CmpBranchOp +where + Lhs: Decode, + Rhs: Decode, +{ + unsafe fn decode(decoder: &mut D) -> Self { + Self { + lhs: Decode::decode(decoder), + rhs: Decode::decode(decoder), + offset: Decode::decode(decoder), + } + } +} + +#[derive(Copy, Clone)] +pub struct CmpSelectOp { + pub result: Stack, + pub lhs: Lhs, + pub rhs: Rhs, + pub val_true: Stack, + pub val_false: Stack, +} + +impl Decode for CmpSelectOp +where + Lhs: Decode, + Rhs: Decode, +{ + unsafe fn decode(decoder: &mut D) -> Self { + Self { + result: Decode::decode(decoder), + lhs: Decode::decode(decoder), + rhs: Decode::decode(decoder), + val_true: Decode::decode(decoder), + val_false: Decode::decode(decoder), + } + } +} + +#[derive(Copy, Clone)] +pub struct LoadOp_Ss { + pub result: Stack, + pub ptr: Stack, + pub offset: u64, + pub memory: Memory, +} + +impl Decode for LoadOp_Ss { + unsafe fn decode(decoder: &mut D) -> Self { + Self { + result: Decode::decode(decoder), + ptr: Decode::decode(decoder), + offset: Decode::decode(decoder), + memory: Decode::decode(decoder), + } + } +} + +#[derive(Copy, Clone)] +pub struct LoadOp_Si { + pub result: Stack, + pub address: Address, + pub memory: Memory, +} + +impl Decode for LoadOp_Si { + unsafe fn decode(decoder: &mut D) -> Self { + Self { + result: Decode::decode(decoder), + address: Decode::decode(decoder), + memory: Decode::decode(decoder), + } + } +} + +#[derive(Copy, Clone)] +pub struct LoadOpMem0Offset16_Ss { + pub result: Stack, + pub ptr: Stack, + pub offset: Offset16, +} + +impl Decode for LoadOpMem0Offset16_Ss { + unsafe fn decode(decoder: &mut D) -> Self { + Self { + result: Decode::decode(decoder), + ptr: Decode::decode(decoder), + offset: Decode::decode(decoder), + } + } +} + +#[derive(Copy, Clone)] +pub struct StoreOp_S { + pub ptr: Stack, + pub offset: u64, + pub value: T, + pub memory: Memory, +} + +impl Decode for StoreOp_S { + unsafe fn decode(decoder: &mut D) -> Self { + Self { + ptr: Decode::decode(decoder), + offset: Decode::decode(decoder), + value: Decode::decode(decoder), + memory: Decode::decode(decoder), + } + } +} + +#[derive(Copy, Clone)] +pub struct StoreOp_I { + pub address: Address, + pub value: T, + pub memory: Memory, +} + +impl Decode for StoreOp_I { + unsafe fn decode(decoder: &mut D) -> Self { + Self { + address: Decode::decode(decoder), + value: Decode::decode(decoder), + memory: Decode::decode(decoder), + } + } +} + +#[derive(Copy, Clone)] +pub struct StoreOpMem0Offset16_S { + pub ptr: Stack, + pub offset: Offset16, + pub value: T, +} + +impl Decode for StoreOpMem0Offset16_S { + unsafe fn decode(decoder: &mut D) -> Self { + Self { + ptr: Decode::decode(decoder), + offset: Decode::decode(decoder), + value: Decode::decode(decoder), + } + } +} + +#[derive(Copy, Clone)] +pub struct TableGet { + pub result: Stack, + pub index: T, + pub table: Table, +} + +impl Decode for TableGet { + unsafe fn decode(decoder: &mut D) -> Self { + Self { + result: Decode::decode(decoder), + index: Decode::decode(decoder), + table: Decode::decode(decoder), + } + } +} + +#[derive(Copy, Clone)] +pub struct TableSet { + pub table: Table, + pub index: I, + pub value: V, +} + +impl Decode for TableSet { + unsafe fn decode(decoder: &mut D) -> Self { + Self { + table: Decode::decode(decoder), + index: Decode::decode(decoder), + value: Decode::decode(decoder), + } + } +} diff --git a/crates/ir2/src/lib.rs b/crates/ir2/src/lib.rs index fc608dd27d..ed871ad07c 100644 --- a/crates/ir2/src/lib.rs +++ b/crates/ir2/src/lib.rs @@ -4,7 +4,7 @@ extern crate alloc; #[cfg(feature = "std")] extern crate std; -mod decode; +pub mod decode; mod encode; mod error; pub mod index; From 13848cd3aa2fe0d8a90db18c306306f2d46144de Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 28 Aug 2025 11:55:44 +0200 Subject: [PATCH 118/186] add Encode impls for tuples --- crates/ir2/src/encode.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/crates/ir2/src/encode.rs b/crates/ir2/src/encode.rs index 61c076b1be..0dc939b2f0 100644 --- a/crates/ir2/src/encode.rs +++ b/crates/ir2/src/encode.rs @@ -162,4 +162,30 @@ impl_encode_using! { }, } +macro_rules! for_tuple { + ( $mac:ident ) => { + $mac! { T0 } + $mac! { T0, T1 } + $mac! { T0, T1, T2 } + $mac! { T0, T1, T2, T3 } + $mac! { T0, T1, T2, T3, T4 } + $mac! { T0, T1, T2, T3, T4, T5 } + $mac! { T0, T1, T2, T3, T4, T5, T6 } + }; +} +macro_rules! impl_encode_for_tuple { + ( $t0:ident $(, $t:ident)* $(,)? ) => { + impl<$t0: Encode $(, $t: Encode)*> Encode for ($t0, $($t,)*) { + fn encode(&self, encoder: &mut E) -> Result { + #[allow(non_snake_case)] + let ($t0, $($t,)*) = self; + let pos = $t0.encode(encoder)?; + $( $t.encode(encoder)?; )* + Ok(pos) + } + } + }; +} +for_tuple!(impl_encode_for_tuple); + include!(concat!(env!("OUT_DIR"), "/encode.rs")); From ffcd62b4524104a170921b20c587f853f0999963 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 28 Aug 2025 12:02:25 +0200 Subject: [PATCH 119/186] add generic Encode impl for &T --- crates/ir2/src/encode.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/crates/ir2/src/encode.rs b/crates/ir2/src/encode.rs index 0dc939b2f0..ea1a842d1a 100644 --- a/crates/ir2/src/encode.rs +++ b/crates/ir2/src/encode.rs @@ -188,4 +188,10 @@ macro_rules! impl_encode_for_tuple { } for_tuple!(impl_encode_for_tuple); +impl Encode for &'_ T { + fn encode(&self, encoder: &mut E) -> Result { + ::encode(*self, encoder) + } +} + include!(concat!(env!("OUT_DIR"), "/encode.rs")); From c1aa506d8ef0afde6cae05b50c7707ce4cff1b2a Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 28 Aug 2025 12:02:38 +0200 Subject: [PATCH 120/186] drastically reduce codegen for Encode impls --- crates/ir2/build/display/encode.rs | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/crates/ir2/build/display/encode.rs b/crates/ir2/build/display/encode.rs index 6010efb9cd..865f698425 100644 --- a/crates/ir2/build/display/encode.rs +++ b/crates/ir2/build/display/encode.rs @@ -1,9 +1,5 @@ use crate::build::{ - display::{ - ident::DisplayIdent, - utils::{DisplayConcat, DisplaySequence}, - Indent, - }, + display::{ident::DisplayIdent, utils::DisplaySequence, Indent}, isa::Isa, op::{ BinaryOp, @@ -55,23 +51,11 @@ impl<'a, T> DisplayEncode<&'a T> { .map(|field| field.ident) .map(SnakeCase), ); - let encode_params = DisplaySequence::new( - "", - fields - .iter() - .filter_map(Option::as_ref) - .map(|field| field.ident) - .map(SnakeCase) - .map(|param| (indent.inc(), param, ".encode(encoder)?;\n")) - .map(DisplayConcat), - ); write!( f, "\ {indent}Self::{camel_ident} {{ {match_params} }} => {{\n\ - {indent} let pos = OpCode::{camel_ident}.encode(encoder)?;\n\ - {encode_params}\ - {indent} Ok(pos)\n\ + {indent} (OpCode::{camel_ident}, {match_params}).encode(encoder)\n\ {indent}}}\n\ " ) From 82924b9252b9f5d1ab4fec77bee6e95b749781f9 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 28 Aug 2025 12:07:28 +0200 Subject: [PATCH 121/186] inline crate re-exports --- crates/ir2/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/ir2/src/lib.rs b/crates/ir2/src/lib.rs index ed871ad07c..d245b87ffd 100644 --- a/crates/ir2/src/lib.rs +++ b/crates/ir2/src/lib.rs @@ -14,6 +14,7 @@ mod span; use wasmi_core as core; +#[doc(inline)] pub use self::{ decode::{Decode, Decoder}, encode::{Encode, Encoder}, From dc4ef980abe05da3c0e8946ab4b14c433e60b122 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 28 Aug 2025 16:47:25 +0200 Subject: [PATCH 122/186] fix indentation of OpCode enum --- crates/ir2/build/display/op_code.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ir2/build/display/op_code.rs b/crates/ir2/build/display/op_code.rs index 56e452779c..8867aaaa4d 100644 --- a/crates/ir2/build/display/op_code.rs +++ b/crates/ir2/build/display/op_code.rs @@ -42,7 +42,7 @@ impl Display for DisplayOpCode<&'_ Isa> { f, "\ {indent}#[allow(non_camel_case_types)]\n\ - {indent}#[repr(u16)] + {indent}#[repr(u16)]\n\ {indent}pub enum OpCode {{\n\ {variants}\n\ {indent}}}\n\ From 7c75d144e022e3aedec619ec0044d6182628cdd3 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 28 Aug 2025 16:58:36 +0200 Subject: [PATCH 123/186] fix idents of some div/rem ops --- crates/ir2/build/op.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 16ca505154..fe6b966539 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -559,28 +559,28 @@ impl BinaryOpKind { | Self::I32Add | Self::I32Sub | Self::I32Mul - | Self::S32Div - | Self::S32Rem | Self::I32BitAnd | Self::I32BitOr | Self::I32BitXor | Self::I32Shl - | Self::S32Shr | Self::I32Rotl | Self::I32Rotr => Ty::I32, + | Self::S32Div + | Self::S32Rem + | Self::S32Shr => Ty::S32, | Self::U32Div | Self::U32Rem | Self::U32Shr => Ty::U32, | Self::I64Add | Self::I64Sub | Self::I64Mul - | Self::S64Div - | Self::S64Rem | Self::I64BitAnd | Self::I64BitOr | Self::I64BitXor | Self::I64Shl - | Self::S64Shr | Self::I64Rotl | Self::I64Rotr => Ty::I64, + | Self::S64Div + | Self::S64Rem + | Self::S64Shr => Ty::S64, | Self::U64Div | Self::U64Rem | Self::U64Shr => Ty::U64, | Self::F32Add | Self::F32Sub From 52cac2a9cfaf234cdd77a7603d833aeae9d9eadd Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 28 Aug 2025 16:58:41 +0200 Subject: [PATCH 124/186] fix broken doc link --- crates/ir2/src/primitive.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ir2/src/primitive.rs b/crates/ir2/src/primitive.rs index b35379e777..7a5ebb98ee 100644 --- a/crates/ir2/src/primitive.rs +++ b/crates/ir2/src/primitive.rs @@ -139,9 +139,9 @@ impl BranchOffset { } } -/// The accumulated fuel to execute a block via [`Instruction::ConsumeFuel`]. +/// The accumulated fuel to execute a block via [`Op::ConsumeFuel`]. /// -/// [`Instruction::ConsumeFuel`]: [`super::Instruction::ConsumeFuel`] +/// [`Op::ConsumeFuel`]: crate::Op::ConsumeFuel #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[repr(transparent)] pub struct BlockFuel(u64); From b78910237660710de17fdf2d23caba38961db0ec Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Fri, 29 Aug 2025 12:10:24 +0200 Subject: [PATCH 125/186] move Input more to top of file --- crates/ir2/build/op.rs | 52 +++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index fe6b966539..908ef84b14 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -64,6 +64,32 @@ impl Display for Field { } } +#[derive(Copy, Clone)] +pub enum Input { + Stack, + Immediate, +} + +impl Display for CamelCase { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s = match self.0 { + Input::Stack => "S", + Input::Immediate => "I", + }; + write!(f, "{s}") + } +} + +impl Display for SnakeCase { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s = match self.0 { + Input::Stack => "s", + Input::Immediate => "i", + }; + write!(f, "{s}") + } +} + #[derive(Copy, Clone)] pub struct GenericOp { pub ident: Ident, @@ -1293,29 +1319,3 @@ impl TableSetOp { [self.index_field(), self.value_field(), self.table_field()] } } - -#[derive(Copy, Clone)] -pub enum Input { - Stack, - Immediate, -} - -impl Display for CamelCase { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let s = match self.0 { - Input::Stack => "S", - Input::Immediate => "I", - }; - write!(f, "{s}") - } -} - -impl Display for SnakeCase { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let s = match self.0 { - Input::Stack => "s", - Input::Immediate => "i", - }; - write!(f, "{s}") - } -} From ed49ba9a6e90f1bfce4b109c4ba49da8f1e3fd4f Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Fri, 29 Aug 2025 12:12:25 +0200 Subject: [PATCH 126/186] rename Input -> OperandKind --- crates/ir2/build/display/decode.rs | 4 +- crates/ir2/build/display/ident.rs | 14 ++-- crates/ir2/build/isa.rs | 86 +++++++++++--------- crates/ir2/build/op.rs | 121 +++++++++++++++-------------- 4 files changed, 121 insertions(+), 104 deletions(-) diff --git a/crates/ir2/build/display/decode.rs b/crates/ir2/build/display/decode.rs index 633f08bbbc..6f58a8c1b4 100644 --- a/crates/ir2/build/display/decode.rs +++ b/crates/ir2/build/display/decode.rs @@ -9,9 +9,9 @@ use crate::build::{ CmpBranchOp, CmpSelectOp, GenericOp, - Input, LoadOp, Op, + OperandKind, StoreOp, TableGetOp, TableSetOp, @@ -119,7 +119,7 @@ impl Display for DisplayDecode<&'_ LoadOp> { let mem0_offset16 = (op.mem0 && op.offset16) .then_some("Mem0Offset16") .display_maybe(); - let result_suffix = CamelCase(Input::Stack); + let result_suffix = CamelCase(OperandKind::Stack); let ptr_suffix = SnakeCase(op.ptr); writeln!( f, diff --git a/crates/ir2/build/display/ident.rs b/crates/ir2/build/display/ident.rs index 41574d9f09..ffb349612a 100644 --- a/crates/ir2/build/display/ident.rs +++ b/crates/ir2/build/display/ident.rs @@ -5,9 +5,9 @@ use crate::build::{ CmpBranchOp, CmpSelectOp, GenericOp, - Input, LoadOp, Op, + OperandKind, StoreOp, TableGetOp, TableSetOp, @@ -81,8 +81,8 @@ impl Display for DisplayIdent<&'_ UnaryOp> { .map(|i| (sep, case.wrap(i))) .map(DisplayConcat) .display_maybe(); - let result_suffix = case.wrap(Input::Stack); - let value_suffix = SnakeCase(Input::Stack); + let result_suffix = case.wrap(OperandKind::Stack); + let value_suffix = SnakeCase(OperandKind::Stack); write!( f, "{ident_prefix}{ident}{ident_suffix}_{result_suffix}{value_suffix}" @@ -97,7 +97,7 @@ impl Display for DisplayIdent<&'_ BinaryOp> { let kind = self.value.kind; let ident = case.wrap(kind.ident()); let ident_prefix = case.wrap(kind.ident_prefix()); - let result_suffix = case.wrap(Input::Stack); + let result_suffix = case.wrap(OperandKind::Stack); let lhs_suffix = SnakeCase(self.value.lhs); let rhs_suffix = SnakeCase(self.value.rhs); write!( @@ -131,7 +131,7 @@ impl Display for DisplayIdent<&'_ CmpSelectOp> { let select = case.wrap(Ident::Select); let ident = case.wrap(cmp.ident()); let input_ident = case.wrap(Ident::from(cmp.input_ty())); - let result_suffix = case.wrap(Input::Stack); + let result_suffix = case.wrap(OperandKind::Stack); let lhs_suffix = SnakeCase(self.value.lhs); let rhs_suffix = SnakeCase(self.value.rhs); write!( @@ -146,7 +146,7 @@ impl Display for DisplayIdent<&'_ LoadOp> { let case = self.case; let kind = self.value.kind; let ident = case.wrap(kind.ident()); - let result_suffix = case.wrap(Input::Stack); + let result_suffix = case.wrap(OperandKind::Stack); let ptr_suffix = SnakeCase(self.value.ptr); let sep = case.wrap(Sep); let ident_prefix = self @@ -224,7 +224,7 @@ impl Display for DisplayIdent<&'_ TableGetOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let case = self.case; let ident = case.wrap(Ident::TableGet); - let result_suffix = case.wrap(Input::Stack); + let result_suffix = case.wrap(OperandKind::Stack); let index_suffix = SnakeCase(self.value.index); write!(f, "{ident}_{result_suffix}{index_suffix}") } diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 8a514b3de9..8ae6e8229e 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -9,9 +9,9 @@ use crate::build::{ Field, FieldTy, GenericOp, - Input, LoadOp, LoadOpKind, + OperandKind, StoreOp, StoreOpKind, TableGetOp, @@ -204,17 +204,21 @@ fn add_binary_ops(isa: &mut Isa) { BinaryOpKind::F64Copysign, ]; for op in ops { - isa.push_op(Op::Binary(BinaryOp::new(op, Input::Stack, Input::Stack))); isa.push_op(Op::Binary(BinaryOp::new( op, - Input::Stack, - Input::Immediate, + OperandKind::Stack, + OperandKind::Stack, + ))); + isa.push_op(Op::Binary(BinaryOp::new( + op, + OperandKind::Stack, + OperandKind::Immediate, ))); if matches!(op.commutativity(), Commutativity::NonCommutative) { isa.push_op(Op::Binary(BinaryOp::new( op, - Input::Immediate, - Input::Stack, + OperandKind::Immediate, + OperandKind::Stack, ))); } } @@ -262,19 +266,19 @@ fn add_cmp_branch_ops(isa: &mut Isa) { for op in ops { isa.push_op(Op::CmpBranch(CmpBranchOp::new( op, - Input::Stack, - Input::Stack, + OperandKind::Stack, + OperandKind::Stack, ))); isa.push_op(Op::CmpBranch(CmpBranchOp::new( op, - Input::Stack, - Input::Immediate, + OperandKind::Stack, + OperandKind::Immediate, ))); if matches!(op.commutativity(), Commutativity::NonCommutative) { isa.push_op(Op::CmpBranch(CmpBranchOp::new( op, - Input::Immediate, - Input::Stack, + OperandKind::Immediate, + OperandKind::Stack, ))); } } @@ -310,19 +314,19 @@ fn add_cmp_select_ops(isa: &mut Isa) { for op in ops { isa.push_op(Op::CmpSelect(CmpSelectOp::new( op, - Input::Stack, - Input::Stack, + OperandKind::Stack, + OperandKind::Stack, ))); isa.push_op(Op::CmpSelect(CmpSelectOp::new( op, - Input::Stack, - Input::Immediate, + OperandKind::Stack, + OperandKind::Immediate, ))); if matches!(op.commutativity(), Commutativity::NonCommutative) { isa.push_op(Op::CmpSelect(CmpSelectOp::new( op, - Input::Immediate, - Input::Stack, + OperandKind::Immediate, + OperandKind::Stack, ))); } } @@ -347,9 +351,14 @@ fn add_load_ops(isa: &mut Isa) { LoadOpKind::U64Load32, ]; for op in ops { - isa.push_op(Op::Load(LoadOp::new(op, Input::Stack, false, false))); - isa.push_op(Op::Load(LoadOp::new(op, Input::Immediate, false, false))); - isa.push_op(Op::Load(LoadOp::new(op, Input::Stack, true, true))); + isa.push_op(Op::Load(LoadOp::new(op, OperandKind::Stack, false, false))); + isa.push_op(Op::Load(LoadOp::new( + op, + OperandKind::Immediate, + false, + false, + ))); + isa.push_op(Op::Load(LoadOp::new(op, OperandKind::Stack, true, true))); } } @@ -369,36 +378,36 @@ fn add_store_ops(isa: &mut Isa) { for op in ops { isa.push_op(Op::Store(StoreOp::new( op, - Input::Stack, - Input::Stack, + OperandKind::Stack, + OperandKind::Stack, false, false, ))); isa.push_op(Op::Store(StoreOp::new( op, - Input::Stack, - Input::Immediate, + OperandKind::Stack, + OperandKind::Immediate, false, false, ))); isa.push_op(Op::Store(StoreOp::new( op, - Input::Immediate, - Input::Stack, + OperandKind::Immediate, + OperandKind::Stack, false, false, ))); isa.push_op(Op::Store(StoreOp::new( op, - Input::Stack, - Input::Stack, + OperandKind::Stack, + OperandKind::Stack, true, true, ))); isa.push_op(Op::Store(StoreOp::new( op, - Input::Stack, - Input::Immediate, + OperandKind::Stack, + OperandKind::Immediate, true, true, ))); @@ -587,12 +596,15 @@ fn add_global_ops(isa: &mut Isa) { fn add_table_ops(isa: &mut Isa) { let ops = [ - Op::TableGet(TableGetOp::new(Input::Stack)), - Op::TableGet(TableGetOp::new(Input::Immediate)), - Op::TableSet(TableSetOp::new(Input::Stack, Input::Stack)), - Op::TableSet(TableSetOp::new(Input::Stack, Input::Immediate)), - Op::TableSet(TableSetOp::new(Input::Immediate, Input::Stack)), - Op::TableSet(TableSetOp::new(Input::Immediate, Input::Immediate)), + Op::TableGet(TableGetOp::new(OperandKind::Stack)), + Op::TableGet(TableGetOp::new(OperandKind::Immediate)), + Op::TableSet(TableSetOp::new(OperandKind::Stack, OperandKind::Stack)), + Op::TableSet(TableSetOp::new(OperandKind::Stack, OperandKind::Immediate)), + Op::TableSet(TableSetOp::new(OperandKind::Immediate, OperandKind::Stack)), + Op::TableSet(TableSetOp::new( + OperandKind::Immediate, + OperandKind::Immediate, + )), Op::from(GenericOp::new( Ident::TableSize, [ diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 908ef84b14..3e5f60dfef 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -64,27 +64,30 @@ impl Display for Field { } } +/// The kind of an operand of an [`Op`]. #[derive(Copy, Clone)] -pub enum Input { +pub enum OperandKind { + /// The operand is a [`Stack`] index. Stack, + /// The operand is an immediate value. Immediate, } -impl Display for CamelCase { +impl Display for CamelCase { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let s = match self.0 { - Input::Stack => "S", - Input::Immediate => "I", + OperandKind::Stack => "S", + OperandKind::Immediate => "I", }; write!(f, "{s}") } } -impl Display for SnakeCase { +impl Display for SnakeCase { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let s = match self.0 { - Input::Stack => "s", - Input::Immediate => "i", + OperandKind::Stack => "s", + OperandKind::Immediate => "i", }; write!(f, "{s}") } @@ -344,12 +347,12 @@ impl UnaryOpKind { #[derive(Copy, Clone)] pub struct BinaryOp { pub kind: BinaryOpKind, - pub lhs: Input, - pub rhs: Input, + pub lhs: OperandKind, + pub rhs: OperandKind, } impl BinaryOp { - pub fn new(kind: BinaryOpKind, lhs: Input, rhs: Input) -> Self { + pub fn new(kind: BinaryOpKind, lhs: OperandKind, rhs: OperandKind) -> Self { Self { kind, lhs, rhs } } @@ -483,10 +486,10 @@ impl BinaryOpKind { Ident::from(ty) } - fn lhs_field(&self, input: Input) -> FieldTy { + fn lhs_field(&self, input: OperandKind) -> FieldTy { match input { - Input::Stack => FieldTy::Stack, - Input::Immediate => match self { + OperandKind::Stack => FieldTy::Stack, + OperandKind::Immediate => match self { | Self::Cmp(cmp) => cmp.input_field(input), | Self::I32Add | Self::I32Sub @@ -536,10 +539,10 @@ impl BinaryOpKind { } } - fn rhs_field(&self, input: Input) -> FieldTy { + fn rhs_field(&self, input: OperandKind) -> FieldTy { match input { - Input::Stack => FieldTy::Stack, - Input::Immediate => match self { + OperandKind::Stack => FieldTy::Stack, + OperandKind::Immediate => match self { | Self::Cmp(cmp) => cmp.input_field(input), | Self::I32Add | Self::I32Sub @@ -591,9 +594,7 @@ impl BinaryOpKind { | Self::I32Shl | Self::I32Rotl | Self::I32Rotr => Ty::I32, - | Self::S32Div - | Self::S32Rem - | Self::S32Shr => Ty::S32, + | Self::S32Div | Self::S32Rem | Self::S32Shr => Ty::S32, | Self::U32Div | Self::U32Rem | Self::U32Shr => Ty::U32, | Self::I64Add | Self::I64Sub @@ -604,9 +605,7 @@ impl BinaryOpKind { | Self::I64Shl | Self::I64Rotl | Self::I64Rotr => Ty::I64, - | Self::S64Div - | Self::S64Rem - | Self::S64Shr => Ty::S64, + | Self::S64Div | Self::S64Rem | Self::S64Shr => Ty::S64, | Self::U64Div | Self::U64Rem | Self::U64Shr => Ty::U64, | Self::F32Add | Self::F32Sub @@ -652,12 +651,12 @@ pub enum Commutativity { #[derive(Copy, Clone)] pub struct CmpBranchOp { pub cmp: CmpOpKind, - pub lhs: Input, - pub rhs: Input, + pub lhs: OperandKind, + pub rhs: OperandKind, } impl CmpBranchOp { - pub fn new(cmp: CmpOpKind, lhs: Input, rhs: Input) -> Self { + pub fn new(cmp: CmpOpKind, lhs: OperandKind, rhs: OperandKind) -> Self { Self { cmp, lhs, rhs } } @@ -681,12 +680,12 @@ impl CmpBranchOp { #[derive(Copy, Clone)] pub struct CmpSelectOp { pub cmp: CmpOpKind, - pub lhs: Input, - pub rhs: Input, + pub lhs: OperandKind, + pub rhs: OperandKind, } impl CmpSelectOp { - pub fn new(cmp: CmpOpKind, lhs: Input, rhs: Input) -> Self { + pub fn new(cmp: CmpOpKind, lhs: OperandKind, rhs: OperandKind) -> Self { Self { cmp, lhs, rhs } } @@ -906,10 +905,10 @@ impl CmpOpKind { } } - fn input_field(&self, input: Input) -> FieldTy { + fn input_field(&self, input: OperandKind) -> FieldTy { match input { - Input::Stack => FieldTy::Stack, - Input::Immediate => match self { + OperandKind::Stack => FieldTy::Stack, + OperandKind::Immediate => match self { | Self::I32Eq | Self::I32NotEq | Self::I32And @@ -1020,7 +1019,7 @@ pub struct LoadOp { /// The kind of the load operator. pub kind: LoadOpKind, /// The `ptr` field type. - pub ptr: Input, + pub ptr: OperandKind, /// True, if the operator is always operating on (`memory 0`). pub mem0: bool, /// True, if the operator uses a 16-bit offset field. @@ -1028,7 +1027,7 @@ pub struct LoadOp { } impl LoadOp { - pub fn new(kind: LoadOpKind, ptr: Input, mem0: bool, offset16: bool) -> Self { + pub fn new(kind: LoadOpKind, ptr: OperandKind, mem0: bool, offset16: bool) -> Self { Self { kind, ptr, @@ -1043,19 +1042,19 @@ impl LoadOp { pub fn ptr_field(&self) -> Field { let ptr_ty = match self.ptr { - Input::Stack => FieldTy::Stack, - Input::Immediate => FieldTy::Address, + OperandKind::Stack => FieldTy::Stack, + OperandKind::Immediate => FieldTy::Address, }; Field::new(Ident::Ptr, ptr_ty) } pub fn offset_field(&self) -> Option { let offset_ty = match self.ptr { - Input::Stack => match self.offset16 { + OperandKind::Stack => match self.offset16 { true => FieldTy::Offset16, false => FieldTy::U64, }, - Input::Immediate => return None, + OperandKind::Immediate => return None, }; Some(Field::new(Ident::Offset, offset_ty)) } @@ -1134,9 +1133,9 @@ pub struct StoreOp { /// The kind of the load operator. pub kind: StoreOpKind, /// The `ptr` input type. - pub ptr: Input, + pub ptr: OperandKind, /// The `value` input type. - pub value: Input, + pub value: OperandKind, /// True, if the operator is always operating on (`memory 0`). pub mem0: bool, /// True, if the operator uses a 16-bit offset field. @@ -1144,7 +1143,13 @@ pub struct StoreOp { } impl StoreOp { - pub fn new(kind: StoreOpKind, ptr: Input, value: Input, mem0: bool, offset16: bool) -> Self { + pub fn new( + kind: StoreOpKind, + ptr: OperandKind, + value: OperandKind, + mem0: bool, + offset16: bool, + ) -> Self { Self { kind, ptr, @@ -1156,19 +1161,19 @@ impl StoreOp { pub fn ptr_field(&self) -> Field { let ptr_ty = match self.ptr { - Input::Stack => FieldTy::Stack, - Input::Immediate => FieldTy::Address, + OperandKind::Stack => FieldTy::Stack, + OperandKind::Immediate => FieldTy::Address, }; Field::new(Ident::Ptr, ptr_ty) } pub fn offset_field(&self) -> Option { let offset_ty = match self.ptr { - Input::Stack => match self.offset16 { + OperandKind::Stack => match self.offset16 { true => FieldTy::Offset16, false => FieldTy::U64, }, - Input::Immediate => return None, + OperandKind::Immediate => return None, }; Some(Field::new(Ident::Offset, offset_ty)) } @@ -1234,10 +1239,10 @@ impl StoreOpKind { } } - fn value_ty(&self, input: Input) -> FieldTy { + fn value_ty(&self, input: OperandKind) -> FieldTy { match input { - Input::Stack => FieldTy::Stack, - Input::Immediate => match self { + OperandKind::Stack => FieldTy::Stack, + OperandKind::Immediate => match self { Self::Store32 => FieldTy::U32, Self::Store64 => FieldTy::U64, Self::I32Store8 => FieldTy::I8, @@ -1253,11 +1258,11 @@ impl StoreOpKind { #[derive(Copy, Clone)] pub struct TableGetOp { /// The `index` type. - pub index: Input, + pub index: OperandKind, } impl TableGetOp { - pub fn new(index: Input) -> Self { + pub fn new(index: OperandKind) -> Self { Self { index } } @@ -1267,8 +1272,8 @@ impl TableGetOp { pub fn index_field(&self) -> Field { let index_ty = match self.index { - Input::Stack => FieldTy::Stack, - Input::Immediate => FieldTy::U32, + OperandKind::Stack => FieldTy::Stack, + OperandKind::Immediate => FieldTy::U32, }; Field::new(Ident::Index, index_ty) } @@ -1285,28 +1290,28 @@ impl TableGetOp { #[derive(Copy, Clone)] pub struct TableSetOp { /// The `index` input. - pub index: Input, + pub index: OperandKind, /// The `value` input. - pub value: Input, + pub value: OperandKind, } impl TableSetOp { - pub fn new(index: Input, value: Input) -> Self { + pub fn new(index: OperandKind, value: OperandKind) -> Self { Self { index, value } } pub fn index_field(&self) -> Field { let index_ty = match self.index { - Input::Stack => FieldTy::Stack, - Input::Immediate => FieldTy::U32, + OperandKind::Stack => FieldTy::Stack, + OperandKind::Immediate => FieldTy::U32, }; Field::new(Ident::Index, index_ty) } pub fn value_field(&self) -> Field { let value_ty = match self.value { - Input::Stack => FieldTy::Stack, - Input::Immediate => FieldTy::U64, + OperandKind::Stack => FieldTy::Stack, + OperandKind::Immediate => FieldTy::U64, }; Field::new(Ident::Value, value_ty) } From eadc8095c38afd22ec6d76436863fddda0a3daff Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Fri, 29 Aug 2025 12:30:08 +0200 Subject: [PATCH 127/186] add v128.splat ops codegen --- crates/ir2/build/display/constructors.rs | 9 ++++++ crates/ir2/build/display/decode.rs | 13 +++++++- crates/ir2/build/display/encode.rs | 9 ++++++ crates/ir2/build/display/ident.rs | 18 +++++++++++ crates/ir2/build/display/op.rs | 9 ++++++ crates/ir2/build/display/result_mut.rs | 8 +++++ crates/ir2/build/isa.rs | 24 +++++++++----- crates/ir2/build/op.rs | 40 ++++++++++++++++++++++++ crates/ir2/build/token.rs | 1 + crates/ir2/src/decode/op.rs | 6 ++-- 10 files changed, 125 insertions(+), 12 deletions(-) diff --git a/crates/ir2/build/display/constructors.rs b/crates/ir2/build/display/constructors.rs index d49f8923d7..c5921c0fa3 100644 --- a/crates/ir2/build/display/constructors.rs +++ b/crates/ir2/build/display/constructors.rs @@ -13,6 +13,7 @@ use crate::build::{ TableGetOp, TableSetOp, UnaryOp, + V128Splat, }, token::SnakeCase, }; @@ -102,6 +103,7 @@ impl Display for DisplayConstructor<&'_ Op> { Op::Generic3(op) => self.map(op).fmt(f), Op::Generic4(op) => self.map(op).fmt(f), Op::Generic5(op) => self.map(op).fmt(f), + Op::V128Splat(op) => self.map(op).fmt(f), } } } @@ -168,3 +170,10 @@ impl Display for DisplayConstructor<&'_ GenericOp> { self.display_constructor(f, &fields) } } + +impl Display for DisplayConstructor<&'_ V128Splat> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fields = self.value.fields().map(Option::from); + self.display_constructor(f, &fields) + } +} diff --git a/crates/ir2/build/display/decode.rs b/crates/ir2/build/display/decode.rs index 6f58a8c1b4..ae0b932fd8 100644 --- a/crates/ir2/build/display/decode.rs +++ b/crates/ir2/build/display/decode.rs @@ -16,6 +16,7 @@ use crate::build::{ TableGetOp, TableSetOp, UnaryOp, + V128Splat, }, token::{CamelCase, SnakeCase}, Isa, @@ -71,6 +72,7 @@ impl Display for DisplayDecode<&'_ Op> { Op::Generic3(op) => self.map(op).fmt(f), Op::Generic4(op) => self.map(op).fmt(f), Op::Generic5(op) => self.map(op).fmt(f), + Op::V128Splat(op) => self.map(op).fmt(f), } } } @@ -78,7 +80,7 @@ impl Display for DisplayDecode<&'_ Op> { impl Display for DisplayDecode<&'_ UnaryOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let camel_ident = DisplayIdent::camel(self.value); - writeln!(f, "pub type {camel_ident} = UnaryOp;") + writeln!(f, "pub type {camel_ident} = UnaryOp;") } } @@ -208,3 +210,12 @@ impl Display for DisplayDecode<&'_ GenericOp> { ) } } + +impl Display for DisplayDecode<&'_ V128Splat> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let op = self.value; + let camel_ident = DisplayIdent::camel(op); + let value_ty = op.value_field().ty; + writeln!(f, "pub type {camel_ident} = UnaryOp<{value_ty}>;") + } +} diff --git a/crates/ir2/build/display/encode.rs b/crates/ir2/build/display/encode.rs index 865f698425..10abf4ac3b 100644 --- a/crates/ir2/build/display/encode.rs +++ b/crates/ir2/build/display/encode.rs @@ -13,6 +13,7 @@ use crate::build::{ TableGetOp, TableSetOp, UnaryOp, + V128Splat, }, token::SnakeCase, }; @@ -104,6 +105,7 @@ impl Display for DisplayEncode<&'_ Op> { Op::Generic3(op) => self.map(op).fmt(f), Op::Generic4(op) => self.map(op).fmt(f), Op::Generic5(op) => self.map(op).fmt(f), + Op::V128Splat(op) => self.map(op).fmt(f), } } } @@ -170,3 +172,10 @@ impl Display for DisplayEncode<&'_ GenericOp> { self.display_encode(f, &fields) } } + +impl Display for DisplayEncode<&'_ V128Splat> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fields = self.value.fields().map(Option::from); + self.display_encode(f, &fields) + } +} diff --git a/crates/ir2/build/display/ident.rs b/crates/ir2/build/display/ident.rs index ffb349612a..7d957ef6d7 100644 --- a/crates/ir2/build/display/ident.rs +++ b/crates/ir2/build/display/ident.rs @@ -8,10 +8,12 @@ use crate::build::{ LoadOp, Op, OperandKind, + SplatType, StoreOp, TableGetOp, TableSetOp, UnaryOp, + V128Splat, }, token::{Case, Ident, Sep, SnakeCase}, }; @@ -62,6 +64,7 @@ impl Display for DisplayIdent<&'_ Op> { Op::Generic3(op) => self.map(op).fmt(f), Op::Generic4(op) => self.map(op).fmt(f), Op::Generic5(op) => self.map(op).fmt(f), + Op::V128Splat(op) => self.map(op).fmt(f), } } } @@ -239,3 +242,18 @@ impl Display for DisplayIdent<&'_ TableSetOp> { write!(f, "{ident}_{index_suffix}{value_suffix}") } } + +impl Display for DisplayIdent<&'_ V128Splat> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let case = self.case; + let op = self.value; + let ident = case.wrap(Ident::V128Splat); + let width = match op.ty { + SplatType::U32 => "32", + SplatType::U64 => "64", + }; + let result_suffix = case.wrap(OperandKind::Stack); + let value_suffix = SnakeCase(op.value); + write!(f, "{ident}{width}_{result_suffix}{value_suffix}") + } +} diff --git a/crates/ir2/build/display/op.rs b/crates/ir2/build/display/op.rs index 938b851194..a470d3fac3 100644 --- a/crates/ir2/build/display/op.rs +++ b/crates/ir2/build/display/op.rs @@ -17,6 +17,7 @@ use crate::build::{ TableGetOp, TableSetOp, UnaryOp, + V128Splat, }, }; use core::fmt::{self, Display}; @@ -104,6 +105,7 @@ impl Display for DisplayOp<&'_ Op> { Op::Generic3(op) => self.map(op).fmt(f), Op::Generic4(op) => self.map(op).fmt(f), Op::Generic5(op) => self.map(op).fmt(f), + Op::V128Splat(op) => self.map(op).fmt(f), } } } @@ -170,3 +172,10 @@ impl Display for DisplayOp<&'_ TableSetOp> { self.display_variant(f, &fields) } } + +impl Display for DisplayOp<&'_ V128Splat> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fields = self.val.fields().map(Option::from); + self.display_variant(f, &fields) + } +} diff --git a/crates/ir2/build/display/result_mut.rs b/crates/ir2/build/display/result_mut.rs index f1e869f8bd..4d475bc775 100644 --- a/crates/ir2/build/display/result_mut.rs +++ b/crates/ir2/build/display/result_mut.rs @@ -12,6 +12,7 @@ use crate::build::{ TableGetOp, TableSetOp, UnaryOp, + V128Splat, }, }; use core::fmt::{self, Display}; @@ -89,6 +90,7 @@ impl Display for DisplayResultMut<&'_ Op> { Op::Generic3(op) => self.map(op).fmt(f), Op::Generic4(op) => self.map(op).fmt(f), Op::Generic5(op) => self.map(op).fmt(f), + Op::V128Splat(op) => self.map(op).fmt(f), } } } @@ -149,3 +151,9 @@ impl Display for DisplayResultMut<&'_ GenericOp> { self.display_match_arm(f) } } + +impl Display for DisplayResultMut<&'_ V128Splat> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.display_match_arm(f) + } +} diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 8ae6e8229e..2ff535d347 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -12,12 +12,14 @@ use crate::build::{ LoadOp, LoadOpKind, OperandKind, + SplatType, StoreOp, StoreOpKind, TableGetOp, TableSetOp, UnaryOp, UnaryOpKind, + V128Splat, }, token::Ident, Config, @@ -764,14 +766,20 @@ fn add_simd_ops(isa: &mut Isa, config: &Config) { if !config.simd { return; } - let ops = [Op::from(GenericOp::new( - Ident::Copy128, - [ - Field::new(Ident::Result, FieldTy::Stack), - Field::new(Ident::ValueLo, FieldTy::U64), - Field::new(Ident::ValueHi, FieldTy::U64), - ], - ))]; + let ops = [ + Op::from(GenericOp::new( + Ident::Copy128, + [ + Field::new(Ident::Result, FieldTy::Stack), + Field::new(Ident::ValueLo, FieldTy::U64), + Field::new(Ident::ValueHi, FieldTy::U64), + ], + )), + Op::from(V128Splat::new(SplatType::U32, OperandKind::Stack)), + Op::from(V128Splat::new(SplatType::U32, OperandKind::Immediate)), + Op::from(V128Splat::new(SplatType::U64, OperandKind::Stack)), + Op::from(V128Splat::new(SplatType::U64, OperandKind::Immediate)), + ]; for op in ops { isa.push_op(op); } diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 3e5f60dfef..d09967fad9 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -41,6 +41,7 @@ impl_from_for_op! { Generic3(GenericOp<3>), Generic4(GenericOp<4>), Generic5(GenericOp<5>), + V128Splat(V128Splat), } } @@ -1324,3 +1325,42 @@ impl TableSetOp { [self.index_field(), self.value_field(), self.table_field()] } } + +#[derive(Copy, Clone)] +pub struct V128Splat { + /// The type of the value to be splatted. + pub ty: SplatType, + /// The `value` to be splatted. + pub value: OperandKind, +} + +#[derive(Copy, Clone)] +pub enum SplatType { + U32, + U64, +} + +impl V128Splat { + pub fn new(ty: SplatType, value: OperandKind) -> Self { + Self { ty, value } + } + + pub fn result_field(&self) -> Field { + Field::new(Ident::Result, FieldTy::Stack) + } + + pub fn value_field(&self) -> Field { + let value_ty = match self.value { + OperandKind::Stack => FieldTy::Stack, + OperandKind::Immediate => match self.ty { + SplatType::U32 => FieldTy::U32, + SplatType::U64 => FieldTy::U64, + }, + }; + Field::new(Ident::Value, value_ty) + } + + pub fn fields(&self) -> [Field; 2] { + [self.result_field(), self.value_field()] + } +} diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index 8c80121b22..6aff8630b3 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -248,4 +248,5 @@ define_ident!( Copy128: copy128, ValueLo: value_lo, ValueHi: value_hi, + V128Splat: v128_splat, ); diff --git a/crates/ir2/src/decode/op.rs b/crates/ir2/src/decode/op.rs index 52c1cd13ba..f7e995f759 100644 --- a/crates/ir2/src/decode/op.rs +++ b/crates/ir2/src/decode/op.rs @@ -9,12 +9,12 @@ use crate::{ }; #[derive(Copy, Clone)] -pub struct UnaryOp { +pub struct UnaryOp { pub result: Stack, - pub value: Stack, + pub value: V, } -impl Decode for UnaryOp { +impl Decode for UnaryOp { unsafe fn decode(decoder: &mut D) -> Self { Self { result: Decode::decode(decoder), From 475a38352a1c4777ec0f58e50c69f5d39ca7a983 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Fri, 29 Aug 2025 12:50:50 +0200 Subject: [PATCH 128/186] apply clippy suggestion --- crates/ir2/build/display/utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ir2/build/display/utils.rs b/crates/ir2/build/display/utils.rs index c10da573da..890806b553 100644 --- a/crates/ir2/build/display/utils.rs +++ b/crates/ir2/build/display/utils.rs @@ -68,7 +68,7 @@ where let Some(first) = iter.next() else { return Ok(()); }; - write!(f, "{}", first)?; + write!(f, "{first}")?; let sep = &self.sep; for item in iter { write!(f, "{sep}{item}")?; From 69fa5477954554e90afe52fb5d1d234bbc7182a3 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Fri, 29 Aug 2025 12:51:44 +0200 Subject: [PATCH 129/186] fix invalid doc link --- crates/ir2/src/primitive.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ir2/src/primitive.rs b/crates/ir2/src/primitive.rs index 7a5ebb98ee..204a8a9ab5 100644 --- a/crates/ir2/src/primitive.rs +++ b/crates/ir2/src/primitive.rs @@ -1,7 +1,7 @@ use crate::Error; use core::marker::PhantomData; -/// Error that may occur upon converting values to [`Const16`]. +/// Error that may occur upon converting values to [`Address`] and [`Offset16`]. #[derive(Debug, Copy, Clone)] pub struct OutOfBoundsConst; From 537905bf40bea91318263c800d5135d79094b0b5 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Fri, 29 Aug 2025 15:06:07 +0200 Subject: [PATCH 130/186] use TrapCode and u8 conversions in wasmi_ir2 --- crates/ir2/src/decode/mod.rs | 14 +------------- crates/ir2/src/encode.rs | 16 +--------------- 2 files changed, 2 insertions(+), 28 deletions(-) diff --git a/crates/ir2/src/decode/mod.rs b/crates/ir2/src/decode/mod.rs index e5efeaea3d..e2f3a168e4 100644 --- a/crates/ir2/src/decode/mod.rs +++ b/crates/ir2/src/decode/mod.rs @@ -111,19 +111,7 @@ impl_decode_using! { NonZero as u64 = |value| unsafe { NonZero::new_unchecked(value) }, TrapCode as u8 = |code: u8| -> TrapCode { - match code { - 0 => TrapCode::UnreachableCodeReached, - 1 => TrapCode::MemoryOutOfBounds, - 2 => TrapCode::TableOutOfBounds, - 3 => TrapCode::IndirectCallToNull, - 4 => TrapCode::IntegerDivisionByZero, - 5 => TrapCode::IntegerOverflow, - 6 => TrapCode::BadConversionToInteger, - 7 => TrapCode::StackOverflow, - 8 => TrapCode::BadSignature, - 9 => TrapCode::OutOfFuel, - _ => TrapCode::GrowthOperationLimited, - } + TrapCode::try_from(code).unwrap_unchecked() }, } diff --git a/crates/ir2/src/encode.rs b/crates/ir2/src/encode.rs index ea1a842d1a..871213b588 100644 --- a/crates/ir2/src/encode.rs +++ b/crates/ir2/src/encode.rs @@ -145,21 +145,7 @@ impl_encode_using! { NonZero as u32 = NonZero::get, NonZero as u64 = NonZero::get, - TrapCode as u8 = |code: TrapCode| -> u8 { - match code { - TrapCode::UnreachableCodeReached => 0, - TrapCode::MemoryOutOfBounds => 1, - TrapCode::TableOutOfBounds => 2, - TrapCode::IndirectCallToNull => 3, - TrapCode::IntegerDivisionByZero => 4, - TrapCode::IntegerOverflow => 5, - TrapCode::BadConversionToInteger => 6, - TrapCode::StackOverflow => 7, - TrapCode::BadSignature => 8, - TrapCode::OutOfFuel => 9, - TrapCode::GrowthOperationLimited => 10, - } - }, + TrapCode as u8 = |code: TrapCode| -> u8 { code as _ }, } macro_rules! for_tuple { From 1085222a479fedf257bb12eb747a06c4b8ce0584 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Fri, 29 Aug 2025 16:38:00 +0200 Subject: [PATCH 131/186] rename V128Splat -> V128SplatOp --- crates/ir2/build/display/constructors.rs | 4 ++-- crates/ir2/build/display/decode.rs | 4 ++-- crates/ir2/build/display/encode.rs | 4 ++-- crates/ir2/build/display/ident.rs | 4 ++-- crates/ir2/build/display/op.rs | 4 ++-- crates/ir2/build/display/result_mut.rs | 4 ++-- crates/ir2/build/isa.rs | 10 +++++----- crates/ir2/build/op.rs | 6 +++--- 8 files changed, 20 insertions(+), 20 deletions(-) diff --git a/crates/ir2/build/display/constructors.rs b/crates/ir2/build/display/constructors.rs index c5921c0fa3..44d814bc78 100644 --- a/crates/ir2/build/display/constructors.rs +++ b/crates/ir2/build/display/constructors.rs @@ -13,7 +13,7 @@ use crate::build::{ TableGetOp, TableSetOp, UnaryOp, - V128Splat, + V128SplatOp, }, token::SnakeCase, }; @@ -171,7 +171,7 @@ impl Display for DisplayConstructor<&'_ GenericOp> { } } -impl Display for DisplayConstructor<&'_ V128Splat> { +impl Display for DisplayConstructor<&'_ V128SplatOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let fields = self.value.fields().map(Option::from); self.display_constructor(f, &fields) diff --git a/crates/ir2/build/display/decode.rs b/crates/ir2/build/display/decode.rs index ae0b932fd8..9284bbce34 100644 --- a/crates/ir2/build/display/decode.rs +++ b/crates/ir2/build/display/decode.rs @@ -16,7 +16,7 @@ use crate::build::{ TableGetOp, TableSetOp, UnaryOp, - V128Splat, + V128SplatOp, }, token::{CamelCase, SnakeCase}, Isa, @@ -211,7 +211,7 @@ impl Display for DisplayDecode<&'_ GenericOp> { } } -impl Display for DisplayDecode<&'_ V128Splat> { +impl Display for DisplayDecode<&'_ V128SplatOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let op = self.value; let camel_ident = DisplayIdent::camel(op); diff --git a/crates/ir2/build/display/encode.rs b/crates/ir2/build/display/encode.rs index 10abf4ac3b..b4c13c7983 100644 --- a/crates/ir2/build/display/encode.rs +++ b/crates/ir2/build/display/encode.rs @@ -13,7 +13,7 @@ use crate::build::{ TableGetOp, TableSetOp, UnaryOp, - V128Splat, + V128SplatOp, }, token::SnakeCase, }; @@ -173,7 +173,7 @@ impl Display for DisplayEncode<&'_ GenericOp> { } } -impl Display for DisplayEncode<&'_ V128Splat> { +impl Display for DisplayEncode<&'_ V128SplatOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let fields = self.value.fields().map(Option::from); self.display_encode(f, &fields) diff --git a/crates/ir2/build/display/ident.rs b/crates/ir2/build/display/ident.rs index 7d957ef6d7..f5b0c9e60c 100644 --- a/crates/ir2/build/display/ident.rs +++ b/crates/ir2/build/display/ident.rs @@ -13,7 +13,7 @@ use crate::build::{ TableGetOp, TableSetOp, UnaryOp, - V128Splat, + V128SplatOp, }, token::{Case, Ident, Sep, SnakeCase}, }; @@ -243,7 +243,7 @@ impl Display for DisplayIdent<&'_ TableSetOp> { } } -impl Display for DisplayIdent<&'_ V128Splat> { +impl Display for DisplayIdent<&'_ V128SplatOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let case = self.case; let op = self.value; diff --git a/crates/ir2/build/display/op.rs b/crates/ir2/build/display/op.rs index a470d3fac3..6920d8f9cd 100644 --- a/crates/ir2/build/display/op.rs +++ b/crates/ir2/build/display/op.rs @@ -17,7 +17,7 @@ use crate::build::{ TableGetOp, TableSetOp, UnaryOp, - V128Splat, + V128SplatOp, }, }; use core::fmt::{self, Display}; @@ -173,7 +173,7 @@ impl Display for DisplayOp<&'_ TableSetOp> { } } -impl Display for DisplayOp<&'_ V128Splat> { +impl Display for DisplayOp<&'_ V128SplatOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let fields = self.val.fields().map(Option::from); self.display_variant(f, &fields) diff --git a/crates/ir2/build/display/result_mut.rs b/crates/ir2/build/display/result_mut.rs index 4d475bc775..91b34d17ac 100644 --- a/crates/ir2/build/display/result_mut.rs +++ b/crates/ir2/build/display/result_mut.rs @@ -12,7 +12,7 @@ use crate::build::{ TableGetOp, TableSetOp, UnaryOp, - V128Splat, + V128SplatOp, }, }; use core::fmt::{self, Display}; @@ -152,7 +152,7 @@ impl Display for DisplayResultMut<&'_ GenericOp> { } } -impl Display for DisplayResultMut<&'_ V128Splat> { +impl Display for DisplayResultMut<&'_ V128SplatOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.display_match_arm(f) } diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 2ff535d347..f09a65b4fc 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -19,7 +19,7 @@ use crate::build::{ TableSetOp, UnaryOp, UnaryOpKind, - V128Splat, + V128SplatOp, }, token::Ident, Config, @@ -775,10 +775,10 @@ fn add_simd_ops(isa: &mut Isa, config: &Config) { Field::new(Ident::ValueHi, FieldTy::U64), ], )), - Op::from(V128Splat::new(SplatType::U32, OperandKind::Stack)), - Op::from(V128Splat::new(SplatType::U32, OperandKind::Immediate)), - Op::from(V128Splat::new(SplatType::U64, OperandKind::Stack)), - Op::from(V128Splat::new(SplatType::U64, OperandKind::Immediate)), + Op::from(V128SplatOp::new(SplatType::U32, OperandKind::Stack)), + Op::from(V128SplatOp::new(SplatType::U32, OperandKind::Immediate)), + Op::from(V128SplatOp::new(SplatType::U64, OperandKind::Stack)), + Op::from(V128SplatOp::new(SplatType::U64, OperandKind::Immediate)), ]; for op in ops { isa.push_op(op); diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index d09967fad9..e3483a1605 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -41,7 +41,7 @@ impl_from_for_op! { Generic3(GenericOp<3>), Generic4(GenericOp<4>), Generic5(GenericOp<5>), - V128Splat(V128Splat), + V128Splat(V128SplatOp), } } @@ -1327,7 +1327,7 @@ impl TableSetOp { } #[derive(Copy, Clone)] -pub struct V128Splat { +pub struct V128SplatOp { /// The type of the value to be splatted. pub ty: SplatType, /// The `value` to be splatted. @@ -1340,7 +1340,7 @@ pub enum SplatType { U64, } -impl V128Splat { +impl V128SplatOp { pub fn new(ty: SplatType, value: OperandKind) -> Self { Self { ty, value } } From 74dd307e3d87fd02541ccb4579211da4e5ce24de Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Fri, 29 Aug 2025 17:05:48 +0200 Subject: [PATCH 132/186] add Encode and Decode impls for ImmLaneIdx type --- crates/ir2/src/decode/mod.rs | 9 +++++++++ crates/ir2/src/encode.rs | 12 ++++++++++++ 2 files changed, 21 insertions(+) diff --git a/crates/ir2/src/decode/mod.rs b/crates/ir2/src/decode/mod.rs index e2f3a168e4..84d5e60a6e 100644 --- a/crates/ir2/src/decode/mod.rs +++ b/crates/ir2/src/decode/mod.rs @@ -16,6 +16,8 @@ use self::op::{ TableSet, UnaryOp, }; +#[cfg(feature = "simd")] +use crate::core::simd::ImmLaneIdx; use crate::{ core::TrapCode, index::{Data, Elem, Func, FuncType, Global, InternalFunc, Memory, Table}, @@ -115,4 +117,11 @@ impl_decode_using! { }, } +#[cfg(feature = "simd")] +impl Decode for ImmLaneIdx { + unsafe fn decode(decoder: &mut D) -> Self { + ImmLaneIdx::try_from(u8::decode(decoder)).unwrap_unchecked() + } +} + include!(concat!(env!("OUT_DIR"), "/decode.rs")); diff --git a/crates/ir2/src/encode.rs b/crates/ir2/src/encode.rs index 871213b588..9045d79937 100644 --- a/crates/ir2/src/encode.rs +++ b/crates/ir2/src/encode.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "simd")] +use crate::core::simd::ImmLaneIdx; use crate::{ core::TrapCode, index::{Data, Elem, Func, FuncType, Global, InternalFunc, Memory, Table}, @@ -148,6 +150,16 @@ impl_encode_using! { TrapCode as u8 = |code: TrapCode| -> u8 { code as _ }, } +#[cfg(feature = "simd")] +impl Encode for ImmLaneIdx { + fn encode(&self, encoder: &mut E) -> Result + where + E: Encoder, + { + u8::from(*self).encode(encoder) + } +} + macro_rules! for_tuple { ( $mac:ident ) => { $mac! { T0 } From 607d79873f3fe3d60e7013a23974c39fa3eccb5a Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Fri, 29 Aug 2025 17:06:12 +0200 Subject: [PATCH 133/186] add extract_lane simd ops codegen --- crates/ir2/build/isa.rs | 50 +++++++++++++++++++++++++++++++++++++++ crates/ir2/build/mod.rs | 2 +- crates/ir2/build/op.rs | 8 +++++++ crates/ir2/build/token.rs | 8 +++++++ crates/ir2/src/op.rs | 2 ++ 5 files changed, 69 insertions(+), 1 deletion(-) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index f09a65b4fc..fa9cad7d23 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -775,10 +775,60 @@ fn add_simd_ops(isa: &mut Isa, config: &Config) { Field::new(Ident::ValueHi, FieldTy::U64), ], )), + // Splat Ops Op::from(V128SplatOp::new(SplatType::U32, OperandKind::Stack)), Op::from(V128SplatOp::new(SplatType::U32, OperandKind::Immediate)), Op::from(V128SplatOp::new(SplatType::U64, OperandKind::Stack)), Op::from(V128SplatOp::new(SplatType::U64, OperandKind::Immediate)), + // Extract Ops + Op::from(GenericOp::new( + Ident::S8x16ExtractLane, + [ + Field::new(Ident::Result, FieldTy::Stack), + Field::new(Ident::Value, FieldTy::Stack), + Field::new(Ident::Lane, FieldTy::ImmLaneIdx16), + ], + )), + Op::from(GenericOp::new( + Ident::U8x16ExtractLane, + [ + Field::new(Ident::Result, FieldTy::Stack), + Field::new(Ident::Value, FieldTy::Stack), + Field::new(Ident::Lane, FieldTy::ImmLaneIdx16), + ], + )), + Op::from(GenericOp::new( + Ident::S16x8ExtractLane, + [ + Field::new(Ident::Result, FieldTy::Stack), + Field::new(Ident::Value, FieldTy::Stack), + Field::new(Ident::Lane, FieldTy::ImmLaneIdx8), + ], + )), + Op::from(GenericOp::new( + Ident::U16x8ExtractLane, + [ + Field::new(Ident::Result, FieldTy::Stack), + Field::new(Ident::Value, FieldTy::Stack), + Field::new(Ident::Lane, FieldTy::ImmLaneIdx8), + ], + )), + Op::from(GenericOp::new( + Ident::U32x4ExtractLane, + [ + Field::new(Ident::Result, FieldTy::Stack), + Field::new(Ident::Value, FieldTy::Stack), + Field::new(Ident::Lane, FieldTy::ImmLaneIdx4), + ], + )), + Op::from(GenericOp::new( + Ident::U64x2ExtractLane, + [ + Field::new(Ident::Result, FieldTy::Stack), + Field::new(Ident::Value, FieldTy::Stack), + Field::new(Ident::Lane, FieldTy::ImmLaneIdx2), + ], + )), ]; for op in ops { isa.push_op(op); diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index ef9d90685f..71e6ba0795 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -112,7 +112,7 @@ fn generate_encode_rs(config: &Config, isa: &Isa, contents: &mut String) -> Resu } fn generate_decode_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<(), Error> { - const EXPECTED_SIZE: usize = 35_000; + const EXPECTED_SIZE: usize = 40_000; contents.clear(); contents.reserve_exact(EXPECTED_SIZE); write!(contents, "{}", DisplayDecode::new(isa, Indent::default()))?; diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index e3483a1605..d67ede0531 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -804,6 +804,10 @@ pub enum FieldTy { Data, TrapCode, BlockFuel, + ImmLaneIdx16, + ImmLaneIdx8, + ImmLaneIdx4, + ImmLaneIdx2, } impl Display for FieldTy { @@ -839,6 +843,10 @@ impl Display for FieldTy { Self::Data => "Data", Self::TrapCode => "TrapCode", Self::BlockFuel => "BlockFuel", + Self::ImmLaneIdx16 => "ImmLaneIdx<16>", + Self::ImmLaneIdx8 => "ImmLaneIdx<8>", + Self::ImmLaneIdx4 => "ImmLaneIdx<4>", + Self::ImmLaneIdx2 => "ImmLaneIdx<2>", }; write!(f, "{s}") } diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index 6aff8630b3..de61696802 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -249,4 +249,12 @@ define_ident!( ValueLo: value_lo, ValueHi: value_hi, V128Splat: v128_splat, + + Lane: lane, + S8x16ExtractLane: s8x16_extract_lane, + U8x16ExtractLane: u8x16_extract_lane, + S16x8ExtractLane: s16x8_extract_lane, + U16x8ExtractLane: u16x8_extract_lane, + U32x4ExtractLane: u32x4_extract_lane, + U64x2ExtractLane: u64x2_extract_lane, ); diff --git a/crates/ir2/src/op.rs b/crates/ir2/src/op.rs index 1fc6bb17e4..184c77f60f 100644 --- a/crates/ir2/src/op.rs +++ b/crates/ir2/src/op.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "simd")] +use crate::core::simd::ImmLaneIdx; use crate::{ core::TrapCode, index::{Data, Elem, Func, FuncType, Global, InternalFunc, Memory, Table}, From 742a861cc11af3adf56d1035f39ec67c075b5be2 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Fri, 29 Aug 2025 17:07:21 +0200 Subject: [PATCH 134/186] improve comment --- crates/ir2/build/isa.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index fa9cad7d23..1690815958 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -780,7 +780,7 @@ fn add_simd_ops(isa: &mut Isa, config: &Config) { Op::from(V128SplatOp::new(SplatType::U32, OperandKind::Immediate)), Op::from(V128SplatOp::new(SplatType::U64, OperandKind::Stack)), Op::from(V128SplatOp::new(SplatType::U64, OperandKind::Immediate)), - // Extract Ops + // ExtractLane Ops Op::from(GenericOp::new( Ident::S8x16ExtractLane, [ From 20d5f1a172a385a441dd688b84f8de1b27894af3 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Fri, 29 Aug 2025 17:40:07 +0200 Subject: [PATCH 135/186] add v128.replace_lane ops codegen --- crates/ir2/build/display/constructors.rs | 9 ++++ crates/ir2/build/display/decode.rs | 21 ++++++++ crates/ir2/build/display/encode.rs | 9 ++++ crates/ir2/build/display/ident.rs | 26 ++++++++++ crates/ir2/build/display/op.rs | 9 ++++ crates/ir2/build/display/result_mut.rs | 8 +++ crates/ir2/build/isa.rs | 35 +++++++++++++ crates/ir2/build/mod.rs | 2 +- crates/ir2/build/op.rs | 63 ++++++++++++++++++++++++ crates/ir2/build/token.rs | 2 + crates/ir2/src/decode/mod.rs | 2 + crates/ir2/src/decode/op.rs | 23 +++++++++ 12 files changed, 208 insertions(+), 1 deletion(-) diff --git a/crates/ir2/build/display/constructors.rs b/crates/ir2/build/display/constructors.rs index 44d814bc78..740a14476d 100644 --- a/crates/ir2/build/display/constructors.rs +++ b/crates/ir2/build/display/constructors.rs @@ -13,6 +13,7 @@ use crate::build::{ TableGetOp, TableSetOp, UnaryOp, + V128ReplaceLaneOp, V128SplatOp, }, token::SnakeCase, @@ -104,6 +105,7 @@ impl Display for DisplayConstructor<&'_ Op> { Op::Generic4(op) => self.map(op).fmt(f), Op::Generic5(op) => self.map(op).fmt(f), Op::V128Splat(op) => self.map(op).fmt(f), + Op::V128ReplaceLane(op) => self.map(op).fmt(f), } } } @@ -177,3 +179,10 @@ impl Display for DisplayConstructor<&'_ V128SplatOp> { self.display_constructor(f, &fields) } } + +impl Display for DisplayConstructor<&'_ V128ReplaceLaneOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fields = self.value.fields().map(Option::from); + self.display_constructor(f, &fields) + } +} diff --git a/crates/ir2/build/display/decode.rs b/crates/ir2/build/display/decode.rs index 9284bbce34..2cbb542c5f 100644 --- a/crates/ir2/build/display/decode.rs +++ b/crates/ir2/build/display/decode.rs @@ -12,10 +12,12 @@ use crate::build::{ LoadOp, Op, OperandKind, + ReplaceLaneWidth, StoreOp, TableGetOp, TableSetOp, UnaryOp, + V128ReplaceLaneOp, V128SplatOp, }, token::{CamelCase, SnakeCase}, @@ -73,6 +75,7 @@ impl Display for DisplayDecode<&'_ Op> { Op::Generic4(op) => self.map(op).fmt(f), Op::Generic5(op) => self.map(op).fmt(f), Op::V128Splat(op) => self.map(op).fmt(f), + Op::V128ReplaceLane(op) => self.map(op).fmt(f), } } } @@ -219,3 +222,21 @@ impl Display for DisplayDecode<&'_ V128SplatOp> { writeln!(f, "pub type {camel_ident} = UnaryOp<{value_ty}>;") } } + +impl Display for DisplayDecode<&'_ V128ReplaceLaneOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let op = self.value; + let camel_ident = DisplayIdent::camel(op); + let value_ty = op.value_field().ty; + let lane_items = match op.width { + ReplaceLaneWidth::W8 => "16", + ReplaceLaneWidth::W16 => "8", + ReplaceLaneWidth::W32 => "4", + ReplaceLaneWidth::W64 => "2", + }; + writeln!( + f, + "pub type {camel_ident} = V128ReplaceLaneOp<{value_ty}, {lane_items}>;" + ) + } +} diff --git a/crates/ir2/build/display/encode.rs b/crates/ir2/build/display/encode.rs index b4c13c7983..c528b6fbff 100644 --- a/crates/ir2/build/display/encode.rs +++ b/crates/ir2/build/display/encode.rs @@ -13,6 +13,7 @@ use crate::build::{ TableGetOp, TableSetOp, UnaryOp, + V128ReplaceLaneOp, V128SplatOp, }, token::SnakeCase, @@ -106,6 +107,7 @@ impl Display for DisplayEncode<&'_ Op> { Op::Generic4(op) => self.map(op).fmt(f), Op::Generic5(op) => self.map(op).fmt(f), Op::V128Splat(op) => self.map(op).fmt(f), + Op::V128ReplaceLane(op) => self.map(op).fmt(f), } } } @@ -179,3 +181,10 @@ impl Display for DisplayEncode<&'_ V128SplatOp> { self.display_encode(f, &fields) } } + +impl Display for DisplayEncode<&'_ V128ReplaceLaneOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fields = self.value.fields().map(Option::from); + self.display_encode(f, &fields) + } +} diff --git a/crates/ir2/build/display/ident.rs b/crates/ir2/build/display/ident.rs index f5b0c9e60c..6c41d7dbdb 100644 --- a/crates/ir2/build/display/ident.rs +++ b/crates/ir2/build/display/ident.rs @@ -8,11 +8,13 @@ use crate::build::{ LoadOp, Op, OperandKind, + ReplaceLaneWidth, SplatType, StoreOp, TableGetOp, TableSetOp, UnaryOp, + V128ReplaceLaneOp, V128SplatOp, }, token::{Case, Ident, Sep, SnakeCase}, @@ -65,6 +67,7 @@ impl Display for DisplayIdent<&'_ Op> { Op::Generic4(op) => self.map(op).fmt(f), Op::Generic5(op) => self.map(op).fmt(f), Op::V128Splat(op) => self.map(op).fmt(f), + Op::V128ReplaceLane(op) => self.map(op).fmt(f), } } } @@ -257,3 +260,26 @@ impl Display for DisplayIdent<&'_ V128SplatOp> { write!(f, "{ident}{width}_{result_suffix}{value_suffix}") } } + +impl Display for DisplayIdent<&'_ V128ReplaceLaneOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let case = self.case; + let op = self.value; + let sep = case.wrap(Sep); + let v128 = case.wrap(Ident::V128); + let ident = case.wrap(Ident::ReplaceLane); + let width = match op.width { + ReplaceLaneWidth::W8 => "8x16", + ReplaceLaneWidth::W16 => "16x8", + ReplaceLaneWidth::W32 => "32x4", + ReplaceLaneWidth::W64 => "64x2", + }; + let result_suffix = case.wrap(OperandKind::Stack); + let v128_suffix = SnakeCase(OperandKind::Stack); + let value_suffix = SnakeCase(op.value); + write!( + f, + "{v128}{sep}{ident}{width}_{result_suffix}{v128_suffix}{value_suffix}" + ) + } +} diff --git a/crates/ir2/build/display/op.rs b/crates/ir2/build/display/op.rs index 6920d8f9cd..6087d8193e 100644 --- a/crates/ir2/build/display/op.rs +++ b/crates/ir2/build/display/op.rs @@ -17,6 +17,7 @@ use crate::build::{ TableGetOp, TableSetOp, UnaryOp, + V128ReplaceLaneOp, V128SplatOp, }, }; @@ -106,6 +107,7 @@ impl Display for DisplayOp<&'_ Op> { Op::Generic4(op) => self.map(op).fmt(f), Op::Generic5(op) => self.map(op).fmt(f), Op::V128Splat(op) => self.map(op).fmt(f), + Op::V128ReplaceLane(op) => self.map(op).fmt(f), } } } @@ -179,3 +181,10 @@ impl Display for DisplayOp<&'_ V128SplatOp> { self.display_variant(f, &fields) } } + +impl Display for DisplayOp<&'_ V128ReplaceLaneOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fields = self.val.fields().map(Option::from); + self.display_variant(f, &fields) + } +} diff --git a/crates/ir2/build/display/result_mut.rs b/crates/ir2/build/display/result_mut.rs index 91b34d17ac..0080e7df4a 100644 --- a/crates/ir2/build/display/result_mut.rs +++ b/crates/ir2/build/display/result_mut.rs @@ -12,6 +12,7 @@ use crate::build::{ TableGetOp, TableSetOp, UnaryOp, + V128ReplaceLaneOp, V128SplatOp, }, }; @@ -91,6 +92,7 @@ impl Display for DisplayResultMut<&'_ Op> { Op::Generic4(op) => self.map(op).fmt(f), Op::Generic5(op) => self.map(op).fmt(f), Op::V128Splat(op) => self.map(op).fmt(f), + Op::V128ReplaceLane(op) => self.map(op).fmt(f), } } } @@ -157,3 +159,9 @@ impl Display for DisplayResultMut<&'_ V128SplatOp> { self.display_match_arm(f) } } + +impl Display for DisplayResultMut<&'_ V128ReplaceLaneOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.display_match_arm(f) + } +} diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 1690815958..4f9b55e3a0 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -12,6 +12,7 @@ use crate::build::{ LoadOp, LoadOpKind, OperandKind, + ReplaceLaneWidth, SplatType, StoreOp, StoreOpKind, @@ -19,6 +20,7 @@ use crate::build::{ TableSetOp, UnaryOp, UnaryOpKind, + V128ReplaceLaneOp, V128SplatOp, }, token::Ident, @@ -829,6 +831,39 @@ fn add_simd_ops(isa: &mut Isa, config: &Config) { Field::new(Ident::Lane, FieldTy::ImmLaneIdx2), ], )), + // ReplaceLane Ops + Op::from(V128ReplaceLaneOp::new( + ReplaceLaneWidth::W8, + OperandKind::Stack, + )), + Op::from(V128ReplaceLaneOp::new( + ReplaceLaneWidth::W8, + OperandKind::Immediate, + )), + Op::from(V128ReplaceLaneOp::new( + ReplaceLaneWidth::W16, + OperandKind::Stack, + )), + Op::from(V128ReplaceLaneOp::new( + ReplaceLaneWidth::W16, + OperandKind::Immediate, + )), + Op::from(V128ReplaceLaneOp::new( + ReplaceLaneWidth::W32, + OperandKind::Stack, + )), + Op::from(V128ReplaceLaneOp::new( + ReplaceLaneWidth::W32, + OperandKind::Immediate, + )), + Op::from(V128ReplaceLaneOp::new( + ReplaceLaneWidth::W64, + OperandKind::Stack, + )), + Op::from(V128ReplaceLaneOp::new( + ReplaceLaneWidth::W64, + OperandKind::Immediate, + )), ]; for op in ops { isa.push_op(op); diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index 71e6ba0795..7ff5a12cac 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -72,7 +72,7 @@ pub fn generate_code(config: &Config) -> Result<(), Error> { } fn generate_op_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<(), Error> { - const EXPECTED_SIZE: usize = 180_000; + const EXPECTED_SIZE: usize = 190_000; contents.clear(); contents.reserve_exact(EXPECTED_SIZE); write!( diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index d67ede0531..b32e7dfaec 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -42,6 +42,7 @@ impl_from_for_op! { Generic4(GenericOp<4>), Generic5(GenericOp<5>), V128Splat(V128SplatOp), + V128ReplaceLane(V128ReplaceLaneOp), } } @@ -1372,3 +1373,65 @@ impl V128SplatOp { [self.result_field(), self.value_field()] } } + +#[derive(Copy, Clone)] +pub struct V128ReplaceLaneOp { + /// The type of the value to be splatted. + pub width: ReplaceLaneWidth, + /// The `value` used for replacing. + pub value: OperandKind, +} + +#[derive(Copy, Clone)] +pub enum ReplaceLaneWidth { + W8, + W16, + W32, + W64, +} + +impl V128ReplaceLaneOp { + pub fn new(width: ReplaceLaneWidth, value: OperandKind) -> Self { + Self { width, value } + } + + pub fn result_field(&self) -> Field { + Field::new(Ident::Result, FieldTy::Stack) + } + + pub fn v128_field(&self) -> Field { + Field::new(Ident::V128, FieldTy::Stack) + } + + pub fn value_field(&self) -> Field { + let value_ty = match self.value { + OperandKind::Stack => FieldTy::Stack, + OperandKind::Immediate => match self.width { + ReplaceLaneWidth::W8 => FieldTy::U8, + ReplaceLaneWidth::W16 => FieldTy::U16, + ReplaceLaneWidth::W32 => FieldTy::U32, + ReplaceLaneWidth::W64 => FieldTy::U64, + }, + }; + Field::new(Ident::Value, value_ty) + } + + pub fn lane_field(&self) -> Field { + let lane_ty = match self.width { + ReplaceLaneWidth::W8 => FieldTy::ImmLaneIdx16, + ReplaceLaneWidth::W16 => FieldTy::ImmLaneIdx8, + ReplaceLaneWidth::W32 => FieldTy::ImmLaneIdx4, + ReplaceLaneWidth::W64 => FieldTy::ImmLaneIdx2, + }; + Field::new(Ident::Lane, lane_ty) + } + + pub fn fields(&self) -> [Field; 4] { + [ + self.result_field(), + self.v128_field(), + self.value_field(), + self.lane_field(), + ] + } +} diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index de61696802..8af0d6223d 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -250,6 +250,7 @@ define_ident!( ValueHi: value_hi, V128Splat: v128_splat, + V128: v128, Lane: lane, S8x16ExtractLane: s8x16_extract_lane, U8x16ExtractLane: u8x16_extract_lane, @@ -257,4 +258,5 @@ define_ident!( U16x8ExtractLane: u16x8_extract_lane, U32x4ExtractLane: u32x4_extract_lane, U64x2ExtractLane: u64x2_extract_lane, + ReplaceLane: replace_lane, ); diff --git a/crates/ir2/src/decode/mod.rs b/crates/ir2/src/decode/mod.rs index 84d5e60a6e..5033b7c53b 100644 --- a/crates/ir2/src/decode/mod.rs +++ b/crates/ir2/src/decode/mod.rs @@ -2,6 +2,8 @@ mod op; +#[cfg(feature = "simd")] +use self::op::V128ReplaceLaneOp; use self::op::{ BinaryOp, CmpBranchOp, diff --git a/crates/ir2/src/decode/op.rs b/crates/ir2/src/decode/op.rs index f7e995f759..13350bd10d 100644 --- a/crates/ir2/src/decode/op.rs +++ b/crates/ir2/src/decode/op.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "simd")] +use crate::core::simd::ImmLaneIdx; use crate::{ index::{Memory, Table}, Address, @@ -229,3 +231,24 @@ impl Decode for TableSet { } } } + +#[derive(Copy, Clone)] +#[cfg(feature = "simd")] +pub struct V128ReplaceLaneOp { + pub result: Stack, + pub v128: Stack, + pub value: V, + pub lane: ImmLaneIdx, +} + +#[cfg(feature = "simd")] +impl Decode for V128ReplaceLaneOp { + unsafe fn decode(decoder: &mut D) -> Self { + Self { + result: Decode::decode(decoder), + v128: Decode::decode(decoder), + value: Decode::decode(decoder), + lane: Decode::decode(decoder), + } + } +} From 005b8157a6cbc59fa7042a8ff216337aac9b393d Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Sat, 30 Aug 2025 08:10:12 +0200 Subject: [PATCH 136/186] deduplicate lots of code in build.rs --- crates/ir2/build/display/constructors.rs | 24 ----------- crates/ir2/build/display/decode.rs | 24 ----------- crates/ir2/build/display/encode.rs | 24 ----------- crates/ir2/build/display/ident.rs | 28 +------------ crates/ir2/build/display/mod.rs | 22 ++++++++++ crates/ir2/build/display/result_mut.rs | 24 ----------- crates/ir2/build/mod.rs | 3 +- crates/ir2/build/op.rs | 53 ++++++++++++------------ 8 files changed, 53 insertions(+), 149 deletions(-) diff --git a/crates/ir2/build/display/constructors.rs b/crates/ir2/build/display/constructors.rs index 740a14476d..6168b90384 100644 --- a/crates/ir2/build/display/constructors.rs +++ b/crates/ir2/build/display/constructors.rs @@ -8,7 +8,6 @@ use crate::build::{ Field, GenericOp, LoadOp, - Op, StoreOp, TableGetOp, TableSetOp, @@ -87,29 +86,6 @@ impl Display for DisplayConstructor<&'_ Isa> { } } -impl Display for DisplayConstructor<&'_ Op> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.value { - Op::Unary(op) => self.map(op).fmt(f), - Op::Binary(op) => self.map(op).fmt(f), - Op::CmpBranch(op) => self.map(op).fmt(f), - Op::CmpSelect(op) => self.map(op).fmt(f), - Op::Load(op) => self.map(op).fmt(f), - Op::Store(op) => self.map(op).fmt(f), - Op::TableGet(op) => self.map(op).fmt(f), - Op::TableSet(op) => self.map(op).fmt(f), - Op::Generic0(op) => self.map(op).fmt(f), - Op::Generic1(op) => self.map(op).fmt(f), - Op::Generic2(op) => self.map(op).fmt(f), - Op::Generic3(op) => self.map(op).fmt(f), - Op::Generic4(op) => self.map(op).fmt(f), - Op::Generic5(op) => self.map(op).fmt(f), - Op::V128Splat(op) => self.map(op).fmt(f), - Op::V128ReplaceLane(op) => self.map(op).fmt(f), - } - } -} - impl Display for DisplayConstructor<&'_ UnaryOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let fields = self.value.fields().map(Option::from); diff --git a/crates/ir2/build/display/decode.rs b/crates/ir2/build/display/decode.rs index 2cbb542c5f..7f6c86a69b 100644 --- a/crates/ir2/build/display/decode.rs +++ b/crates/ir2/build/display/decode.rs @@ -10,7 +10,6 @@ use crate::build::{ CmpSelectOp, GenericOp, LoadOp, - Op, OperandKind, ReplaceLaneWidth, StoreOp, @@ -57,29 +56,6 @@ impl Display for DisplayDecode<&'_ Isa> { } } -impl Display for DisplayDecode<&'_ Op> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.value { - Op::Unary(op) => self.map(op).fmt(f), - Op::Binary(op) => self.map(op).fmt(f), - Op::CmpBranch(op) => self.map(op).fmt(f), - Op::CmpSelect(op) => self.map(op).fmt(f), - Op::Load(op) => self.map(op).fmt(f), - Op::Store(op) => self.map(op).fmt(f), - Op::TableGet(op) => self.map(op).fmt(f), - Op::TableSet(op) => self.map(op).fmt(f), - Op::Generic0(op) => self.map(op).fmt(f), - Op::Generic1(op) => self.map(op).fmt(f), - Op::Generic2(op) => self.map(op).fmt(f), - Op::Generic3(op) => self.map(op).fmt(f), - Op::Generic4(op) => self.map(op).fmt(f), - Op::Generic5(op) => self.map(op).fmt(f), - Op::V128Splat(op) => self.map(op).fmt(f), - Op::V128ReplaceLane(op) => self.map(op).fmt(f), - } - } -} - impl Display for DisplayDecode<&'_ UnaryOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let camel_ident = DisplayIdent::camel(self.value); diff --git a/crates/ir2/build/display/encode.rs b/crates/ir2/build/display/encode.rs index c528b6fbff..a0092033fe 100644 --- a/crates/ir2/build/display/encode.rs +++ b/crates/ir2/build/display/encode.rs @@ -8,7 +8,6 @@ use crate::build::{ Field, GenericOp, LoadOp, - Op, StoreOp, TableGetOp, TableSetOp, @@ -89,29 +88,6 @@ impl Display for DisplayEncode<&'_ Isa> { } } -impl Display for DisplayEncode<&'_ Op> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.value { - Op::Unary(op) => self.map(op).fmt(f), - Op::Binary(op) => self.map(op).fmt(f), - Op::CmpBranch(op) => self.map(op).fmt(f), - Op::CmpSelect(op) => self.map(op).fmt(f), - Op::Load(op) => self.map(op).fmt(f), - Op::Store(op) => self.map(op).fmt(f), - Op::TableGet(op) => self.map(op).fmt(f), - Op::TableSet(op) => self.map(op).fmt(f), - Op::Generic0(op) => self.map(op).fmt(f), - Op::Generic1(op) => self.map(op).fmt(f), - Op::Generic2(op) => self.map(op).fmt(f), - Op::Generic3(op) => self.map(op).fmt(f), - Op::Generic4(op) => self.map(op).fmt(f), - Op::Generic5(op) => self.map(op).fmt(f), - Op::V128Splat(op) => self.map(op).fmt(f), - Op::V128ReplaceLane(op) => self.map(op).fmt(f), - } - } -} - impl Display for DisplayEncode<&'_ UnaryOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let fields = self.value.fields().map(Option::from); diff --git a/crates/ir2/build/display/ident.rs b/crates/ir2/build/display/ident.rs index 6c41d7dbdb..53c01c7714 100644 --- a/crates/ir2/build/display/ident.rs +++ b/crates/ir2/build/display/ident.rs @@ -6,7 +6,6 @@ use crate::build::{ CmpSelectOp, GenericOp, LoadOp, - Op, OperandKind, ReplaceLaneWidth, SplatType, @@ -22,8 +21,8 @@ use crate::build::{ use core::fmt::{self, Display}; pub struct DisplayIdent { - value: T, - case: Case, + pub value: T, + pub case: Case, } impl DisplayIdent { @@ -49,29 +48,6 @@ impl DisplayIdent { } } -impl Display for DisplayIdent<&'_ Op> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.value { - Op::Unary(op) => self.map(op).fmt(f), - Op::Binary(op) => self.map(op).fmt(f), - Op::CmpBranch(op) => self.map(op).fmt(f), - Op::CmpSelect(op) => self.map(op).fmt(f), - Op::Load(op) => self.map(op).fmt(f), - Op::Store(op) => self.map(op).fmt(f), - Op::TableGet(op) => self.map(op).fmt(f), - Op::TableSet(op) => self.map(op).fmt(f), - Op::Generic0(op) => self.map(op).fmt(f), - Op::Generic1(op) => self.map(op).fmt(f), - Op::Generic2(op) => self.map(op).fmt(f), - Op::Generic3(op) => self.map(op).fmt(f), - Op::Generic4(op) => self.map(op).fmt(f), - Op::Generic5(op) => self.map(op).fmt(f), - Op::V128Splat(op) => self.map(op).fmt(f), - Op::V128ReplaceLane(op) => self.map(op).fmt(f), - } - } -} - impl Display for DisplayIdent<&'_ UnaryOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let case = self.case; diff --git a/crates/ir2/build/display/mod.rs b/crates/ir2/build/display/mod.rs index 6362dcc3c9..d6fac49ee2 100644 --- a/crates/ir2/build/display/mod.rs +++ b/crates/ir2/build/display/mod.rs @@ -16,3 +16,25 @@ pub use self::{ result_mut::DisplayResultMut, utils::Indent, }; +use crate::build::{display::ident::DisplayIdent, op::Op}; +use core::fmt::{self, Display}; + +macro_rules! impl_trait_for_op { + ( + $trait:ident, + $($variant:ident($op_ty:ty)),* $(,)? + ) => { + impl Display for $trait<&'_ Op> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.value { + $( Op::$variant(op) => self.map(op).fmt(f), )* + } + } + } + }; +} +apply_macro_for_ops!(impl_trait_for_op, DisplayResultMut); +apply_macro_for_ops!(impl_trait_for_op, DisplayIdent); +apply_macro_for_ops!(impl_trait_for_op, DisplayEncode); +apply_macro_for_ops!(impl_trait_for_op, DisplayDecode); +apply_macro_for_ops!(impl_trait_for_op, DisplayConstructor); diff --git a/crates/ir2/build/display/result_mut.rs b/crates/ir2/build/display/result_mut.rs index 0080e7df4a..7a85f60d37 100644 --- a/crates/ir2/build/display/result_mut.rs +++ b/crates/ir2/build/display/result_mut.rs @@ -7,7 +7,6 @@ use crate::build::{ CmpSelectOp, GenericOp, LoadOp, - Op, StoreOp, TableGetOp, TableSetOp, @@ -74,29 +73,6 @@ impl Display for DisplayResultMut<&'_ Isa> { } } -impl Display for DisplayResultMut<&'_ Op> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.value { - Op::Unary(op) => self.map(op).fmt(f), - Op::Binary(op) => self.map(op).fmt(f), - Op::CmpBranch(op) => self.map(op).fmt(f), - Op::CmpSelect(op) => self.map(op).fmt(f), - Op::Load(op) => self.map(op).fmt(f), - Op::Store(op) => self.map(op).fmt(f), - Op::TableGet(op) => self.map(op).fmt(f), - Op::TableSet(op) => self.map(op).fmt(f), - Op::Generic0(op) => self.map(op).fmt(f), - Op::Generic1(op) => self.map(op).fmt(f), - Op::Generic2(op) => self.map(op).fmt(f), - Op::Generic3(op) => self.map(op).fmt(f), - Op::Generic4(op) => self.map(op).fmt(f), - Op::Generic5(op) => self.map(op).fmt(f), - Op::V128Splat(op) => self.map(op).fmt(f), - Op::V128ReplaceLane(op) => self.map(op).fmt(f), - } - } -} - impl Display for DisplayResultMut<&'_ UnaryOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.display_match_arm(f) diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index 7ff5a12cac..b193ea68f7 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -1,6 +1,7 @@ +#[macro_use] +mod op; mod display; mod isa; -mod op; pub mod token; use self::{ diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index b32e7dfaec..d344584d2c 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -1,14 +1,35 @@ use crate::build::{CamelCase, Ident, SnakeCase}; use core::fmt::{self, Display}; +macro_rules! apply_macro_for_ops { + ($mac:ident $(, $param:ident)* $(,)?) => { + $mac! { + $($param,)* + Unary(UnaryOp), + Binary(BinaryOp), + CmpBranch(CmpBranchOp), + CmpSelect(CmpSelectOp), + Load(LoadOp), + Store(StoreOp), + TableGet(TableGetOp), + TableSet(TableSetOp), + Generic0(GenericOp<0>), + Generic1(GenericOp<1>), + Generic2(GenericOp<2>), + Generic3(GenericOp<3>), + Generic4(GenericOp<4>), + Generic5(GenericOp<5>), + V128Splat(V128SplatOp), + V128ReplaceLane(V128ReplaceLaneOp), + } + }; +} + macro_rules! impl_from_for_op { ( - $( #[$attr:meta] )* - pub enum Op { - $($variant:ident($op_ty:ty)),* $(,)? - } + $($variant:ident($op_ty:ty)),* $(,)? ) => { - $( #[$attr] )* + #[derive(Copy, Clone)] pub enum Op { $( $variant($op_ty), @@ -24,27 +45,7 @@ macro_rules! impl_from_for_op { )* }; } -impl_from_for_op! { - #[derive(Copy, Clone)] - pub enum Op { - Unary(UnaryOp), - Binary(BinaryOp), - CmpBranch(CmpBranchOp), - CmpSelect(CmpSelectOp), - Load(LoadOp), - Store(StoreOp), - TableGet(TableGetOp), - TableSet(TableSetOp), - Generic0(GenericOp<0>), - Generic1(GenericOp<1>), - Generic2(GenericOp<2>), - Generic3(GenericOp<3>), - Generic4(GenericOp<4>), - Generic5(GenericOp<5>), - V128Splat(V128SplatOp), - V128ReplaceLane(V128ReplaceLaneOp), - } -} +apply_macro_for_ops!(impl_from_for_op); #[derive(Copy, Clone)] pub struct Field { From ca9e17c530b5dc341ed024e644a107252fadd6e4 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Sat, 30 Aug 2025 08:25:14 +0200 Subject: [PATCH 137/186] refactor and clean-up isa construction --- crates/ir2/build/isa.rs | 164 ++++++++++++++++++---------------------- 1 file changed, 75 insertions(+), 89 deletions(-) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 4f9b55e3a0..7c3459e041 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -34,8 +34,14 @@ pub struct Isa { } impl Isa { - fn push_op(&mut self, op: Op) { - self.ops.push(op); + fn push_op(&mut self, op: impl Into) { + self.ops.push(op.into()); + } + + fn push_ops(&mut self, ops: impl IntoIterator) { + for op in ops { + self.ops.push(op); + } } } @@ -120,7 +126,7 @@ fn add_unary_ops(isa: &mut Isa) { UnaryOpKind::U64TruncSatF64, ]; for op in ops { - isa.push_op(Op::Unary(UnaryOp::new(op))); + isa.push_op(UnaryOp::new(op)); } } @@ -208,22 +214,18 @@ fn add_binary_ops(isa: &mut Isa) { BinaryOpKind::F64Copysign, ]; for op in ops { - isa.push_op(Op::Binary(BinaryOp::new( - op, - OperandKind::Stack, - OperandKind::Stack, - ))); - isa.push_op(Op::Binary(BinaryOp::new( + isa.push_op(BinaryOp::new(op, OperandKind::Stack, OperandKind::Stack)); + isa.push_op(BinaryOp::new( op, OperandKind::Stack, OperandKind::Immediate, - ))); + )); if matches!(op.commutativity(), Commutativity::NonCommutative) { - isa.push_op(Op::Binary(BinaryOp::new( + isa.push_op(BinaryOp::new( op, OperandKind::Immediate, OperandKind::Stack, - ))); + )); } } } @@ -268,22 +270,18 @@ fn add_cmp_branch_ops(isa: &mut Isa) { CmpOpKind::F64NotLe, ]; for op in ops { - isa.push_op(Op::CmpBranch(CmpBranchOp::new( - op, - OperandKind::Stack, - OperandKind::Stack, - ))); - isa.push_op(Op::CmpBranch(CmpBranchOp::new( + isa.push_op(CmpBranchOp::new(op, OperandKind::Stack, OperandKind::Stack)); + isa.push_op(CmpBranchOp::new( op, OperandKind::Stack, OperandKind::Immediate, - ))); + )); if matches!(op.commutativity(), Commutativity::NonCommutative) { - isa.push_op(Op::CmpBranch(CmpBranchOp::new( + isa.push_op(CmpBranchOp::new( op, OperandKind::Immediate, OperandKind::Stack, - ))); + )); } } } @@ -316,22 +314,18 @@ fn add_cmp_select_ops(isa: &mut Isa) { CmpOpKind::F64Le, ]; for op in ops { - isa.push_op(Op::CmpSelect(CmpSelectOp::new( - op, - OperandKind::Stack, - OperandKind::Stack, - ))); - isa.push_op(Op::CmpSelect(CmpSelectOp::new( + isa.push_op(CmpSelectOp::new(op, OperandKind::Stack, OperandKind::Stack)); + isa.push_op(CmpSelectOp::new( op, OperandKind::Stack, OperandKind::Immediate, - ))); + )); if matches!(op.commutativity(), Commutativity::NonCommutative) { - isa.push_op(Op::CmpSelect(CmpSelectOp::new( + isa.push_op(CmpSelectOp::new( op, OperandKind::Immediate, OperandKind::Stack, - ))); + )); } } } @@ -355,14 +349,9 @@ fn add_load_ops(isa: &mut Isa) { LoadOpKind::U64Load32, ]; for op in ops { - isa.push_op(Op::Load(LoadOp::new(op, OperandKind::Stack, false, false))); - isa.push_op(Op::Load(LoadOp::new( - op, - OperandKind::Immediate, - false, - false, - ))); - isa.push_op(Op::Load(LoadOp::new(op, OperandKind::Stack, true, true))); + isa.push_op(LoadOp::new(op, OperandKind::Stack, false, false)); + isa.push_op(LoadOp::new(op, OperandKind::Immediate, false, false)); + isa.push_op(LoadOp::new(op, OperandKind::Stack, true, true)); } } @@ -380,41 +369,41 @@ fn add_store_ops(isa: &mut Isa) { StoreOpKind::I64Store32, ]; for op in ops { - isa.push_op(Op::Store(StoreOp::new( + isa.push_op(StoreOp::new( op, OperandKind::Stack, OperandKind::Stack, false, false, - ))); - isa.push_op(Op::Store(StoreOp::new( + )); + isa.push_op(StoreOp::new( op, OperandKind::Stack, OperandKind::Immediate, false, false, - ))); - isa.push_op(Op::Store(StoreOp::new( + )); + isa.push_op(StoreOp::new( op, OperandKind::Immediate, OperandKind::Stack, false, false, - ))); - isa.push_op(Op::Store(StoreOp::new( + )); + isa.push_op(StoreOp::new( op, OperandKind::Stack, OperandKind::Stack, true, true, - ))); - isa.push_op(Op::Store(StoreOp::new( + )); + isa.push_op(StoreOp::new( op, OperandKind::Stack, OperandKind::Immediate, true, true, - ))); + )); } } @@ -466,9 +455,7 @@ fn add_control_ops(isa: &mut Isa) { ], )), ]; - for op in ops { - isa.push_op(op); - } + isa.push_ops(ops); } fn add_copy_ops(isa: &mut Isa) { @@ -503,9 +490,7 @@ fn add_copy_ops(isa: &mut Isa) { ], )), ]; - for op in ops { - isa.push_op(op); - } + isa.push_ops(ops); } fn add_call_ops(isa: &mut Isa) { @@ -557,9 +542,7 @@ fn add_call_ops(isa: &mut Isa) { ], )), ]; - for op in ops { - isa.push_op(op); - } + isa.push_ops(ops); } fn add_global_ops(isa: &mut Isa) { @@ -593,9 +576,7 @@ fn add_global_ops(isa: &mut Isa) { ], )), ]; - for op in ops { - isa.push_op(op); - } + isa.push_ops(ops); } fn add_table_ops(isa: &mut Isa) { @@ -659,9 +640,7 @@ fn add_table_ops(isa: &mut Isa) { [Field::new(Ident::Elem, FieldTy::Elem)], )), ]; - for op in ops { - isa.push_op(op); - } + isa.push_ops(ops); } fn add_memory_ops(isa: &mut Isa) { @@ -715,9 +694,7 @@ fn add_memory_ops(isa: &mut Isa) { ], )), ]; - for op in ops { - isa.push_op(op); - } + isa.push_ops(ops); } fn add_wide_arithmetic_ops(isa: &mut Isa) { @@ -759,30 +736,19 @@ fn add_wide_arithmetic_ops(isa: &mut Isa) { ], )), ]; - for op in ops { - isa.push_op(op); - } + isa.push_ops(ops); } -fn add_simd_ops(isa: &mut Isa, config: &Config) { - if !config.simd { - return; +fn add_simd_splat_ops(isa: &mut Isa) { + let kinds = [SplatType::U32, SplatType::U64]; + for kind in kinds { + isa.push_op(V128SplatOp::new(kind, OperandKind::Immediate)); + isa.push_op(V128SplatOp::new(kind, OperandKind::Stack)); } +} + +fn add_simd_extract_lane_ops(isa: &mut Isa) { let ops = [ - Op::from(GenericOp::new( - Ident::Copy128, - [ - Field::new(Ident::Result, FieldTy::Stack), - Field::new(Ident::ValueLo, FieldTy::U64), - Field::new(Ident::ValueHi, FieldTy::U64), - ], - )), - // Splat Ops - Op::from(V128SplatOp::new(SplatType::U32, OperandKind::Stack)), - Op::from(V128SplatOp::new(SplatType::U32, OperandKind::Immediate)), - Op::from(V128SplatOp::new(SplatType::U64, OperandKind::Stack)), - Op::from(V128SplatOp::new(SplatType::U64, OperandKind::Immediate)), - // ExtractLane Ops Op::from(GenericOp::new( Ident::S8x16ExtractLane, [ @@ -831,7 +797,12 @@ fn add_simd_ops(isa: &mut Isa, config: &Config) { Field::new(Ident::Lane, FieldTy::ImmLaneIdx2), ], )), - // ReplaceLane Ops + ]; + isa.push_ops(ops); +} + +fn add_simd_replace_lane_ops(isa: &mut Isa) { + let ops = [ Op::from(V128ReplaceLaneOp::new( ReplaceLaneWidth::W8, OperandKind::Stack, @@ -865,7 +836,22 @@ fn add_simd_ops(isa: &mut Isa, config: &Config) { OperandKind::Immediate, )), ]; - for op in ops { - isa.push_op(op); + isa.push_ops(ops); +} + +fn add_simd_ops(isa: &mut Isa, config: &Config) { + if !config.simd { + return; } + isa.push_op(GenericOp::new( + Ident::Copy128, + [ + Field::new(Ident::Result, FieldTy::Stack), + Field::new(Ident::ValueLo, FieldTy::U64), + Field::new(Ident::ValueHi, FieldTy::U64), + ], + )); + add_simd_splat_ops(isa); + add_simd_extract_lane_ops(isa); + add_simd_replace_lane_ops(isa); } From 2277f8f228b8f7552c216d8ac79cdce48cd0675b Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Sat, 30 Aug 2025 08:27:44 +0200 Subject: [PATCH 138/186] clean-up add_simd_replace_lane_ops --- crates/ir2/build/isa.rs | 43 +++++++++-------------------------------- 1 file changed, 9 insertions(+), 34 deletions(-) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 7c3459e041..14ca816c47 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -802,41 +802,16 @@ fn add_simd_extract_lane_ops(isa: &mut Isa) { } fn add_simd_replace_lane_ops(isa: &mut Isa) { - let ops = [ - Op::from(V128ReplaceLaneOp::new( - ReplaceLaneWidth::W8, - OperandKind::Stack, - )), - Op::from(V128ReplaceLaneOp::new( - ReplaceLaneWidth::W8, - OperandKind::Immediate, - )), - Op::from(V128ReplaceLaneOp::new( - ReplaceLaneWidth::W16, - OperandKind::Stack, - )), - Op::from(V128ReplaceLaneOp::new( - ReplaceLaneWidth::W16, - OperandKind::Immediate, - )), - Op::from(V128ReplaceLaneOp::new( - ReplaceLaneWidth::W32, - OperandKind::Stack, - )), - Op::from(V128ReplaceLaneOp::new( - ReplaceLaneWidth::W32, - OperandKind::Immediate, - )), - Op::from(V128ReplaceLaneOp::new( - ReplaceLaneWidth::W64, - OperandKind::Stack, - )), - Op::from(V128ReplaceLaneOp::new( - ReplaceLaneWidth::W64, - OperandKind::Immediate, - )), + let widths = [ + ReplaceLaneWidth::W8, + ReplaceLaneWidth::W16, + ReplaceLaneWidth::W32, + ReplaceLaneWidth::W64, ]; - isa.push_ops(ops); + for width in widths { + isa.push_op(V128ReplaceLaneOp::new(width, OperandKind::Stack)); + isa.push_op(V128ReplaceLaneOp::new(width, OperandKind::Immediate)); + } } fn add_simd_ops(isa: &mut Isa, config: &Config) { From 8b5acd8358d80e5a512e495c23d0be7e73dd945f Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Sat, 30 Aug 2025 08:29:18 +0200 Subject: [PATCH 139/186] move add_simd_ops to top of simd construction --- crates/ir2/build/isa.rs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 14ca816c47..935cc68b91 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -739,6 +739,23 @@ fn add_wide_arithmetic_ops(isa: &mut Isa) { isa.push_ops(ops); } +fn add_simd_ops(isa: &mut Isa, config: &Config) { + if !config.simd { + return; + } + isa.push_op(GenericOp::new( + Ident::Copy128, + [ + Field::new(Ident::Result, FieldTy::Stack), + Field::new(Ident::ValueLo, FieldTy::U64), + Field::new(Ident::ValueHi, FieldTy::U64), + ], + )); + add_simd_splat_ops(isa); + add_simd_extract_lane_ops(isa); + add_simd_replace_lane_ops(isa); +} + fn add_simd_splat_ops(isa: &mut Isa) { let kinds = [SplatType::U32, SplatType::U64]; for kind in kinds { @@ -813,20 +830,3 @@ fn add_simd_replace_lane_ops(isa: &mut Isa) { isa.push_op(V128ReplaceLaneOp::new(width, OperandKind::Immediate)); } } - -fn add_simd_ops(isa: &mut Isa, config: &Config) { - if !config.simd { - return; - } - isa.push_op(GenericOp::new( - Ident::Copy128, - [ - Field::new(Ident::Result, FieldTy::Stack), - Field::new(Ident::ValueLo, FieldTy::U64), - Field::new(Ident::ValueHi, FieldTy::U64), - ], - )); - add_simd_splat_ops(isa); - add_simd_extract_lane_ops(isa); - add_simd_replace_lane_ops(isa); -} From 7c476be460444d4c0f25b12a96f76bc9ddf246a1 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Sat, 30 Aug 2025 08:51:09 +0200 Subject: [PATCH 140/186] add Encode and Decode for arrays --- crates/ir2/src/decode/mod.rs | 6 ++++++ crates/ir2/src/encode.rs | 13 +++++++++++++ 2 files changed, 19 insertions(+) diff --git a/crates/ir2/src/decode/mod.rs b/crates/ir2/src/decode/mod.rs index 5033b7c53b..2dbeccb1e4 100644 --- a/crates/ir2/src/decode/mod.rs +++ b/crates/ir2/src/decode/mod.rs @@ -119,6 +119,12 @@ impl_decode_using! { }, } +impl Decode for [T; N] { + unsafe fn decode(decoder: &mut D) -> Self { + core::array::from_fn(|_| ::decode(decoder)) + } +} + #[cfg(feature = "simd")] impl Decode for ImmLaneIdx { unsafe fn decode(decoder: &mut D) -> Self { diff --git a/crates/ir2/src/encode.rs b/crates/ir2/src/encode.rs index 9045d79937..e343f8ff26 100644 --- a/crates/ir2/src/encode.rs +++ b/crates/ir2/src/encode.rs @@ -192,4 +192,17 @@ impl Encode for &'_ T { } } +impl Encode for [T; N] { + fn encode(&self, encoder: &mut E) -> Result { + let Some((first, rest)) = self.split_first() else { + panic!("cannot encode zero-sized arrays") + }; + let pos = first.encode(encoder)?; + for item in rest { + item.encode(encoder)?; + } + Ok(pos) + } +} + include!(concat!(env!("OUT_DIR"), "/encode.rs")); From 654f15116b7c59ceb66b307d65699a4b5807eb9c Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Sat, 30 Aug 2025 09:25:55 +0200 Subject: [PATCH 141/186] add more binary simd ops to isa --- crates/ir2/build/isa.rs | 55 ++++++++++++++ crates/ir2/build/mod.rs | 2 +- crates/ir2/build/op.rs | 156 ++++++++++++++++++++++++++++++++++++++ crates/ir2/build/token.rs | 19 +++++ 4 files changed, 231 insertions(+), 1 deletion(-) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 935cc68b91..a3e815939f 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -751,9 +751,19 @@ fn add_simd_ops(isa: &mut Isa, config: &Config) { Field::new(Ident::ValueHi, FieldTy::U64), ], )); + isa.push_op(GenericOp::new( + Ident::I8x16Shuffle, + [ + Field::new(Ident::Result, FieldTy::Stack), + Field::new(Ident::Lhs, FieldTy::Stack), + Field::new(Ident::Rhs, FieldTy::Stack), + Field::new(Ident::Selector, FieldTy::Array16ImmLaneIdx32), + ], + )); add_simd_splat_ops(isa); add_simd_extract_lane_ops(isa); add_simd_replace_lane_ops(isa); + add_simd_binary_ops(isa); } fn add_simd_splat_ops(isa: &mut Isa) { @@ -830,3 +840,48 @@ fn add_simd_replace_lane_ops(isa: &mut Isa) { isa.push_op(V128ReplaceLaneOp::new(width, OperandKind::Immediate)); } } + +fn add_simd_binary_ops(isa: &mut Isa) { + let kinds = [ + BinaryOpKind::I8x16Swizzle, + BinaryOpKind::I8x16Eq, + BinaryOpKind::I8x16NotEq, + BinaryOpKind::I16x8Eq, + BinaryOpKind::I16x8NotEq, + BinaryOpKind::I32x4Eq, + BinaryOpKind::I32x4NotEq, + BinaryOpKind::I64x2Eq, + BinaryOpKind::I64x2NotEq, + BinaryOpKind::S8x16Lt, + BinaryOpKind::S8x16Le, + BinaryOpKind::S16x8Lt, + BinaryOpKind::S16x8Le, + BinaryOpKind::S32x4Lt, + BinaryOpKind::S32x4Le, + BinaryOpKind::S64x2Lt, + BinaryOpKind::S64x2Le, + BinaryOpKind::U8x16Lt, + BinaryOpKind::U8x16Le, + BinaryOpKind::U16x8Lt, + BinaryOpKind::U16x8Le, + BinaryOpKind::U32x4Lt, + BinaryOpKind::U32x4Le, + BinaryOpKind::U64x2Lt, + BinaryOpKind::U64x2Le, + BinaryOpKind::F32x4Eq, + BinaryOpKind::F32x4NotEq, + BinaryOpKind::F32x4Lt, + BinaryOpKind::F32x4Le, + BinaryOpKind::F64x2Eq, + BinaryOpKind::F64x2NotEq, + BinaryOpKind::F64x2Lt, + BinaryOpKind::F64x2Le, + BinaryOpKind::V128And, + BinaryOpKind::V128AndNot, + BinaryOpKind::V128Or, + BinaryOpKind::V128Xor, + ]; + for kind in kinds { + isa.push_op(BinaryOp::new(kind, OperandKind::Stack, OperandKind::Stack)); + } +} diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index b193ea68f7..88efa0f301 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -73,7 +73,7 @@ pub fn generate_code(config: &Config) -> Result<(), Error> { } fn generate_op_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<(), Error> { - const EXPECTED_SIZE: usize = 190_000; + const EXPECTED_SIZE: usize = 200_000; contents.clear(); contents.reserve_exact(EXPECTED_SIZE); write!( diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index d344584d2c..7ff578a0e3 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -428,6 +428,44 @@ pub enum BinaryOpKind { F64Min, F64Max, F64Copysign, + // Simd Operators + I8x16Swizzle, + I8x16Eq, + I8x16NotEq, + I16x8Eq, + I16x8NotEq, + I32x4Eq, + I32x4NotEq, + I64x2Eq, + I64x2NotEq, + S8x16Lt, + S8x16Le, + S16x8Lt, + S16x8Le, + S32x4Lt, + S32x4Le, + S64x2Lt, + S64x2Le, + U8x16Lt, + U8x16Le, + U16x8Lt, + U16x8Le, + U32x4Lt, + U32x4Le, + U64x2Lt, + U64x2Le, + F32x4Eq, + F32x4NotEq, + F32x4Lt, + F32x4Le, + F64x2Eq, + F64x2NotEq, + F64x2Lt, + F64x2Le, + V128And, + V128AndNot, + V128Or, + V128Xor, } impl BinaryOpKind { @@ -478,6 +516,44 @@ impl BinaryOpKind { Self::F64Min => Ident::Min, Self::F64Max => Ident::Max, Self::F64Copysign => Ident::Copysign, + // Simd Ops + Self::I8x16Swizzle => Ident::Swizzle, + Self::I8x16Eq => Ident::Eq, + Self::I8x16NotEq => Ident::NotEq, + Self::I16x8Eq => Ident::Eq, + Self::I16x8NotEq => Ident::NotEq, + Self::I32x4Eq => Ident::Eq, + Self::I32x4NotEq => Ident::NotEq, + Self::I64x2Eq => Ident::Eq, + Self::I64x2NotEq => Ident::NotEq, + Self::S8x16Lt => Ident::Lt, + Self::S8x16Le => Ident::Le, + Self::S16x8Lt => Ident::Lt, + Self::S16x8Le => Ident::Le, + Self::S32x4Lt => Ident::Lt, + Self::S32x4Le => Ident::Le, + Self::S64x2Lt => Ident::Lt, + Self::S64x2Le => Ident::Le, + Self::U8x16Lt => Ident::Lt, + Self::U8x16Le => Ident::Le, + Self::U16x8Lt => Ident::Lt, + Self::U16x8Le => Ident::Le, + Self::U32x4Lt => Ident::Lt, + Self::U32x4Le => Ident::Le, + Self::U64x2Lt => Ident::Lt, + Self::U64x2Le => Ident::Le, + Self::F32x4Eq => Ident::Eq, + Self::F32x4NotEq => Ident::NotEq, + Self::F32x4Lt => Ident::Lt, + Self::F32x4Le => Ident::Le, + Self::F64x2Eq => Ident::Eq, + Self::F64x2NotEq => Ident::NotEq, + Self::F64x2Lt => Ident::Lt, + Self::F64x2Le => Ident::Le, + Self::V128And => Ident::And, + Self::V128AndNot => Ident::AndNot, + Self::V128Or => Ident::Or, + Self::V128Xor => Ident::Xor, } } @@ -538,6 +614,7 @@ impl BinaryOpKind { | Self::F64Min | Self::F64Max | Self::F64Copysign => FieldTy::F64, + _ => panic!("operator cannot have an immediate `lhs` field"), }, } } @@ -581,6 +658,7 @@ impl BinaryOpKind { | Self::F64Min | Self::F64Max => FieldTy::F64, | Self::F64Copysign => FieldTy::SignF64, + _ => panic!("operator cannot have an immediate `rhs` field"), }, } } @@ -624,6 +702,22 @@ impl BinaryOpKind { | Self::F64Min | Self::F64Max | Self::F64Copysign => Ty::F64, + | Self::I8x16Swizzle => Ty::I8x16, + | Self::I8x16Eq | Self::I8x16NotEq => Ty::I8x16, + | Self::I16x8Eq | Self::I16x8NotEq => Ty::I16x8, + | Self::I32x4Eq | Self::I32x4NotEq => Ty::I32x4, + | Self::I64x2Eq | Self::I64x2NotEq => Ty::I64x2, + | Self::S8x16Lt | Self::S8x16Le => Ty::S8x16, + | Self::S16x8Lt | Self::S16x8Le => Ty::S16x8, + | Self::S32x4Lt | Self::S32x4Le => Ty::S32x4, + | Self::S64x2Lt | Self::S64x2Le => Ty::S64x2, + | Self::U8x16Lt | Self::U8x16Le => Ty::U8x16, + | Self::U16x8Lt | Self::U16x8Le => Ty::U16x8, + | Self::U32x4Lt | Self::U32x4Le => Ty::U32x4, + | Self::U64x2Lt | Self::U64x2Le => Ty::U64x2, + | Self::F32x4Eq | Self::F32x4NotEq | Self::F32x4Lt | Self::F32x4Le => Ty::F32x4, + | Self::F64x2Eq | Self::F64x2NotEq | Self::F64x2Lt | Self::F64x2Le => Ty::F64x2, + | Self::V128And | Self::V128AndNot | Self::V128Or | Self::V128Xor => Ty::V128, } } @@ -741,6 +835,36 @@ pub enum Ty { F32, /// A 64-bit float type. F64, + /// A generic `simd` vector type. + V128, + /// A `i8x16` vector type for `simd`. + I8x16, + /// A `i16x8` vector type for `simd`. + I16x8, + /// A `i32x4` vector type for `simd`. + I32x4, + /// A `i64x2` vector type for `simd`. + I64x2, + /// A `u8x16` vector type for `simd`. + U8x16, + /// A `u16x8` vector type for `simd`. + U16x8, + /// A `u32x4` vector type for `simd`. + U32x4, + /// A `u64x2` vector type for `simd`. + U64x2, + /// A `s8x16` vector type for `simd`. + S8x16, + /// A `s16x8` vector type for `simd`. + S16x8, + /// A `s32x4` vector type for `simd`. + S32x4, + /// A `s64x2` vector type for `simd`. + S64x2, + /// A `f32x4` vector type for `simd`. + F32x4, + /// A `f64x2` vector type for `simd`. + F64x2, } impl Display for Ty { @@ -754,6 +878,21 @@ impl Display for Ty { Ty::U64 => "u64", Ty::F32 => "f32", Ty::F64 => "f64", + Ty::V128 => "v128", + Ty::I8x16 => "i8x16", + Ty::I16x8 => "i16x8", + Ty::I32x4 => "i32x4", + Ty::I64x2 => "i64x2", + Ty::U8x16 => "u8x16", + Ty::U16x8 => "u16x8", + Ty::U32x4 => "u32x4", + Ty::U64x2 => "u64x2", + Ty::S8x16 => "s8x16", + Ty::S16x8 => "s16x8", + Ty::S32x4 => "s32x4", + Ty::S64x2 => "s64x2", + Ty::F32x4 => "f32x4", + Ty::F64x2 => "f64x2", }; write!(f, "{s}") } @@ -770,6 +909,21 @@ impl From for Ident { Ty::U64 => Self::U64, Ty::F32 => Self::F32, Ty::F64 => Self::F64, + Ty::V128 => Self::V128, + Ty::I8x16 => Self::I8x16, + Ty::I16x8 => Self::I16x8, + Ty::I32x4 => Self::I32x4, + Ty::I64x2 => Self::I64x2, + Ty::U8x16 => Self::U8x16, + Ty::U16x8 => Self::U16x8, + Ty::U32x4 => Self::U32x4, + Ty::U64x2 => Self::U64x2, + Ty::S8x16 => Self::S8x16, + Ty::S16x8 => Self::S16x8, + Ty::S32x4 => Self::S32x4, + Ty::S64x2 => Self::S64x2, + Ty::F32x4 => Self::F32x4, + Ty::F64x2 => Self::F64x2, } } } @@ -806,6 +960,7 @@ pub enum FieldTy { Data, TrapCode, BlockFuel, + Array16ImmLaneIdx32, ImmLaneIdx16, ImmLaneIdx8, ImmLaneIdx4, @@ -845,6 +1000,7 @@ impl Display for FieldTy { Self::Data => "Data", Self::TrapCode => "TrapCode", Self::BlockFuel => "BlockFuel", + Self::Array16ImmLaneIdx32 => "[ImmLaneIdx<32>; 16]", Self::ImmLaneIdx16 => "ImmLaneIdx<16>", Self::ImmLaneIdx8 => "ImmLaneIdx<8>", Self::ImmLaneIdx4 => "ImmLaneIdx<4>", diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index 8af0d6223d..a29dd476fb 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -109,7 +109,9 @@ define_ident!( Eq: eq, And: and, + AndNot: and_not, Or: or, + Xor: xor, NotEq: ne, NotAnd: not_and, NotOr: not_or, @@ -249,8 +251,23 @@ define_ident!( ValueLo: value_lo, ValueHi: value_hi, V128Splat: v128_splat, + Selector: selector, V128: v128, + I8x16: i8x16, + I16x8: i16x8, + I32x4: i32x4, + I64x2: i64x2, + U8x16: u8x16, + U16x8: u16x8, + U32x4: u32x4, + U64x2: u64x2, + S8x16: s8x16, + S16x8: s16x8, + S32x4: s32x4, + S64x2: s64x2, + F32x4: f32x4, + F64x2: f64x2, Lane: lane, S8x16ExtractLane: s8x16_extract_lane, U8x16ExtractLane: u8x16_extract_lane, @@ -259,4 +276,6 @@ define_ident!( U32x4ExtractLane: u32x4_extract_lane, U64x2ExtractLane: u64x2_extract_lane, ReplaceLane: replace_lane, + Swizzle: swizzle, + I8x16Shuffle: i8x16_shuffle, ); From ac00b9858edc9b29f36be555476cb17fdeb213ca Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Sat, 30 Aug 2025 09:29:07 +0200 Subject: [PATCH 142/186] rename val -> value --- crates/ir2/build/display/op.rs | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/crates/ir2/build/display/op.rs b/crates/ir2/build/display/op.rs index 6087d8193e..d2119a129f 100644 --- a/crates/ir2/build/display/op.rs +++ b/crates/ir2/build/display/op.rs @@ -24,18 +24,18 @@ use crate::build::{ use core::fmt::{self, Display}; pub struct DisplayOp { - pub val: T, + pub value: T, pub indent: Indent, } impl DisplayOp { pub fn new(val: T, indent: Indent) -> Self { - Self { val, indent } + Self { value: val, indent } } pub fn map(&self, val: V) -> DisplayOp { DisplayOp { - val, + value: val, indent: self.indent, } } @@ -47,7 +47,7 @@ where { fn display_variant(&self, f: &mut fmt::Formatter<'_>, fields: &[Option]) -> fmt::Result { let indent = self.indent; - let ident = DisplayIdent::camel(self.val); + let ident = DisplayIdent::camel(self.value); let fields = DisplaySequence::new( ",\n", fields @@ -72,7 +72,7 @@ impl Display for DisplayOp<&'_ Isa> { let indent = self.indent; let variants = DisplaySequence::new( ",\n", - self.val + self.value .ops .iter() .map(|op| DisplayOp::new(op, indent.inc())), @@ -114,77 +114,77 @@ impl Display for DisplayOp<&'_ Op> { impl Display for DisplayOp<&'_ UnaryOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.val.fields().map(Option::from); + let fields = self.value.fields().map(Option::from); self.display_variant(f, &fields) } } impl Display for DisplayOp<&'_ BinaryOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.val.fields().map(Option::from); + let fields = self.value.fields().map(Option::from); self.display_variant(f, &fields) } } impl Display for DisplayOp<&'_ CmpBranchOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.val.fields().map(Option::from); + let fields = self.value.fields().map(Option::from); self.display_variant(f, &fields) } } impl Display for DisplayOp<&'_ CmpSelectOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.val.fields().map(Option::from); + let fields = self.value.fields().map(Option::from); self.display_variant(f, &fields) } } impl Display for DisplayOp<&'_ LoadOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.val.fields(); + let fields = self.value.fields(); self.display_variant(f, &fields) } } impl Display for DisplayOp<&'_ StoreOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.val.fields().map(Option::from); + let fields = self.value.fields().map(Option::from); self.display_variant(f, &fields) } } impl Display for DisplayOp<&'_ GenericOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.val.fields.map(Option::from); + let fields = self.value.fields.map(Option::from); self.display_variant(f, &fields) } } impl Display for DisplayOp<&'_ TableGetOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.val.fields().map(Option::from); + let fields = self.value.fields().map(Option::from); self.display_variant(f, &fields) } } impl Display for DisplayOp<&'_ TableSetOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.val.fields().map(Option::from); + let fields = self.value.fields().map(Option::from); self.display_variant(f, &fields) } } impl Display for DisplayOp<&'_ V128SplatOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.val.fields().map(Option::from); + let fields = self.value.fields().map(Option::from); self.display_variant(f, &fields) } } impl Display for DisplayOp<&'_ V128ReplaceLaneOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.val.fields().map(Option::from); + let fields = self.value.fields().map(Option::from); self.display_variant(f, &fields) } } From 2354ce1c452d05062cd4f715e5c0ff70b7ea3412 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Sat, 30 Aug 2025 09:29:33 +0200 Subject: [PATCH 143/186] reorder macro generated Op impls --- crates/ir2/build/display/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ir2/build/display/mod.rs b/crates/ir2/build/display/mod.rs index d6fac49ee2..2402436afc 100644 --- a/crates/ir2/build/display/mod.rs +++ b/crates/ir2/build/display/mod.rs @@ -33,8 +33,8 @@ macro_rules! impl_trait_for_op { } }; } -apply_macro_for_ops!(impl_trait_for_op, DisplayResultMut); apply_macro_for_ops!(impl_trait_for_op, DisplayIdent); +apply_macro_for_ops!(impl_trait_for_op, DisplayConstructor); +apply_macro_for_ops!(impl_trait_for_op, DisplayResultMut); apply_macro_for_ops!(impl_trait_for_op, DisplayEncode); apply_macro_for_ops!(impl_trait_for_op, DisplayDecode); -apply_macro_for_ops!(impl_trait_for_op, DisplayConstructor); From 5b38f4c6503875f09e7d2fb11c77e0334e704b18 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Sat, 30 Aug 2025 09:29:46 +0200 Subject: [PATCH 144/186] generate code for DisplayOp for Op --- crates/ir2/build/display/mod.rs | 1 + crates/ir2/build/display/op.rs | 24 ------------------------ 2 files changed, 1 insertion(+), 24 deletions(-) diff --git a/crates/ir2/build/display/mod.rs b/crates/ir2/build/display/mod.rs index 2402436afc..e509379618 100644 --- a/crates/ir2/build/display/mod.rs +++ b/crates/ir2/build/display/mod.rs @@ -33,6 +33,7 @@ macro_rules! impl_trait_for_op { } }; } +apply_macro_for_ops!(impl_trait_for_op, DisplayOp); apply_macro_for_ops!(impl_trait_for_op, DisplayIdent); apply_macro_for_ops!(impl_trait_for_op, DisplayConstructor); apply_macro_for_ops!(impl_trait_for_op, DisplayResultMut); diff --git a/crates/ir2/build/display/op.rs b/crates/ir2/build/display/op.rs index d2119a129f..dd9b08b002 100644 --- a/crates/ir2/build/display/op.rs +++ b/crates/ir2/build/display/op.rs @@ -12,7 +12,6 @@ use crate::build::{ Field, GenericOp, LoadOp, - Op, StoreOp, TableGetOp, TableSetOp, @@ -89,29 +88,6 @@ impl Display for DisplayOp<&'_ Isa> { } } -impl Display for DisplayOp<&'_ Op> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.val { - Op::Unary(op) => self.map(op).fmt(f), - Op::Binary(op) => self.map(op).fmt(f), - Op::CmpBranch(op) => self.map(op).fmt(f), - Op::CmpSelect(op) => self.map(op).fmt(f), - Op::Load(op) => self.map(op).fmt(f), - Op::Store(op) => self.map(op).fmt(f), - Op::TableGet(op) => self.map(op).fmt(f), - Op::TableSet(op) => self.map(op).fmt(f), - Op::Generic0(op) => self.map(op).fmt(f), - Op::Generic1(op) => self.map(op).fmt(f), - Op::Generic2(op) => self.map(op).fmt(f), - Op::Generic3(op) => self.map(op).fmt(f), - Op::Generic4(op) => self.map(op).fmt(f), - Op::Generic5(op) => self.map(op).fmt(f), - Op::V128Splat(op) => self.map(op).fmt(f), - Op::V128ReplaceLane(op) => self.map(op).fmt(f), - } - } -} - impl Display for DisplayOp<&'_ UnaryOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let fields = self.value.fields().map(Option::from); From 178ec01315ebfe336589ba494ca801b18b4b288d Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Sat, 30 Aug 2025 10:52:11 +0200 Subject: [PATCH 145/186] refactor and clean-up ident_prefix queries --- crates/ir2/build/display/ident.rs | 4 +- crates/ir2/build/op.rs | 115 ++++++++++++++---------------- 2 files changed, 56 insertions(+), 63 deletions(-) diff --git a/crates/ir2/build/display/ident.rs b/crates/ir2/build/display/ident.rs index 53c01c7714..7652804fe2 100644 --- a/crates/ir2/build/display/ident.rs +++ b/crates/ir2/build/display/ident.rs @@ -96,7 +96,7 @@ impl Display for DisplayIdent<&'_ CmpBranchOp> { let cmp = self.value.cmp; let branch = case.wrap(Ident::Branch); let ident = case.wrap(cmp.ident()); - let input_ident = case.wrap(Ident::from(cmp.input_ty())); + let input_ident = case.wrap(Ident::from(cmp.ident_prefix())); let lhs_suffix = case.wrap(self.value.lhs); let rhs_suffix = SnakeCase(self.value.rhs); write!( @@ -112,7 +112,7 @@ impl Display for DisplayIdent<&'_ CmpSelectOp> { let cmp = self.value.cmp; let select = case.wrap(Ident::Select); let ident = case.wrap(cmp.ident()); - let input_ident = case.wrap(Ident::from(cmp.input_ty())); + let input_ident = case.wrap(Ident::from(cmp.ident_prefix())); let result_suffix = case.wrap(OperandKind::Stack); let lhs_suffix = SnakeCase(self.value.lhs); let rhs_suffix = SnakeCase(self.value.rhs); diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 7ff578a0e3..2f75d7ddba 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -559,8 +559,59 @@ impl BinaryOpKind { pub fn ident_prefix(&self) -> Ident { let ty = match self { - BinaryOpKind::Cmp(op) => op.input_ty(), - _ => self.result_ty(), + | BinaryOpKind::Cmp(op) => op.ident_prefix(), + | Self::I32Add + | Self::I32Sub + | Self::I32Mul + | Self::I32BitAnd + | Self::I32BitOr + | Self::I32BitXor + | Self::I32Shl + | Self::I32Rotl + | Self::I32Rotr => Ty::I32, + | Self::S32Div | Self::S32Rem | Self::S32Shr => Ty::S32, + | Self::U32Div | Self::U32Rem | Self::U32Shr => Ty::U32, + | Self::I64Add + | Self::I64Sub + | Self::I64Mul + | Self::I64BitAnd + | Self::I64BitOr + | Self::I64BitXor + | Self::I64Shl + | Self::I64Rotl + | Self::I64Rotr => Ty::I64, + | Self::S64Div | Self::S64Rem | Self::S64Shr => Ty::S64, + | Self::U64Div | Self::U64Rem | Self::U64Shr => Ty::U64, + | Self::F32Add + | Self::F32Sub + | Self::F32Mul + | Self::F32Div + | Self::F32Min + | Self::F32Max + | Self::F32Copysign => Ty::F32, + | Self::F64Add + | Self::F64Sub + | Self::F64Mul + | Self::F64Div + | Self::F64Min + | Self::F64Max + | Self::F64Copysign => Ty::F64, + | Self::I8x16Swizzle => Ty::I8x16, + | Self::I8x16Eq | Self::I8x16NotEq => Ty::I8x16, + | Self::I16x8Eq | Self::I16x8NotEq => Ty::I16x8, + | Self::I32x4Eq | Self::I32x4NotEq => Ty::I32x4, + | Self::I64x2Eq | Self::I64x2NotEq => Ty::I64x2, + | Self::S8x16Lt | Self::S8x16Le => Ty::S8x16, + | Self::S16x8Lt | Self::S16x8Le => Ty::S16x8, + | Self::S32x4Lt | Self::S32x4Le => Ty::S32x4, + | Self::S64x2Lt | Self::S64x2Le => Ty::S64x2, + | Self::U8x16Lt | Self::U8x16Le => Ty::U8x16, + | Self::U16x8Lt | Self::U16x8Le => Ty::U16x8, + | Self::U32x4Lt | Self::U32x4Le => Ty::U32x4, + | Self::U64x2Lt | Self::U64x2Le => Ty::U64x2, + | Self::F32x4Eq | Self::F32x4NotEq | Self::F32x4Lt | Self::F32x4Le => Ty::F32x4, + | Self::F64x2Eq | Self::F64x2NotEq | Self::F64x2Lt | Self::F64x2Le => Ty::F64x2, + | Self::V128And | Self::V128AndNot | Self::V128Or | Self::V128Xor => Ty::V128, }; Ident::from(ty) } @@ -663,64 +714,6 @@ impl BinaryOpKind { } } - pub fn result_ty(&self) -> Ty { - match self { - | Self::Cmp(_) => Ty::I32, - | Self::I32Add - | Self::I32Sub - | Self::I32Mul - | Self::I32BitAnd - | Self::I32BitOr - | Self::I32BitXor - | Self::I32Shl - | Self::I32Rotl - | Self::I32Rotr => Ty::I32, - | Self::S32Div | Self::S32Rem | Self::S32Shr => Ty::S32, - | Self::U32Div | Self::U32Rem | Self::U32Shr => Ty::U32, - | Self::I64Add - | Self::I64Sub - | Self::I64Mul - | Self::I64BitAnd - | Self::I64BitOr - | Self::I64BitXor - | Self::I64Shl - | Self::I64Rotl - | Self::I64Rotr => Ty::I64, - | Self::S64Div | Self::S64Rem | Self::S64Shr => Ty::S64, - | Self::U64Div | Self::U64Rem | Self::U64Shr => Ty::U64, - | Self::F32Add - | Self::F32Sub - | Self::F32Mul - | Self::F32Div - | Self::F32Min - | Self::F32Max - | Self::F32Copysign => Ty::F32, - | Self::F64Add - | Self::F64Sub - | Self::F64Mul - | Self::F64Div - | Self::F64Min - | Self::F64Max - | Self::F64Copysign => Ty::F64, - | Self::I8x16Swizzle => Ty::I8x16, - | Self::I8x16Eq | Self::I8x16NotEq => Ty::I8x16, - | Self::I16x8Eq | Self::I16x8NotEq => Ty::I16x8, - | Self::I32x4Eq | Self::I32x4NotEq => Ty::I32x4, - | Self::I64x2Eq | Self::I64x2NotEq => Ty::I64x2, - | Self::S8x16Lt | Self::S8x16Le => Ty::S8x16, - | Self::S16x8Lt | Self::S16x8Le => Ty::S16x8, - | Self::S32x4Lt | Self::S32x4Le => Ty::S32x4, - | Self::S64x2Lt | Self::S64x2Le => Ty::S64x2, - | Self::U8x16Lt | Self::U8x16Le => Ty::U8x16, - | Self::U16x8Lt | Self::U16x8Le => Ty::U16x8, - | Self::U32x4Lt | Self::U32x4Le => Ty::U32x4, - | Self::U64x2Lt | Self::U64x2Le => Ty::U64x2, - | Self::F32x4Eq | Self::F32x4NotEq | Self::F32x4Lt | Self::F32x4Le => Ty::F32x4, - | Self::F64x2Eq | Self::F64x2NotEq | Self::F64x2Lt | Self::F64x2Le => Ty::F64x2, - | Self::V128And | Self::V128AndNot | Self::V128Or | Self::V128Xor => Ty::V128, - } - } - pub fn commutativity(&self) -> Commutativity { match self { | Self::Cmp(cmp) => cmp.commutativity(), @@ -1110,7 +1103,7 @@ impl CmpOpKind { } } - pub fn input_ty(&self) -> Ty { + pub fn ident_prefix(&self) -> Ty { match self { | Self::I32Eq | Self::I32NotEq From 4d5a127e2b57e51e8ffaa3c49de1cb0d0135e7e9 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Sat, 30 Aug 2025 10:54:18 +0200 Subject: [PATCH 146/186] add comments to signal splits --- crates/ir2/build/isa.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index a3e815939f..6866700001 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -843,7 +843,9 @@ fn add_simd_replace_lane_ops(isa: &mut Isa) { fn add_simd_binary_ops(isa: &mut Isa) { let kinds = [ + // Miscellaneous BinaryOpKind::I8x16Swizzle, + // Integer Comparisons BinaryOpKind::I8x16Eq, BinaryOpKind::I8x16NotEq, BinaryOpKind::I16x8Eq, @@ -868,6 +870,7 @@ fn add_simd_binary_ops(isa: &mut Isa) { BinaryOpKind::U32x4Le, BinaryOpKind::U64x2Lt, BinaryOpKind::U64x2Le, + // Float Comparisons BinaryOpKind::F32x4Eq, BinaryOpKind::F32x4NotEq, BinaryOpKind::F32x4Lt, @@ -876,6 +879,7 @@ fn add_simd_binary_ops(isa: &mut Isa) { BinaryOpKind::F64x2NotEq, BinaryOpKind::F64x2Lt, BinaryOpKind::F64x2Le, + // Bitwise BinaryOpKind::V128And, BinaryOpKind::V128AndNot, BinaryOpKind::V128Or, From 253ee8826e341cac966a3bcdd7ed1c2cecd45684 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Sat, 30 Aug 2025 11:33:03 +0200 Subject: [PATCH 147/186] add binary simd ops codegen --- crates/ir2/build/isa.rs | 73 +++++++++++++ crates/ir2/build/mod.rs | 4 +- crates/ir2/build/op.rs | 219 ++++++++++++++++++++++++++++++++++++++ crates/ir2/build/token.rs | 15 +++ 4 files changed, 309 insertions(+), 2 deletions(-) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 6866700001..36344a4de2 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -884,6 +884,79 @@ fn add_simd_binary_ops(isa: &mut Isa) { BinaryOpKind::V128AndNot, BinaryOpKind::V128Or, BinaryOpKind::V128Xor, + // i8x16 Ops + BinaryOpKind::S8x16NarrowI16x8, + BinaryOpKind::U8x16NarrowI16x8, + BinaryOpKind::I8x16Add, + BinaryOpKind::S8x16AddSat, + BinaryOpKind::U8x16AddSat, + BinaryOpKind::I8x16Sub, + BinaryOpKind::S8x16SubSat, + BinaryOpKind::U8x16SubSat, + BinaryOpKind::S8x16Min, + BinaryOpKind::U8x16Min, + BinaryOpKind::S8x16Max, + BinaryOpKind::U8x16Max, + BinaryOpKind::U8x16Avgr, + // i16x8 Ops + BinaryOpKind::S16x8Q15MulrSat, + BinaryOpKind::S16x8NarrowI32x4, + BinaryOpKind::U16x8NarrowI32x4, + BinaryOpKind::S16x8ExtmulLowI8x16, + BinaryOpKind::U16x8ExtmulLowI8x16, + BinaryOpKind::S16x8ExtmulHighI8x16, + BinaryOpKind::U16x8ExtmulHighI8x16, + BinaryOpKind::I16x8Add, + BinaryOpKind::S16x8AddSat, + BinaryOpKind::U16x8AddSat, + BinaryOpKind::I16x8Sub, + BinaryOpKind::S16x8SubSat, + BinaryOpKind::U16x8SubSat, + BinaryOpKind::I16x8Mul, + BinaryOpKind::S16x8Min, + BinaryOpKind::U16x8Min, + BinaryOpKind::S16x8Max, + BinaryOpKind::U16x8Max, + BinaryOpKind::U16x8Avgr, + // i32x4 Ops + BinaryOpKind::I32x4Add, + BinaryOpKind::I32x4Sub, + BinaryOpKind::I32x4Mul, + BinaryOpKind::S32x4Min, + BinaryOpKind::U32x4Min, + BinaryOpKind::S32x4Max, + BinaryOpKind::U32x4Max, + BinaryOpKind::S32x4DotI16x8, + BinaryOpKind::S32x4ExtmulLowI16x8, + BinaryOpKind::U32x4ExtmulLowI16x8, + BinaryOpKind::S32x4ExtmulHighI16x8, + BinaryOpKind::U32x4ExtmulHighI16x8, + // i64x2 Ops + BinaryOpKind::I64x2Add, + BinaryOpKind::I64x2Sub, + BinaryOpKind::I64x2Mul, + BinaryOpKind::S64x2ExtmulLowI32x4, + BinaryOpKind::U64x2ExtmulLowI32x4, + BinaryOpKind::S64x2ExtmulHighI32x4, + BinaryOpKind::U64x2ExtmulHighI32x4, + // f32x4 Ops + BinaryOpKind::F32x4Add, + BinaryOpKind::F32x4Sub, + BinaryOpKind::F32x4Mul, + BinaryOpKind::F32x4Div, + BinaryOpKind::F32x4Min, + BinaryOpKind::F32x4Max, + BinaryOpKind::F32x4Pmin, + BinaryOpKind::F32x4Pmax, + // f64x2 Ops + BinaryOpKind::F64x2Add, + BinaryOpKind::F64x2Sub, + BinaryOpKind::F64x2Mul, + BinaryOpKind::F64x2Div, + BinaryOpKind::F64x2Min, + BinaryOpKind::F64x2Max, + BinaryOpKind::F64x2Pmin, + BinaryOpKind::F64x2Pmax, ]; for kind in kinds { isa.push_op(BinaryOp::new(kind, OperandKind::Stack, OperandKind::Stack)); diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index 88efa0f301..f4de9af312 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -73,7 +73,7 @@ pub fn generate_code(config: &Config) -> Result<(), Error> { } fn generate_op_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<(), Error> { - const EXPECTED_SIZE: usize = 200_000; + const EXPECTED_SIZE: usize = 225_000; contents.clear(); contents.reserve_exact(EXPECTED_SIZE); write!( @@ -113,7 +113,7 @@ fn generate_encode_rs(config: &Config, isa: &Isa, contents: &mut String) -> Resu } fn generate_decode_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<(), Error> { - const EXPECTED_SIZE: usize = 40_000; + const EXPECTED_SIZE: usize = 45_000; contents.clear(); contents.reserve_exact(EXPECTED_SIZE); write!(contents, "{}", DisplayDecode::new(isa, Indent::default()))?; diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 2f75d7ddba..af14d38818 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -466,6 +466,79 @@ pub enum BinaryOpKind { V128AndNot, V128Or, V128Xor, + // i8x16 Ops + S8x16NarrowI16x8, + U8x16NarrowI16x8, + I8x16Add, + S8x16AddSat, + U8x16AddSat, + I8x16Sub, + S8x16SubSat, + U8x16SubSat, + S8x16Min, + U8x16Min, + S8x16Max, + U8x16Max, + U8x16Avgr, + // i16x8 Ops + S16x8Q15MulrSat, + S16x8NarrowI32x4, + U16x8NarrowI32x4, + S16x8ExtmulLowI8x16, + U16x8ExtmulLowI8x16, + S16x8ExtmulHighI8x16, + U16x8ExtmulHighI8x16, + I16x8Add, + S16x8AddSat, + U16x8AddSat, + I16x8Sub, + S16x8SubSat, + U16x8SubSat, + I16x8Mul, + S16x8Min, + U16x8Min, + S16x8Max, + U16x8Max, + U16x8Avgr, + // i32x4 Ops + I32x4Add, + I32x4Sub, + I32x4Mul, + S32x4Min, + U32x4Min, + S32x4Max, + U32x4Max, + S32x4DotI16x8, + S32x4ExtmulLowI16x8, + U32x4ExtmulLowI16x8, + S32x4ExtmulHighI16x8, + U32x4ExtmulHighI16x8, + // i64x2 Ops + I64x2Add, + I64x2Sub, + I64x2Mul, + S64x2ExtmulLowI32x4, + U64x2ExtmulLowI32x4, + S64x2ExtmulHighI32x4, + U64x2ExtmulHighI32x4, + // f32x4 Ops + F32x4Add, + F32x4Sub, + F32x4Mul, + F32x4Div, + F32x4Min, + F32x4Max, + F32x4Pmin, + F32x4Pmax, + // f64x2 Ops + F64x2Add, + F64x2Sub, + F64x2Mul, + F64x2Div, + F64x2Min, + F64x2Max, + F64x2Pmin, + F64x2Pmax, } impl BinaryOpKind { @@ -554,6 +627,79 @@ impl BinaryOpKind { Self::V128AndNot => Ident::AndNot, Self::V128Or => Ident::Or, Self::V128Xor => Ident::Xor, + // i8x16 Ops + Self::S8x16NarrowI16x8 => Ident::NarrowI16x8, + Self::U8x16NarrowI16x8 => Ident::NarrowI16x8, + Self::I8x16Add => Ident::Add, + Self::S8x16AddSat => Ident::AddSat, + Self::U8x16AddSat => Ident::AddSat, + Self::I8x16Sub => Ident::Sub, + Self::S8x16SubSat => Ident::SubSat, + Self::U8x16SubSat => Ident::SubSat, + Self::S8x16Min => Ident::Min, + Self::U8x16Min => Ident::Min, + Self::S8x16Max => Ident::Max, + Self::U8x16Max => Ident::Max, + Self::U8x16Avgr => Ident::Avgr, + // i16x8 Ops + Self::S16x8Q15MulrSat => Ident::Q15MulrSat, + Self::S16x8NarrowI32x4 => Ident::NarrowI32x4, + Self::U16x8NarrowI32x4 => Ident::NarrowI32x4, + Self::S16x8ExtmulLowI8x16 => Ident::ExtmulLowI8x16, + Self::U16x8ExtmulLowI8x16 => Ident::ExtmulLowI8x16, + Self::S16x8ExtmulHighI8x16 => Ident::ExtmulHighI8x16, + Self::U16x8ExtmulHighI8x16 => Ident::ExtmulHighI8x16, + Self::I16x8Add => Ident::Add, + Self::S16x8AddSat => Ident::AddSat, + Self::U16x8AddSat => Ident::AddSat, + Self::I16x8Sub => Ident::Sub, + Self::S16x8SubSat => Ident::SubSat, + Self::U16x8SubSat => Ident::SubSat, + Self::I16x8Mul => Ident::Mul, + Self::S16x8Min => Ident::Min, + Self::U16x8Min => Ident::Min, + Self::S16x8Max => Ident::Max, + Self::U16x8Max => Ident::Max, + Self::U16x8Avgr => Ident::Avgr, + // i32x4 Ops + Self::I32x4Add => Ident::Add, + Self::I32x4Sub => Ident::Sub, + Self::I32x4Mul => Ident::Mul, + Self::S32x4Min => Ident::Min, + Self::U32x4Min => Ident::Min, + Self::S32x4Max => Ident::Max, + Self::U32x4Max => Ident::Max, + Self::S32x4DotI16x8 => Ident::DotI16x8, + Self::S32x4ExtmulLowI16x8 => Ident::ExtmulLowI16x8, + Self::U32x4ExtmulLowI16x8 => Ident::ExtmulLowI16x8, + Self::S32x4ExtmulHighI16x8 => Ident::ExtmulHighI16x8, + Self::U32x4ExtmulHighI16x8 => Ident::ExtmulHighI16x8, + // i64x2 Ops + Self::I64x2Add => Ident::Add, + Self::I64x2Sub => Ident::Sub, + Self::I64x2Mul => Ident::Mul, + Self::S64x2ExtmulLowI32x4 => Ident::ExtmulLowI32x4, + Self::U64x2ExtmulLowI32x4 => Ident::ExtmulLowI32x4, + Self::S64x2ExtmulHighI32x4 => Ident::ExtmulHighI32x4, + Self::U64x2ExtmulHighI32x4 => Ident::ExtmulHighI32x4, + // f32x4 Ops + Self::F32x4Add => Ident::Add, + Self::F32x4Sub => Ident::Sub, + Self::F32x4Mul => Ident::Mul, + Self::F32x4Div => Ident::Div, + Self::F32x4Min => Ident::Min, + Self::F32x4Max => Ident::Max, + Self::F32x4Pmin => Ident::Pmin, + Self::F32x4Pmax => Ident::Pmax, + // f64x2 Ops + Self::F64x2Add => Ident::Add, + Self::F64x2Sub => Ident::Sub, + Self::F64x2Mul => Ident::Mul, + Self::F64x2Div => Ident::Div, + Self::F64x2Min => Ident::Min, + Self::F64x2Max => Ident::Max, + Self::F64x2Pmin => Ident::Pmin, + Self::F64x2Pmax => Ident::Pmax, } } @@ -612,6 +758,79 @@ impl BinaryOpKind { | Self::F32x4Eq | Self::F32x4NotEq | Self::F32x4Lt | Self::F32x4Le => Ty::F32x4, | Self::F64x2Eq | Self::F64x2NotEq | Self::F64x2Lt | Self::F64x2Le => Ty::F64x2, | Self::V128And | Self::V128AndNot | Self::V128Or | Self::V128Xor => Ty::V128, + // i8x16 Ops + | Self::S8x16NarrowI16x8 => Ty::S8x16, + | Self::U8x16NarrowI16x8 => Ty::U8x16, + | Self::I8x16Add => Ty::I8x16, + | Self::S8x16AddSat => Ty::S8x16, + | Self::U8x16AddSat => Ty::U8x16, + | Self::I8x16Sub => Ty::I8x16, + | Self::S8x16SubSat => Ty::S8x16, + | Self::U8x16SubSat => Ty::U8x16, + | Self::S8x16Min => Ty::S8x16, + | Self::U8x16Min => Ty::U8x16, + | Self::S8x16Max => Ty::S8x16, + | Self::U8x16Max => Ty::U8x16, + | Self::U8x16Avgr => Ty::U8x16, + // i16x8 Ops + | Self::S16x8Q15MulrSat => Ty::S16x8, + | Self::S16x8NarrowI32x4 => Ty::S16x8, + | Self::U16x8NarrowI32x4 => Ty::U16x8, + | Self::S16x8ExtmulLowI8x16 => Ty::S16x8, + | Self::U16x8ExtmulLowI8x16 => Ty::U16x8, + | Self::S16x8ExtmulHighI8x16 => Ty::S16x8, + | Self::U16x8ExtmulHighI8x16 => Ty::U16x8, + | Self::I16x8Add => Ty::I16x8, + | Self::S16x8AddSat => Ty::S16x8, + | Self::U16x8AddSat => Ty::U16x8, + | Self::I16x8Sub => Ty::I16x8, + | Self::S16x8SubSat => Ty::S16x8, + | Self::U16x8SubSat => Ty::U16x8, + | Self::I16x8Mul => Ty::I16x8, + | Self::S16x8Min => Ty::S16x8, + | Self::U16x8Min => Ty::U16x8, + | Self::S16x8Max => Ty::S16x8, + | Self::U16x8Max => Ty::U16x8, + | Self::U16x8Avgr => Ty::U16x8, + // i32x4 Ops + | Self::I32x4Add + | Self::I32x4Sub + | Self::I32x4Mul => Ty::I32x4, + | Self::S32x4Min => Ty::S32x4, + | Self::U32x4Min => Ty::U32x4, + | Self::S32x4Max => Ty::S32x4, + | Self::U32x4Max => Ty::U32x4, + | Self::S32x4DotI16x8 => Ty::S32x4, + | Self::S32x4ExtmulLowI16x8 => Ty::S32x4, + | Self::U32x4ExtmulLowI16x8 => Ty::U32x4, + | Self::S32x4ExtmulHighI16x8 => Ty::S32x4, + | Self::U32x4ExtmulHighI16x8 => Ty::U32x4, + // i64x2 Ops + | Self::I64x2Add + | Self::I64x2Sub + | Self::I64x2Mul => Ty::I64x2, + | Self::S64x2ExtmulLowI32x4 => Ty::S64x2, + | Self::U64x2ExtmulLowI32x4 => Ty::U64x2, + | Self::S64x2ExtmulHighI32x4 => Ty::S64x2, + | Self::U64x2ExtmulHighI32x4 => Ty::U64x2, + // f32x4 Ops + | Self::F32x4Add + | Self::F32x4Sub + | Self::F32x4Mul + | Self::F32x4Div + | Self::F32x4Min + | Self::F32x4Max + | Self::F32x4Pmin + | Self::F32x4Pmax => Ty::F32x4, + // f64x2 Ops + | Self::F64x2Add + | Self::F64x2Sub + | Self::F64x2Mul + | Self::F64x2Div + | Self::F64x2Min + | Self::F64x2Max + | Self::F64x2Pmin + | Self::F64x2Pmax => Ty::F64x2, }; Ident::from(ty) } diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index a29dd476fb..f2a89e45d4 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -94,13 +94,18 @@ macro_rules! define_ident { } define_ident!( Add: add, + AddSat: add_sat, Sub: sub, + SubSat: sub_sat, Mul: mul, Div: div, Rem: rem, Min: min, Max: max, + Pmin: pmin, + Pmax: pmax, Copysign: copysign, + Avgr: avgr, Shl: shl, Shr: shr, @@ -278,4 +283,14 @@ define_ident!( ReplaceLane: replace_lane, Swizzle: swizzle, I8x16Shuffle: i8x16_shuffle, + Q15MulrSat: q15_mulr_sat, + NarrowI16x8: narrow_i16x8, + NarrowI32x4: narrow_i32x4, + ExtmulLowI8x16: extmul_low_i8x16, + ExtmulHighI8x16: extmul_high_i8x16, + ExtmulLowI16x8: extmul_low_i16x8, + ExtmulHighI16x8: extmul_high_i16x8, + ExtmulLowI32x4: extmul_low_i32x4, + ExtmulHighI32x4: extmul_high_i32x4, + DotI16x8: dot_i16x8, ); From 533d1cc94038e9aa2dafccc2f8aa9e2f0dc575ff Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Sat, 30 Aug 2025 11:38:01 +0200 Subject: [PATCH 148/186] adjust expected generated file sizes --- crates/ir2/build/mod.rs | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index f4de9af312..6a060195cc 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -73,9 +73,12 @@ pub fn generate_code(config: &Config) -> Result<(), Error> { } fn generate_op_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<(), Error> { - const EXPECTED_SIZE: usize = 225_000; + let expected_size = match config.simd { + true => 225_000, + false => 175_000, + }; contents.clear(); - contents.reserve_exact(EXPECTED_SIZE); + contents.reserve_exact(expected_size); write!( contents, "\ @@ -91,36 +94,42 @@ fn generate_op_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<( )?; let len_contents = contents.len(); assert!( - len_contents <= EXPECTED_SIZE, - "reserved bytes: {EXPECTED_SIZE}, contents.len() = {len_contents}", + len_contents <= expected_size, + "reserved bytes: {expected_size}, contents.len() = {len_contents}", ); fs::write(config.out_dir.join("op.rs"), contents)?; Ok(()) } fn generate_encode_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<(), Error> { - const EXPECTED_SIZE: usize = 150_000; + let expected_size = match config.simd { + true => 95_000, + false => 75_000, + }; contents.clear(); - contents.reserve_exact(EXPECTED_SIZE); + contents.reserve_exact(expected_size); write!(contents, "{}", DisplayEncode::new(isa, Indent::default()))?; let len_contents = contents.len(); assert!( - len_contents <= EXPECTED_SIZE, - "reserved bytes: {EXPECTED_SIZE}, contents.len() = {len_contents}", + len_contents <= expected_size, + "reserved bytes: {expected_size}, contents.len() = {len_contents}", ); fs::write(config.out_dir.join("encode.rs"), contents)?; Ok(()) } fn generate_decode_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<(), Error> { - const EXPECTED_SIZE: usize = 45_000; + let expected_size = match config.simd { + true => 45_000, + false => 35_000, + }; contents.clear(); - contents.reserve_exact(EXPECTED_SIZE); + contents.reserve_exact(expected_size); write!(contents, "{}", DisplayDecode::new(isa, Indent::default()))?; let len_contents = contents.len(); assert!( - len_contents <= EXPECTED_SIZE, - "reserved bytes: {EXPECTED_SIZE}, contents.len() = {len_contents}", + len_contents <= expected_size, + "reserved bytes: {expected_size}, contents.len() = {len_contents}", ); fs::write(config.out_dir.join("decode.rs"), contents)?; Ok(()) From 07eac128350152da80f944ade7603cfc2cea0832 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Sat, 30 Aug 2025 11:48:39 +0200 Subject: [PATCH 149/186] deduplicate codegen code --- crates/ir2/build/mod.rs | 67 +++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index 6a060195cc..4b61912b7f 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -77,26 +77,21 @@ fn generate_op_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<( true => 225_000, false => 175_000, }; - contents.clear(); - contents.reserve_exact(expected_size); - write!( - contents, - "\ - {}\n\ - {}\n\ - {}\n\ - {}\n\ - ", - DisplayOp::new(isa, Indent::default()), - DisplayResultMut::new(isa, Indent::default()), - DisplayConstructor::new(isa, Indent::default()), - DisplayOpCode::new(isa, Indent::default()), - )?; - let len_contents = contents.len(); - assert!( - len_contents <= expected_size, - "reserved bytes: {expected_size}, contents.len() = {len_contents}", - ); + write_to_buffer(contents, expected_size, |buffer| { + write!( + buffer, + "\ + {}\n\ + {}\n\ + {}\n\ + {}\n\ + ", + DisplayOp::new(isa, Indent::default()), + DisplayResultMut::new(isa, Indent::default()), + DisplayConstructor::new(isa, Indent::default()), + DisplayOpCode::new(isa, Indent::default()), + ) + })?; fs::write(config.out_dir.join("op.rs"), contents)?; Ok(()) } @@ -106,14 +101,9 @@ fn generate_encode_rs(config: &Config, isa: &Isa, contents: &mut String) -> Resu true => 95_000, false => 75_000, }; - contents.clear(); - contents.reserve_exact(expected_size); - write!(contents, "{}", DisplayEncode::new(isa, Indent::default()))?; - let len_contents = contents.len(); - assert!( - len_contents <= expected_size, - "reserved bytes: {expected_size}, contents.len() = {len_contents}", - ); + write_to_buffer(contents, expected_size, |buffer| { + write!(buffer, "{}", DisplayEncode::new(isa, Indent::default())) + })?; fs::write(config.out_dir.join("encode.rs"), contents)?; Ok(()) } @@ -123,14 +113,25 @@ fn generate_decode_rs(config: &Config, isa: &Isa, contents: &mut String) -> Resu true => 45_000, false => 35_000, }; - contents.clear(); - contents.reserve_exact(expected_size); - write!(contents, "{}", DisplayDecode::new(isa, Indent::default()))?; - let len_contents = contents.len(); + write_to_buffer(contents, expected_size, |buffer| { + write!(buffer, "{}", DisplayDecode::new(isa, Indent::default())) + })?; + fs::write(config.out_dir.join("decode.rs"), contents)?; + Ok(()) +} + +fn write_to_buffer( + buffer: &mut String, + expected_size: usize, + f: impl FnOnce(&mut String) -> fmt::Result, +) -> Result<(), Error> { + buffer.clear(); + buffer.reserve_exact(expected_size); + f(buffer)?; + let len_contents = buffer.len(); assert!( len_contents <= expected_size, "reserved bytes: {expected_size}, contents.len() = {len_contents}", ); - fs::write(config.out_dir.join("decode.rs"), contents)?; Ok(()) } From fba95a92aab2fe448dacf0134771a0ea29de264a Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Sat, 30 Aug 2025 11:48:46 +0200 Subject: [PATCH 150/186] apply rustfmt --- crates/ir2/build/op.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index af14d38818..94a7afa70b 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -793,9 +793,7 @@ impl BinaryOpKind { | Self::U16x8Max => Ty::U16x8, | Self::U16x8Avgr => Ty::U16x8, // i32x4 Ops - | Self::I32x4Add - | Self::I32x4Sub - | Self::I32x4Mul => Ty::I32x4, + | Self::I32x4Add | Self::I32x4Sub | Self::I32x4Mul => Ty::I32x4, | Self::S32x4Min => Ty::S32x4, | Self::U32x4Min => Ty::U32x4, | Self::S32x4Max => Ty::S32x4, @@ -806,9 +804,7 @@ impl BinaryOpKind { | Self::S32x4ExtmulHighI16x8 => Ty::S32x4, | Self::U32x4ExtmulHighI16x8 => Ty::U32x4, // i64x2 Ops - | Self::I64x2Add - | Self::I64x2Sub - | Self::I64x2Mul => Ty::I64x2, + | Self::I64x2Add | Self::I64x2Sub | Self::I64x2Mul => Ty::I64x2, | Self::S64x2ExtmulLowI32x4 => Ty::S64x2, | Self::U64x2ExtmulLowI32x4 => Ty::U64x2, | Self::S64x2ExtmulHighI32x4 => Ty::S64x2, From ca154fdf41eecea2dd7a0bab6d981126568dc1e7 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Sat, 30 Aug 2025 12:12:32 +0200 Subject: [PATCH 151/186] add simd shift ops codegen --- crates/ir2/build/isa.rs | 22 ++++++++++++++++++ crates/ir2/build/mod.rs | 4 ++-- crates/ir2/build/op.rs | 51 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 2 deletions(-) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 36344a4de2..0ab0310691 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -764,6 +764,7 @@ fn add_simd_ops(isa: &mut Isa, config: &Config) { add_simd_extract_lane_ops(isa); add_simd_replace_lane_ops(isa); add_simd_binary_ops(isa); + add_simd_shift_ops(isa); } fn add_simd_splat_ops(isa: &mut Isa) { @@ -962,3 +963,24 @@ fn add_simd_binary_ops(isa: &mut Isa) { isa.push_op(BinaryOp::new(kind, OperandKind::Stack, OperandKind::Stack)); } } + +fn add_simd_shift_ops(isa: &mut Isa) { + let kinds = [ + BinaryOpKind::I8x16Shl, + BinaryOpKind::S8x16Shr, + BinaryOpKind::U8x16Shr, + BinaryOpKind::I16x8Shl, + BinaryOpKind::S16x8Shr, + BinaryOpKind::U16x8Shr, + BinaryOpKind::I32x4Shl, + BinaryOpKind::S32x4Shr, + BinaryOpKind::U32x4Shr, + BinaryOpKind::I64x2Shl, + BinaryOpKind::S64x2Shr, + BinaryOpKind::U64x2Shr, + ]; + for kind in kinds { + isa.push_op(BinaryOp::new(kind, OperandKind::Stack, OperandKind::Stack)); + isa.push_op(BinaryOp::new(kind, OperandKind::Stack, OperandKind::Immediate)); + } +} diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index 4b61912b7f..db4da1db93 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -74,7 +74,7 @@ pub fn generate_code(config: &Config) -> Result<(), Error> { fn generate_op_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<(), Error> { let expected_size = match config.simd { - true => 225_000, + true => 230_000, false => 175_000, }; write_to_buffer(contents, expected_size, |buffer| { @@ -98,7 +98,7 @@ fn generate_op_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<( fn generate_encode_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<(), Error> { let expected_size = match config.simd { - true => 95_000, + true => 100_000, false => 75_000, }; write_to_buffer(contents, expected_size, |buffer| { diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 94a7afa70b..88ac4c8cdd 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -539,6 +539,19 @@ pub enum BinaryOpKind { F64x2Max, F64x2Pmin, F64x2Pmax, + // Simd Shift Ops + I8x16Shl, + S8x16Shr, + U8x16Shr, + I16x8Shl, + S16x8Shr, + U16x8Shr, + I32x4Shl, + S32x4Shr, + U32x4Shr, + I64x2Shl, + S64x2Shr, + U64x2Shr, } impl BinaryOpKind { @@ -700,6 +713,19 @@ impl BinaryOpKind { Self::F64x2Max => Ident::Max, Self::F64x2Pmin => Ident::Pmin, Self::F64x2Pmax => Ident::Pmax, + // Simd Shift Ops + Self::I8x16Shl => Ident::Shl, + Self::S8x16Shr => Ident::Shr, + Self::U8x16Shr => Ident::Shr, + Self::I16x8Shl => Ident::Shl, + Self::S16x8Shr => Ident::Shr, + Self::U16x8Shr => Ident::Shr, + Self::I32x4Shl => Ident::Shl, + Self::S32x4Shr => Ident::Shr, + Self::U32x4Shr => Ident::Shr, + Self::I64x2Shl => Ident::Shl, + Self::S64x2Shr => Ident::Shr, + Self::U64x2Shr => Ident::Shr, } } @@ -827,6 +853,19 @@ impl BinaryOpKind { | Self::F64x2Max | Self::F64x2Pmin | Self::F64x2Pmax => Ty::F64x2, + // Simd Shift Ops + | Self::I8x16Shl => Ty::I8x16, + | Self::S8x16Shr => Ty::S8x16, + | Self::U8x16Shr => Ty::U8x16, + | Self::I16x8Shl => Ty::I16x8, + | Self::S16x8Shr => Ty::S16x8, + | Self::U16x8Shr => Ty::U16x8, + | Self::I32x4Shl => Ty::I32x4, + | Self::S32x4Shr => Ty::S32x4, + | Self::U32x4Shr => Ty::U32x4, + | Self::I64x2Shl => Ty::I64x2, + | Self::S64x2Shr => Ty::S64x2, + | Self::U64x2Shr => Ty::U64x2, }; Ident::from(ty) } @@ -924,6 +963,18 @@ impl BinaryOpKind { | Self::F64Min | Self::F64Max => FieldTy::F64, | Self::F64Copysign => FieldTy::SignF64, + | Self::I8x16Shl + | Self::S8x16Shr + | Self::U8x16Shr + | Self::I16x8Shl + | Self::S16x8Shr + | Self::U16x8Shr + | Self::I32x4Shl + | Self::S32x4Shr + | Self::U32x4Shr + | Self::I64x2Shl + | Self::S64x2Shr + | Self::U64x2Shr => FieldTy::U8, _ => panic!("operator cannot have an immediate `rhs` field"), }, } From c870f16bc7647db69aaa81e4a33decd16d364333 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Sat, 30 Aug 2025 12:12:44 +0200 Subject: [PATCH 152/186] add #[track_caller] for write_to_buffer --- crates/ir2/build/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index db4da1db93..0eb967858f 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -120,6 +120,7 @@ fn generate_decode_rs(config: &Config, isa: &Isa, contents: &mut String) -> Resu Ok(()) } +#[track_caller] fn write_to_buffer( buffer: &mut String, expected_size: usize, From 3c5179cf75742a6bbaab8c1193e04c06269ec5d1 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Sat, 30 Aug 2025 13:59:10 +0200 Subject: [PATCH 153/186] add unary SIMD ops codegen --- crates/ir2/build/isa.rs | 82 +++++++++++- crates/ir2/build/mod.rs | 6 +- crates/ir2/build/op.rs | 259 ++++++++++++++++++++++++++++++++++++++ crates/ir2/build/token.rs | 11 ++ 4 files changed, 354 insertions(+), 4 deletions(-) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 0ab0310691..0dd82d2549 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -765,6 +765,7 @@ fn add_simd_ops(isa: &mut Isa, config: &Config) { add_simd_replace_lane_ops(isa); add_simd_binary_ops(isa); add_simd_shift_ops(isa); + add_simd_unary_ops(isa); } fn add_simd_splat_ops(isa: &mut Isa) { @@ -981,6 +982,85 @@ fn add_simd_shift_ops(isa: &mut Isa) { ]; for kind in kinds { isa.push_op(BinaryOp::new(kind, OperandKind::Stack, OperandKind::Stack)); - isa.push_op(BinaryOp::new(kind, OperandKind::Stack, OperandKind::Immediate)); + isa.push_op(BinaryOp::new( + kind, + OperandKind::Stack, + OperandKind::Immediate, + )); + } +} + +fn add_simd_unary_ops(isa: &mut Isa) { + let kinds = [ + // SIMD: Generic Unary Ops + UnaryOpKind::V128Not, + UnaryOpKind::V128AnyTrue, + // SIMD: `i8x16` Unary Ops + UnaryOpKind::I8x16Abs, + UnaryOpKind::I8x16Neg, + UnaryOpKind::I8x16Popcnt, + UnaryOpKind::I8x16AllTrue, + UnaryOpKind::I8x16Bitmask, + // SIMD: `i16x8` Unary Ops + UnaryOpKind::I16x8Abs, + UnaryOpKind::I16x8Neg, + UnaryOpKind::I16x8AllTrue, + UnaryOpKind::I16x8Bitmask, + UnaryOpKind::S16x8ExtaddPairwiseI8x16, + UnaryOpKind::U16x8ExtaddPairwiseI8x16, + UnaryOpKind::S16x8ExtendLowI8x16, + UnaryOpKind::U16x8ExtendLowI8x16, + UnaryOpKind::S16x8ExtendHighI8x16, + UnaryOpKind::U16x8ExtendHighI8x16, + // SIMD: `i32x4` Unary Ops + UnaryOpKind::I32x4Abs, + UnaryOpKind::I32x4Neg, + UnaryOpKind::I32x4AllTrue, + UnaryOpKind::I32x4Bitmask, + UnaryOpKind::S32x4ExtaddPairwiseI16x8, + UnaryOpKind::U32x4ExtaddPairwiseI16x8, + UnaryOpKind::S32x4ExtendLowI16x8, + UnaryOpKind::U32x4ExtendLowI16x8, + UnaryOpKind::S32x4ExtendHighI16x8, + UnaryOpKind::U32x4ExtendHighI16x8, + // SIMD: `i64x2` Unary Ops + UnaryOpKind::I64x2Abs, + UnaryOpKind::I64x2Neg, + UnaryOpKind::I64x2AllTrue, + UnaryOpKind::I64x2Bitmask, + UnaryOpKind::S64x2ExtendLowI32x4, + UnaryOpKind::U64x2ExtendLowI32x4, + UnaryOpKind::S64x2ExtendHighI32x4, + UnaryOpKind::U64x2ExtendHighI32x4, + // SIMD: `f32x4` Unary Ops + UnaryOpKind::F32x4DemoteZeroF64x2, + UnaryOpKind::F32x4Ceil, + UnaryOpKind::F32x4Floor, + UnaryOpKind::F32x4Trunc, + UnaryOpKind::F32x4Nearest, + UnaryOpKind::F32x4Abs, + UnaryOpKind::F32x4Neg, + UnaryOpKind::F32x4Sqrt, + // SIMD: `f64x2` Unary Ops + UnaryOpKind::F64x2PromoteLowF32x4, + UnaryOpKind::F64x2Ceil, + UnaryOpKind::F64x2Floor, + UnaryOpKind::F64x2Trunc, + UnaryOpKind::F64x2Nearest, + UnaryOpKind::F64x2Abs, + UnaryOpKind::F64x2Neg, + UnaryOpKind::F64x2Sqrt, + // SIMD: Conversions + UnaryOpKind::S32x4TruncSatF32x4, + UnaryOpKind::U32x4TruncSatF32x4, + UnaryOpKind::S32x4TruncSatZeroF64x2, + UnaryOpKind::U32x4TruncSatZeroF64x2, + UnaryOpKind::F32x4ConvertS32x4, + UnaryOpKind::F32x4ConvertU32x4, + UnaryOpKind::F64x2ConvertLowS32x4, + UnaryOpKind::F64x2ConvertLowU32x4, + ]; + for kind in kinds { + isa.push_op(UnaryOp::new(kind)); } } diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index 0eb967858f..5f4ed06784 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -74,7 +74,7 @@ pub fn generate_code(config: &Config) -> Result<(), Error> { fn generate_op_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<(), Error> { let expected_size = match config.simd { - true => 230_000, + true => 255_000, false => 175_000, }; write_to_buffer(contents, expected_size, |buffer| { @@ -98,7 +98,7 @@ fn generate_op_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<( fn generate_encode_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<(), Error> { let expected_size = match config.simd { - true => 100_000, + true => 110_000, false => 75_000, }; write_to_buffer(contents, expected_size, |buffer| { @@ -110,7 +110,7 @@ fn generate_encode_rs(config: &Config, isa: &Isa, contents: &mut String) -> Resu fn generate_decode_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<(), Error> { let expected_size = match config.simd { - true => 45_000, + true => 50_000, false => 35_000, }; write_to_buffer(contents, expected_size, |buffer| { diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 88ac4c8cdd..a55594284c 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -201,6 +201,74 @@ pub enum UnaryOpKind { F64ConvertU32, F64ConvertS64, F64ConvertU64, + + // SIMD: Generic Unary Ops + V128Not, + V128AnyTrue, + // SIMD: `i8x16` Unary Ops + I8x16Abs, + I8x16Neg, + I8x16Popcnt, + I8x16AllTrue, + I8x16Bitmask, + // SIMD: `i16x8` Unary Ops + I16x8Abs, + I16x8Neg, + I16x8AllTrue, + I16x8Bitmask, + S16x8ExtaddPairwiseI8x16, + U16x8ExtaddPairwiseI8x16, + S16x8ExtendLowI8x16, + U16x8ExtendLowI8x16, + S16x8ExtendHighI8x16, + U16x8ExtendHighI8x16, + // SIMD: `i32x4` Unary Ops + I32x4Abs, + I32x4Neg, + I32x4AllTrue, + I32x4Bitmask, + S32x4ExtaddPairwiseI16x8, + U32x4ExtaddPairwiseI16x8, + S32x4ExtendLowI16x8, + U32x4ExtendLowI16x8, + S32x4ExtendHighI16x8, + U32x4ExtendHighI16x8, + // SIMD: `i64x2` Unary Ops + I64x2Abs, + I64x2Neg, + I64x2AllTrue, + I64x2Bitmask, + S64x2ExtendLowI32x4, + U64x2ExtendLowI32x4, + S64x2ExtendHighI32x4, + U64x2ExtendHighI32x4, + // SIMD: `f32x4` Unary Ops + F32x4DemoteZeroF64x2, + F32x4Ceil, + F32x4Floor, + F32x4Trunc, + F32x4Nearest, + F32x4Abs, + F32x4Neg, + F32x4Sqrt, + // SIMD: `f64x2` Unary Ops + F64x2PromoteLowF32x4, + F64x2Ceil, + F64x2Floor, + F64x2Trunc, + F64x2Nearest, + F64x2Abs, + F64x2Neg, + F64x2Sqrt, + // SIMD: Conversions + S32x4TruncSatF32x4, + U32x4TruncSatF32x4, + S32x4TruncSatZeroF64x2, + U32x4TruncSatZeroF64x2, + F32x4ConvertS32x4, + F32x4ConvertU32x4, + F64x2ConvertLowS32x4, + F64x2ConvertLowU32x4, } impl UnaryOpKind { @@ -245,6 +313,70 @@ impl UnaryOpKind { | Self::F64ConvertU32 => Ty::U32, | Self::F64ConvertS64 => Ty::I64, | Self::F64ConvertU64 => Ty::U64, + + // SIMD: Generic Unary Ops + | Self::V128Not | Self::V128AnyTrue => Ty::V128, + // SIMD: `i8x16` Unary Ops + | Self::I8x16Abs + | Self::I8x16Neg + | Self::I8x16Popcnt + | Self::I8x16AllTrue + | Self::I8x16Bitmask => Ty::I8x16, + // SIMD: `i16x8` Unary Ops + | Self::I16x8Abs | Self::I16x8Neg | Self::I16x8AllTrue | Self::I16x8Bitmask => { + Ty::I16x8 + } + | Self::S16x8ExtaddPairwiseI8x16 + | Self::S16x8ExtendLowI8x16 + | Self::S16x8ExtendHighI8x16 + | Self::U16x8ExtaddPairwiseI8x16 + | Self::U16x8ExtendLowI8x16 + | Self::U16x8ExtendHighI8x16 => Ty::I8x16, + // SIMD: `i32x4` Unary Ops + | Self::I32x4Abs | Self::I32x4Neg | Self::I32x4AllTrue | Self::I32x4Bitmask => { + Ty::I32x4 + } + | Self::S32x4ExtaddPairwiseI16x8 + | Self::S32x4ExtendLowI16x8 + | Self::S32x4ExtendHighI16x8 + | Self::U32x4ExtaddPairwiseI16x8 + | Self::U32x4ExtendLowI16x8 + | Self::U32x4ExtendHighI16x8 => Ty::I16x8, + // SIMD: `i64x2` Unary Ops + | Self::I64x2Abs | Self::I64x2Neg | Self::I64x2AllTrue | Self::I64x2Bitmask => { + Ty::I64x2 + } + | Self::S64x2ExtendLowI32x4 + | Self::S64x2ExtendHighI32x4 + | Self::U64x2ExtendLowI32x4 + | Self::U64x2ExtendHighI32x4 => Ty::I32x4, + // SIMD: `f32x4` Unary Ops + | Self::F32x4DemoteZeroF64x2 => Ty::F64x2, + | Self::F32x4Ceil + | Self::F32x4Floor + | Self::F32x4Trunc + | Self::F32x4Nearest + | Self::F32x4Abs + | Self::F32x4Neg + | Self::F32x4Sqrt => Ty::F32x4, + // SIMD: `f64x2` Unary Ops + | Self::F64x2PromoteLowF32x4 => Ty::F32x4, + | Self::F64x2Ceil + | Self::F64x2Floor + | Self::F64x2Trunc + | Self::F64x2Nearest + | Self::F64x2Abs + | Self::F64x2Neg + | Self::F64x2Sqrt => Ty::F64x2, + // SIMD: Conversions + | Self::S32x4TruncSatF32x4 => Ty::F32x4, + | Self::S32x4TruncSatZeroF64x2 => Ty::F64x2, + | Self::U32x4TruncSatF32x4 => Ty::F32x4, + | Self::U32x4TruncSatZeroF64x2 => Ty::F64x2, + | Self::F32x4ConvertS32x4 => Ty::S32x4, + | Self::F32x4ConvertU32x4 => Ty::U32x4, + | Self::F64x2ConvertLowS32x4 => Ty::S32x4, + | Self::F64x2ConvertLowU32x4 => Ty::U32x4, } } @@ -286,6 +418,65 @@ impl UnaryOpKind { | Self::F64ConvertU32 | Self::F64ConvertS64 | Self::F64ConvertU64 => Ty::F64, + + // SIMD: Generic Unary Ops + | Self::V128Not | Self::V128AnyTrue => Ty::V128, + // SIMD: `i8x16` Unary Ops + | Self::I8x16Abs + | Self::I8x16Neg + | Self::I8x16Popcnt + | Self::I8x16AllTrue + | Self::I8x16Bitmask => Ty::I8x16, + // SIMD: `i16x8` Unary Ops + | Self::I16x8Abs => Ty::I16x8, + | Self::I16x8Neg => Ty::I16x8, + | Self::I16x8AllTrue => Ty::I16x8, + | Self::I16x8Bitmask => Ty::I16x8, + | Self::S16x8ExtaddPairwiseI8x16 + | Self::S16x8ExtendLowI8x16 + | Self::S16x8ExtendHighI8x16 => Ty::S16x8, + | Self::U16x8ExtaddPairwiseI8x16 + | Self::U16x8ExtendLowI8x16 + | Self::U16x8ExtendHighI8x16 => Ty::U16x8, + // SIMD: `i32x4` Unary Ops + | Self::I32x4Abs | Self::I32x4Neg | Self::I32x4AllTrue | Self::I32x4Bitmask => { + Ty::I32x4 + } + | Self::S32x4ExtaddPairwiseI16x8 + | Self::S32x4ExtendLowI16x8 + | Self::S32x4ExtendHighI16x8 => Ty::S32x4, + | Self::U32x4ExtaddPairwiseI16x8 + | Self::U32x4ExtendLowI16x8 + | Self::U32x4ExtendHighI16x8 => Ty::U32x4, + // SIMD: `i64x2` Unary Ops + | Self::I64x2Abs | Self::I64x2Neg | Self::I64x2AllTrue | Self::I64x2Bitmask => { + Ty::I64x2 + } + | Self::S64x2ExtendLowI32x4 | Self::S64x2ExtendHighI32x4 => Ty::S64x2, + | Self::U64x2ExtendLowI32x4 | Self::U64x2ExtendHighI32x4 => Ty::U64x2, + // SIMD: `f32x4` Unary Ops + | Self::F32x4DemoteZeroF64x2 + | Self::F32x4Ceil + | Self::F32x4Floor + | Self::F32x4Trunc + | Self::F32x4Nearest + | Self::F32x4Abs + | Self::F32x4Neg + | Self::F32x4Sqrt => Ty::F32x4, + // SIMD: `f64x2` Unary Ops + | Self::F64x2PromoteLowF32x4 + | Self::F64x2Ceil + | Self::F64x2Floor + | Self::F64x2Trunc + | Self::F64x2Nearest + | Self::F64x2Abs + | Self::F64x2Neg + | Self::F64x2Sqrt => Ty::F64x2, + // SIMD: Conversions + | Self::S32x4TruncSatF32x4 | Self::S32x4TruncSatZeroF64x2 => Ty::S32x4, + | Self::U32x4TruncSatF32x4 | Self::U32x4TruncSatZeroF64x2 => Ty::U32x4, + | Self::F32x4ConvertS32x4 | Self::F32x4ConvertU32x4 => Ty::F32x4, + | Self::F64x2ConvertLowS32x4 | Self::F64x2ConvertLowU32x4 => Ty::F64x2, } } @@ -343,6 +534,74 @@ impl UnaryOpKind { Self::F64ConvertU32 => Ident::Convert, Self::F64ConvertS64 => Ident::Convert, Self::F64ConvertU64 => Ident::Convert, + + // SIMD: Generic Unary Ops + Self::V128Not => Ident::Not, + Self::V128AnyTrue => Ident::AnyTrue, + // SIMD: `i8x16` Unary Ops + Self::I8x16Abs => Ident::Abs, + Self::I8x16Neg => Ident::Neg, + Self::I8x16Popcnt => Ident::Popcnt, + Self::I8x16AllTrue => Ident::AllTrue, + Self::I8x16Bitmask => Ident::Bitmask, + // SIMD: `i16x8` Unary Ops + Self::I16x8Abs => Ident::Abs, + Self::I16x8Neg => Ident::Neg, + Self::I16x8AllTrue => Ident::AllTrue, + Self::I16x8Bitmask => Ident::Bitmask, + Self::S16x8ExtaddPairwiseI8x16 => Ident::ExtaddPairwise, + Self::U16x8ExtaddPairwiseI8x16 => Ident::ExtaddPairwise, + Self::S16x8ExtendLowI8x16 => Ident::ExtendLow, + Self::U16x8ExtendLowI8x16 => Ident::ExtendLow, + Self::S16x8ExtendHighI8x16 => Ident::ExtendHigh, + Self::U16x8ExtendHighI8x16 => Ident::ExtendHigh, + // SIMD: `i32x4` Unary Ops + Self::I32x4Abs => Ident::Abs, + Self::I32x4Neg => Ident::Neg, + Self::I32x4AllTrue => Ident::AllTrue, + Self::I32x4Bitmask => Ident::Bitmask, + Self::S32x4ExtaddPairwiseI16x8 => Ident::ExtaddPairwise, + Self::U32x4ExtaddPairwiseI16x8 => Ident::ExtaddPairwise, + Self::S32x4ExtendLowI16x8 => Ident::ExtendLow, + Self::U32x4ExtendLowI16x8 => Ident::ExtendLow, + Self::S32x4ExtendHighI16x8 => Ident::ExtendHigh, + Self::U32x4ExtendHighI16x8 => Ident::ExtendHigh, + // SIMD: `i64x2` Unary Ops + Self::I64x2Abs => Ident::Abs, + Self::I64x2Neg => Ident::Neg, + Self::I64x2AllTrue => Ident::AllTrue, + Self::I64x2Bitmask => Ident::Bitmask, + Self::S64x2ExtendLowI32x4 => Ident::ExtendLow, + Self::U64x2ExtendLowI32x4 => Ident::ExtendLow, + Self::S64x2ExtendHighI32x4 => Ident::ExtendHigh, + Self::U64x2ExtendHighI32x4 => Ident::ExtendHigh, + // SIMD: `f32x4` Unary Ops + Self::F32x4DemoteZeroF64x2 => Ident::DemoteZero, + Self::F32x4Ceil => Ident::Ceil, + Self::F32x4Floor => Ident::Floor, + Self::F32x4Trunc => Ident::Trunc, + Self::F32x4Nearest => Ident::Nearest, + Self::F32x4Abs => Ident::Abs, + Self::F32x4Neg => Ident::Neg, + Self::F32x4Sqrt => Ident::Sqrt, + // SIMD: `f64x2` Unary Ops + Self::F64x2PromoteLowF32x4 => Ident::PromoteLow, + Self::F64x2Ceil => Ident::Ceil, + Self::F64x2Floor => Ident::Floor, + Self::F64x2Trunc => Ident::Trunc, + Self::F64x2Nearest => Ident::Nearest, + Self::F64x2Abs => Ident::Abs, + Self::F64x2Neg => Ident::Neg, + Self::F64x2Sqrt => Ident::Sqrt, + // SIMD: Conversions + Self::S32x4TruncSatF32x4 => Ident::TruncSat, + Self::U32x4TruncSatF32x4 => Ident::TruncSat, + Self::S32x4TruncSatZeroF64x2 => Ident::TruncSatZero, + Self::U32x4TruncSatZeroF64x2 => Ident::TruncSatZero, + Self::F32x4ConvertS32x4 => Ident::Convert, + Self::F32x4ConvertU32x4 => Ident::Convert, + Self::F64x2ConvertLowS32x4 => Ident::ConvertLow, + Self::F64x2ConvertLowU32x4 => Ident::ConvertLow, } } } diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index f2a89e45d4..9f1ccd3b4e 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -292,5 +292,16 @@ define_ident!( ExtmulHighI16x8: extmul_high_i16x8, ExtmulLowI32x4: extmul_low_i32x4, ExtmulHighI32x4: extmul_high_i32x4, + Not: not, + AnyTrue: any_true, DotI16x8: dot_i16x8, + AllTrue: all_true, + Bitmask: bitmask, + ExtaddPairwise: extadd_pairwise, + ExtendLow: extend_low, + ExtendHigh: extend_high, + DemoteZero: demote_zero, + PromoteLow: promote_low, + TruncSatZero: trunc_sat_zero, + ConvertLow: convert_low, ); From db35ebf739aff2289339d59ed8967ea5c8892c12 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Sat, 30 Aug 2025 14:00:06 +0200 Subject: [PATCH 154/186] rename UnaryOpKind::input_ty -> value_ty --- crates/ir2/build/display/ident.rs | 2 +- crates/ir2/build/op.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/ir2/build/display/ident.rs b/crates/ir2/build/display/ident.rs index 7652804fe2..8c50daa1fc 100644 --- a/crates/ir2/build/display/ident.rs +++ b/crates/ir2/build/display/ident.rs @@ -59,7 +59,7 @@ impl Display for DisplayIdent<&'_ UnaryOp> { .value .kind .is_conversion() - .then_some(Ident::from(kind.input_ty())) + .then_some(Ident::from(kind.value_ty())) .map(|i| (sep, case.wrap(i))) .map(DisplayConcat) .display_maybe(); diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index a55594284c..7b21f45d9a 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -273,10 +273,10 @@ pub enum UnaryOpKind { impl UnaryOpKind { pub fn is_conversion(&self) -> bool { - self.input_ty() != self.result_ty() + self.value_ty() != self.result_ty() } - pub fn input_ty(&self) -> Ty { + pub fn value_ty(&self) -> Ty { match self { | Self::I32Clz | Self::I32Ctz | Self::I32Popcnt => Ty::I32, | Self::I64Clz | Self::I64Ctz | Self::I64Popcnt | Self::I32WrapI64 => Ty::I64, From 254a3b9a6096fabce3c21acbe2a542f2d28e3440 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Sat, 30 Aug 2025 16:36:40 +0200 Subject: [PATCH 155/186] remove V128SplatOp and use UnaryOp instead + clean-ups --- crates/ir2/build/display/constructors.rs | 8 -- crates/ir2/build/display/decode.rs | 10 -- crates/ir2/build/display/encode.rs | 8 -- crates/ir2/build/display/ident.rs | 34 ++--- crates/ir2/build/display/op.rs | 8 -- crates/ir2/build/display/result_mut.rs | 7 - crates/ir2/build/isa.rs | 12 +- crates/ir2/build/op.rs | 156 ++++++++++++----------- crates/ir2/build/token.rs | 18 +-- 9 files changed, 95 insertions(+), 166 deletions(-) diff --git a/crates/ir2/build/display/constructors.rs b/crates/ir2/build/display/constructors.rs index 6168b90384..a9a2f32951 100644 --- a/crates/ir2/build/display/constructors.rs +++ b/crates/ir2/build/display/constructors.rs @@ -13,7 +13,6 @@ use crate::build::{ TableSetOp, UnaryOp, V128ReplaceLaneOp, - V128SplatOp, }, token::SnakeCase, }; @@ -149,13 +148,6 @@ impl Display for DisplayConstructor<&'_ GenericOp> { } } -impl Display for DisplayConstructor<&'_ V128SplatOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields().map(Option::from); - self.display_constructor(f, &fields) - } -} - impl Display for DisplayConstructor<&'_ V128ReplaceLaneOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let fields = self.value.fields().map(Option::from); diff --git a/crates/ir2/build/display/decode.rs b/crates/ir2/build/display/decode.rs index 7f6c86a69b..e9a2409654 100644 --- a/crates/ir2/build/display/decode.rs +++ b/crates/ir2/build/display/decode.rs @@ -17,7 +17,6 @@ use crate::build::{ TableSetOp, UnaryOp, V128ReplaceLaneOp, - V128SplatOp, }, token::{CamelCase, SnakeCase}, Isa, @@ -190,15 +189,6 @@ impl Display for DisplayDecode<&'_ GenericOp> { } } -impl Display for DisplayDecode<&'_ V128SplatOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let op = self.value; - let camel_ident = DisplayIdent::camel(op); - let value_ty = op.value_field().ty; - writeln!(f, "pub type {camel_ident} = UnaryOp<{value_ty}>;") - } -} - impl Display for DisplayDecode<&'_ V128ReplaceLaneOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let op = self.value; diff --git a/crates/ir2/build/display/encode.rs b/crates/ir2/build/display/encode.rs index a0092033fe..f7ed5261af 100644 --- a/crates/ir2/build/display/encode.rs +++ b/crates/ir2/build/display/encode.rs @@ -13,7 +13,6 @@ use crate::build::{ TableSetOp, UnaryOp, V128ReplaceLaneOp, - V128SplatOp, }, token::SnakeCase, }; @@ -151,13 +150,6 @@ impl Display for DisplayEncode<&'_ GenericOp> { } } -impl Display for DisplayEncode<&'_ V128SplatOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields().map(Option::from); - self.display_encode(f, &fields) - } -} - impl Display for DisplayEncode<&'_ V128ReplaceLaneOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let fields = self.value.fields().map(Option::from); diff --git a/crates/ir2/build/display/ident.rs b/crates/ir2/build/display/ident.rs index 8c50daa1fc..9a6e47253c 100644 --- a/crates/ir2/build/display/ident.rs +++ b/crates/ir2/build/display/ident.rs @@ -8,13 +8,11 @@ use crate::build::{ LoadOp, OperandKind, ReplaceLaneWidth, - SplatType, StoreOp, TableGetOp, TableSetOp, UnaryOp, V128ReplaceLaneOp, - V128SplatOp, }, token::{Case, Ident, Sep, SnakeCase}, }; @@ -51,20 +49,19 @@ impl DisplayIdent { impl Display for DisplayIdent<&'_ UnaryOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let case = self.case; - let kind = self.value.kind; + let op = self.value; + let kind = op.kind; let ident = case.wrap(kind.ident()); let sep = case.wrap(Sep); - let ident_prefix = DisplayConcat((case.wrap(Ident::from(kind.result_ty())), sep)); - let ident_suffix = self - .value - .kind + let ident_prefix = DisplayConcat((case.wrap(kind.result_ty()), sep)); + let ident_suffix = kind .is_conversion() - .then_some(Ident::from(kind.value_ty())) + .then_some(kind.value_ty()) .map(|i| (sep, case.wrap(i))) .map(DisplayConcat) .display_maybe(); let result_suffix = case.wrap(OperandKind::Stack); - let value_suffix = SnakeCase(OperandKind::Stack); + let value_suffix = SnakeCase(op.value); write!( f, "{ident_prefix}{ident}{ident_suffix}_{result_suffix}{value_suffix}" @@ -96,7 +93,7 @@ impl Display for DisplayIdent<&'_ CmpBranchOp> { let cmp = self.value.cmp; let branch = case.wrap(Ident::Branch); let ident = case.wrap(cmp.ident()); - let input_ident = case.wrap(Ident::from(cmp.ident_prefix())); + let input_ident = case.wrap(cmp.ident_prefix()); let lhs_suffix = case.wrap(self.value.lhs); let rhs_suffix = SnakeCase(self.value.rhs); write!( @@ -112,7 +109,7 @@ impl Display for DisplayIdent<&'_ CmpSelectOp> { let cmp = self.value.cmp; let select = case.wrap(Ident::Select); let ident = case.wrap(cmp.ident()); - let input_ident = case.wrap(Ident::from(cmp.ident_prefix())); + let input_ident = case.wrap(cmp.ident_prefix()); let result_suffix = case.wrap(OperandKind::Stack); let lhs_suffix = SnakeCase(self.value.lhs); let rhs_suffix = SnakeCase(self.value.rhs); @@ -222,21 +219,6 @@ impl Display for DisplayIdent<&'_ TableSetOp> { } } -impl Display for DisplayIdent<&'_ V128SplatOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let case = self.case; - let op = self.value; - let ident = case.wrap(Ident::V128Splat); - let width = match op.ty { - SplatType::U32 => "32", - SplatType::U64 => "64", - }; - let result_suffix = case.wrap(OperandKind::Stack); - let value_suffix = SnakeCase(op.value); - write!(f, "{ident}{width}_{result_suffix}{value_suffix}") - } -} - impl Display for DisplayIdent<&'_ V128ReplaceLaneOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let case = self.case; diff --git a/crates/ir2/build/display/op.rs b/crates/ir2/build/display/op.rs index dd9b08b002..082afce851 100644 --- a/crates/ir2/build/display/op.rs +++ b/crates/ir2/build/display/op.rs @@ -17,7 +17,6 @@ use crate::build::{ TableSetOp, UnaryOp, V128ReplaceLaneOp, - V128SplatOp, }, }; use core::fmt::{self, Display}; @@ -151,13 +150,6 @@ impl Display for DisplayOp<&'_ TableSetOp> { } } -impl Display for DisplayOp<&'_ V128SplatOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields().map(Option::from); - self.display_variant(f, &fields) - } -} - impl Display for DisplayOp<&'_ V128ReplaceLaneOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let fields = self.value.fields().map(Option::from); diff --git a/crates/ir2/build/display/result_mut.rs b/crates/ir2/build/display/result_mut.rs index 7a85f60d37..8663731d39 100644 --- a/crates/ir2/build/display/result_mut.rs +++ b/crates/ir2/build/display/result_mut.rs @@ -12,7 +12,6 @@ use crate::build::{ TableSetOp, UnaryOp, V128ReplaceLaneOp, - V128SplatOp, }, }; use core::fmt::{self, Display}; @@ -130,12 +129,6 @@ impl Display for DisplayResultMut<&'_ GenericOp> { } } -impl Display for DisplayResultMut<&'_ V128SplatOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.display_match_arm(f) - } -} - impl Display for DisplayResultMut<&'_ V128ReplaceLaneOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.display_match_arm(f) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 0dd82d2549..b786fec029 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -13,7 +13,6 @@ use crate::build::{ LoadOpKind, OperandKind, ReplaceLaneWidth, - SplatType, StoreOp, StoreOpKind, TableGetOp, @@ -21,7 +20,6 @@ use crate::build::{ UnaryOp, UnaryOpKind, V128ReplaceLaneOp, - V128SplatOp, }, token::Ident, Config, @@ -126,7 +124,7 @@ fn add_unary_ops(isa: &mut Isa) { UnaryOpKind::U64TruncSatF64, ]; for op in ops { - isa.push_op(UnaryOp::new(op)); + isa.push_op(UnaryOp::new(op, OperandKind::Stack)); } } @@ -769,10 +767,10 @@ fn add_simd_ops(isa: &mut Isa, config: &Config) { } fn add_simd_splat_ops(isa: &mut Isa) { - let kinds = [SplatType::U32, SplatType::U64]; + let kinds = [UnaryOpKind::V128Splat32, UnaryOpKind::V128Splat64]; for kind in kinds { - isa.push_op(V128SplatOp::new(kind, OperandKind::Immediate)); - isa.push_op(V128SplatOp::new(kind, OperandKind::Stack)); + isa.push_op(UnaryOp::new(kind, OperandKind::Stack)); + isa.push_op(UnaryOp::new(kind, OperandKind::Immediate)); } } @@ -1061,6 +1059,6 @@ fn add_simd_unary_ops(isa: &mut Isa) { UnaryOpKind::F64x2ConvertLowU32x4, ]; for kind in kinds { - isa.push_op(UnaryOp::new(kind)); + isa.push_op(UnaryOp::new(kind, OperandKind::Stack)); } } diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 7b21f45d9a..3e9e6b055e 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -19,7 +19,6 @@ macro_rules! apply_macro_for_ops { Generic3(GenericOp<3>), Generic4(GenericOp<4>), Generic5(GenericOp<5>), - V128Splat(V128SplatOp), V128ReplaceLane(V128ReplaceLaneOp), } }; @@ -117,11 +116,12 @@ impl GenericOp { #[derive(Copy, Clone)] pub struct UnaryOp { pub kind: UnaryOpKind, + pub value: OperandKind, } impl UnaryOp { - pub fn new(kind: UnaryOpKind) -> Self { - Self { kind } + pub fn new(kind: UnaryOpKind, value: OperandKind) -> Self { + Self { kind, value } } pub fn result_field(&self) -> Field { @@ -129,7 +129,17 @@ impl UnaryOp { } pub fn value_field(&self) -> Field { - Field::new(Ident::Value, FieldTy::Stack) + let ty = match self.value { + OperandKind::Stack => FieldTy::Stack, + OperandKind::Immediate => { + let value_ty = self.kind.value_ty(); + match value_ty.to_field_ty() { + Some(ty) => ty, + None => panic!("no `FieldTy` for `Ty`: {value_ty}"), + } + } + }; + Field::new(Ident::Value, ty) } pub fn fields(&self) -> [Field; 2] { @@ -203,6 +213,8 @@ pub enum UnaryOpKind { F64ConvertU64, // SIMD: Generic Unary Ops + V128Splat32, + V128Splat64, V128Not, V128AnyTrue, // SIMD: `i8x16` Unary Ops @@ -315,6 +327,8 @@ impl UnaryOpKind { | Self::F64ConvertU64 => Ty::U64, // SIMD: Generic Unary Ops + | Self::V128Splat32 => Ty::B32, + | Self::V128Splat64 => Ty::B64, | Self::V128Not | Self::V128AnyTrue => Ty::V128, // SIMD: `i8x16` Unary Ops | Self::I8x16Abs @@ -420,7 +434,7 @@ impl UnaryOpKind { | Self::F64ConvertU64 => Ty::F64, // SIMD: Generic Unary Ops - | Self::V128Not | Self::V128AnyTrue => Ty::V128, + | Self::V128Splat32 | Self::V128Splat64 | Self::V128Not | Self::V128AnyTrue => Ty::V128, // SIMD: `i8x16` Unary Ops | Self::I8x16Abs | Self::I8x16Neg @@ -536,6 +550,8 @@ impl UnaryOpKind { Self::F64ConvertU64 => Ident::Convert, // SIMD: Generic Unary Ops + Self::V128Splat32 => Ident::Splat, + Self::V128Splat64 => Ident::Splat, Self::V128Not => Ident::Not, Self::V128AnyTrue => Ident::AnyTrue, // SIMD: `i8x16` Unary Ops @@ -988,8 +1004,8 @@ impl BinaryOpKind { } } - pub fn ident_prefix(&self) -> Ident { - let ty = match self { + pub fn ident_prefix(&self) -> Ty { + match self { | BinaryOpKind::Cmp(op) => op.ident_prefix(), | Self::I32Add | Self::I32Sub @@ -1125,8 +1141,7 @@ impl BinaryOpKind { | Self::I64x2Shl => Ty::I64x2, | Self::S64x2Shr => Ty::S64x2, | Self::U64x2Shr => Ty::U64x2, - }; - Ident::from(ty) + } } fn lhs_field(&self, input: OperandKind) -> FieldTy { @@ -1349,6 +1364,10 @@ pub enum Ty { U32, /// A unsigned 64-bit integer type. U64, + /// A generic 32-bits value. + B32, + /// A generic 64-bits value. + B64, /// A 32-bit float type. F32, /// A 64-bit float type. @@ -1385,6 +1404,21 @@ pub enum Ty { F64x2, } +impl Ty { + pub fn to_field_ty(self) -> Option { + let ty = match self { + | Ty::S32 | Ty::I32 => FieldTy::I32, + | Ty::S64 | Ty::I64 => FieldTy::I64, + | Ty::B32 | Ty::U32 => FieldTy::U32, + | Ty::B64 | Ty::U64 => FieldTy::U64, + | Ty::F32 => FieldTy::F32, + | Ty::F64 => FieldTy::F64, + _ => return None, + }; + Some(ty) + } +} + impl Display for Ty { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let s = match self { @@ -1394,6 +1428,8 @@ impl Display for Ty { Ty::S64 => "i64", Ty::U32 => "u32", Ty::U64 => "u64", + Ty::B32 => "32", + Ty::B64 => "64", Ty::F32 => "f32", Ty::F64 => "f64", Ty::V128 => "v128", @@ -1416,33 +1452,42 @@ impl Display for Ty { } } -impl From for Ident { - fn from(ty: Ty) -> Self { - match ty { - Ty::I32 => Self::I32, - Ty::I64 => Self::I64, - Ty::S32 => Self::S32, - Ty::S64 => Self::S64, - Ty::U32 => Self::U32, - Ty::U64 => Self::U64, - Ty::F32 => Self::F32, - Ty::F64 => Self::F64, - Ty::V128 => Self::V128, - Ty::I8x16 => Self::I8x16, - Ty::I16x8 => Self::I16x8, - Ty::I32x4 => Self::I32x4, - Ty::I64x2 => Self::I64x2, - Ty::U8x16 => Self::U8x16, - Ty::U16x8 => Self::U16x8, - Ty::U32x4 => Self::U32x4, - Ty::U64x2 => Self::U64x2, - Ty::S8x16 => Self::S8x16, - Ty::S16x8 => Self::S16x8, - Ty::S32x4 => Self::S32x4, - Ty::S64x2 => Self::S64x2, - Ty::F32x4 => Self::F32x4, - Ty::F64x2 => Self::F64x2, - } +impl Display for SnakeCase { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +impl Display for CamelCase { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let s = match self.0 { + Ty::I32 => "I32", + Ty::I64 => "I64", + Ty::S32 => "I32", + Ty::S64 => "I64", + Ty::U32 => "U32", + Ty::U64 => "U64", + Ty::B32 => "32", + Ty::B64 => "64", + Ty::F32 => "F32", + Ty::F64 => "F64", + Ty::V128 => "V128", + Ty::I8x16 => "I8x16", + Ty::I16x8 => "I16x8", + Ty::I32x4 => "I32x4", + Ty::I64x2 => "I64x2", + Ty::U8x16 => "U8x16", + Ty::U16x8 => "U16x8", + Ty::U32x4 => "U32x4", + Ty::U64x2 => "U64x2", + Ty::S8x16 => "S8x16", + Ty::S16x8 => "S16x8", + Ty::S32x4 => "S32x4", + Ty::S64x2 => "S64x2", + Ty::F32x4 => "F32x4", + Ty::F64x2 => "F64x2", + }; + write!(f, "{s}") } } @@ -2010,45 +2055,6 @@ impl TableSetOp { } } -#[derive(Copy, Clone)] -pub struct V128SplatOp { - /// The type of the value to be splatted. - pub ty: SplatType, - /// The `value` to be splatted. - pub value: OperandKind, -} - -#[derive(Copy, Clone)] -pub enum SplatType { - U32, - U64, -} - -impl V128SplatOp { - pub fn new(ty: SplatType, value: OperandKind) -> Self { - Self { ty, value } - } - - pub fn result_field(&self) -> Field { - Field::new(Ident::Result, FieldTy::Stack) - } - - pub fn value_field(&self) -> Field { - let value_ty = match self.value { - OperandKind::Stack => FieldTy::Stack, - OperandKind::Immediate => match self.ty { - SplatType::U32 => FieldTy::U32, - SplatType::U64 => FieldTy::U64, - }, - }; - Field::new(Ident::Value, value_ty) - } - - pub fn fields(&self) -> [Field; 2] { - [self.result_field(), self.value_field()] - } -} - #[derive(Copy, Clone)] pub struct V128ReplaceLaneOp { /// The type of the value to be splatted. diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index 9f1ccd3b4e..7b44200159 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -169,8 +169,6 @@ define_ident!( I64: i64, S32: s32, S64: s64, - F32: f32, - F64: f64, Clz: clz, Ctz: ctz, @@ -255,25 +253,11 @@ define_ident!( Copy128: copy128, ValueLo: value_lo, ValueHi: value_hi, - V128Splat: v128_splat, Selector: selector, V128: v128, - I8x16: i8x16, - I16x8: i16x8, - I32x4: i32x4, - I64x2: i64x2, - U8x16: u8x16, - U16x8: u16x8, - U32x4: u32x4, - U64x2: u64x2, - S8x16: s8x16, - S16x8: s16x8, - S32x4: s32x4, - S64x2: s64x2, - F32x4: f32x4, - F64x2: f64x2, Lane: lane, + Splat: splat, S8x16ExtractLane: s8x16_extract_lane, U8x16ExtractLane: u8x16_extract_lane, S16x8ExtractLane: s16x8_extract_lane, From 5fec2973cd7f06c0a4f2e392b0583eb135888e7c Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Mon, 1 Sep 2025 15:57:04 +0200 Subject: [PATCH 156/186] add partial v128.load ops codegen --- crates/ir2/build/isa.rs | 27 +++++++++++++++ crates/ir2/build/mod.rs | 2 +- crates/ir2/build/op.rs | 71 ++++++++++++++++++++++++++++++--------- crates/ir2/build/token.rs | 14 +++++--- 4 files changed, 94 insertions(+), 20 deletions(-) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index b786fec029..192de53757 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -764,6 +764,8 @@ fn add_simd_ops(isa: &mut Isa, config: &Config) { add_simd_binary_ops(isa); add_simd_shift_ops(isa); add_simd_unary_ops(isa); + add_simd_load_ops(isa); + add_simd_store_ops(isa); } fn add_simd_splat_ops(isa: &mut Isa) { @@ -1062,3 +1064,28 @@ fn add_simd_unary_ops(isa: &mut Isa) { isa.push_op(UnaryOp::new(kind, OperandKind::Stack)); } } + +fn add_simd_load_ops(isa: &mut Isa) { + let ops = [ + LoadOpKind::V128Load, + LoadOpKind::S16x8Load8x8, + LoadOpKind::U16x8Load8x8, + LoadOpKind::S32x4Load16x4, + LoadOpKind::U32x4Load16x4, + LoadOpKind::S64x2Load32x2, + LoadOpKind::U64x2Load32x2, + LoadOpKind::V128Load8Splat, + LoadOpKind::V128Load16Splat, + LoadOpKind::V128Load32Splat, + LoadOpKind::V128Load64Splat, + LoadOpKind::V128Load32Zero, + LoadOpKind::V128Load64Zero, + ]; + for op in ops { + isa.push_op(LoadOp::new(op, OperandKind::Stack, false, false)); + isa.push_op(LoadOp::new(op, OperandKind::Stack, true, true)); + } +} + +fn add_simd_store_ops(_isa: &mut Isa) { +} diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index 5f4ed06784..8eaa3d9a07 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -74,7 +74,7 @@ pub fn generate_code(config: &Config) -> Result<(), Error> { fn generate_op_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<(), Error> { let expected_size = match config.simd { - true => 255_000, + true => 265_000, false => 175_000, }; write_to_buffer(contents, expected_size, |buffer| { diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 3e9e6b055e..81d709e8c9 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -1808,6 +1808,7 @@ impl LoadOp { #[derive(Copy, Clone)] pub enum LoadOpKind { + // Scalar Load32, Load64, S32Load8, @@ -1820,6 +1821,20 @@ pub enum LoadOpKind { U64Load16, S64Load32, U64Load32, + // Simd + V128Load, + S16x8Load8x8, + U16x8Load8x8, + S32x4Load16x4, + U32x4Load16x4, + S64x2Load32x2, + U64x2Load32x2, + V128Load8Splat, + V128Load16Splat, + V128Load32Splat, + V128Load64Splat, + V128Load32Zero, + V128Load64Zero, } impl LoadOpKind { @@ -1837,24 +1852,50 @@ impl LoadOpKind { Self::U64Load16 => Ident::Load16, Self::S64Load32 => Ident::Load32, Self::U64Load32 => Ident::Load32, + Self::V128Load => Ident::Load, + Self::S16x8Load8x8 => Ident::Load8x8, + Self::U16x8Load8x8 => Ident::Load8x8, + Self::S32x4Load16x4 => Ident::Load16x4, + Self::U32x4Load16x4 => Ident::Load16x4, + Self::S64x2Load32x2 => Ident::Load32x2, + Self::U64x2Load32x2 => Ident::Load32x2, + Self::V128Load8Splat => Ident::Load8Splat, + Self::V128Load16Splat => Ident::Load16Splat, + Self::V128Load32Splat => Ident::Load32Splat, + Self::V128Load64Splat => Ident::Load64Splat, + Self::V128Load32Zero => Ident::Load32Zero, + Self::V128Load64Zero => Ident::Load64Zero, } } - pub fn ident_prefix(&self) -> Option { - match self { - Self::Load32 => None, - Self::Load64 => None, - Self::S32Load8 => Some(Ident::S32), - Self::U32Load8 => Some(Ident::U32), - Self::S32Load16 => Some(Ident::S32), - Self::U32Load16 => Some(Ident::U32), - Self::S64Load8 => Some(Ident::S64), - Self::U64Load8 => Some(Ident::U64), - Self::S64Load16 => Some(Ident::S64), - Self::U64Load16 => Some(Ident::U64), - Self::S64Load32 => Some(Ident::S64), - Self::U64Load32 => Some(Ident::U64), - } + pub fn ident_prefix(&self) -> Option { + let prefix = match self { + | Self::Load32 | Self::Load64 => return None, + | Self::S32Load8 => Ty::S32, + | Self::U32Load8 => Ty::U32, + | Self::S32Load16 => Ty::S32, + | Self::U32Load16 => Ty::U32, + | Self::S64Load8 => Ty::S64, + | Self::U64Load8 => Ty::U64, + | Self::S64Load16 => Ty::S64, + | Self::U64Load16 => Ty::U64, + | Self::S64Load32 => Ty::S64, + | Self::U64Load32 => Ty::U64, + | Self::V128Load => Ty::V128, + | Self::S16x8Load8x8 => Ty::S16x8, + | Self::U16x8Load8x8 => Ty::U16x8, + | Self::S32x4Load16x4 => Ty::S32x4, + | Self::U32x4Load16x4 => Ty::U32x4, + | Self::S64x2Load32x2 => Ty::S64x2, + | Self::U64x2Load32x2 => Ty::U64x2, + | Self::V128Load8Splat => Ty::V128, + | Self::V128Load16Splat => Ty::V128, + | Self::V128Load32Splat => Ty::V128, + | Self::V128Load64Splat => Ty::V128, + | Self::V128Load32Zero => Ty::V128, + | Self::V128Load64Zero => Ty::V128, + }; + Some(prefix) } } diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index 7b44200159..1d7751d007 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -141,6 +141,16 @@ define_ident!( Load16: load16, Load32: load32, Load64: load64, + Load: load, + Load8x8: load8x8, + Load16x4: load16x4, + Load32x2: load32x2, + Load8Splat: load8_splat, + Load16Splat: load16_splat, + Load32Splat: load32_splat, + Load64Splat: load64_splat, + Load32Zero: load32_zero, + Load64Zero: load64_zero, Copy: copy, Copy32: copy32, @@ -163,12 +173,8 @@ define_ident!( ReturnCallImported: return_call_imported, ReturnCallIndirect: return_call_indirect, - U32: u32, - U64: u64, I32: i32, I64: i64, - S32: s32, - S64: s64, Clz: clz, Ctz: ctz, From 9f5a86fb20c3d6fabac888185019c985d4baabd1 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Mon, 1 Sep 2025 22:11:42 +0200 Subject: [PATCH 157/186] refactor ReplaceLaneWidth -> LaneWidth --- crates/ir2/build/display/decode.rs | 10 +--- crates/ir2/build/display/ident.rs | 8 +--- crates/ir2/build/isa.rs | 10 ++-- crates/ir2/build/op.rs | 75 +++++++++++++++++++++++------- 4 files changed, 65 insertions(+), 38 deletions(-) diff --git a/crates/ir2/build/display/decode.rs b/crates/ir2/build/display/decode.rs index e9a2409654..c3b91101a0 100644 --- a/crates/ir2/build/display/decode.rs +++ b/crates/ir2/build/display/decode.rs @@ -11,7 +11,6 @@ use crate::build::{ GenericOp, LoadOp, OperandKind, - ReplaceLaneWidth, StoreOp, TableGetOp, TableSetOp, @@ -194,15 +193,10 @@ impl Display for DisplayDecode<&'_ V128ReplaceLaneOp> { let op = self.value; let camel_ident = DisplayIdent::camel(op); let value_ty = op.value_field().ty; - let lane_items = match op.width { - ReplaceLaneWidth::W8 => "16", - ReplaceLaneWidth::W16 => "8", - ReplaceLaneWidth::W32 => "4", - ReplaceLaneWidth::W64 => "2", - }; + let len_lanes = op.width.len_lanes(); writeln!( f, - "pub type {camel_ident} = V128ReplaceLaneOp<{value_ty}, {lane_items}>;" + "pub type {camel_ident} = V128ReplaceLaneOp<{value_ty}, {len_lanes}>;" ) } } diff --git a/crates/ir2/build/display/ident.rs b/crates/ir2/build/display/ident.rs index 9a6e47253c..628bd24ea8 100644 --- a/crates/ir2/build/display/ident.rs +++ b/crates/ir2/build/display/ident.rs @@ -7,7 +7,6 @@ use crate::build::{ GenericOp, LoadOp, OperandKind, - ReplaceLaneWidth, StoreOp, TableGetOp, TableSetOp, @@ -226,12 +225,7 @@ impl Display for DisplayIdent<&'_ V128ReplaceLaneOp> { let sep = case.wrap(Sep); let v128 = case.wrap(Ident::V128); let ident = case.wrap(Ident::ReplaceLane); - let width = match op.width { - ReplaceLaneWidth::W8 => "8x16", - ReplaceLaneWidth::W16 => "16x8", - ReplaceLaneWidth::W32 => "32x4", - ReplaceLaneWidth::W64 => "64x2", - }; + let width = op.width; let result_suffix = case.wrap(OperandKind::Stack); let v128_suffix = SnakeCase(OperandKind::Stack); let value_suffix = SnakeCase(op.value); diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 192de53757..47550ff133 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -9,10 +9,10 @@ use crate::build::{ Field, FieldTy, GenericOp, + LaneWidth, LoadOp, LoadOpKind, OperandKind, - ReplaceLaneWidth, StoreOp, StoreOpKind, TableGetOp, @@ -832,10 +832,10 @@ fn add_simd_extract_lane_ops(isa: &mut Isa) { fn add_simd_replace_lane_ops(isa: &mut Isa) { let widths = [ - ReplaceLaneWidth::W8, - ReplaceLaneWidth::W16, - ReplaceLaneWidth::W32, - ReplaceLaneWidth::W64, + LaneWidth::W8, + LaneWidth::W16, + LaneWidth::W32, + LaneWidth::W64, ]; for width in widths { isa.push_op(V128ReplaceLaneOp::new(width, OperandKind::Stack)); diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 81d709e8c9..64e758fe90 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -2097,23 +2097,62 @@ impl TableSetOp { } #[derive(Copy, Clone)] -pub struct V128ReplaceLaneOp { - /// The type of the value to be splatted. - pub width: ReplaceLaneWidth, - /// The `value` used for replacing. - pub value: OperandKind, -} - -#[derive(Copy, Clone)] -pub enum ReplaceLaneWidth { +pub enum LaneWidth { W8, W16, W32, W64, } +impl Display for LaneWidth { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let width = u8::from(*self); + let len_lanes = self.len_lanes(); + write!(f, "{width}x{len_lanes}") + } +} + +impl From for u8 { + fn from(width: LaneWidth) -> Self { + match width { + LaneWidth::W8 => 8, + LaneWidth::W16 => 16, + LaneWidth::W32 => 32, + LaneWidth::W64 => 64, + } + } +} + +impl LaneWidth { + pub fn len_lanes(self) -> u8 { + match self { + Self::W8 => 16, + Self::W16 => 8, + Self::W32 => 4, + Self::W64 => 2, + } + } + + pub fn to_laneidx(self) -> FieldTy { + match self { + Self::W8 => FieldTy::ImmLaneIdx16, + Self::W16 => FieldTy::ImmLaneIdx8, + Self::W32 => FieldTy::ImmLaneIdx4, + Self::W64 => FieldTy::ImmLaneIdx2, + } + } +} + +#[derive(Copy, Clone)] +pub struct V128ReplaceLaneOp { + /// The type of the value to be splatted. + pub width: LaneWidth, + /// The `value` used for replacing. + pub value: OperandKind, +} + impl V128ReplaceLaneOp { - pub fn new(width: ReplaceLaneWidth, value: OperandKind) -> Self { + pub fn new(width: LaneWidth, value: OperandKind) -> Self { Self { width, value } } @@ -2129,10 +2168,10 @@ impl V128ReplaceLaneOp { let value_ty = match self.value { OperandKind::Stack => FieldTy::Stack, OperandKind::Immediate => match self.width { - ReplaceLaneWidth::W8 => FieldTy::U8, - ReplaceLaneWidth::W16 => FieldTy::U16, - ReplaceLaneWidth::W32 => FieldTy::U32, - ReplaceLaneWidth::W64 => FieldTy::U64, + LaneWidth::W8 => FieldTy::U8, + LaneWidth::W16 => FieldTy::U16, + LaneWidth::W32 => FieldTy::U32, + LaneWidth::W64 => FieldTy::U64, }, }; Field::new(Ident::Value, value_ty) @@ -2140,10 +2179,10 @@ impl V128ReplaceLaneOp { pub fn lane_field(&self) -> Field { let lane_ty = match self.width { - ReplaceLaneWidth::W8 => FieldTy::ImmLaneIdx16, - ReplaceLaneWidth::W16 => FieldTy::ImmLaneIdx8, - ReplaceLaneWidth::W32 => FieldTy::ImmLaneIdx4, - ReplaceLaneWidth::W64 => FieldTy::ImmLaneIdx2, + LaneWidth::W8 => FieldTy::ImmLaneIdx16, + LaneWidth::W16 => FieldTy::ImmLaneIdx8, + LaneWidth::W32 => FieldTy::ImmLaneIdx4, + LaneWidth::W64 => FieldTy::ImmLaneIdx2, }; Field::new(Ident::Lane, lane_ty) } From 463c9be68c4d5aa7f7d7662c6f73f46bc851e035 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Mon, 1 Sep 2025 22:14:57 +0200 Subject: [PATCH 158/186] add V128LoadLane simd ops codegen --- crates/ir2/build/display/constructors.rs | 8 +++ crates/ir2/build/display/decode.rs | 18 ++++++ crates/ir2/build/display/encode.rs | 8 +++ crates/ir2/build/display/ident.rs | 33 ++++++++++ crates/ir2/build/display/op.rs | 8 +++ crates/ir2/build/display/result_mut.rs | 7 +++ crates/ir2/build/isa.rs | 16 +++++ crates/ir2/build/mod.rs | 4 +- crates/ir2/build/op.rs | 79 ++++++++++++++++++++++++ crates/ir2/build/token.rs | 1 + crates/ir2/src/decode/mod.rs | 4 +- crates/ir2/src/decode/op.rs | 48 ++++++++++++++ 12 files changed, 230 insertions(+), 4 deletions(-) diff --git a/crates/ir2/build/display/constructors.rs b/crates/ir2/build/display/constructors.rs index a9a2f32951..cefe205aa9 100644 --- a/crates/ir2/build/display/constructors.rs +++ b/crates/ir2/build/display/constructors.rs @@ -12,6 +12,7 @@ use crate::build::{ TableGetOp, TableSetOp, UnaryOp, + V128LoadLaneOp, V128ReplaceLaneOp, }, token::SnakeCase, @@ -154,3 +155,10 @@ impl Display for DisplayConstructor<&'_ V128ReplaceLaneOp> { self.display_constructor(f, &fields) } } + +impl Display for DisplayConstructor<&'_ V128LoadLaneOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fields = self.value.fields().map(Option::from); + self.display_constructor(f, &fields) + } +} diff --git a/crates/ir2/build/display/decode.rs b/crates/ir2/build/display/decode.rs index c3b91101a0..458b4001e6 100644 --- a/crates/ir2/build/display/decode.rs +++ b/crates/ir2/build/display/decode.rs @@ -15,6 +15,7 @@ use crate::build::{ TableGetOp, TableSetOp, UnaryOp, + V128LoadLaneOp, V128ReplaceLaneOp, }, token::{CamelCase, SnakeCase}, @@ -200,3 +201,20 @@ impl Display for DisplayDecode<&'_ V128ReplaceLaneOp> { ) } } + +impl Display for DisplayDecode<&'_ V128LoadLaneOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let op = self.value; + let camel_ident = DisplayIdent::camel(op); + let result_suffix = CamelCase(OperandKind::Stack); + let mem0_offset16 = (op.mem0 && op.offset16) + .then_some("Mem0Offset16") + .display_maybe(); + let ptr_suffix = SnakeCase(op.ptr); + let laneidx = op.width.to_laneidx(); + writeln!( + f, + "pub type {camel_ident} = V128LoadLaneOp{mem0_offset16}_{result_suffix}{ptr_suffix}<{laneidx}>;" + ) + } +} diff --git a/crates/ir2/build/display/encode.rs b/crates/ir2/build/display/encode.rs index f7ed5261af..1116c07b54 100644 --- a/crates/ir2/build/display/encode.rs +++ b/crates/ir2/build/display/encode.rs @@ -12,6 +12,7 @@ use crate::build::{ TableGetOp, TableSetOp, UnaryOp, + V128LoadLaneOp, V128ReplaceLaneOp, }, token::SnakeCase, @@ -156,3 +157,10 @@ impl Display for DisplayEncode<&'_ V128ReplaceLaneOp> { self.display_encode(f, &fields) } } + +impl Display for DisplayEncode<&'_ V128LoadLaneOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fields = self.value.fields().map(Option::from); + self.display_encode(f, &fields) + } +} diff --git a/crates/ir2/build/display/ident.rs b/crates/ir2/build/display/ident.rs index 628bd24ea8..692d97937a 100644 --- a/crates/ir2/build/display/ident.rs +++ b/crates/ir2/build/display/ident.rs @@ -11,6 +11,7 @@ use crate::build::{ TableGetOp, TableSetOp, UnaryOp, + V128LoadLaneOp, V128ReplaceLaneOp, }, token::{Case, Ident, Sep, SnakeCase}, @@ -235,3 +236,35 @@ impl Display for DisplayIdent<&'_ V128ReplaceLaneOp> { ) } } + +impl Display for DisplayIdent<&'_ V128LoadLaneOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let case = self.case; + let op = self.value; + let sep = case.wrap(Sep); + let v128 = case.wrap(Ident::V128); + let ident = case.wrap(Ident::LoadLane); + let width = u8::from(op.width); + let result_suffix = case.wrap(OperandKind::Stack); + let ptr_suffix = SnakeCase(op.ptr); + let v128_suffix = SnakeCase(OperandKind::Stack); + let mem0_ident = self + .value + .mem0 + .then_some(Ident::Mem0) + .map(|v| (sep, case.wrap(v))) + .map(DisplayConcat) + .display_maybe(); + let offset16_ident = self + .value + .offset16 + .then_some(Ident::Offset16) + .map(|v| (sep, case.wrap(v))) + .map(DisplayConcat) + .display_maybe(); + write!( + f, + "{v128}{sep}{ident}{width}{mem0_ident}{offset16_ident}_{result_suffix}{ptr_suffix}{v128_suffix}" + ) + } +} diff --git a/crates/ir2/build/display/op.rs b/crates/ir2/build/display/op.rs index 082afce851..bd3e046e3a 100644 --- a/crates/ir2/build/display/op.rs +++ b/crates/ir2/build/display/op.rs @@ -16,6 +16,7 @@ use crate::build::{ TableGetOp, TableSetOp, UnaryOp, + V128LoadLaneOp, V128ReplaceLaneOp, }, }; @@ -156,3 +157,10 @@ impl Display for DisplayOp<&'_ V128ReplaceLaneOp> { self.display_variant(f, &fields) } } + +impl Display for DisplayOp<&'_ V128LoadLaneOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fields = self.value.fields().map(Option::from); + self.display_variant(f, &fields) + } +} diff --git a/crates/ir2/build/display/result_mut.rs b/crates/ir2/build/display/result_mut.rs index 8663731d39..212c78f582 100644 --- a/crates/ir2/build/display/result_mut.rs +++ b/crates/ir2/build/display/result_mut.rs @@ -11,6 +11,7 @@ use crate::build::{ TableGetOp, TableSetOp, UnaryOp, + V128LoadLaneOp, V128ReplaceLaneOp, }, }; @@ -134,3 +135,9 @@ impl Display for DisplayResultMut<&'_ V128ReplaceLaneOp> { self.display_match_arm(f) } } + +impl Display for DisplayResultMut<&'_ V128LoadLaneOp> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.display_match_arm(f) + } +} diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 47550ff133..070b1422a9 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -19,6 +19,7 @@ use crate::build::{ TableSetOp, UnaryOp, UnaryOpKind, + V128LoadLaneOp, V128ReplaceLaneOp, }, token::Ident, @@ -1085,7 +1086,22 @@ fn add_simd_load_ops(isa: &mut Isa) { isa.push_op(LoadOp::new(op, OperandKind::Stack, false, false)); isa.push_op(LoadOp::new(op, OperandKind::Stack, true, true)); } + let widths = [ + LaneWidth::W8, + LaneWidth::W16, + LaneWidth::W32, + LaneWidth::W64, + ]; + for width in widths { + isa.push_op(V128LoadLaneOp::new(width, OperandKind::Stack, false, false)); + isa.push_op(V128LoadLaneOp::new(width, OperandKind::Stack, true, true)); + } } fn add_simd_store_ops(_isa: &mut Isa) { + // v128.store memarg: (i32 v128) -> () + // v128.store8_lane memarg laneidx: (i32 v128) -> () + // v128.store16_lane memarg laneidx: (i32 v128) -> () + // v128.store32_lane memarg laneidx: (i32 v128) -> () + // v128.store64_lane memarg laneidx: (i32 v128) -> () } diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index 8eaa3d9a07..eff2c7a97a 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -74,7 +74,7 @@ pub fn generate_code(config: &Config) -> Result<(), Error> { fn generate_op_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<(), Error> { let expected_size = match config.simd { - true => 265_000, + true => 270_000, false => 175_000, }; write_to_buffer(contents, expected_size, |buffer| { @@ -98,7 +98,7 @@ fn generate_op_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<( fn generate_encode_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<(), Error> { let expected_size = match config.simd { - true => 110_000, + true => 115_000, false => 75_000, }; write_to_buffer(contents, expected_size, |buffer| { diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 64e758fe90..18be18ff27 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -20,6 +20,7 @@ macro_rules! apply_macro_for_ops { Generic4(GenericOp<4>), Generic5(GenericOp<5>), V128ReplaceLane(V128ReplaceLaneOp), + V128LoadLane(V128LoadLaneOp), } }; } @@ -2196,3 +2197,81 @@ impl V128ReplaceLaneOp { ] } } + +#[derive(Copy, Clone)] +pub struct V128LoadLaneOp { + /// The type of the value to be splatted. + pub width: LaneWidth, + /// The `value` used for replacing. + pub ptr: OperandKind, + /// True, if the operator is always operating on (`memory 0`). + pub mem0: bool, + /// True, if the operator uses a 16-bit offset field. + pub offset16: bool, +} + +impl V128LoadLaneOp { + pub fn new(width: LaneWidth, ptr: OperandKind, mem0: bool, offset16: bool) -> Self { + Self { + width, + ptr, + mem0, + offset16, + } + } + + pub fn result_field(&self) -> Field { + Field::new(Ident::Result, FieldTy::Stack) + } + + pub fn ptr_field(&self) -> Field { + let ptr_ty = match self.ptr { + OperandKind::Stack => FieldTy::Stack, + OperandKind::Immediate => FieldTy::Address, + }; + Field::new(Ident::Ptr, ptr_ty) + } + + pub fn offset_field(&self) -> Option { + let offset_ty = match self.ptr { + OperandKind::Stack => match self.offset16 { + true => FieldTy::Offset16, + false => FieldTy::U64, + }, + OperandKind::Immediate => return None, + }; + Some(Field::new(Ident::Offset, offset_ty)) + } + + pub fn v128_field(&self) -> Field { + Field::new(Ident::V128, FieldTy::Stack) + } + + pub fn memory_field(&self) -> Option { + if self.mem0 { + return None; + } + Some(Field::new(Ident::Memory, FieldTy::Memory)) + } + + pub fn laneidx_field(&self) -> Field { + let ty = match self.width { + LaneWidth::W8 => FieldTy::ImmLaneIdx16, + LaneWidth::W16 => FieldTy::ImmLaneIdx8, + LaneWidth::W32 => FieldTy::ImmLaneIdx4, + LaneWidth::W64 => FieldTy::ImmLaneIdx2, + }; + Field::new(Ident::Lane, ty) + } + + pub fn fields(&self) -> [Option; 6] { + [ + Some(self.result_field()), + Some(self.ptr_field()), + self.offset_field(), + self.memory_field(), + Some(self.v128_field()), + Some(self.laneidx_field()), + ] + } +} diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index 1d7751d007..e98eb6e5b3 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -271,6 +271,7 @@ define_ident!( U32x4ExtractLane: u32x4_extract_lane, U64x2ExtractLane: u64x2_extract_lane, ReplaceLane: replace_lane, + LoadLane: load_lane, Swizzle: swizzle, I8x16Shuffle: i8x16_shuffle, Q15MulrSat: q15_mulr_sat, diff --git a/crates/ir2/src/decode/mod.rs b/crates/ir2/src/decode/mod.rs index 2dbeccb1e4..a4bb88970b 100644 --- a/crates/ir2/src/decode/mod.rs +++ b/crates/ir2/src/decode/mod.rs @@ -2,8 +2,6 @@ mod op; -#[cfg(feature = "simd")] -use self::op::V128ReplaceLaneOp; use self::op::{ BinaryOp, CmpBranchOp, @@ -19,6 +17,8 @@ use self::op::{ UnaryOp, }; #[cfg(feature = "simd")] +use self::op::{V128LoadLaneOpMem0Offset16_Ss, V128LoadLaneOp_Ss, V128ReplaceLaneOp}; +#[cfg(feature = "simd")] use crate::core::simd::ImmLaneIdx; use crate::{ core::TrapCode, diff --git a/crates/ir2/src/decode/op.rs b/crates/ir2/src/decode/op.rs index 13350bd10d..60c6927fc7 100644 --- a/crates/ir2/src/decode/op.rs +++ b/crates/ir2/src/decode/op.rs @@ -252,3 +252,51 @@ impl Decode for V128ReplaceLaneOp { } } } + +#[derive(Copy, Clone)] +#[cfg(feature = "simd")] +pub struct V128LoadLaneOp_Ss { + pub result: Stack, + pub ptr: Stack, + pub offset: u64, + pub memory: Memory, + pub v128: Stack, + pub lane: LaneIdx, +} + +#[cfg(feature = "simd")] +impl Decode for V128LoadLaneOp_Ss { + unsafe fn decode(decoder: &mut D) -> Self { + Self { + result: Decode::decode(decoder), + ptr: Decode::decode(decoder), + offset: Decode::decode(decoder), + memory: Decode::decode(decoder), + v128: Decode::decode(decoder), + lane: Decode::decode(decoder), + } + } +} + +#[derive(Copy, Clone)] +#[cfg(feature = "simd")] +pub struct V128LoadLaneOpMem0Offset16_Ss { + pub result: Stack, + pub ptr: Stack, + pub offset: Offset16, + pub v128: Stack, + pub lane: LaneIdx, +} + +#[cfg(feature = "simd")] +impl Decode for V128LoadLaneOpMem0Offset16_Ss { + unsafe fn decode(decoder: &mut D) -> Self { + Self { + result: Decode::decode(decoder), + ptr: Decode::decode(decoder), + offset: Decode::decode(decoder), + v128: Decode::decode(decoder), + lane: Decode::decode(decoder), + } + } +} From 1c703e94602f672a2c4bb2cb5f00086f28e1fa17 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Tue, 2 Sep 2025 10:05:00 +0200 Subject: [PATCH 159/186] dedup constructor codegen with macro --- crates/ir2/build/display/constructors.rs | 89 ++++++------------------ 1 file changed, 22 insertions(+), 67 deletions(-) diff --git a/crates/ir2/build/display/constructors.rs b/crates/ir2/build/display/constructors.rs index cefe205aa9..8beabd0678 100644 --- a/crates/ir2/build/display/constructors.rs +++ b/crates/ir2/build/display/constructors.rs @@ -86,60 +86,29 @@ impl Display for DisplayConstructor<&'_ Isa> { } } -impl Display for DisplayConstructor<&'_ UnaryOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields().map(Option::from); - self.display_constructor(f, &fields) - } -} - -impl Display for DisplayConstructor<&'_ BinaryOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields().map(Option::from); - self.display_constructor(f, &fields) - } -} - -impl Display for DisplayConstructor<&'_ CmpBranchOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields().map(Option::from); - self.display_constructor(f, &fields) - } -} - -impl Display for DisplayConstructor<&'_ CmpSelectOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields().map(Option::from); - self.display_constructor(f, &fields) - } +macro_rules! impl_display_constructor { + ( $($ty:ty),* $(,)? ) => { + $( + impl Display for DisplayConstructor<&'_ $ty> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fields = self.value.fields().map(Option::from); + self.display_constructor(f, &fields) + } + } + )* + }; } - -impl Display for DisplayConstructor<&'_ LoadOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields(); - self.display_constructor(f, &fields) - } -} - -impl Display for DisplayConstructor<&'_ StoreOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields(); - self.display_constructor(f, &fields) - } -} - -impl Display for DisplayConstructor<&'_ TableGetOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields().map(Option::from); - self.display_constructor(f, &fields) - } -} - -impl Display for DisplayConstructor<&'_ TableSetOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields().map(Option::from); - self.display_constructor(f, &fields) - } +impl_display_constructor! { + UnaryOp, + BinaryOp, + CmpBranchOp, + CmpSelectOp, + LoadOp, + StoreOp, + TableGetOp, + TableSetOp, + V128ReplaceLaneOp, + V128LoadLaneOp, } impl Display for DisplayConstructor<&'_ GenericOp> { @@ -148,17 +117,3 @@ impl Display for DisplayConstructor<&'_ GenericOp> { self.display_constructor(f, &fields) } } - -impl Display for DisplayConstructor<&'_ V128ReplaceLaneOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields().map(Option::from); - self.display_constructor(f, &fields) - } -} - -impl Display for DisplayConstructor<&'_ V128LoadLaneOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields().map(Option::from); - self.display_constructor(f, &fields) - } -} From e76033fb1138d07a728b69fb2a2dcf5666811764 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Tue, 2 Sep 2025 10:06:51 +0200 Subject: [PATCH 160/186] dedup encode codegen with macro --- crates/ir2/build/display/encode.rs | 89 ++++++++---------------------- 1 file changed, 22 insertions(+), 67 deletions(-) diff --git a/crates/ir2/build/display/encode.rs b/crates/ir2/build/display/encode.rs index 1116c07b54..d466340665 100644 --- a/crates/ir2/build/display/encode.rs +++ b/crates/ir2/build/display/encode.rs @@ -88,60 +88,29 @@ impl Display for DisplayEncode<&'_ Isa> { } } -impl Display for DisplayEncode<&'_ UnaryOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields().map(Option::from); - self.display_encode(f, &fields) - } -} - -impl Display for DisplayEncode<&'_ BinaryOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields().map(Option::from); - self.display_encode(f, &fields) - } -} - -impl Display for DisplayEncode<&'_ CmpBranchOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields().map(Option::from); - self.display_encode(f, &fields) - } -} - -impl Display for DisplayEncode<&'_ CmpSelectOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields().map(Option::from); - self.display_encode(f, &fields) - } +macro_rules! impl_display_encode { + ( $($ty:ty),* $(,)? ) => { + $( + impl Display for DisplayEncode<&'_ $ty> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fields = self.value.fields().map(Option::from); + self.display_encode(f, &fields) + } + } + )* + }; } - -impl Display for DisplayEncode<&'_ LoadOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields(); - self.display_encode(f, &fields) - } -} - -impl Display for DisplayEncode<&'_ StoreOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields(); - self.display_encode(f, &fields) - } -} - -impl Display for DisplayEncode<&'_ TableGetOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields().map(Option::from); - self.display_encode(f, &fields) - } -} - -impl Display for DisplayEncode<&'_ TableSetOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields().map(Option::from); - self.display_encode(f, &fields) - } +impl_display_encode! { + UnaryOp, + BinaryOp, + CmpBranchOp, + CmpSelectOp, + LoadOp, + StoreOp, + TableGetOp, + TableSetOp, + V128ReplaceLaneOp, + V128LoadLaneOp, } impl Display for DisplayEncode<&'_ GenericOp> { @@ -150,17 +119,3 @@ impl Display for DisplayEncode<&'_ GenericOp> { self.display_encode(f, &fields) } } - -impl Display for DisplayEncode<&'_ V128ReplaceLaneOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields().map(Option::from); - self.display_encode(f, &fields) - } -} - -impl Display for DisplayEncode<&'_ V128LoadLaneOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields().map(Option::from); - self.display_encode(f, &fields) - } -} From cedcef9ccb6ca58dce0d08f0d73fdc5285ac2d34 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Tue, 2 Sep 2025 10:09:15 +0200 Subject: [PATCH 161/186] dedup variant codegen with macro --- crates/ir2/build/display/op.rs | 89 +++++++++------------------------- 1 file changed, 22 insertions(+), 67 deletions(-) diff --git a/crates/ir2/build/display/op.rs b/crates/ir2/build/display/op.rs index bd3e046e3a..232a11008d 100644 --- a/crates/ir2/build/display/op.rs +++ b/crates/ir2/build/display/op.rs @@ -88,46 +88,29 @@ impl Display for DisplayOp<&'_ Isa> { } } -impl Display for DisplayOp<&'_ UnaryOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields().map(Option::from); - self.display_variant(f, &fields) - } -} - -impl Display for DisplayOp<&'_ BinaryOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields().map(Option::from); - self.display_variant(f, &fields) - } -} - -impl Display for DisplayOp<&'_ CmpBranchOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields().map(Option::from); - self.display_variant(f, &fields) - } -} - -impl Display for DisplayOp<&'_ CmpSelectOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields().map(Option::from); - self.display_variant(f, &fields) - } +macro_rules! impl_display_variant { + ( $($ty:ty),* $(,)? ) => { + $( + impl Display for DisplayOp<&'_ $ty> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fields = self.value.fields().map(Option::from); + self.display_variant(f, &fields) + } + } + )* + }; } - -impl Display for DisplayOp<&'_ LoadOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields(); - self.display_variant(f, &fields) - } -} - -impl Display for DisplayOp<&'_ StoreOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields().map(Option::from); - self.display_variant(f, &fields) - } +impl_display_variant! { + UnaryOp, + BinaryOp, + CmpBranchOp, + CmpSelectOp, + LoadOp, + StoreOp, + TableGetOp, + TableSetOp, + V128ReplaceLaneOp, + V128LoadLaneOp, } impl Display for DisplayOp<&'_ GenericOp> { @@ -136,31 +119,3 @@ impl Display for DisplayOp<&'_ GenericOp> { self.display_variant(f, &fields) } } - -impl Display for DisplayOp<&'_ TableGetOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields().map(Option::from); - self.display_variant(f, &fields) - } -} - -impl Display for DisplayOp<&'_ TableSetOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields().map(Option::from); - self.display_variant(f, &fields) - } -} - -impl Display for DisplayOp<&'_ V128ReplaceLaneOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields().map(Option::from); - self.display_variant(f, &fields) - } -} - -impl Display for DisplayOp<&'_ V128LoadLaneOp> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let fields = self.value.fields().map(Option::from); - self.display_variant(f, &fields) - } -} From 07137745ff68d44ac96d3c70784a6fd13cf0f35d Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Tue, 2 Sep 2025 10:49:41 +0200 Subject: [PATCH 162/186] add StoreNLane simd ops codegen --- crates/ir2/build/display/decode.rs | 13 +++++++-- crates/ir2/build/isa.rs | 30 +++++++++++++++---- crates/ir2/build/mod.rs | 2 +- crates/ir2/build/op.rs | 46 +++++++++++++++++++++++++++++- crates/ir2/build/token.rs | 5 ++++ crates/ir2/src/decode/mod.rs | 8 +++++- crates/ir2/src/decode/op.rs | 44 ++++++++++++++++++++++++++++ 7 files changed, 137 insertions(+), 11 deletions(-) diff --git a/crates/ir2/build/display/decode.rs b/crates/ir2/build/display/decode.rs index 458b4001e6..8a7b74f0da 100644 --- a/crates/ir2/build/display/decode.rs +++ b/crates/ir2/build/display/decode.rs @@ -18,7 +18,7 @@ use crate::build::{ V128LoadLaneOp, V128ReplaceLaneOp, }, - token::{CamelCase, SnakeCase}, + token::{CamelCase, Ident, SnakeCase}, Isa, }; use core::fmt::{self, Display}; @@ -112,14 +112,23 @@ impl Display for DisplayDecode<&'_ StoreOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let op = self.value; let camel_ident = DisplayIdent::camel(op); + let lane_ident = op + .laneidx_field() + .map(|_| CamelCase(Ident::Lane)) + .display_maybe(); let mem0_offset16 = (op.mem0 && op.offset16) .then_some("Mem0Offset16") .display_maybe(); let ptr_suffix = CamelCase(op.ptr); let value_ty = op.value_field().ty; + let laneidx_ty = op + .laneidx_field() + .map(|field| (", ", field.ty)) + .map(DisplayConcat) + .display_maybe(); writeln!( f, - "pub type {camel_ident} = StoreOp{mem0_offset16}_{ptr_suffix}<{value_ty}>;" + "pub type {camel_ident} = Store{lane_ident}Op{mem0_offset16}_{ptr_suffix}<{value_ty}{laneidx_ty}>;" ) } } diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 070b1422a9..72d15c2b0f 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -1098,10 +1098,28 @@ fn add_simd_load_ops(isa: &mut Isa) { } } -fn add_simd_store_ops(_isa: &mut Isa) { - // v128.store memarg: (i32 v128) -> () - // v128.store8_lane memarg laneidx: (i32 v128) -> () - // v128.store16_lane memarg laneidx: (i32 v128) -> () - // v128.store32_lane memarg laneidx: (i32 v128) -> () - // v128.store64_lane memarg laneidx: (i32 v128) -> () +fn add_simd_store_ops(isa: &mut Isa) { + let kinds = [ + StoreOpKind::Store128, + StoreOpKind::V128Store8Lane, + StoreOpKind::V128Store16Lane, + StoreOpKind::V128Store32Lane, + StoreOpKind::V128Store64Lane, + ]; + for kind in kinds { + isa.push_op(StoreOp::new( + kind, + OperandKind::Stack, + OperandKind::Stack, + false, + false, + )); + isa.push_op(StoreOp::new( + kind, + OperandKind::Stack, + OperandKind::Stack, + true, + true, + )); + } } diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index eff2c7a97a..fadb36d91d 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -74,7 +74,7 @@ pub fn generate_code(config: &Config) -> Result<(), Error> { fn generate_op_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<(), Error> { let expected_size = match config.simd { - true => 270_000, + true => 275_000, false => 175_000, }; write_to_buffer(contents, expected_size, |buffer| { diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 18be18ff27..74c4abfb8d 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -1529,6 +1529,8 @@ pub enum FieldTy { ImmLaneIdx8, ImmLaneIdx4, ImmLaneIdx2, + Bytes16, + V128, } impl Display for FieldTy { @@ -1569,6 +1571,8 @@ impl Display for FieldTy { Self::ImmLaneIdx8 => "ImmLaneIdx<8>", Self::ImmLaneIdx4 => "ImmLaneIdx<4>", Self::ImmLaneIdx2 => "ImmLaneIdx<2>", + Self::Bytes16 => "[u8; 16]", + Self::V128 => "V128", }; write!(f, "{s}") } @@ -1962,12 +1966,20 @@ impl StoreOp { Some(Field::new(Ident::Memory, FieldTy::Memory)) } - pub fn fields(&self) -> [Option; 4] { + pub fn laneidx_field(&self) -> Option { + let Some(ty) = self.kind.laneidx_ty() else { + return None; + }; + Some(Field::new(Ident::Lane, ty)) + } + + pub fn fields(&self) -> [Option; 5] { [ Some(self.ptr_field()), self.offset_field(), Some(self.value_field()), self.memory_field(), + self.laneidx_field(), ] } } @@ -1984,6 +1996,12 @@ pub enum StoreOpKind { I64Store8, I64Store16, I64Store32, + // v128 + Store128, + V128Store8Lane, + V128Store16Lane, + V128Store32Lane, + V128Store64Lane, } impl StoreOpKind { @@ -1996,6 +2014,11 @@ impl StoreOpKind { Self::I64Store8 => Ident::Store8, Self::I64Store16 => Ident::Store16, Self::I64Store32 => Ident::Store32, + Self::Store128 => Ident::Store128, + Self::V128Store8Lane => Ident::Store8Lane, + Self::V128Store16Lane => Ident::Store16Lane, + Self::V128Store32Lane => Ident::Store32Lane, + Self::V128Store64Lane => Ident::Store64Lane, } } @@ -2008,6 +2031,11 @@ impl StoreOpKind { Self::I64Store8 => Some(Ident::I64), Self::I64Store16 => Some(Ident::I64), Self::I64Store32 => Some(Ident::I64), + Self::Store128 => None, + Self::V128Store8Lane => Some(Ident::V128), + Self::V128Store16Lane => Some(Ident::V128), + Self::V128Store32Lane => Some(Ident::V128), + Self::V128Store64Lane => Some(Ident::V128), } } @@ -2022,9 +2050,25 @@ impl StoreOpKind { Self::I64Store8 => FieldTy::I8, Self::I64Store16 => FieldTy::I16, Self::I64Store32 => FieldTy::I32, + Self::Store128 => FieldTy::Bytes16, + Self::V128Store8Lane => FieldTy::V128, + Self::V128Store16Lane => FieldTy::V128, + Self::V128Store32Lane => FieldTy::V128, + Self::V128Store64Lane => FieldTy::V128, }, } } + + fn laneidx_ty(&self) -> Option { + let ty = match self { + Self::V128Store8Lane => FieldTy::ImmLaneIdx16, + Self::V128Store16Lane => FieldTy::ImmLaneIdx8, + Self::V128Store32Lane => FieldTy::ImmLaneIdx4, + Self::V128Store64Lane => FieldTy::ImmLaneIdx2, + _ => return None, + }; + Some(ty) + } } #[derive(Copy, Clone)] diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index e98eb6e5b3..34fef0588f 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -137,6 +137,7 @@ define_ident!( Store16: store16, Store32: store32, Store64: store64, + Store128: store128, Load8: load8, Load16: load16, Load32: load32, @@ -295,4 +296,8 @@ define_ident!( PromoteLow: promote_low, TruncSatZero: trunc_sat_zero, ConvertLow: convert_low, + Store8Lane: store8_lane, + Store16Lane: store16_lane, + Store32Lane: store32_lane, + Store64Lane: store64_lane, ); diff --git a/crates/ir2/src/decode/mod.rs b/crates/ir2/src/decode/mod.rs index a4bb88970b..124910f871 100644 --- a/crates/ir2/src/decode/mod.rs +++ b/crates/ir2/src/decode/mod.rs @@ -17,7 +17,13 @@ use self::op::{ UnaryOp, }; #[cfg(feature = "simd")] -use self::op::{V128LoadLaneOpMem0Offset16_Ss, V128LoadLaneOp_Ss, V128ReplaceLaneOp}; +use self::op::{ + StoreLaneOpMem0Offset16_S, + StoreLaneOp_S, + V128LoadLaneOpMem0Offset16_Ss, + V128LoadLaneOp_Ss, + V128ReplaceLaneOp, +}; #[cfg(feature = "simd")] use crate::core::simd::ImmLaneIdx; use crate::{ diff --git a/crates/ir2/src/decode/op.rs b/crates/ir2/src/decode/op.rs index 60c6927fc7..d40912ac80 100644 --- a/crates/ir2/src/decode/op.rs +++ b/crates/ir2/src/decode/op.rs @@ -198,6 +198,50 @@ impl Decode for StoreOpMem0Offset16_S { } } +#[derive(Copy, Clone)] +#[cfg(feature = "simd")] +pub struct StoreLaneOp_S { + pub ptr: Stack, + pub offset: u64, + pub value: T, + pub memory: Memory, + pub lane: LaneIdx, +} + +#[cfg(feature = "simd")] +impl Decode for StoreLaneOp_S { + unsafe fn decode(decoder: &mut D) -> Self { + Self { + ptr: Decode::decode(decoder), + offset: Decode::decode(decoder), + value: Decode::decode(decoder), + memory: Decode::decode(decoder), + lane: Decode::decode(decoder), + } + } +} + +#[derive(Copy, Clone)] +#[cfg(feature = "simd")] +pub struct StoreLaneOpMem0Offset16_S { + pub ptr: Stack, + pub offset: Offset16, + pub value: T, + pub lane: LaneIdx, +} + +#[cfg(feature = "simd")] +impl Decode for StoreLaneOpMem0Offset16_S { + unsafe fn decode(decoder: &mut D) -> Self { + Self { + ptr: Decode::decode(decoder), + offset: Decode::decode(decoder), + value: Decode::decode(decoder), + lane: Decode::decode(decoder), + } + } +} + #[derive(Copy, Clone)] pub struct TableGet { pub result: Stack, From 4d404ad15f9560173d05c15ee66ac9f2fe3532cd Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Tue, 2 Sep 2025 11:02:09 +0200 Subject: [PATCH 163/186] add relaxed-simd ops codegen --- crates/ir2/build/isa.rs | 15 +++++++++++++++ crates/ir2/build/op.rs | 19 +++++++++++++++++++ crates/ir2/build/token.rs | 5 +++++ 3 files changed, 39 insertions(+) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 72d15c2b0f..a9ac2fd5b9 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -767,6 +767,7 @@ fn add_simd_ops(isa: &mut Isa, config: &Config) { add_simd_unary_ops(isa); add_simd_load_ops(isa); add_simd_store_ops(isa); + add_relaxed_simd_ops(isa); } fn add_simd_splat_ops(isa: &mut Isa) { @@ -1123,3 +1124,17 @@ fn add_simd_store_ops(isa: &mut Isa) { )); } } + +fn add_relaxed_simd_ops(isa: &mut Isa) { + let kinds = [ + BinaryOpKind::S16x8RelaxedDotI8x16I7x16, + BinaryOpKind::S32x4RelaxedDotI8x16I7x16Add, + BinaryOpKind::F32x4RelaxedMadd, + BinaryOpKind::F32x4RelaxedNmadd, + BinaryOpKind::F64x2RelaxedMadd, + BinaryOpKind::F64x2RelaxedNmadd, + ]; + for kind in kinds { + isa.push_op(BinaryOp::new(kind, OperandKind::Stack, OperandKind::Stack)); + } +} diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 74c4abfb8d..2fd2ef1141 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -828,6 +828,13 @@ pub enum BinaryOpKind { I64x2Shl, S64x2Shr, U64x2Shr, + // Relaxed SIMD + S16x8RelaxedDotI8x16I7x16, + S32x4RelaxedDotI8x16I7x16Add, + F32x4RelaxedMadd, + F32x4RelaxedNmadd, + F64x2RelaxedMadd, + F64x2RelaxedNmadd, } impl BinaryOpKind { @@ -1002,6 +1009,13 @@ impl BinaryOpKind { Self::I64x2Shl => Ident::Shl, Self::S64x2Shr => Ident::Shr, Self::U64x2Shr => Ident::Shr, + // Relaxed SIMD + Self::S16x8RelaxedDotI8x16I7x16 => Ident::RelaxedDotI8x16I7x16, + Self::S32x4RelaxedDotI8x16I7x16Add => Ident::RelaxedDotI8x16I7x16Add, + Self::F32x4RelaxedMadd => Ident::RelaxedMadd, + Self::F32x4RelaxedNmadd => Ident::RelaxedNmadd, + Self::F64x2RelaxedMadd => Ident::RelaxedMadd, + Self::F64x2RelaxedNmadd => Ident::RelaxedNmadd, } } @@ -1142,6 +1156,11 @@ impl BinaryOpKind { | Self::I64x2Shl => Ty::I64x2, | Self::S64x2Shr => Ty::S64x2, | Self::U64x2Shr => Ty::U64x2, + // Relaxed SIMD + | Self::S16x8RelaxedDotI8x16I7x16 => Ty::S16x8, + | Self::S32x4RelaxedDotI8x16I7x16Add => Ty::S32x4, + | Self::F32x4RelaxedMadd | Self::F32x4RelaxedNmadd => Ty::F32x4, + | Self::F64x2RelaxedMadd | Self::F64x2RelaxedNmadd => Ty::F64x2, } } diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/token.rs index 34fef0588f..6707195876 100644 --- a/crates/ir2/build/token.rs +++ b/crates/ir2/build/token.rs @@ -300,4 +300,9 @@ define_ident!( Store16Lane: store16_lane, Store32Lane: store32_lane, Store64Lane: store64_lane, + + RelaxedDotI8x16I7x16: relaxed_dot_i8x16_i7x16, + RelaxedDotI8x16I7x16Add: relaxed_dot_i8x16_i7x16_add, + RelaxedMadd: relaxed_madd, + RelaxedNmadd: relaxed_nmadd, ); From 4821995f1519558ebf0e4c2d42b477f2e060ffc7 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Tue, 2 Sep 2025 11:07:47 +0200 Subject: [PATCH 164/186] rename submodule: token -> ident --- crates/ir2/build/display/constructors.rs | 2 +- crates/ir2/build/display/decode.rs | 2 +- crates/ir2/build/display/encode.rs | 2 +- crates/ir2/build/display/ident.rs | 2 +- crates/ir2/build/{token.rs => ident.rs} | 0 crates/ir2/build/isa.rs | 2 +- crates/ir2/build/mod.rs | 4 ++-- 7 files changed, 7 insertions(+), 7 deletions(-) rename crates/ir2/build/{token.rs => ident.rs} (100%) diff --git a/crates/ir2/build/display/constructors.rs b/crates/ir2/build/display/constructors.rs index 8beabd0678..3edb53b14e 100644 --- a/crates/ir2/build/display/constructors.rs +++ b/crates/ir2/build/display/constructors.rs @@ -1,5 +1,6 @@ use crate::build::{ display::{ident::DisplayIdent, utils::DisplaySequence, Indent}, + ident::SnakeCase, isa::Isa, op::{ BinaryOp, @@ -15,7 +16,6 @@ use crate::build::{ V128LoadLaneOp, V128ReplaceLaneOp, }, - token::SnakeCase, }; use core::fmt::{self, Display}; diff --git a/crates/ir2/build/display/decode.rs b/crates/ir2/build/display/decode.rs index 8a7b74f0da..841fb2117f 100644 --- a/crates/ir2/build/display/decode.rs +++ b/crates/ir2/build/display/decode.rs @@ -4,6 +4,7 @@ use crate::build::{ utils::{DisplayConcat, DisplaySequence, IntoDisplayMaybe as _}, Indent, }, + ident::{CamelCase, Ident, SnakeCase}, op::{ BinaryOp, CmpBranchOp, @@ -18,7 +19,6 @@ use crate::build::{ V128LoadLaneOp, V128ReplaceLaneOp, }, - token::{CamelCase, Ident, SnakeCase}, Isa, }; use core::fmt::{self, Display}; diff --git a/crates/ir2/build/display/encode.rs b/crates/ir2/build/display/encode.rs index d466340665..4b379c2e4c 100644 --- a/crates/ir2/build/display/encode.rs +++ b/crates/ir2/build/display/encode.rs @@ -1,5 +1,6 @@ use crate::build::{ display::{ident::DisplayIdent, utils::DisplaySequence, Indent}, + ident::SnakeCase, isa::Isa, op::{ BinaryOp, @@ -15,7 +16,6 @@ use crate::build::{ V128LoadLaneOp, V128ReplaceLaneOp, }, - token::SnakeCase, }; use core::fmt::{self, Display}; diff --git a/crates/ir2/build/display/ident.rs b/crates/ir2/build/display/ident.rs index 692d97937a..b49a7bccc9 100644 --- a/crates/ir2/build/display/ident.rs +++ b/crates/ir2/build/display/ident.rs @@ -1,5 +1,6 @@ use crate::build::{ display::utils::{DisplayConcat, IntoDisplayMaybe as _}, + ident::{Case, Ident, Sep, SnakeCase}, op::{ BinaryOp, CmpBranchOp, @@ -14,7 +15,6 @@ use crate::build::{ V128LoadLaneOp, V128ReplaceLaneOp, }, - token::{Case, Ident, Sep, SnakeCase}, }; use core::fmt::{self, Display}; diff --git a/crates/ir2/build/token.rs b/crates/ir2/build/ident.rs similarity index 100% rename from crates/ir2/build/token.rs rename to crates/ir2/build/ident.rs diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index a9ac2fd5b9..4f7c1ef752 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -1,4 +1,5 @@ use crate::build::{ + ident::Ident, op::{ BinaryOp, BinaryOpKind, @@ -22,7 +23,6 @@ use crate::build::{ V128LoadLaneOp, V128ReplaceLaneOp, }, - token::Ident, Config, Op, }; diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index fadb36d91d..47f577beb7 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -1,8 +1,8 @@ #[macro_use] mod op; mod display; +pub mod ident; mod isa; -pub mod token; use self::{ display::{ @@ -14,9 +14,9 @@ use self::{ DisplayResultMut, Indent, }, + ident::{CamelCase, Ident, SnakeCase}, isa::Isa, op::Op, - token::{CamelCase, Ident, SnakeCase}, }; use core::fmt::{self, Display, Error as FmtError, Write as _}; use std::{env, fs, io::Error as IoError, path::PathBuf}; From 153fc8212186e26310f63f718ea6b3a770753c82 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Tue, 2 Sep 2025 11:08:04 +0200 Subject: [PATCH 165/186] apply clippy suggestion --- crates/ir2/build/op.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 2fd2ef1141..9c54f1f823 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -1986,9 +1986,7 @@ impl StoreOp { } pub fn laneidx_field(&self) -> Option { - let Some(ty) = self.kind.laneidx_ty() else { - return None; - }; + let ty = self.kind.laneidx_ty()?; Some(Field::new(Ident::Lane, ty)) } From ffa4b44278dcc7d37d76e58ffbc32889a666c2db Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 3 Sep 2025 09:49:38 +0200 Subject: [PATCH 166/186] rename [{Bounded,Fixed}]Stack[Span]: Stack -> Slot --- crates/ir2/build/display/decode.rs | 8 +- crates/ir2/build/display/ident.rs | 18 +- crates/ir2/build/display/result_mut.rs | 2 +- crates/ir2/build/ident.rs | 2 +- crates/ir2/build/isa.rs | 238 ++++++++++++------------- crates/ir2/build/op.rs | 72 ++++---- crates/ir2/src/decode/mod.rs | 18 +- crates/ir2/src/decode/op.rs | 48 ++--- crates/ir2/src/encode.rs | 16 +- crates/ir2/src/error.rs | 2 +- crates/ir2/src/index.rs | 14 +- crates/ir2/src/lib.rs | 4 +- crates/ir2/src/op.rs | 6 +- crates/ir2/src/span.rs | 200 ++++++++++----------- 14 files changed, 321 insertions(+), 327 deletions(-) diff --git a/crates/ir2/build/display/decode.rs b/crates/ir2/build/display/decode.rs index 841fb2117f..a7f8ab5b4a 100644 --- a/crates/ir2/build/display/decode.rs +++ b/crates/ir2/build/display/decode.rs @@ -9,6 +9,7 @@ use crate::build::{ BinaryOp, CmpBranchOp, CmpSelectOp, + FieldTy, GenericOp, LoadOp, OperandKind, @@ -58,7 +59,8 @@ impl Display for DisplayDecode<&'_ Isa> { impl Display for DisplayDecode<&'_ UnaryOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let camel_ident = DisplayIdent::camel(self.value); - writeln!(f, "pub type {camel_ident} = UnaryOp;") + let slot_ty = FieldTy::Slot; + writeln!(f, "pub type {camel_ident} = UnaryOp<{slot_ty}>;") } } @@ -99,7 +101,7 @@ impl Display for DisplayDecode<&'_ LoadOp> { let mem0_offset16 = (op.mem0 && op.offset16) .then_some("Mem0Offset16") .display_maybe(); - let result_suffix = CamelCase(OperandKind::Stack); + let result_suffix = CamelCase(OperandKind::Slot); let ptr_suffix = SnakeCase(op.ptr); writeln!( f, @@ -215,7 +217,7 @@ impl Display for DisplayDecode<&'_ V128LoadLaneOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let op = self.value; let camel_ident = DisplayIdent::camel(op); - let result_suffix = CamelCase(OperandKind::Stack); + let result_suffix = CamelCase(OperandKind::Slot); let mem0_offset16 = (op.mem0 && op.offset16) .then_some("Mem0Offset16") .display_maybe(); diff --git a/crates/ir2/build/display/ident.rs b/crates/ir2/build/display/ident.rs index b49a7bccc9..72e39b206d 100644 --- a/crates/ir2/build/display/ident.rs +++ b/crates/ir2/build/display/ident.rs @@ -60,7 +60,7 @@ impl Display for DisplayIdent<&'_ UnaryOp> { .map(|i| (sep, case.wrap(i))) .map(DisplayConcat) .display_maybe(); - let result_suffix = case.wrap(OperandKind::Stack); + let result_suffix = case.wrap(OperandKind::Slot); let value_suffix = SnakeCase(op.value); write!( f, @@ -76,7 +76,7 @@ impl Display for DisplayIdent<&'_ BinaryOp> { let kind = self.value.kind; let ident = case.wrap(kind.ident()); let ident_prefix = case.wrap(kind.ident_prefix()); - let result_suffix = case.wrap(OperandKind::Stack); + let result_suffix = case.wrap(OperandKind::Slot); let lhs_suffix = SnakeCase(self.value.lhs); let rhs_suffix = SnakeCase(self.value.rhs); write!( @@ -110,7 +110,7 @@ impl Display for DisplayIdent<&'_ CmpSelectOp> { let select = case.wrap(Ident::Select); let ident = case.wrap(cmp.ident()); let input_ident = case.wrap(cmp.ident_prefix()); - let result_suffix = case.wrap(OperandKind::Stack); + let result_suffix = case.wrap(OperandKind::Slot); let lhs_suffix = SnakeCase(self.value.lhs); let rhs_suffix = SnakeCase(self.value.rhs); write!( @@ -125,7 +125,7 @@ impl Display for DisplayIdent<&'_ LoadOp> { let case = self.case; let kind = self.value.kind; let ident = case.wrap(kind.ident()); - let result_suffix = case.wrap(OperandKind::Stack); + let result_suffix = case.wrap(OperandKind::Slot); let ptr_suffix = SnakeCase(self.value.ptr); let sep = case.wrap(Sep); let ident_prefix = self @@ -203,7 +203,7 @@ impl Display for DisplayIdent<&'_ TableGetOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let case = self.case; let ident = case.wrap(Ident::TableGet); - let result_suffix = case.wrap(OperandKind::Stack); + let result_suffix = case.wrap(OperandKind::Slot); let index_suffix = SnakeCase(self.value.index); write!(f, "{ident}_{result_suffix}{index_suffix}") } @@ -227,8 +227,8 @@ impl Display for DisplayIdent<&'_ V128ReplaceLaneOp> { let v128 = case.wrap(Ident::V128); let ident = case.wrap(Ident::ReplaceLane); let width = op.width; - let result_suffix = case.wrap(OperandKind::Stack); - let v128_suffix = SnakeCase(OperandKind::Stack); + let result_suffix = case.wrap(OperandKind::Slot); + let v128_suffix = SnakeCase(OperandKind::Slot); let value_suffix = SnakeCase(op.value); write!( f, @@ -245,9 +245,9 @@ impl Display for DisplayIdent<&'_ V128LoadLaneOp> { let v128 = case.wrap(Ident::V128); let ident = case.wrap(Ident::LoadLane); let width = u8::from(op.width); - let result_suffix = case.wrap(OperandKind::Stack); + let result_suffix = case.wrap(OperandKind::Slot); let ptr_suffix = SnakeCase(op.ptr); - let v128_suffix = SnakeCase(OperandKind::Stack); + let v128_suffix = SnakeCase(OperandKind::Slot); let mem0_ident = self .value .mem0 diff --git a/crates/ir2/build/display/result_mut.rs b/crates/ir2/build/display/result_mut.rs index 212c78f582..2824006465 100644 --- a/crates/ir2/build/display/result_mut.rs +++ b/crates/ir2/build/display/result_mut.rs @@ -60,7 +60,7 @@ impl Display for DisplayResultMut<&'_ Isa> { f, "\ {indent}impl Op {{\n\ - {indent} pub fn result_mut(&mut self) -> Option<&mut Stack> {{\n\ + {indent} pub fn result_mut(&mut self) -> Option<&mut Slot> {{\n\ {indent} let res = match self {{\n\ {variants}\ {indent} _ => return None,\n\ diff --git a/crates/ir2/build/ident.rs b/crates/ir2/build/ident.rs index 6707195876..170ccb874a 100644 --- a/crates/ir2/build/ident.rs +++ b/crates/ir2/build/ident.rs @@ -203,7 +203,7 @@ define_ident!( Return: r#return, Return32: return32, Return64: return64, - ReturnStack: return_stack, + ReturnSlot: return_slot, ReturnSpan: return_span, Values: values, Value: value, diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 4f7c1ef752..9190588418 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -125,7 +125,7 @@ fn add_unary_ops(isa: &mut Isa) { UnaryOpKind::U64TruncSatF64, ]; for op in ops { - isa.push_op(UnaryOp::new(op, OperandKind::Stack)); + isa.push_op(UnaryOp::new(op, OperandKind::Slot)); } } @@ -213,18 +213,10 @@ fn add_binary_ops(isa: &mut Isa) { BinaryOpKind::F64Copysign, ]; for op in ops { - isa.push_op(BinaryOp::new(op, OperandKind::Stack, OperandKind::Stack)); - isa.push_op(BinaryOp::new( - op, - OperandKind::Stack, - OperandKind::Immediate, - )); + isa.push_op(BinaryOp::new(op, OperandKind::Slot, OperandKind::Slot)); + isa.push_op(BinaryOp::new(op, OperandKind::Slot, OperandKind::Immediate)); if matches!(op.commutativity(), Commutativity::NonCommutative) { - isa.push_op(BinaryOp::new( - op, - OperandKind::Immediate, - OperandKind::Stack, - )); + isa.push_op(BinaryOp::new(op, OperandKind::Immediate, OperandKind::Slot)); } } } @@ -269,17 +261,17 @@ fn add_cmp_branch_ops(isa: &mut Isa) { CmpOpKind::F64NotLe, ]; for op in ops { - isa.push_op(CmpBranchOp::new(op, OperandKind::Stack, OperandKind::Stack)); + isa.push_op(CmpBranchOp::new(op, OperandKind::Slot, OperandKind::Slot)); isa.push_op(CmpBranchOp::new( op, - OperandKind::Stack, + OperandKind::Slot, OperandKind::Immediate, )); if matches!(op.commutativity(), Commutativity::NonCommutative) { isa.push_op(CmpBranchOp::new( op, OperandKind::Immediate, - OperandKind::Stack, + OperandKind::Slot, )); } } @@ -313,17 +305,17 @@ fn add_cmp_select_ops(isa: &mut Isa) { CmpOpKind::F64Le, ]; for op in ops { - isa.push_op(CmpSelectOp::new(op, OperandKind::Stack, OperandKind::Stack)); + isa.push_op(CmpSelectOp::new(op, OperandKind::Slot, OperandKind::Slot)); isa.push_op(CmpSelectOp::new( op, - OperandKind::Stack, + OperandKind::Slot, OperandKind::Immediate, )); if matches!(op.commutativity(), Commutativity::NonCommutative) { isa.push_op(CmpSelectOp::new( op, OperandKind::Immediate, - OperandKind::Stack, + OperandKind::Slot, )); } } @@ -348,9 +340,9 @@ fn add_load_ops(isa: &mut Isa) { LoadOpKind::U64Load32, ]; for op in ops { - isa.push_op(LoadOp::new(op, OperandKind::Stack, false, false)); + isa.push_op(LoadOp::new(op, OperandKind::Slot, false, false)); isa.push_op(LoadOp::new(op, OperandKind::Immediate, false, false)); - isa.push_op(LoadOp::new(op, OperandKind::Stack, true, true)); + isa.push_op(LoadOp::new(op, OperandKind::Slot, true, true)); } } @@ -370,14 +362,14 @@ fn add_store_ops(isa: &mut Isa) { for op in ops { isa.push_op(StoreOp::new( op, - OperandKind::Stack, - OperandKind::Stack, + OperandKind::Slot, + OperandKind::Slot, false, false, )); isa.push_op(StoreOp::new( op, - OperandKind::Stack, + OperandKind::Slot, OperandKind::Immediate, false, false, @@ -385,20 +377,20 @@ fn add_store_ops(isa: &mut Isa) { isa.push_op(StoreOp::new( op, OperandKind::Immediate, - OperandKind::Stack, + OperandKind::Slot, false, false, )); isa.push_op(StoreOp::new( op, - OperandKind::Stack, - OperandKind::Stack, + OperandKind::Slot, + OperandKind::Slot, true, true, )); isa.push_op(StoreOp::new( op, - OperandKind::Stack, + OperandKind::Slot, OperandKind::Immediate, true, true, @@ -418,8 +410,8 @@ fn add_control_ops(isa: &mut Isa) { )), Op::from(GenericOp::new(Ident::Return, [])), Op::from(GenericOp::new( - Ident::ReturnStack, - [Field::new(Ident::Value, FieldTy::Stack)], + Ident::ReturnSlot, + [Field::new(Ident::Value, FieldTy::Slot)], )), Op::from(GenericOp::new( Ident::Return32, @@ -435,21 +427,21 @@ fn add_control_ops(isa: &mut Isa) { )), Op::from(GenericOp::new( Ident::Branch, - [Field::new(Ident::Values, FieldTy::StackSpan)], + [Field::new(Ident::Values, FieldTy::SlotSpan)], )), Op::from(GenericOp::new( Ident::BranchTable, [ - Field::new(Ident::Index, FieldTy::Stack), + Field::new(Ident::Index, FieldTy::Slot), Field::new(Ident::LenTargets, FieldTy::U16), ], )), Op::from(GenericOp::new( Ident::BranchTableSpan, [ - Field::new(Ident::Index, FieldTy::Stack), + Field::new(Ident::Index, FieldTy::Slot), Field::new(Ident::LenTargets, FieldTy::U16), - Field::new(Ident::Values, FieldTy::StackSpan), + Field::new(Ident::Values, FieldTy::SlotSpan), Field::new(Ident::LenValues, FieldTy::U16), ], )), @@ -462,29 +454,29 @@ fn add_copy_ops(isa: &mut Isa) { Op::from(GenericOp::new( Ident::Copy, [ - Field::new(Ident::Result, FieldTy::Stack), - Field::new(Ident::Value, FieldTy::Stack), + Field::new(Ident::Result, FieldTy::Slot), + Field::new(Ident::Value, FieldTy::Slot), ], )), Op::from(GenericOp::new( Ident::Copy32, [ - Field::new(Ident::Result, FieldTy::Stack), + Field::new(Ident::Result, FieldTy::Slot), Field::new(Ident::Value, FieldTy::U32), ], )), Op::from(GenericOp::new( Ident::Copy64, [ - Field::new(Ident::Result, FieldTy::Stack), + Field::new(Ident::Result, FieldTy::Slot), Field::new(Ident::Value, FieldTy::U64), ], )), Op::from(GenericOp::new( Ident::CopySpan, [ - Field::new(Ident::Results, FieldTy::StackSpan), - Field::new(Ident::Values, FieldTy::StackSpan), + Field::new(Ident::Results, FieldTy::SlotSpan), + Field::new(Ident::Values, FieldTy::SlotSpan), Field::new(Ident::Len, FieldTy::U16), ], )), @@ -497,29 +489,29 @@ fn add_call_ops(isa: &mut Isa) { Op::from(GenericOp::new( Ident::RefFunc, [ - Field::new(Ident::Result, FieldTy::Stack), + Field::new(Ident::Result, FieldTy::Slot), Field::new(Ident::Func, FieldTy::Func), ], )), Op::from(GenericOp::new( Ident::CallInternal, [ - Field::new(Ident::Results, FieldTy::StackSpan), + Field::new(Ident::Results, FieldTy::SlotSpan), Field::new(Ident::Func, FieldTy::InternalFunc), ], )), Op::from(GenericOp::new( Ident::CallImported, [ - Field::new(Ident::Results, FieldTy::StackSpan), + Field::new(Ident::Results, FieldTy::SlotSpan), Field::new(Ident::Func, FieldTy::Func), ], )), Op::from(GenericOp::new( Ident::CallIndirect, [ - Field::new(Ident::Results, FieldTy::StackSpan), - Field::new(Ident::Index, FieldTy::Stack), + Field::new(Ident::Results, FieldTy::SlotSpan), + Field::new(Ident::Index, FieldTy::Slot), Field::new(Ident::FuncType, FieldTy::FuncType), Field::new(Ident::Table, FieldTy::Table), ], @@ -535,7 +527,7 @@ fn add_call_ops(isa: &mut Isa) { Op::from(GenericOp::new( Ident::ReturnCallIndirect, [ - Field::new(Ident::Index, FieldTy::Stack), + Field::new(Ident::Index, FieldTy::Slot), Field::new(Ident::FuncType, FieldTy::FuncType), Field::new(Ident::Table, FieldTy::Table), ], @@ -549,7 +541,7 @@ fn add_global_ops(isa: &mut Isa) { Op::from(GenericOp::new( Ident::GlobalGet, [ - Field::new(Ident::Result, FieldTy::Stack), + Field::new(Ident::Result, FieldTy::Slot), Field::new(Ident::Global, FieldTy::Global), ], )), @@ -557,7 +549,7 @@ fn add_global_ops(isa: &mut Isa) { Ident::GlobalSet, [ Field::new(Ident::Global, FieldTy::Global), - Field::new(Ident::Value, FieldTy::Stack), + Field::new(Ident::Value, FieldTy::Slot), ], )), Op::from(GenericOp::new( @@ -580,11 +572,11 @@ fn add_global_ops(isa: &mut Isa) { fn add_table_ops(isa: &mut Isa) { let ops = [ - Op::TableGet(TableGetOp::new(OperandKind::Stack)), + Op::TableGet(TableGetOp::new(OperandKind::Slot)), Op::TableGet(TableGetOp::new(OperandKind::Immediate)), - Op::TableSet(TableSetOp::new(OperandKind::Stack, OperandKind::Stack)), - Op::TableSet(TableSetOp::new(OperandKind::Stack, OperandKind::Immediate)), - Op::TableSet(TableSetOp::new(OperandKind::Immediate, OperandKind::Stack)), + Op::TableSet(TableSetOp::new(OperandKind::Slot, OperandKind::Slot)), + Op::TableSet(TableSetOp::new(OperandKind::Slot, OperandKind::Immediate)), + Op::TableSet(TableSetOp::new(OperandKind::Immediate, OperandKind::Slot)), Op::TableSet(TableSetOp::new( OperandKind::Immediate, OperandKind::Immediate, @@ -592,16 +584,16 @@ fn add_table_ops(isa: &mut Isa) { Op::from(GenericOp::new( Ident::TableSize, [ - Field::new(Ident::Result, FieldTy::Stack), + Field::new(Ident::Result, FieldTy::Slot), Field::new(Ident::Table, FieldTy::Table), ], )), Op::from(GenericOp::new( Ident::TableGrow, [ - Field::new(Ident::Result, FieldTy::Stack), - Field::new(Ident::Delta, FieldTy::Stack), - Field::new(Ident::Value, FieldTy::Stack), + Field::new(Ident::Result, FieldTy::Slot), + Field::new(Ident::Delta, FieldTy::Slot), + Field::new(Ident::Value, FieldTy::Slot), Field::new(Ident::Table, FieldTy::Table), ], )), @@ -610,18 +602,18 @@ fn add_table_ops(isa: &mut Isa) { [ Field::new(Ident::DstTable, FieldTy::Table), Field::new(Ident::SrcTable, FieldTy::Table), - Field::new(Ident::Dst, FieldTy::Stack), - Field::new(Ident::Src, FieldTy::Stack), - Field::new(Ident::Len, FieldTy::Stack), + Field::new(Ident::Dst, FieldTy::Slot), + Field::new(Ident::Src, FieldTy::Slot), + Field::new(Ident::Len, FieldTy::Slot), ], )), Op::from(GenericOp::new( Ident::TableFill, [ Field::new(Ident::Table, FieldTy::Table), - Field::new(Ident::Dst, FieldTy::Stack), - Field::new(Ident::Len, FieldTy::Stack), - Field::new(Ident::Value, FieldTy::Stack), + Field::new(Ident::Dst, FieldTy::Slot), + Field::new(Ident::Len, FieldTy::Slot), + Field::new(Ident::Value, FieldTy::Slot), ], )), Op::from(GenericOp::new( @@ -629,9 +621,9 @@ fn add_table_ops(isa: &mut Isa) { [ Field::new(Ident::Table, FieldTy::Table), Field::new(Ident::Elem, FieldTy::Elem), - Field::new(Ident::Dst, FieldTy::Stack), - Field::new(Ident::Src, FieldTy::Stack), - Field::new(Ident::Len, FieldTy::Stack), + Field::new(Ident::Dst, FieldTy::Slot), + Field::new(Ident::Src, FieldTy::Slot), + Field::new(Ident::Len, FieldTy::Slot), ], )), Op::from(GenericOp::new( @@ -651,15 +643,15 @@ fn add_memory_ops(isa: &mut Isa) { Op::from(GenericOp::new( Ident::MemorySize, [ - Field::new(Ident::Result, FieldTy::Stack), + Field::new(Ident::Result, FieldTy::Slot), Field::new(Ident::Memory, FieldTy::Memory), ], )), Op::from(GenericOp::new( Ident::MemoryGrow, [ - Field::new(Ident::Result, FieldTy::Stack), - Field::new(Ident::Delta, FieldTy::Stack), + Field::new(Ident::Result, FieldTy::Slot), + Field::new(Ident::Delta, FieldTy::Slot), Field::new(Ident::Memory, FieldTy::Memory), ], )), @@ -668,18 +660,18 @@ fn add_memory_ops(isa: &mut Isa) { [ Field::new(Ident::DstMemory, FieldTy::Memory), Field::new(Ident::SrcMemory, FieldTy::Memory), - Field::new(Ident::Dst, FieldTy::Stack), - Field::new(Ident::Src, FieldTy::Stack), - Field::new(Ident::Len, FieldTy::Stack), + Field::new(Ident::Dst, FieldTy::Slot), + Field::new(Ident::Src, FieldTy::Slot), + Field::new(Ident::Len, FieldTy::Slot), ], )), Op::from(GenericOp::new( Ident::MemoryFill, [ Field::new(Ident::Memory, FieldTy::Memory), - Field::new(Ident::Dst, FieldTy::Stack), - Field::new(Ident::Len, FieldTy::Stack), - Field::new(Ident::Value, FieldTy::Stack), + Field::new(Ident::Dst, FieldTy::Slot), + Field::new(Ident::Len, FieldTy::Slot), + Field::new(Ident::Value, FieldTy::Slot), ], )), Op::from(GenericOp::new( @@ -687,9 +679,9 @@ fn add_memory_ops(isa: &mut Isa) { [ Field::new(Ident::Memory, FieldTy::Memory), Field::new(Ident::Data, FieldTy::Data), - Field::new(Ident::Dst, FieldTy::Stack), - Field::new(Ident::Src, FieldTy::Stack), - Field::new(Ident::Len, FieldTy::Stack), + Field::new(Ident::Dst, FieldTy::Slot), + Field::new(Ident::Src, FieldTy::Slot), + Field::new(Ident::Len, FieldTy::Slot), ], )), ]; @@ -701,37 +693,37 @@ fn add_wide_arithmetic_ops(isa: &mut Isa) { Op::from(GenericOp::new( Ident::I64Add128, [ - Field::new(Ident::Results, FieldTy::FixedStackSpan2), - Field::new(Ident::LhsLo, FieldTy::Stack), - Field::new(Ident::LhsHi, FieldTy::Stack), - Field::new(Ident::RhsLo, FieldTy::Stack), - Field::new(Ident::RhsHi, FieldTy::Stack), + Field::new(Ident::Results, FieldTy::FixedSlotSpan2), + Field::new(Ident::LhsLo, FieldTy::Slot), + Field::new(Ident::LhsHi, FieldTy::Slot), + Field::new(Ident::RhsLo, FieldTy::Slot), + Field::new(Ident::RhsHi, FieldTy::Slot), ], )), Op::from(GenericOp::new( Ident::I64Sub128, [ - Field::new(Ident::Results, FieldTy::FixedStackSpan2), - Field::new(Ident::LhsLo, FieldTy::Stack), - Field::new(Ident::LhsHi, FieldTy::Stack), - Field::new(Ident::RhsLo, FieldTy::Stack), - Field::new(Ident::RhsHi, FieldTy::Stack), + Field::new(Ident::Results, FieldTy::FixedSlotSpan2), + Field::new(Ident::LhsLo, FieldTy::Slot), + Field::new(Ident::LhsHi, FieldTy::Slot), + Field::new(Ident::RhsLo, FieldTy::Slot), + Field::new(Ident::RhsHi, FieldTy::Slot), ], )), Op::from(GenericOp::new( Ident::S64MulWide, [ - Field::new(Ident::Results, FieldTy::FixedStackSpan2), - Field::new(Ident::Lhs, FieldTy::Stack), - Field::new(Ident::Rhs, FieldTy::Stack), + Field::new(Ident::Results, FieldTy::FixedSlotSpan2), + Field::new(Ident::Lhs, FieldTy::Slot), + Field::new(Ident::Rhs, FieldTy::Slot), ], )), Op::from(GenericOp::new( Ident::U64MulWide, [ - Field::new(Ident::Results, FieldTy::FixedStackSpan2), - Field::new(Ident::Lhs, FieldTy::Stack), - Field::new(Ident::Rhs, FieldTy::Stack), + Field::new(Ident::Results, FieldTy::FixedSlotSpan2), + Field::new(Ident::Lhs, FieldTy::Slot), + Field::new(Ident::Rhs, FieldTy::Slot), ], )), ]; @@ -745,7 +737,7 @@ fn add_simd_ops(isa: &mut Isa, config: &Config) { isa.push_op(GenericOp::new( Ident::Copy128, [ - Field::new(Ident::Result, FieldTy::Stack), + Field::new(Ident::Result, FieldTy::Slot), Field::new(Ident::ValueLo, FieldTy::U64), Field::new(Ident::ValueHi, FieldTy::U64), ], @@ -753,9 +745,9 @@ fn add_simd_ops(isa: &mut Isa, config: &Config) { isa.push_op(GenericOp::new( Ident::I8x16Shuffle, [ - Field::new(Ident::Result, FieldTy::Stack), - Field::new(Ident::Lhs, FieldTy::Stack), - Field::new(Ident::Rhs, FieldTy::Stack), + Field::new(Ident::Result, FieldTy::Slot), + Field::new(Ident::Lhs, FieldTy::Slot), + Field::new(Ident::Rhs, FieldTy::Slot), Field::new(Ident::Selector, FieldTy::Array16ImmLaneIdx32), ], )); @@ -773,7 +765,7 @@ fn add_simd_ops(isa: &mut Isa, config: &Config) { fn add_simd_splat_ops(isa: &mut Isa) { let kinds = [UnaryOpKind::V128Splat32, UnaryOpKind::V128Splat64]; for kind in kinds { - isa.push_op(UnaryOp::new(kind, OperandKind::Stack)); + isa.push_op(UnaryOp::new(kind, OperandKind::Slot)); isa.push_op(UnaryOp::new(kind, OperandKind::Immediate)); } } @@ -783,48 +775,48 @@ fn add_simd_extract_lane_ops(isa: &mut Isa) { Op::from(GenericOp::new( Ident::S8x16ExtractLane, [ - Field::new(Ident::Result, FieldTy::Stack), - Field::new(Ident::Value, FieldTy::Stack), + Field::new(Ident::Result, FieldTy::Slot), + Field::new(Ident::Value, FieldTy::Slot), Field::new(Ident::Lane, FieldTy::ImmLaneIdx16), ], )), Op::from(GenericOp::new( Ident::U8x16ExtractLane, [ - Field::new(Ident::Result, FieldTy::Stack), - Field::new(Ident::Value, FieldTy::Stack), + Field::new(Ident::Result, FieldTy::Slot), + Field::new(Ident::Value, FieldTy::Slot), Field::new(Ident::Lane, FieldTy::ImmLaneIdx16), ], )), Op::from(GenericOp::new( Ident::S16x8ExtractLane, [ - Field::new(Ident::Result, FieldTy::Stack), - Field::new(Ident::Value, FieldTy::Stack), + Field::new(Ident::Result, FieldTy::Slot), + Field::new(Ident::Value, FieldTy::Slot), Field::new(Ident::Lane, FieldTy::ImmLaneIdx8), ], )), Op::from(GenericOp::new( Ident::U16x8ExtractLane, [ - Field::new(Ident::Result, FieldTy::Stack), - Field::new(Ident::Value, FieldTy::Stack), + Field::new(Ident::Result, FieldTy::Slot), + Field::new(Ident::Value, FieldTy::Slot), Field::new(Ident::Lane, FieldTy::ImmLaneIdx8), ], )), Op::from(GenericOp::new( Ident::U32x4ExtractLane, [ - Field::new(Ident::Result, FieldTy::Stack), - Field::new(Ident::Value, FieldTy::Stack), + Field::new(Ident::Result, FieldTy::Slot), + Field::new(Ident::Value, FieldTy::Slot), Field::new(Ident::Lane, FieldTy::ImmLaneIdx4), ], )), Op::from(GenericOp::new( Ident::U64x2ExtractLane, [ - Field::new(Ident::Result, FieldTy::Stack), - Field::new(Ident::Value, FieldTy::Stack), + Field::new(Ident::Result, FieldTy::Slot), + Field::new(Ident::Value, FieldTy::Slot), Field::new(Ident::Lane, FieldTy::ImmLaneIdx2), ], )), @@ -840,7 +832,7 @@ fn add_simd_replace_lane_ops(isa: &mut Isa) { LaneWidth::W64, ]; for width in widths { - isa.push_op(V128ReplaceLaneOp::new(width, OperandKind::Stack)); + isa.push_op(V128ReplaceLaneOp::new(width, OperandKind::Slot)); isa.push_op(V128ReplaceLaneOp::new(width, OperandKind::Immediate)); } } @@ -963,7 +955,7 @@ fn add_simd_binary_ops(isa: &mut Isa) { BinaryOpKind::F64x2Pmax, ]; for kind in kinds { - isa.push_op(BinaryOp::new(kind, OperandKind::Stack, OperandKind::Stack)); + isa.push_op(BinaryOp::new(kind, OperandKind::Slot, OperandKind::Slot)); } } @@ -983,10 +975,10 @@ fn add_simd_shift_ops(isa: &mut Isa) { BinaryOpKind::U64x2Shr, ]; for kind in kinds { - isa.push_op(BinaryOp::new(kind, OperandKind::Stack, OperandKind::Stack)); + isa.push_op(BinaryOp::new(kind, OperandKind::Slot, OperandKind::Slot)); isa.push_op(BinaryOp::new( kind, - OperandKind::Stack, + OperandKind::Slot, OperandKind::Immediate, )); } @@ -1063,7 +1055,7 @@ fn add_simd_unary_ops(isa: &mut Isa) { UnaryOpKind::F64x2ConvertLowU32x4, ]; for kind in kinds { - isa.push_op(UnaryOp::new(kind, OperandKind::Stack)); + isa.push_op(UnaryOp::new(kind, OperandKind::Slot)); } } @@ -1084,8 +1076,8 @@ fn add_simd_load_ops(isa: &mut Isa) { LoadOpKind::V128Load64Zero, ]; for op in ops { - isa.push_op(LoadOp::new(op, OperandKind::Stack, false, false)); - isa.push_op(LoadOp::new(op, OperandKind::Stack, true, true)); + isa.push_op(LoadOp::new(op, OperandKind::Slot, false, false)); + isa.push_op(LoadOp::new(op, OperandKind::Slot, true, true)); } let widths = [ LaneWidth::W8, @@ -1094,8 +1086,8 @@ fn add_simd_load_ops(isa: &mut Isa) { LaneWidth::W64, ]; for width in widths { - isa.push_op(V128LoadLaneOp::new(width, OperandKind::Stack, false, false)); - isa.push_op(V128LoadLaneOp::new(width, OperandKind::Stack, true, true)); + isa.push_op(V128LoadLaneOp::new(width, OperandKind::Slot, false, false)); + isa.push_op(V128LoadLaneOp::new(width, OperandKind::Slot, true, true)); } } @@ -1110,15 +1102,15 @@ fn add_simd_store_ops(isa: &mut Isa) { for kind in kinds { isa.push_op(StoreOp::new( kind, - OperandKind::Stack, - OperandKind::Stack, + OperandKind::Slot, + OperandKind::Slot, false, false, )); isa.push_op(StoreOp::new( kind, - OperandKind::Stack, - OperandKind::Stack, + OperandKind::Slot, + OperandKind::Slot, true, true, )); @@ -1135,6 +1127,6 @@ fn add_relaxed_simd_ops(isa: &mut Isa) { BinaryOpKind::F64x2RelaxedNmadd, ]; for kind in kinds { - isa.push_op(BinaryOp::new(kind, OperandKind::Stack, OperandKind::Stack)); + isa.push_op(BinaryOp::new(kind, OperandKind::Slot, OperandKind::Slot)); } } diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index 9c54f1f823..e9050d3cba 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -70,8 +70,8 @@ impl Display for Field { /// The kind of an operand of an [`Op`]. #[derive(Copy, Clone)] pub enum OperandKind { - /// The operand is a [`Stack`] index. - Stack, + /// The operand is a [`Slot`] index. + Slot, /// The operand is an immediate value. Immediate, } @@ -79,7 +79,7 @@ pub enum OperandKind { impl Display for CamelCase { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let s = match self.0 { - OperandKind::Stack => "S", + OperandKind::Slot => "S", OperandKind::Immediate => "I", }; write!(f, "{s}") @@ -89,7 +89,7 @@ impl Display for CamelCase { impl Display for SnakeCase { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let s = match self.0 { - OperandKind::Stack => "s", + OperandKind::Slot => "s", OperandKind::Immediate => "i", }; write!(f, "{s}") @@ -126,12 +126,12 @@ impl UnaryOp { } pub fn result_field(&self) -> Field { - Field::new(Ident::Result, FieldTy::Stack) + Field::new(Ident::Result, FieldTy::Slot) } pub fn value_field(&self) -> Field { let ty = match self.value { - OperandKind::Stack => FieldTy::Stack, + OperandKind::Slot => FieldTy::Slot, OperandKind::Immediate => { let value_ty = self.kind.value_ty(); match value_ty.to_field_ty() { @@ -636,7 +636,7 @@ impl BinaryOp { } pub fn result_field(&self) -> Field { - Field::new(Ident::Result, FieldTy::Stack) + Field::new(Ident::Result, FieldTy::Slot) } pub fn lhs_field(&self) -> Field { @@ -1166,7 +1166,7 @@ impl BinaryOpKind { fn lhs_field(&self, input: OperandKind) -> FieldTy { match input { - OperandKind::Stack => FieldTy::Stack, + OperandKind::Slot => FieldTy::Slot, OperandKind::Immediate => match self { | Self::Cmp(cmp) => cmp.input_field(input), | Self::I32Add @@ -1220,7 +1220,7 @@ impl BinaryOpKind { fn rhs_field(&self, input: OperandKind) -> FieldTy { match input { - OperandKind::Stack => FieldTy::Stack, + OperandKind::Slot => FieldTy::Slot, OperandKind::Immediate => match self { | Self::Cmp(cmp) => cmp.input_field(input), | Self::I32Add @@ -1340,7 +1340,7 @@ impl CmpSelectOp { } pub fn result_field(&self) -> Field { - Field::new(Ident::Result, FieldTy::Stack) + Field::new(Ident::Result, FieldTy::Slot) } pub fn lhs_field(&self) -> Field { @@ -1352,11 +1352,11 @@ impl CmpSelectOp { } pub fn val_true_field(&self) -> Field { - Field::new(Ident::ValTrue, FieldTy::Stack) + Field::new(Ident::ValTrue, FieldTy::Slot) } pub fn val_false_field(&self) -> Field { - Field::new(Ident::ValFalse, FieldTy::Stack) + Field::new(Ident::ValFalse, FieldTy::Slot) } pub fn fields(&self) -> [Field; 5] { @@ -1513,9 +1513,9 @@ impl Display for CamelCase { #[derive(Copy, Clone)] pub enum FieldTy { - Stack, - StackSpan, - FixedStackSpan2, + Slot, + SlotSpan, + FixedSlotSpan2, U8, U16, U32, @@ -1555,9 +1555,9 @@ pub enum FieldTy { impl Display for FieldTy { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let s = match self { - Self::Stack => "Stack", - Self::StackSpan => "StackSpan", - Self::FixedStackSpan2 => "FixedStackSpan<2>", + Self::Slot => "Slot", + Self::SlotSpan => "SlotSpan", + Self::FixedSlotSpan2 => "FixedSlotSpan<2>", Self::U8 => "u8", Self::U16 => "u16", Self::U32 => "u32", @@ -1661,7 +1661,7 @@ impl CmpOpKind { fn input_field(&self, input: OperandKind) -> FieldTy { match input { - OperandKind::Stack => FieldTy::Stack, + OperandKind::Slot => FieldTy::Slot, OperandKind::Immediate => match self { | Self::I32Eq | Self::I32NotEq @@ -1791,12 +1791,12 @@ impl LoadOp { } pub fn result_field(&self) -> Field { - Field::new(Ident::Result, FieldTy::Stack) + Field::new(Ident::Result, FieldTy::Slot) } pub fn ptr_field(&self) -> Field { let ptr_ty = match self.ptr { - OperandKind::Stack => FieldTy::Stack, + OperandKind::Slot => FieldTy::Slot, OperandKind::Immediate => FieldTy::Address, }; Field::new(Ident::Ptr, ptr_ty) @@ -1804,7 +1804,7 @@ impl LoadOp { pub fn offset_field(&self) -> Option { let offset_ty = match self.ptr { - OperandKind::Stack => match self.offset16 { + OperandKind::Slot => match self.offset16 { true => FieldTy::Offset16, false => FieldTy::U64, }, @@ -1956,7 +1956,7 @@ impl StoreOp { pub fn ptr_field(&self) -> Field { let ptr_ty = match self.ptr { - OperandKind::Stack => FieldTy::Stack, + OperandKind::Slot => FieldTy::Slot, OperandKind::Immediate => FieldTy::Address, }; Field::new(Ident::Ptr, ptr_ty) @@ -1964,7 +1964,7 @@ impl StoreOp { pub fn offset_field(&self) -> Option { let offset_ty = match self.ptr { - OperandKind::Stack => match self.offset16 { + OperandKind::Slot => match self.offset16 { true => FieldTy::Offset16, false => FieldTy::U64, }, @@ -2058,7 +2058,7 @@ impl StoreOpKind { fn value_ty(&self, input: OperandKind) -> FieldTy { match input { - OperandKind::Stack => FieldTy::Stack, + OperandKind::Slot => FieldTy::Slot, OperandKind::Immediate => match self { Self::Store32 => FieldTy::U32, Self::Store64 => FieldTy::U64, @@ -2100,12 +2100,12 @@ impl TableGetOp { } pub fn result_field(&self) -> Field { - Field::new(Ident::Result, FieldTy::Stack) + Field::new(Ident::Result, FieldTy::Slot) } pub fn index_field(&self) -> Field { let index_ty = match self.index { - OperandKind::Stack => FieldTy::Stack, + OperandKind::Slot => FieldTy::Slot, OperandKind::Immediate => FieldTy::U32, }; Field::new(Ident::Index, index_ty) @@ -2135,7 +2135,7 @@ impl TableSetOp { pub fn index_field(&self) -> Field { let index_ty = match self.index { - OperandKind::Stack => FieldTy::Stack, + OperandKind::Slot => FieldTy::Slot, OperandKind::Immediate => FieldTy::U32, }; Field::new(Ident::Index, index_ty) @@ -2143,7 +2143,7 @@ impl TableSetOp { pub fn value_field(&self) -> Field { let value_ty = match self.value { - OperandKind::Stack => FieldTy::Stack, + OperandKind::Slot => FieldTy::Slot, OperandKind::Immediate => FieldTy::U64, }; Field::new(Ident::Value, value_ty) @@ -2219,16 +2219,16 @@ impl V128ReplaceLaneOp { } pub fn result_field(&self) -> Field { - Field::new(Ident::Result, FieldTy::Stack) + Field::new(Ident::Result, FieldTy::Slot) } pub fn v128_field(&self) -> Field { - Field::new(Ident::V128, FieldTy::Stack) + Field::new(Ident::V128, FieldTy::Slot) } pub fn value_field(&self) -> Field { let value_ty = match self.value { - OperandKind::Stack => FieldTy::Stack, + OperandKind::Slot => FieldTy::Slot, OperandKind::Immediate => match self.width { LaneWidth::W8 => FieldTy::U8, LaneWidth::W16 => FieldTy::U16, @@ -2282,12 +2282,12 @@ impl V128LoadLaneOp { } pub fn result_field(&self) -> Field { - Field::new(Ident::Result, FieldTy::Stack) + Field::new(Ident::Result, FieldTy::Slot) } pub fn ptr_field(&self) -> Field { let ptr_ty = match self.ptr { - OperandKind::Stack => FieldTy::Stack, + OperandKind::Slot => FieldTy::Slot, OperandKind::Immediate => FieldTy::Address, }; Field::new(Ident::Ptr, ptr_ty) @@ -2295,7 +2295,7 @@ impl V128LoadLaneOp { pub fn offset_field(&self) -> Option { let offset_ty = match self.ptr { - OperandKind::Stack => match self.offset16 { + OperandKind::Slot => match self.offset16 { true => FieldTy::Offset16, false => FieldTy::U64, }, @@ -2305,7 +2305,7 @@ impl V128LoadLaneOp { } pub fn v128_field(&self) -> Field { - Field::new(Ident::V128, FieldTy::Stack) + Field::new(Ident::V128, FieldTy::Slot) } pub fn memory_field(&self) -> Option { diff --git a/crates/ir2/src/decode/mod.rs b/crates/ir2/src/decode/mod.rs index 124910f871..4ee290e9b0 100644 --- a/crates/ir2/src/decode/mod.rs +++ b/crates/ir2/src/decode/mod.rs @@ -31,13 +31,13 @@ use crate::{ index::{Data, Elem, Func, FuncType, Global, InternalFunc, Memory, Table}, Address, BlockFuel, - BoundedStackSpan, + BoundedSlotSpan, BranchOffset, - FixedStackSpan, + FixedSlotSpan, Offset16, Sign, - Stack, - StackSpan, + Slot, + SlotSpan, }; use core::{mem, num::NonZero}; @@ -59,9 +59,9 @@ pub trait Decode { unsafe fn decode(decoder: &mut D) -> Self; } -impl Decode for BoundedStackSpan { +impl Decode for BoundedSlotSpan { unsafe fn decode(decoder: &mut D) -> Self { - let span = ::decode(decoder); + let span = ::decode(decoder); let len = u16::decode(decoder); Self::new(span, len) } @@ -104,7 +104,7 @@ impl_decode_using! { Sign as bool = Sign::new, Sign as bool = Sign::new, - Stack as u16 = Into::into, + Slot as u16 = Into::into, Func as u32 = Into::into, FuncType as u32 = Into::into, InternalFunc as u32 = Into::into, @@ -114,8 +114,8 @@ impl_decode_using! { Data as u32 = Into::into, Elem as u32 = Into::into, - StackSpan as Stack = StackSpan::new, - FixedStackSpan<2> as StackSpan = |span| unsafe { >::new_unchecked(span) }, + SlotSpan as Slot = SlotSpan::new, + FixedSlotSpan<2> as SlotSpan = |span| unsafe { >::new_unchecked(span) }, NonZero as u32 = |value| unsafe { NonZero::new_unchecked(value) }, NonZero as u64 = |value| unsafe { NonZero::new_unchecked(value) }, diff --git a/crates/ir2/src/decode/op.rs b/crates/ir2/src/decode/op.rs index d40912ac80..7ddd378eef 100644 --- a/crates/ir2/src/decode/op.rs +++ b/crates/ir2/src/decode/op.rs @@ -7,12 +7,12 @@ use crate::{ Decode, Decoder, Offset16, - Stack, + Slot, }; #[derive(Copy, Clone)] pub struct UnaryOp { - pub result: Stack, + pub result: Slot, pub value: V, } @@ -27,7 +27,7 @@ impl Decode for UnaryOp { #[derive(Copy, Clone)] pub struct BinaryOp { - pub result: Stack, + pub result: Slot, pub lhs: Lhs, pub rhs: Rhs, } @@ -69,11 +69,11 @@ where #[derive(Copy, Clone)] pub struct CmpSelectOp { - pub result: Stack, + pub result: Slot, pub lhs: Lhs, pub rhs: Rhs, - pub val_true: Stack, - pub val_false: Stack, + pub val_true: Slot, + pub val_false: Slot, } impl Decode for CmpSelectOp @@ -94,8 +94,8 @@ where #[derive(Copy, Clone)] pub struct LoadOp_Ss { - pub result: Stack, - pub ptr: Stack, + pub result: Slot, + pub ptr: Slot, pub offset: u64, pub memory: Memory, } @@ -113,7 +113,7 @@ impl Decode for LoadOp_Ss { #[derive(Copy, Clone)] pub struct LoadOp_Si { - pub result: Stack, + pub result: Slot, pub address: Address, pub memory: Memory, } @@ -130,8 +130,8 @@ impl Decode for LoadOp_Si { #[derive(Copy, Clone)] pub struct LoadOpMem0Offset16_Ss { - pub result: Stack, - pub ptr: Stack, + pub result: Slot, + pub ptr: Slot, pub offset: Offset16, } @@ -147,7 +147,7 @@ impl Decode for LoadOpMem0Offset16_Ss { #[derive(Copy, Clone)] pub struct StoreOp_S { - pub ptr: Stack, + pub ptr: Slot, pub offset: u64, pub value: T, pub memory: Memory, @@ -183,7 +183,7 @@ impl Decode for StoreOp_I { #[derive(Copy, Clone)] pub struct StoreOpMem0Offset16_S { - pub ptr: Stack, + pub ptr: Slot, pub offset: Offset16, pub value: T, } @@ -201,7 +201,7 @@ impl Decode for StoreOpMem0Offset16_S { #[derive(Copy, Clone)] #[cfg(feature = "simd")] pub struct StoreLaneOp_S { - pub ptr: Stack, + pub ptr: Slot, pub offset: u64, pub value: T, pub memory: Memory, @@ -224,7 +224,7 @@ impl Decode for StoreLaneOp_S { #[derive(Copy, Clone)] #[cfg(feature = "simd")] pub struct StoreLaneOpMem0Offset16_S { - pub ptr: Stack, + pub ptr: Slot, pub offset: Offset16, pub value: T, pub lane: LaneIdx, @@ -244,7 +244,7 @@ impl Decode for StoreLaneOpMem0Offset16_S { - pub result: Stack, + pub result: Slot, pub index: T, pub table: Table, } @@ -279,8 +279,8 @@ impl Decode for TableSet { #[derive(Copy, Clone)] #[cfg(feature = "simd")] pub struct V128ReplaceLaneOp { - pub result: Stack, - pub v128: Stack, + pub result: Slot, + pub v128: Slot, pub value: V, pub lane: ImmLaneIdx, } @@ -300,11 +300,11 @@ impl Decode for V128ReplaceLaneOp { #[derive(Copy, Clone)] #[cfg(feature = "simd")] pub struct V128LoadLaneOp_Ss { - pub result: Stack, - pub ptr: Stack, + pub result: Slot, + pub ptr: Slot, pub offset: u64, pub memory: Memory, - pub v128: Stack, + pub v128: Slot, pub lane: LaneIdx, } @@ -325,10 +325,10 @@ impl Decode for V128LoadLaneOp_Ss { #[derive(Copy, Clone)] #[cfg(feature = "simd")] pub struct V128LoadLaneOpMem0Offset16_Ss { - pub result: Stack, - pub ptr: Stack, + pub result: Slot, + pub ptr: Slot, pub offset: Offset16, - pub v128: Stack, + pub v128: Slot, pub lane: LaneIdx, } diff --git a/crates/ir2/src/encode.rs b/crates/ir2/src/encode.rs index e343f8ff26..7a467040d9 100644 --- a/crates/ir2/src/encode.rs +++ b/crates/ir2/src/encode.rs @@ -5,15 +5,15 @@ use crate::{ index::{Data, Elem, Func, FuncType, Global, InternalFunc, Memory, Table}, Address, BlockFuel, - BoundedStackSpan, + BoundedSlotSpan, BranchOffset, - FixedStackSpan, + FixedSlotSpan, Offset16, Op, OpCode, Sign, - Stack, - StackSpan, + Slot, + SlotSpan, }; use core::num::NonZero; @@ -79,7 +79,7 @@ impl Encode for BranchOffset { } } -impl Encode for BoundedStackSpan { +impl Encode for BoundedSlotSpan { fn encode(&self, encoder: &mut E) -> Result where E: Encoder, @@ -131,7 +131,7 @@ impl_encode_using! { Sign as bool = Sign::is_positive, Sign as bool = Sign::is_positive, - Stack as u16 = Into::into, + Slot as u16 = Into::into, Func as u32 = Into::into, FuncType as u32 = Into::into, InternalFunc as u32 = Into::into, @@ -141,8 +141,8 @@ impl_encode_using! { Data as u32 = Into::into, Elem as u32 = Into::into, - StackSpan as Stack = StackSpan::head, - FixedStackSpan<2> as StackSpan = >::span, + SlotSpan as Slot = SlotSpan::head, + FixedSlotSpan<2> as SlotSpan = >::span, NonZero as u32 = NonZero::get, NonZero as u64 = NonZero::get, diff --git a/crates/ir2/src/error.rs b/crates/ir2/src/error.rs index 4b56657145..b515b23f3a 100644 --- a/crates/ir2/src/error.rs +++ b/crates/ir2/src/error.rs @@ -3,7 +3,7 @@ use core::fmt; /// An error that may be occurred when operating with some Wasmi IR primitives. #[derive(Debug)] pub enum Error { - /// Encountered when trying to create a [`Stack`](crate::Stack) from an out of bounds integer. + /// Encountered when trying to create a [`Slot`](crate::Slot) from an out of bounds integer. StackSlotOutOfBounds, /// Encountered when trying to create a [`BranchOffset`](crate::BranchOffset) from an out of bounds integer. BranchOffsetOutOfBounds, diff --git a/crates/ir2/src/index.rs b/crates/ir2/src/index.rs index f996b6b941..aed5db1503 100644 --- a/crates/ir2/src/index.rs +++ b/crates/ir2/src/index.rs @@ -6,7 +6,7 @@ macro_rules! for_each_index { ($mac:ident) => { $mac! { /// A Wasmi stack slot. - Stack(pub(crate) u16); + Slot(pub(crate) u16); /// A Wasm function index. Func(pub(crate) u32); /// A Wasm function type index. @@ -62,7 +62,7 @@ macro_rules! define_index { } for_each_index!(define_index); -impl TryFrom for Stack { +impl TryFrom for Slot { type Error = Error; fn try_from(local_index: u32) -> Result { @@ -72,8 +72,8 @@ impl TryFrom for Stack { } } -impl Stack { - /// Returns the n-th next [`Stack`] from `self` with contiguous index. +impl Slot { + /// Returns the n-th next [`Slot`] from `self` with contiguous index. /// /// # Note /// @@ -83,7 +83,7 @@ impl Stack { Self(self.0.wrapping_add(n)) } - /// Returns the n-th previous [`Stack`] from `self` with contiguous index. + /// Returns the n-th previous [`Slot`] from `self` with contiguous index. /// /// # Note /// @@ -93,12 +93,12 @@ impl Stack { Self(self.0.wrapping_sub(n)) } - /// Returns the [`Stack`] with the next contiguous index. + /// Returns the [`Slot`] with the next contiguous index. pub fn next(self) -> Self { self.next_n(1) } - /// Returns the [`Stack`] with the previous contiguous index. + /// Returns the [`Slot`] with the previous contiguous index. pub fn prev(self) -> Self { self.prev_n(1) } diff --git a/crates/ir2/src/lib.rs b/crates/ir2/src/lib.rs index d245b87ffd..fa88360f72 100644 --- a/crates/ir2/src/lib.rs +++ b/crates/ir2/src/lib.rs @@ -19,8 +19,8 @@ pub use self::{ decode::{Decode, Decoder}, encode::{Encode, Encoder}, error::Error, - index::Stack, + index::Slot, op::{Op, OpCode}, primitive::{Address, BlockFuel, BranchOffset, Offset16, Sign}, - span::{BoundedStackSpan, FixedStackSpan, StackSpan, StackSpanIter}, + span::{BoundedSlotSpan, FixedSlotSpan, SlotSpan, SlotSpanIter}, }; diff --git a/crates/ir2/src/op.rs b/crates/ir2/src/op.rs index 184c77f60f..576340787a 100644 --- a/crates/ir2/src/op.rs +++ b/crates/ir2/src/op.rs @@ -6,11 +6,11 @@ use crate::{ Address, BlockFuel, BranchOffset, - FixedStackSpan, + FixedSlotSpan, Offset16, Sign, - Stack, - StackSpan, + Slot, + SlotSpan, }; use core::num::NonZero; diff --git a/crates/ir2/src/span.rs b/crates/ir2/src/span.rs index a8c5dc1f41..b209f4bf67 100644 --- a/crates/ir2/src/span.rs +++ b/crates/ir2/src/span.rs @@ -1,45 +1,45 @@ -use crate::{Error, Stack}; +use crate::{Error, Slot}; -/// A [`StackSpan`] of contiguous [`Stack`] indices. +/// A [`SlotSpan`] of contiguous [`Slot`] indices. /// /// # Note /// -/// - Represents an amount of contiguous [`Stack`] indices. -/// - For the sake of space efficiency the actual number of [`Stack`] -/// of the [`StackSpan`] is stored externally and provided in -/// [`StackSpan::iter`] when there is a need to iterate over -/// the [`Stack`] of the [`StackSpan`]. +/// - Represents an amount of contiguous [`Slot`] indices. +/// - For the sake of space efficiency the actual number of [`Slot`] +/// of the [`SlotSpan`] is stored externally and provided in +/// [`SlotSpan::iter`] when there is a need to iterate over +/// the [`Slot`] of the [`SlotSpan`]. /// /// The caller is responsible for providing the correct length. /// Due to Wasm validation guided bytecode construction we assert /// that the externally stored length is valid. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] #[repr(transparent)] -pub struct StackSpan(Stack); +pub struct SlotSpan(Slot); -impl StackSpan { - /// Creates a new [`StackSpan`] starting with the given `start` [`Stack`]. - pub fn new(head: Stack) -> Self { +impl SlotSpan { + /// Creates a new [`SlotSpan`] starting with the given `start` [`Slot`]. + pub fn new(head: Slot) -> Self { Self(head) } - /// Returns a [`StackSpanIter`] yielding `len` [`Stack`]s. - pub fn iter_sized(self, len: usize) -> StackSpanIter { - StackSpanIter::new(self.0, len) + /// Returns a [`SlotSpanIter`] yielding `len` [`Slot`]s. + pub fn iter_sized(self, len: usize) -> SlotSpanIter { + SlotSpanIter::new(self.0, len) } - /// Returns a [`StackSpanIter`] yielding `len` [`Stack`]s. - pub fn iter(self, len: u16) -> StackSpanIter { - StackSpanIter::new_u16(self.0, len) + /// Returns a [`SlotSpanIter`] yielding `len` [`Slot`]s. + pub fn iter(self, len: u16) -> SlotSpanIter { + SlotSpanIter::new_u16(self.0, len) } - /// Returns the head [`Stack`] of the [`StackSpan`]. - pub fn head(self) -> Stack { + /// Returns the head [`Slot`] of the [`SlotSpan`]. + pub fn head(self) -> Slot { self.0 } - /// Returns an exclusive reference to the head [`Stack`] of the [`StackSpan`]. - pub fn head_mut(&mut self) -> &mut Stack { + /// Returns an exclusive reference to the head [`Slot`] of the [`SlotSpan`]. + pub fn head_mut(&mut self) -> &mut Slot { &mut self.0 } @@ -52,21 +52,21 @@ impl StackSpan { /// - `[ 0 <- 1, 1 <- 2, 2 <- 3 ]`: no overlap /// - `[ 1 <- 0, 2 <- 1 ]`: overlaps! pub fn has_overlapping_copies(results: Self, values: Self, len: u16) -> bool { - StackSpanIter::has_overlapping_copies(results.iter(len), values.iter(len)) + SlotSpanIter::has_overlapping_copies(results.iter(len), values.iter(len)) } } -/// A [`StackSpan`] with a statically known number of [`Stack`]. +/// A [`SlotSpan`] with a statically known number of [`Slot`]. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] #[repr(transparent)] -pub struct FixedStackSpan { - /// The underlying [`StackSpan`] without the known length. - span: StackSpan, +pub struct FixedSlotSpan { + /// The underlying [`SlotSpan`] without the known length. + span: SlotSpan, } -impl FixedStackSpan<2> { +impl FixedSlotSpan<2> { /// Returns an array of the results represented by `self`. - pub fn to_array(self) -> [Stack; 2] { + pub fn to_array(self) -> [Slot; 2] { let span = self.span(); let fst = span.head(); let snd = fst.next(); @@ -74,9 +74,9 @@ impl FixedStackSpan<2> { } } -impl FixedStackSpan { - /// Creates a new [`StackSpan`] starting with the given `start` [`Stack`]. - pub fn new(span: StackSpan) -> Result { +impl FixedSlotSpan { + /// Creates a new [`SlotSpan`] starting with the given `start` [`Slot`]. + pub fn new(span: SlotSpan) -> Result { let head = span.head(); if head >= head.next_n(N) { return Err(Error::StackSlotOutOfBounds); @@ -84,40 +84,40 @@ impl FixedStackSpan { Ok(Self { span }) } - /// Creates a new [`StackSpan`] starting with the given `start` [`Stack`]. + /// Creates a new [`SlotSpan`] starting with the given `start` [`Slot`]. /// /// # Safety /// /// The caller is responsible for making sure that `span` is valid for a length of `N`. - pub unsafe fn new_unchecked(span: StackSpan) -> Self { + pub unsafe fn new_unchecked(span: SlotSpan) -> Self { Self { span } } - /// Returns a [`StackSpanIter`] yielding `N` [`Stack`]s. - pub fn iter(&self) -> StackSpanIter { + /// Returns a [`SlotSpanIter`] yielding `N` [`Slot`]s. + pub fn iter(&self) -> SlotSpanIter { self.span.iter(self.len()) } - /// Creates a new [`BoundedStackSpan`] from `self`. - pub fn bounded(self) -> BoundedStackSpan { - BoundedStackSpan { + /// Creates a new [`BoundedSlotSpan`] from `self`. + pub fn bounded(self) -> BoundedSlotSpan { + BoundedSlotSpan { span: self.span, len: N, } } - /// Returns the underlying [`StackSpan`] of `self`. - pub fn span(self) -> StackSpan { + /// Returns the underlying [`SlotSpan`] of `self`. + pub fn span(self) -> SlotSpan { self.span } - /// Returns an exclusive reference to the underlying [`StackSpan`] of `self`. - pub fn span_mut(&mut self) -> &mut StackSpan { + /// Returns an exclusive reference to the underlying [`SlotSpan`] of `self`. + pub fn span_mut(&mut self) -> &mut SlotSpan { &mut self.span } - /// Returns `true` if the [`Stack`] is contained in `self`. - pub fn contains(self, reg: Stack) -> bool { + /// Returns `true` if the [`Slot`] is contained in `self`. + pub fn contains(self, reg: Slot) -> bool { if self.is_empty() { return false; } @@ -126,7 +126,7 @@ impl FixedStackSpan { min <= reg && reg < max } - /// Returns the number of [`Stack`]s in `self`. + /// Returns the number of [`Slot`]s in `self`. pub fn len(self) -> u16 { N } @@ -137,56 +137,56 @@ impl FixedStackSpan { } } -impl IntoIterator for &FixedStackSpan { - type Item = Stack; - type IntoIter = StackSpanIter; +impl IntoIterator for &FixedSlotSpan { + type Item = Slot; + type IntoIter = SlotSpanIter; fn into_iter(self) -> Self::IntoIter { self.iter() } } -impl IntoIterator for FixedStackSpan { - type Item = Stack; - type IntoIter = StackSpanIter; +impl IntoIterator for FixedSlotSpan { + type Item = Slot; + type IntoIter = SlotSpanIter; fn into_iter(self) -> Self::IntoIter { self.iter() } } -/// A [`StackSpan`] with a known number of [`Stack`]. +/// A [`SlotSpan`] with a known number of [`Slot`]. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct BoundedStackSpan { - /// The first [`Stack`] in `self`. - span: StackSpan, - /// The number of [`Stack`] in `self`. +pub struct BoundedSlotSpan { + /// The first [`Slot`] in `self`. + span: SlotSpan, + /// The number of [`Slot`] in `self`. len: u16, } -impl BoundedStackSpan { - /// Creates a new [`BoundedStackSpan`] from the given `span` and `len`. - pub fn new(span: StackSpan, len: u16) -> Self { +impl BoundedSlotSpan { + /// Creates a new [`BoundedSlotSpan`] from the given `span` and `len`. + pub fn new(span: SlotSpan, len: u16) -> Self { Self { span, len } } - /// Returns a [`StackSpanIter`] yielding `len` [`Stack`]s. - pub fn iter(&self) -> StackSpanIter { + /// Returns a [`SlotSpanIter`] yielding `len` [`Slot`]s. + pub fn iter(&self) -> SlotSpanIter { self.span.iter(self.len()) } - /// Returns `self` as unbounded [`StackSpan`]. - pub fn span(&self) -> StackSpan { + /// Returns `self` as unbounded [`SlotSpan`]. + pub fn span(&self) -> SlotSpan { self.span } - /// Returns a mutable reference to the underlying [`StackSpan`]. - pub fn span_mut(&mut self) -> &mut StackSpan { + /// Returns a mutable reference to the underlying [`SlotSpan`]. + pub fn span_mut(&mut self) -> &mut SlotSpan { &mut self.span } - /// Returns `true` if the [`Stack`] is contained in `self`. - pub fn contains(self, reg: Stack) -> bool { + /// Returns `true` if the [`Slot`] is contained in `self`. + pub fn contains(self, reg: Slot) -> bool { if self.is_empty() { return false; } @@ -195,7 +195,7 @@ impl BoundedStackSpan { min <= reg && reg < max } - /// Returns the number of [`Stack`] in `self`. + /// Returns the number of [`Slot`] in `self`. pub fn len(&self) -> u16 { self.len } @@ -206,36 +206,36 @@ impl BoundedStackSpan { } } -impl IntoIterator for &BoundedStackSpan { - type Item = Stack; - type IntoIter = StackSpanIter; +impl IntoIterator for &BoundedSlotSpan { + type Item = Slot; + type IntoIter = SlotSpanIter; fn into_iter(self) -> Self::IntoIter { self.iter() } } -impl IntoIterator for BoundedStackSpan { - type Item = Stack; - type IntoIter = StackSpanIter; +impl IntoIterator for BoundedSlotSpan { + type Item = Slot; + type IntoIter = SlotSpanIter; fn into_iter(self) -> Self::IntoIter { self.iter() } } -/// A [`StackSpanIter`] iterator yielding contiguous [`Stack`]. +/// A [`SlotSpanIter`] iterator yielding contiguous [`Slot`]. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct StackSpanIter { - /// The next [`Stack`] in the [`StackSpanIter`]. - next: Stack, - /// The last [`Stack`] in the [`StackSpanIter`]. - last: Stack, +pub struct SlotSpanIter { + /// The next [`Slot`] in the [`SlotSpanIter`]. + next: Slot, + /// The last [`Slot`] in the [`SlotSpanIter`]. + last: Slot, } -impl StackSpanIter { - /// Creates a [`StackSpanIter`] from then given raw `start` and `end` [`Stack`]. - pub fn from_raw_parts(start: Stack, end: Stack) -> Self { +impl SlotSpanIter { + /// Creates a [`SlotSpanIter`] from then given raw `start` and `end` [`Slot`]. + pub fn from_raw_parts(start: Slot, end: Slot) -> Self { debug_assert!(u16::from(start) <= u16::from(end)); Self { next: start, @@ -243,43 +243,43 @@ impl StackSpanIter { } } - /// Creates a new [`StackSpanIter`] for the given `start` [`Stack`] and length `len`. + /// Creates a new [`SlotSpanIter`] for the given `start` [`Slot`] and length `len`. /// /// # Panics /// - /// If the `start..end` [`Stack`] span indices are out of bounds. - fn new(start: Stack, len: usize) -> Self { + /// If the `start..end` [`Slot`] span indices are out of bounds. + fn new(start: Slot, len: usize) -> Self { let len = u16::try_from(len) .unwrap_or_else(|_| panic!("out of bounds length for register span: {len}")); Self::new_u16(start, len) } - /// Creates a new [`StackSpanIter`] for the given `start` [`Stack`] and length `len`. + /// Creates a new [`SlotSpanIter`] for the given `start` [`Slot`] and length `len`. /// /// # Panics /// - /// If the `start..end` [`Stack`] span indices are out of bounds. - fn new_u16(start: Stack, len: u16) -> Self { + /// If the `start..end` [`Slot`] span indices are out of bounds. + fn new_u16(start: Slot, len: u16) -> Self { let next = start; let last = start .0 .checked_add(len) - .map(Stack) + .map(Slot) .expect("overflowing register index for register span"); Self::from_raw_parts(next, last) } - /// Creates a [`StackSpan`] from this [`StackSpanIter`]. - pub fn span(self) -> StackSpan { - StackSpan(self.next) + /// Creates a [`SlotSpan`] from this [`SlotSpanIter`]. + pub fn span(self) -> SlotSpan { + SlotSpan(self.next) } - /// Returns the remaining number of [`Stack`]s yielded by the [`StackSpanIter`]. + /// Returns the remaining number of [`Slot`]s yielded by the [`SlotSpanIter`]. pub fn len_as_u16(&self) -> u16 { self.last.0.abs_diff(self.next.0) } - /// Returns `true` if `self` yields no more [`Stack`]s. + /// Returns `true` if `self` yields no more [`Slot`]s. pub fn is_empty(&self) -> bool { self.len_as_u16() == 0 } @@ -317,8 +317,8 @@ impl StackSpanIter { } } -impl Iterator for StackSpanIter { - type Item = Stack; +impl Iterator for SlotSpanIter { + type Item = Slot; fn next(&mut self) -> Option { if self.next == self.last { @@ -330,7 +330,7 @@ impl Iterator for StackSpanIter { } } -impl DoubleEndedIterator for StackSpanIter { +impl DoubleEndedIterator for SlotSpanIter { fn next_back(&mut self) -> Option { if self.next == self.last { return None; @@ -340,8 +340,8 @@ impl DoubleEndedIterator for StackSpanIter { } } -impl ExactSizeIterator for StackSpanIter { +impl ExactSizeIterator for SlotSpanIter { fn len(&self) -> usize { - usize::from(StackSpanIter::len_as_u16(self)) + usize::from(SlotSpanIter::len_as_u16(self)) } } From 6f8c52037ecd2a38ec7abbc459feacf003819dbc Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 3 Sep 2025 10:36:30 +0200 Subject: [PATCH 167/186] add TryFrom impl for OpCode --- crates/ir2/build/display/op_code.rs | 32 +++++++++++++++++++++++++++-- crates/ir2/build/mod.rs | 4 ++-- crates/ir2/src/lib.rs | 2 +- crates/ir2/src/op.rs | 4 ++++ 4 files changed, 37 insertions(+), 5 deletions(-) diff --git a/crates/ir2/build/display/op_code.rs b/crates/ir2/build/display/op_code.rs index 8867aaaa4d..00a0e21863 100644 --- a/crates/ir2/build/display/op_code.rs +++ b/crates/ir2/build/display/op_code.rs @@ -31,13 +31,21 @@ impl Display for DisplayOpCode<&'_ Isa> { .map(|op| (indent.inc(), DisplayIdent::camel(op))) .map(DisplayConcat), ); - let match_arms = DisplaySequence::new( + let match_arms_code = DisplaySequence::new( ",\n", self.value .ops .iter() .map(|op| DisplayOpCode::new(op, indent.inc_by(3))), ); + let match_arms_tryfrom = DisplaySequence::new( + ",\n", + self.value + .ops + .iter() + .map(DisplayTryFromU16) + .map(|op| DisplayOpCode::new(op, indent.inc_by(3))), + ); write!( f, "\ @@ -50,10 +58,21 @@ impl Display for DisplayOpCode<&'_ Isa> { {indent}impl Op {{\n\ {indent} pub fn code(&self) -> OpCode {{\n\ {indent} match self {{\n\ - {match_arms}\n\ + {match_arms_code}\n\ {indent} }}\n\ {indent} }}\n\ {indent}}}\n\ + \n\ + {indent}impl TryFrom for OpCode {{\n\ + {indent} type Error = InvalidOpCode;\n\ + {indent} fn try_from(value: u16) -> Result {{\n\ + {indent} let op_code = match value {{\n\ + {match_arms_tryfrom},\n\ + {indent} _ => return Err(InvalidOpCode),\n\ + {indent} }};\n\ + {indent} Ok(op_code)\n\ + {indent} }}\n\ + {indent}}}\n\ " ) } @@ -66,3 +85,12 @@ impl Display for DisplayOpCode<&'_ Op> { write!(f, "{indent}Self::{ident} {{ .. }} => OpCode::{ident}") } } + +pub struct DisplayTryFromU16(T); +impl Display for DisplayOpCode> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let indent = self.indent; + let ident = DisplayIdent::camel(self.value.0); + write!(f, "{indent}x if x == Self::{ident} as _ => Self::{ident}") + } +} diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index 47f577beb7..cd8ab16555 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -74,8 +74,8 @@ pub fn generate_code(config: &Config) -> Result<(), Error> { fn generate_op_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<(), Error> { let expected_size = match config.simd { - true => 275_000, - false => 175_000, + true => 330_000, + false => 210_000, }; write_to_buffer(contents, expected_size, |buffer| { write!( diff --git a/crates/ir2/src/lib.rs b/crates/ir2/src/lib.rs index fa88360f72..b4c1d5cf74 100644 --- a/crates/ir2/src/lib.rs +++ b/crates/ir2/src/lib.rs @@ -20,7 +20,7 @@ pub use self::{ encode::{Encode, Encoder}, error::Error, index::Slot, - op::{Op, OpCode}, + op::{InvalidOpCode, Op, OpCode}, primitive::{Address, BlockFuel, BranchOffset, Offset16, Sign}, span::{BoundedSlotSpan, FixedSlotSpan, SlotSpan, SlotSpanIter}, }; diff --git a/crates/ir2/src/op.rs b/crates/ir2/src/op.rs index 576340787a..fb350ac427 100644 --- a/crates/ir2/src/op.rs +++ b/crates/ir2/src/op.rs @@ -40,3 +40,7 @@ fn op_size_of_and_alignment() { assert_eq!(core::mem::size_of::(), 24); assert_eq!(core::mem::align_of::(), 8); } + +/// Indicated an invalid `u16` value for an [`OpCode`]. +#[derive(Debug, Copy, Clone)] +pub struct InvalidOpCode; From 1f19cce703df7d9aa389de0c436897ff05973168 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 3 Sep 2025 10:37:30 +0200 Subject: [PATCH 168/186] add Decode impl for OpCode --- crates/ir2/src/decode/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/ir2/src/decode/mod.rs b/crates/ir2/src/decode/mod.rs index 4ee290e9b0..ef0152ebd7 100644 --- a/crates/ir2/src/decode/mod.rs +++ b/crates/ir2/src/decode/mod.rs @@ -35,6 +35,7 @@ use crate::{ BranchOffset, FixedSlotSpan, Offset16, + OpCode, Sign, Slot, SlotSpan, @@ -123,6 +124,9 @@ impl_decode_using! { TrapCode as u8 = |code: u8| -> TrapCode { TrapCode::try_from(code).unwrap_unchecked() }, + OpCode as u16 = |code: u16| -> OpCode { + OpCode::try_from(code).unwrap_unchecked() + } } impl Decode for [T; N] { From fd0dc76b88bdef01a31fdf6728b4a497f43f640f Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 3 Sep 2025 10:47:07 +0200 Subject: [PATCH 169/186] split generated op.rs into op.rs and op_code.rs --- crates/ir2/build/mod.rs | 19 +++++++++++++++---- crates/ir2/src/lib.rs | 4 +++- crates/ir2/src/op.rs | 16 ---------------- crates/ir2/src/opcode.rs | 19 +++++++++++++++++++ 4 files changed, 37 insertions(+), 21 deletions(-) create mode 100644 crates/ir2/src/opcode.rs diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index cd8ab16555..3c98f95908 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -67,6 +67,7 @@ pub fn generate_code(config: &Config) -> Result<(), Error> { let isa = isa::wasmi_isa(config); let mut buffer = String::new(); generate_op_rs(config, &isa, &mut buffer)?; + generate_op_code_rs(config, &isa, &mut buffer)?; generate_encode_rs(config, &isa, &mut buffer)?; generate_decode_rs(config, &isa, &mut buffer)?; Ok(()) @@ -74,8 +75,8 @@ pub fn generate_code(config: &Config) -> Result<(), Error> { fn generate_op_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<(), Error> { let expected_size = match config.simd { - true => 330_000, - false => 210_000, + true => 210_000, + false => 135_000, }; write_to_buffer(contents, expected_size, |buffer| { write!( @@ -84,18 +85,28 @@ fn generate_op_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<( {}\n\ {}\n\ {}\n\ - {}\n\ ", DisplayOp::new(isa, Indent::default()), DisplayResultMut::new(isa, Indent::default()), DisplayConstructor::new(isa, Indent::default()), - DisplayOpCode::new(isa, Indent::default()), ) })?; fs::write(config.out_dir.join("op.rs"), contents)?; Ok(()) } +fn generate_op_code_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<(), Error> { + let expected_size = match config.simd { + true => 125_000, + false => 80_000, + }; + write_to_buffer(contents, expected_size, |buffer| { + writeln!(buffer, "{}", DisplayOpCode::new(isa, Indent::default()),) + })?; + fs::write(config.out_dir.join("op_code.rs"), contents)?; + Ok(()) +} + fn generate_encode_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<(), Error> { let expected_size = match config.simd { true => 115_000, diff --git a/crates/ir2/src/lib.rs b/crates/ir2/src/lib.rs index b4c1d5cf74..9c8a9fd429 100644 --- a/crates/ir2/src/lib.rs +++ b/crates/ir2/src/lib.rs @@ -9,6 +9,7 @@ mod encode; mod error; pub mod index; mod op; +mod opcode; mod primitive; mod span; @@ -20,7 +21,8 @@ pub use self::{ encode::{Encode, Encoder}, error::Error, index::Slot, - op::{InvalidOpCode, Op, OpCode}, + op::Op, + opcode::{InvalidOpCode, OpCode}, primitive::{Address, BlockFuel, BranchOffset, Offset16, Sign}, span::{BoundedSlotSpan, FixedSlotSpan, SlotSpan, SlotSpanIter}, }; diff --git a/crates/ir2/src/op.rs b/crates/ir2/src/op.rs index fb350ac427..4eb10d1c72 100644 --- a/crates/ir2/src/op.rs +++ b/crates/ir2/src/op.rs @@ -23,24 +23,8 @@ impl Clone for Op { } } -impl Copy for OpCode {} -impl Clone for OpCode { - fn clone(&self) -> Self { - *self - } -} -impl From for u16 { - fn from(code: OpCode) -> Self { - code as u16 - } -} - #[test] fn op_size_of_and_alignment() { assert_eq!(core::mem::size_of::(), 24); assert_eq!(core::mem::align_of::(), 8); } - -/// Indicated an invalid `u16` value for an [`OpCode`]. -#[derive(Debug, Copy, Clone)] -pub struct InvalidOpCode; diff --git a/crates/ir2/src/opcode.rs b/crates/ir2/src/opcode.rs new file mode 100644 index 0000000000..e78729c4e0 --- /dev/null +++ b/crates/ir2/src/opcode.rs @@ -0,0 +1,19 @@ +use crate::Op; + +include!(concat!(env!("OUT_DIR"), "/op_code.rs")); + +impl Copy for OpCode {} +impl Clone for OpCode { + fn clone(&self) -> Self { + *self + } +} +impl From for u16 { + fn from(code: OpCode) -> Self { + code as u16 + } +} + +/// Indicated an invalid `u16` value for an [`OpCode`]. +#[derive(Debug, Copy, Clone)] +pub struct InvalidOpCode; From 2a12454ef9f1b1ee0abe87d2103f7bfa76b88037 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 3 Sep 2025 10:54:07 +0200 Subject: [PATCH 170/186] add docs to Op and OpCode types --- crates/ir2/build/display/op.rs | 1 + crates/ir2/build/display/op_code.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/crates/ir2/build/display/op.rs b/crates/ir2/build/display/op.rs index 232a11008d..6f7cb217ac 100644 --- a/crates/ir2/build/display/op.rs +++ b/crates/ir2/build/display/op.rs @@ -79,6 +79,7 @@ impl Display for DisplayOp<&'_ Isa> { write!( f, "\ + {indent}/// A Wasmi bytecode operator or instruction. {indent}#[allow(non_camel_case_types)]\n\ {indent}pub enum Op {{\n\ {variants}\n\ diff --git a/crates/ir2/build/display/op_code.rs b/crates/ir2/build/display/op_code.rs index 00a0e21863..0e2eefab5c 100644 --- a/crates/ir2/build/display/op_code.rs +++ b/crates/ir2/build/display/op_code.rs @@ -50,12 +50,14 @@ impl Display for DisplayOpCode<&'_ Isa> { f, "\ {indent}#[allow(non_camel_case_types)]\n\ + {indent}/// The operator code (op-code) of a Wasmi bytecode [`Op`](crate::Op). {indent}#[repr(u16)]\n\ {indent}pub enum OpCode {{\n\ {variants}\n\ {indent}}}\n\ \n\ {indent}impl Op {{\n\ + {indent} /// Returns the [`OpCode`] associated to `self`. {indent} pub fn code(&self) -> OpCode {{\n\ {indent} match self {{\n\ {match_arms_code}\n\ From cf1e6041e455c23775edb2fe0f97c78d93abd90b Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 3 Sep 2025 11:21:23 +0200 Subject: [PATCH 171/186] fix codegen indentation --- crates/ir2/build/display/op_code.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ir2/build/display/op_code.rs b/crates/ir2/build/display/op_code.rs index 0e2eefab5c..3537b7b746 100644 --- a/crates/ir2/build/display/op_code.rs +++ b/crates/ir2/build/display/op_code.rs @@ -50,7 +50,7 @@ impl Display for DisplayOpCode<&'_ Isa> { f, "\ {indent}#[allow(non_camel_case_types)]\n\ - {indent}/// The operator code (op-code) of a Wasmi bytecode [`Op`](crate::Op). + {indent}/// The operator code (op-code) of a Wasmi bytecode [`Op`].\n\ {indent}#[repr(u16)]\n\ {indent}pub enum OpCode {{\n\ {variants}\n\ From 30b9c2aa5f95ec6f8a519a7ed1e065cc69482b4a Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 3 Sep 2025 12:47:55 +0200 Subject: [PATCH 172/186] add missing f{32,64}.not_{lt,le} operators --- crates/ir2/build/isa.rs | 16 ++++++++++------ crates/ir2/build/mod.rs | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 9190588418..230e0694c8 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -133,10 +133,10 @@ fn add_binary_ops(isa: &mut Isa) { let ops = [ // comparisons: i32 BinaryOpKind::Cmp(CmpOpKind::I32Eq), - BinaryOpKind::Cmp(CmpOpKind::I32NotEq), BinaryOpKind::Cmp(CmpOpKind::I32And), - BinaryOpKind::Cmp(CmpOpKind::I32NotAnd), BinaryOpKind::Cmp(CmpOpKind::I32Or), + BinaryOpKind::Cmp(CmpOpKind::I32NotEq), + BinaryOpKind::Cmp(CmpOpKind::I32NotAnd), BinaryOpKind::Cmp(CmpOpKind::I32NotOr), BinaryOpKind::Cmp(CmpOpKind::S32Lt), BinaryOpKind::Cmp(CmpOpKind::S32Le), @@ -144,10 +144,10 @@ fn add_binary_ops(isa: &mut Isa) { BinaryOpKind::Cmp(CmpOpKind::U32Le), // comparisons: i64 BinaryOpKind::Cmp(CmpOpKind::I64Eq), - BinaryOpKind::Cmp(CmpOpKind::I64NotEq), BinaryOpKind::Cmp(CmpOpKind::I64And), - BinaryOpKind::Cmp(CmpOpKind::I64NotAnd), BinaryOpKind::Cmp(CmpOpKind::I64Or), + BinaryOpKind::Cmp(CmpOpKind::I64NotEq), + BinaryOpKind::Cmp(CmpOpKind::I64NotAnd), BinaryOpKind::Cmp(CmpOpKind::I64NotOr), BinaryOpKind::Cmp(CmpOpKind::S64Lt), BinaryOpKind::Cmp(CmpOpKind::S64Le), @@ -155,14 +155,18 @@ fn add_binary_ops(isa: &mut Isa) { BinaryOpKind::Cmp(CmpOpKind::U64Le), // comparisons: f32 BinaryOpKind::Cmp(CmpOpKind::F32Eq), - BinaryOpKind::Cmp(CmpOpKind::F32NotEq), BinaryOpKind::Cmp(CmpOpKind::F32Lt), BinaryOpKind::Cmp(CmpOpKind::F32Le), + BinaryOpKind::Cmp(CmpOpKind::F32NotEq), + BinaryOpKind::Cmp(CmpOpKind::F32NotLt), + BinaryOpKind::Cmp(CmpOpKind::F32NotLe), // comparisons: f64 BinaryOpKind::Cmp(CmpOpKind::F64Eq), - BinaryOpKind::Cmp(CmpOpKind::F64NotEq), BinaryOpKind::Cmp(CmpOpKind::F64Lt), BinaryOpKind::Cmp(CmpOpKind::F64Le), + BinaryOpKind::Cmp(CmpOpKind::F64NotEq), + BinaryOpKind::Cmp(CmpOpKind::F64NotLt), + BinaryOpKind::Cmp(CmpOpKind::F64NotLe), // i32 BinaryOpKind::I32Add, BinaryOpKind::I32Sub, diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index 3c98f95908..68b3f36ef1 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -110,7 +110,7 @@ fn generate_op_code_rs(config: &Config, isa: &Isa, contents: &mut String) -> Res fn generate_encode_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<(), Error> { let expected_size = match config.simd { true => 115_000, - false => 75_000, + false => 80_000, }; write_to_buffer(contents, expected_size, |buffer| { write!(buffer, "{}", DisplayEncode::new(isa, Indent::default())) From 5cce09d053a49f2aa07b25946dc272c39f98053d Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 3 Sep 2025 12:48:29 +0200 Subject: [PATCH 173/186] bump simd capacity requirements --- crates/ir2/build/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ir2/build/mod.rs b/crates/ir2/build/mod.rs index 68b3f36ef1..6cabdda2bc 100644 --- a/crates/ir2/build/mod.rs +++ b/crates/ir2/build/mod.rs @@ -109,7 +109,7 @@ fn generate_op_code_rs(config: &Config, isa: &Isa, contents: &mut String) -> Res fn generate_encode_rs(config: &Config, isa: &Isa, contents: &mut String) -> Result<(), Error> { let expected_size = match config.simd { - true => 115_000, + true => 120_000, false => 80_000, }; write_to_buffer(contents, expected_size, |buffer| { From 154747919c0dd4af35d893072b5366573508079f Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 4 Sep 2025 13:07:37 +0200 Subject: [PATCH 174/186] fix identifiers of select operators --- crates/ir2/build/display/ident.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/ir2/build/display/ident.rs b/crates/ir2/build/display/ident.rs index 72e39b206d..aa7a3fc5a4 100644 --- a/crates/ir2/build/display/ident.rs +++ b/crates/ir2/build/display/ident.rs @@ -107,6 +107,7 @@ impl Display for DisplayIdent<&'_ CmpSelectOp> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let case = self.case; let cmp = self.value.cmp; + let sep = case.wrap(Sep); let select = case.wrap(Ident::Select); let ident = case.wrap(cmp.ident()); let input_ident = case.wrap(cmp.ident_prefix()); @@ -115,7 +116,7 @@ impl Display for DisplayIdent<&'_ CmpSelectOp> { let rhs_suffix = SnakeCase(self.value.rhs); write!( f, - "{select}{input_ident}{ident}_{result_suffix}{lhs_suffix}{rhs_suffix}" + "{select}{sep}{input_ident}{sep}{ident}_{result_suffix}{lhs_suffix}{rhs_suffix}" ) } } From a74f09d4b81b5a6a1561edf89f67d7c10ce6d865 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 4 Sep 2025 13:08:00 +0200 Subject: [PATCH 175/186] no longer generate icmp select instructions with lhs immediates --- crates/ir2/build/isa.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 230e0694c8..88fed4383a 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -1,6 +1,7 @@ use crate::build::{ ident::Ident, op::{ + Ty, BinaryOp, BinaryOpKind, CmpBranchOp, @@ -315,7 +316,15 @@ fn add_cmp_select_ops(isa: &mut Isa) { OperandKind::Slot, OperandKind::Immediate, )); - if matches!(op.commutativity(), Commutativity::NonCommutative) { + let is_float_op = matches!(op.ident_prefix(), Ty::F32 | Ty::F64); + let is_non_commutative = matches!(op.commutativity(), Commutativity::NonCommutative); + if is_non_commutative && is_float_op { + // Integer ops with `lhs` immediate can be replaced with integer ops with `rhs` immediate + // by also swapping `val_true` and `val_false` operands and comparison operator. + // For example, the following `select` expressions are the same: + // - `if 5 < x then 10 else 20` + // - `if x <= 5 then 20 else 10` + // Float ops cannot simplified the same due to NaN value behavior. isa.push_op(CmpSelectOp::new( op, OperandKind::Immediate, @@ -431,7 +440,7 @@ fn add_control_ops(isa: &mut Isa) { )), Op::from(GenericOp::new( Ident::Branch, - [Field::new(Ident::Values, FieldTy::SlotSpan)], + [Field::new(Ident::Offset, FieldTy::BranchOffset)], )), Op::from(GenericOp::new( Ident::BranchTable, From 170cff7ef8ee8c456ff916d0bf63e318166c33a8 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 4 Sep 2025 13:09:52 +0200 Subject: [PATCH 176/186] apply rustfmt --- crates/ir2/build/isa.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index 88fed4383a..a457ff1e54 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -1,7 +1,6 @@ use crate::build::{ ident::Ident, op::{ - Ty, BinaryOp, BinaryOpKind, CmpBranchOp, @@ -19,6 +18,7 @@ use crate::build::{ StoreOpKind, TableGetOp, TableSetOp, + Ty, UnaryOp, UnaryOpKind, V128LoadLaneOp, From 2ea156d57e0fb9e7cc97b9e48a1dde93094a94d5 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 4 Sep 2025 15:37:18 +0200 Subject: [PATCH 177/186] fix Ident::NotEq snake case identifier --- crates/ir2/build/ident.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ir2/build/ident.rs b/crates/ir2/build/ident.rs index 170ccb874a..6048e03134 100644 --- a/crates/ir2/build/ident.rs +++ b/crates/ir2/build/ident.rs @@ -117,7 +117,7 @@ define_ident!( AndNot: and_not, Or: or, Xor: xor, - NotEq: ne, + NotEq: not_eq, NotAnd: not_and, NotOr: not_or, Lt: lt, From 3f7499ebd8d9b996cfef74826a403e47aa8317e5 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 4 Sep 2025 23:30:55 +0200 Subject: [PATCH 178/186] fix ReturnSpan field --- crates/ir2/build/isa.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ir2/build/isa.rs b/crates/ir2/build/isa.rs index a457ff1e54..0751466f61 100644 --- a/crates/ir2/build/isa.rs +++ b/crates/ir2/build/isa.rs @@ -436,7 +436,7 @@ fn add_control_ops(isa: &mut Isa) { )), Op::from(GenericOp::new( Ident::ReturnSpan, - [Field::new(Ident::Fuel, FieldTy::BlockFuel)], + [Field::new(Ident::Values, FieldTy::SlotSpan)], )), Op::from(GenericOp::new( Ident::Branch, From f2ae148c75b3b4c036c8409d0936a7469aecca3d Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 4 Sep 2025 23:31:12 +0200 Subject: [PATCH 179/186] reorder some CmpOpKind variants --- crates/ir2/build/op.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/ir2/build/op.rs b/crates/ir2/build/op.rs index e9050d3cba..29eac3dae6 100644 --- a/crates/ir2/build/op.rs +++ b/crates/ir2/build/op.rs @@ -1753,16 +1753,16 @@ impl CmpOpKind { Self::S64Le => Ident::Le, Self::U64Le => Ident::Le, Self::F32Eq => Ident::Eq, - Self::F32NotEq => Ident::NotEq, Self::F32Lt => Ident::Lt, - Self::F32NotLt => Ident::NotLt, Self::F32Le => Ident::Le, + Self::F32NotEq => Ident::NotEq, + Self::F32NotLt => Ident::NotLt, Self::F32NotLe => Ident::NotLe, Self::F64Eq => Ident::Eq, - Self::F64NotEq => Ident::NotEq, Self::F64Lt => Ident::Lt, - Self::F64NotLt => Ident::NotLt, Self::F64Le => Ident::Le, + Self::F64NotEq => Ident::NotEq, + Self::F64NotLt => Ident::NotLt, Self::F64NotLe => Ident::NotLe, } } From 6b255669cd4353030c629f74e9b415aca3f9fcf3 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 4 Sep 2025 23:46:28 +0200 Subject: [PATCH 180/186] remove unnecessary angle brackets --- crates/ir2/src/decode/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ir2/src/decode/mod.rs b/crates/ir2/src/decode/mod.rs index ef0152ebd7..ef7d537f91 100644 --- a/crates/ir2/src/decode/mod.rs +++ b/crates/ir2/src/decode/mod.rs @@ -62,7 +62,7 @@ pub trait Decode { impl Decode for BoundedSlotSpan { unsafe fn decode(decoder: &mut D) -> Self { - let span = ::decode(decoder); + let span = SlotSpan::decode(decoder); let len = u16::decode(decoder); Self::new(span, len) } From e0fbbf8460369c66e301954b1a8c65f265801165 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Fri, 5 Sep 2025 00:01:04 +0200 Subject: [PATCH 181/186] simplify Encode impl for BoundedSlotSpan --- crates/ir2/src/encode.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/crates/ir2/src/encode.rs b/crates/ir2/src/encode.rs index 7a467040d9..b7c3bde5f8 100644 --- a/crates/ir2/src/encode.rs +++ b/crates/ir2/src/encode.rs @@ -80,13 +80,8 @@ impl Encode for BranchOffset { } impl Encode for BoundedSlotSpan { - fn encode(&self, encoder: &mut E) -> Result - where - E: Encoder, - { - let pos = self.span().encode(encoder)?; - self.len().encode(encoder)?; - Ok(pos) + fn encode(&self, encoder: &mut E) -> Result { + (self.span(), self.len()).encode(encoder) } } From b4f0ec5712b48df3189fc4fc65488ddc1cba5e5d Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Fri, 5 Sep 2025 00:02:03 +0200 Subject: [PATCH 182/186] add proper Encode/Decode impls for FixedSlotSpan --- crates/ir2/src/decode/mod.rs | 7 ++++++- crates/ir2/src/encode.rs | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/crates/ir2/src/decode/mod.rs b/crates/ir2/src/decode/mod.rs index ef7d537f91..9515e27028 100644 --- a/crates/ir2/src/decode/mod.rs +++ b/crates/ir2/src/decode/mod.rs @@ -68,6 +68,12 @@ impl Decode for BoundedSlotSpan { } } +impl Decode for FixedSlotSpan { + unsafe fn decode(decoder: &mut D) -> Self { + Self::new_unchecked(SlotSpan::decode(decoder)) + } +} + macro_rules! impl_decode_for_primitive { ( $($ty:ty),* $(,)? ) => { $( @@ -116,7 +122,6 @@ impl_decode_using! { Elem as u32 = Into::into, SlotSpan as Slot = SlotSpan::new, - FixedSlotSpan<2> as SlotSpan = |span| unsafe { >::new_unchecked(span) }, NonZero as u32 = |value| unsafe { NonZero::new_unchecked(value) }, NonZero as u64 = |value| unsafe { NonZero::new_unchecked(value) }, diff --git a/crates/ir2/src/encode.rs b/crates/ir2/src/encode.rs index b7c3bde5f8..a7bf13fbc5 100644 --- a/crates/ir2/src/encode.rs +++ b/crates/ir2/src/encode.rs @@ -85,6 +85,12 @@ impl Encode for BoundedSlotSpan { } } +impl Encode for FixedSlotSpan { + fn encode(&self, encoder: &mut E) -> Result { + self.span().encode(encoder) + } +} + macro_rules! impl_encode_for_primitive { ( $($ty:ty),* $(,)? ) => { $( @@ -137,7 +143,6 @@ impl_encode_using! { Elem as u32 = Into::into, SlotSpan as Slot = SlotSpan::head, - FixedSlotSpan<2> as SlotSpan = >::span, NonZero as u32 = NonZero::get, NonZero as u64 = NonZero::get, From 069522cfe4eeb3731bde085a047b2b391be0e93a Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Fri, 5 Sep 2025 00:02:33 +0200 Subject: [PATCH 183/186] add BranchTableTarget type --- crates/ir2/src/decode/mod.rs | 9 +++++++++ crates/ir2/src/encode.rs | 7 +++++++ crates/ir2/src/lib.rs | 2 +- crates/ir2/src/primitive.rs | 18 +++++++++++++++++- 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/crates/ir2/src/decode/mod.rs b/crates/ir2/src/decode/mod.rs index 9515e27028..e35980e52c 100644 --- a/crates/ir2/src/decode/mod.rs +++ b/crates/ir2/src/decode/mod.rs @@ -33,6 +33,7 @@ use crate::{ BlockFuel, BoundedSlotSpan, BranchOffset, + BranchTableTarget, FixedSlotSpan, Offset16, OpCode, @@ -74,6 +75,14 @@ impl Decode for FixedSlotSpan { } } +impl Decode for BranchTableTarget { + unsafe fn decode(decoder: &mut D) -> Self { + let results = SlotSpan::decode(decoder); + let offset = BranchOffset::decode(decoder); + Self::new(results, offset) + } +} + macro_rules! impl_decode_for_primitive { ( $($ty:ty),* $(,)? ) => { $( diff --git a/crates/ir2/src/encode.rs b/crates/ir2/src/encode.rs index a7bf13fbc5..78395b1266 100644 --- a/crates/ir2/src/encode.rs +++ b/crates/ir2/src/encode.rs @@ -7,6 +7,7 @@ use crate::{ BlockFuel, BoundedSlotSpan, BranchOffset, + BranchTableTarget, FixedSlotSpan, Offset16, Op, @@ -91,6 +92,12 @@ impl Encode for FixedSlotSpan { } } +impl Encode for BranchTableTarget { + fn encode(&self, encoder: &mut E) -> Result { + (self.results, self.offset).encode(encoder) + } +} + macro_rules! impl_encode_for_primitive { ( $($ty:ty),* $(,)? ) => { $( diff --git a/crates/ir2/src/lib.rs b/crates/ir2/src/lib.rs index 9c8a9fd429..10c232cdb0 100644 --- a/crates/ir2/src/lib.rs +++ b/crates/ir2/src/lib.rs @@ -23,6 +23,6 @@ pub use self::{ index::Slot, op::Op, opcode::{InvalidOpCode, OpCode}, - primitive::{Address, BlockFuel, BranchOffset, Offset16, Sign}, + primitive::{Address, BlockFuel, BranchOffset, BranchTableTarget, Offset16, Sign}, span::{BoundedSlotSpan, FixedSlotSpan, SlotSpan, SlotSpanIter}, }; diff --git a/crates/ir2/src/primitive.rs b/crates/ir2/src/primitive.rs index 204a8a9ab5..037830aa00 100644 --- a/crates/ir2/src/primitive.rs +++ b/crates/ir2/src/primitive.rs @@ -1,6 +1,22 @@ -use crate::Error; +use crate::{Error, SlotSpan}; use core::marker::PhantomData; +/// An [`Op::BranchTableSpan`](crate::Op::BranchTableSpan) branching target. +#[derive(Debug, Copy, Clone)] +pub struct BranchTableTarget { + /// The result stack slots of the branch target. + pub results: SlotSpan, + /// The offset to branch to for the target. + pub offset: BranchOffset, +} + +impl BranchTableTarget { + /// Creates a new [`BranchTableTarget`] for `results` and `offset`. + pub fn new(results: SlotSpan, offset: BranchOffset) -> Self { + Self { results, offset } + } +} + /// Error that may occur upon converting values to [`Address`] and [`Offset16`]. #[derive(Debug, Copy, Clone)] pub struct OutOfBoundsConst; From 5705e82eb439269b12e2d7bb78511f8fbe5918a4 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Fri, 5 Sep 2025 00:02:49 +0200 Subject: [PATCH 184/186] reorder macro parameters --- crates/ir2/src/decode/mod.rs | 9 +++------ crates/ir2/src/encode.rs | 7 ++----- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/crates/ir2/src/decode/mod.rs b/crates/ir2/src/decode/mod.rs index e35980e52c..85e14488a6 100644 --- a/crates/ir2/src/decode/mod.rs +++ b/crates/ir2/src/decode/mod.rs @@ -116,10 +116,6 @@ impl_decode_using! { Offset16 as u16 = Into::into, BranchOffset as i32 = Into::into, BlockFuel as u64 = Into::into, - Address as u64 = |address| unsafe { Address::try_from(address).unwrap_unchecked() }, - Sign as bool = Sign::new, - Sign as bool = Sign::new, - Slot as u16 = Into::into, Func as u32 = Into::into, FuncType as u32 = Into::into, @@ -130,11 +126,12 @@ impl_decode_using! { Data as u32 = Into::into, Elem as u32 = Into::into, + Address as u64 = |address| unsafe { Address::try_from(address).unwrap_unchecked() }, + Sign as bool = Sign::new, + Sign as bool = Sign::new, SlotSpan as Slot = SlotSpan::new, - NonZero as u32 = |value| unsafe { NonZero::new_unchecked(value) }, NonZero as u64 = |value| unsafe { NonZero::new_unchecked(value) }, - TrapCode as u8 = |code: u8| -> TrapCode { TrapCode::try_from(code).unwrap_unchecked() }, diff --git a/crates/ir2/src/encode.rs b/crates/ir2/src/encode.rs index 78395b1266..3dacf9f50b 100644 --- a/crates/ir2/src/encode.rs +++ b/crates/ir2/src/encode.rs @@ -136,9 +136,6 @@ impl_encode_using! { Offset16 as u16 = Into::into, BlockFuel as u64 = Into::into, Address as u64 = Into::into, - Sign as bool = Sign::is_positive, - Sign as bool = Sign::is_positive, - Slot as u16 = Into::into, Func as u32 = Into::into, FuncType as u32 = Into::into, @@ -149,11 +146,11 @@ impl_encode_using! { Data as u32 = Into::into, Elem as u32 = Into::into, + Sign as bool = Sign::is_positive, + Sign as bool = Sign::is_positive, SlotSpan as Slot = SlotSpan::head, - NonZero as u32 = NonZero::get, NonZero as u64 = NonZero::get, - TrapCode as u8 = |code: TrapCode| -> u8 { code as _ }, } From 7c76b7578475982c9b67aa9609786d44f2c4022e Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Fri, 5 Sep 2025 00:03:10 +0200 Subject: [PATCH 185/186] slightly simplify macro generated Encode impls --- crates/ir2/src/encode.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/crates/ir2/src/encode.rs b/crates/ir2/src/encode.rs index 3dacf9f50b..e82c8d6dd2 100644 --- a/crates/ir2/src/encode.rs +++ b/crates/ir2/src/encode.rs @@ -102,10 +102,7 @@ macro_rules! impl_encode_for_primitive { ( $($ty:ty),* $(,)? ) => { $( impl Encode for $ty { - fn encode(&self, encoder: &mut E) -> Result - where - E: Encoder, - { + fn encode(&self, encoder: &mut E) -> Result { encoder.write_bytes(&self.to_ne_bytes()) } } @@ -120,10 +117,7 @@ macro_rules! impl_encode_using { ( $($ty:ty as $prim:ty = $e:expr),* $(,)? ) => { $( impl Encode for $ty { - fn encode(&self, encoder: &mut E) -> Result - where - E: Encoder, - { + fn encode(&self, encoder: &mut E) -> Result { let conv = |value: &Self| -> $prim { $e(*value) }; conv(self).encode(encoder) } From 0e1e32de5d4301947c40ed23a67b5eec870247be Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Fri, 5 Sep 2025 10:26:36 +0200 Subject: [PATCH 186/186] ignore coverage stats of wasmi_ir2 since it has not yet been integrated --- codecov.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 codecov.yml diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000000..91568e8d68 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,9 @@ +coverage: + status: + project: + default: + target: auto + threshold: 1% + +ignore: + - "crates/ir2/**"