summaryrefslogtreecommitdiff
path: root/crates/parser/src/macros.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/parser/src/macros.rs')
-rw-r--r--crates/parser/src/macros.rs297
1 files changed, 156 insertions, 141 deletions
diff --git a/crates/parser/src/macros.rs b/crates/parser/src/macros.rs
index 8a5330a..ff216a5 100644
--- a/crates/parser/src/macros.rs
+++ b/crates/parser/src/macros.rs
@@ -2,12 +2,13 @@ pub(crate) mod visit {
macro_rules! validate_then_visit {
($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => {$(
fn $visit(&mut self $($(,$arg: $argty)*)?) -> Self::Output {
- self.0.$visit($($($arg.clone()),*)?);
- let validation = self.0.validator.visitor(self.0.position).$visit($($($arg),*)?);
- if let Err(e) = validation {
- cold_path();
- self.0.record_error(crate::ParseError::ParseError { message: e.to_string(), offset: self.0.position });
+ if let Some(validator) = self.validator.as_mut() {
+ if let Err(e) = validator.visitor(self.position).$visit($($($arg.clone()),*)?) {
+ core::hint::cold_path();
+ return Err(crate::ParseError::ParseError { message: e.to_string(), offset: self.position });
+ }
}
+ self.builder.$visit($($($arg),*)?)
}
)*};
}
@@ -15,64 +16,103 @@ pub(crate) mod visit {
macro_rules! validate_then_visit_simd {
($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => {$(
fn $visit(&mut self $($(,$arg: $argty)*)?) -> Self::Output {
- self.0.$visit($($($arg),*)?);
- let validation = self.0.validator.simd_visitor(self.0.position).$visit($($($arg),*)?);
- if let Err(e) = validation {
- cold_path();
- self.0.record_error(crate::ParseError::ParseError { message: e.to_string(), offset: self.0.position });
+ if let Some(validator) = self.validator.as_mut() {
+ if let Err(e) = validator.simd_visitor(self.position).$visit($($($arg.clone()),*)?) {
+ core::hint::cold_path();
+ return Err(crate::ParseError::ParseError { message: e.to_string(), offset: self.position });
+ }
}
+ self.builder.$visit($($($arg),*)?)
}
)*};
}
- macro_rules! define_operand {
- ($name:ident($instr:expr, $ty:ty)) => {
- fn $name(&mut self, arg: $ty) -> Self::Output {
- self.instructions.push($instr(arg).into());
- }
+ macro_rules! lowering_ops {
+ () => {};
+ ($kind:ident $inputs:tt => $outputs:tt {
+ $($visit:ident $(($($arg:ident: $ty:ty),+))? => $instr:ident),* $(,)?
+ } $($rest:tt)*) => {
+ $(lowering_ops!(@$kind $inputs => $outputs $visit $(($($arg: $ty),+))? => $instr);)*
+ lowering_ops!($($rest)*);
+ };
+ (effect $inputs:tt => $outputs:tt { $($visit:ident),* $(,)? } $($rest:tt)*) => {
+ $(lowering_ops!(@effect $inputs => $outputs $visit);)*
+ lowering_ops!($($rest)*);
};
- ($name:ident($instr:expr, $ty:ty, $ty2:ty)) => {
- fn $name(&mut self, arg: $ty, arg2: $ty2) -> Self::Output {
- self.instructions.push($instr(arg, arg2).into());
+ (@fixed [$($input:ident),*] => [$($output:ident),*]
+ $visit:ident $(($($arg:ident: $ty:ty),+))? => $instr:ident
+ ) => {
+ fn $visit(&mut self $(, $($arg: $ty),+)?) -> Self::Output {
+ lowering_ops!(@emit self fixed [$($input),*] => [$($output),*]
+ Instruction::$instr $(($($arg),+))?.into())
}
};
-
- ($name:ident($instr:expr)) => {
- fn $name(&mut self) -> Self::Output {
- self.instructions.push($instr.into());
+ (@memory [$($input:ident),*] => [$($output:ident),*]
+ $visit:ident $(($lane:ident: $ty:ty))? => $instr:ident
+ ) => {
+ fn $visit(&mut self, memarg: wasmparser::MemArg $(, $lane: $ty)?) -> Self::Output {
+ let address = self.metadata.memory_size(memarg.memory)?;
+ lowering_ops!(@emit self address(address) [$($input),*] => [$($output),*]
+ Instruction::$instr(MemoryArg::new(memarg.offset, memarg.memory) $(, $lane)?).into())
}
};
- }
-
- macro_rules! define_operands {
- ($($name:ident($instr:ident $(,$ty:ty)*)),*) => {$(
- define_operand!($name(Instruction::$instr $(,$ty)*));
- )*};
- }
-
- macro_rules! define_mem_operands {
- ($($name:ident($instr:ident)),*) => {$(
- fn $name(&mut self, memarg: wasmparser::MemArg) -> Self::Output {
- self.instructions.push(Instruction::$instr(MemoryArg::new(memarg.offset, memarg.memory)));
+ (@global $inputs:tt => $outputs:tt $($operator:tt)*) => {
+ lowering_ops!(@resolved global_size $inputs => $outputs $($operator)*);
+ };
+ (@memory_index $inputs:tt => $outputs:tt $($operator:tt)*) => {
+ lowering_ops!(@resolved memory_size $inputs => $outputs $($operator)*);
+ };
+ (@table $inputs:tt => $outputs:tt $($operator:tt)*) => {
+ lowering_ops!(@resolved table_size $inputs => $outputs $($operator)*);
+ };
+ (@resolved $resolver:ident [$($input:ident),*] => [$($output:ident),*]
+ $visit:ident($index:ident: $ty:ty) => $instr:ident
+ ) => {
+ fn $visit(&mut self, $index: $ty) -> Self::Output {
+ let address = self.metadata.$resolver($index)?;
+ lowering_ops!(@emit self address(address) [$($input),*] => [$($output),*]
+ Instruction::$instr($index).into())
}
- )*};
- }
-
- macro_rules! define_mem_operands_simd {
- ($($name:ident($instr:ident)),*) => {$(
- fn $name(&mut self, memarg: wasmparser::MemArg) -> Self::Output {
- self.instructions.push(Instruction::$instr(MemoryArg::new(memarg.offset, memarg.memory)).into());
+ };
+ (@resolved $resolver:ident [$($input:ident),*] => [$($output:ident),*]
+ $visit:ident($arg:ident: $arg_ty:ty, $index:ident: $index_ty:ty) => $instr:ident
+ ) => {
+ fn $visit(&mut self, $arg: $arg_ty, $index: $index_ty) -> Self::Output {
+ let address = self.metadata.$resolver($index)?;
+ lowering_ops!(@emit self address(address) [$($input),*] => [$($output),*]
+ Instruction::$instr($arg, $index).into())
}
- )*};
- }
-
- macro_rules! define_mem_operands_simd_lane {
- ($($name:ident($instr:ident)),*) => {$(
- fn $name(&mut self, memarg: wasmparser::MemArg, lane: u8) -> Self::Output {
- self.instructions.push(Instruction::$instr(MemoryArg::new(memarg.offset, memarg.memory), lane).into());
+ };
+ (@effect [$($input:ident),*] => [$($output:ident),*] $visit:ident) => {
+ fn $visit(&mut self) -> Self::Output {
+ self.apply_effect(&[$(lowering_ops!(@size $input)),*], &[$(lowering_ops!(@size $output)),*])
}
- )*};
+ };
+ (@terminating [$($input:ident),*] => [$($output:ident),*] $visit:ident => $instr:ident) => {
+ fn $visit(&mut self) -> Self::Output {
+ self.mark_unreachable();
+ lowering_ops!(@emit self fixed [$($input),*] => [$($output),*] Instruction::$instr)
+ }
+ };
+
+ (@emit $self:ident fixed [$($input:ident),*] => [$($output:ident),*] $instruction:expr) => {
+ $self.emit(
+ &[$(lowering_ops!(@size $input)),*],
+ &[$(lowering_ops!(@size $output)),*],
+ $instruction,
+ )
+ };
+ (@emit $self:ident address($address:ident) [$($input:ident),*] => [$($output:ident),*] $instruction:expr) => {
+ $self.emit(
+ &[$(lowering_ops!(@size $input, $address)),*],
+ &[$(lowering_ops!(@size $output, $address)),*],
+ $instruction,
+ )
+ };
+
+ (@size Addr, $address:ident) => { $address };
+ (@size $size:ident $(, $address:ident)?) => { OperandSize::$size };
}
macro_rules! impl_visit_operator {
@@ -92,100 +132,58 @@ pub(crate) mod visit {
(@@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*)) => {
fn $visit(&mut self $($(,_: $argty)*)?) -> Self::Output {
- self.unsupported(stringify!($visit))
+ Err(crate::ParseError::UnsupportedOperator(stringify!($visit).to_string()))
}
};
}
- pub(crate) use {
- define_mem_operands, define_mem_operands_simd, define_mem_operands_simd_lane, define_operand, define_operands,
- impl_visit_operator, validate_then_visit, validate_then_visit_simd,
- };
+ pub(crate) use {impl_visit_operator, lowering_ops, validate_then_visit, validate_then_visit_simd};
}
pub(crate) mod optimize {
macro_rules! replace {
- ($instructions:ident, $read:ident, $consumed:literal => [$($out:expr),+ $(,)?]) => {{
+ ($instructions:ident, $read:ident, $consumed:expr => [$($out:expr),+ $(,)?]) => {{
const {
assert!($consumed >= 1 && $consumed <= 3);
assert!([$(stringify!($out)),+].len() <= $consumed + 1);
}
let replacements = [$($out),+];
- let replacement_start = $read + 1 - replacements.len();
- $instructions[$read - $consumed..replacement_start].fill(Instruction::Nop);
- $instructions[replacement_start..=$read].copy_from_slice(&replacements);
+ let start = $read - $consumed;
+ $instructions[start..start + replacements.len()].copy_from_slice(&replacements);
+ $instructions.truncate(start + replacements.len());
+ #[allow(unused_assignments)]
+ { $read = $instructions.len() - 1; }
}};
- ($instructions:ident, $read:ident, $consumed:literal => $out:expr) => {
+ ($instructions:ident, $read:ident, $consumed:expr => $out:expr) => {
replace!($instructions, $read, $consumed => [$out]);
};
}
macro_rules! rewrite {
- ($instructions:ident, $read:ident, [$a:pat] if ($($guard:tt)+) => [$($out:expr),+ $(,)?]) => {
- rewrite!($instructions, $read, [$a] if ($($guard)+) => { replace!($instructions, $read, 1 => [$($out),+]); })
- };
- ($instructions:ident, $read:ident, [$a:pat, $b:pat] if ($($guard:tt)+) => [$($out:expr),+ $(,)?]) => {
- rewrite!($instructions, $read, [$a, $b] if ($($guard)+) => { replace!($instructions, $read, 2 => [$($out),+]); })
- };
- ($instructions:ident, $read:ident, [$a:pat, $b:pat, $c:pat] if ($($guard:tt)+) => [$($out:expr),+ $(,)?]) => {
- rewrite!($instructions, $read, [$a, $b, $c] if ($($guard)+) => { replace!($instructions, $read, 3 => [$($out),+]); })
- };
- ($instructions:ident, $read:ident, [$a:pat] => [$($out:expr),+ $(,)?]) => {
- rewrite!($instructions, $read, [$a] => { replace!($instructions, $read, 1 => [$($out),+]); })
- };
- ($instructions:ident, $read:ident, [$a:pat, $b:pat] => [$($out:expr),+ $(,)?]) => {
- rewrite!($instructions, $read, [$a, $b] => { replace!($instructions, $read, 2 => [$($out),+]); })
- };
- ($instructions:ident, $read:ident, [$a:pat, $b:pat, $c:pat] => [$($out:expr),+ $(,)?]) => {
- rewrite!($instructions, $read, [$a, $b, $c] => { replace!($instructions, $read, 3 => [$($out),+]); })
+ ($instructions:ident, $read:ident, [$($pattern:pat),+] $(if ($($guard:tt)+))? => [$($out:expr),+ $(,)?]) => {
+ rewrite!($instructions, $read, [$($pattern),+] $(if ($($guard)+))? => {
+ replace!($instructions, $read, [$(stringify!($pattern)),+].len() => [$($out),+]);
+ })
};
- ($instructions:ident, $read:ident, [$a:pat] if ($($guard:tt)+) => $body:block $(,)?) => {
- if $read > 0 && let $a = $instructions[$read - 1] && $($guard)+ {
- $body
- }
- };
- ($instructions:ident, $read:ident, [$a:pat, $b:pat] if ($($guard:tt)+) => $body:block $(,)?) => {
- if $read > 1 && let ($a, $b) = ($instructions[$read - 2], $instructions[$read - 1]) && $($guard)+ {
- $body
- }
- };
- ($instructions:ident, $read:ident, [$a:pat, $b:pat, $c:pat] if ($($guard:tt)+) => $body:block $(,)?) => {
- if $read > 2 && let ($a, $b, $c) = ($instructions[$read - 3], $instructions[$read - 2], $instructions[$read - 1]) && $($guard)+ {
- $body
- }
- };
- ($instructions:ident, $read:ident, [$a:pat] => $body:block $(,)?) => {
- if $read > 0 && let $a = $instructions[$read - 1] {
- $body
- }
- };
- ($instructions:ident, $read:ident, [$a:pat, $b:pat] => $body:block $(,)?) => {
- if $read > 1 && let ($a, $b) = ($instructions[$read - 2], $instructions[$read - 1]) {
- $body
- }
- };
- ($instructions:ident, $read:ident, [$a:pat, $b:pat, $c:pat] => $body:block $(,)?) => {
- if $read > 2 && let ($a, $b, $c) = ($instructions[$read - 3], $instructions[$read - 2], $instructions[$read - 1]) {
- $body
+ ($instructions:ident, $read:ident, [$($pattern:pat),+] $(if ($($guard:tt)+))? => $body:block $(,)?) => {{
+ const CONSUMED: usize = [$(stringify!($pattern)),+].len();
+ if !$instructions.tail_rewritten
+ && $read < $instructions.len()
+ && $read >= $instructions.block_start + CONSUMED
+ {
+ let previous: [Instruction; CONSUMED] = $instructions[$read - CONSUMED..$read].try_into().unwrap();
+ if let [$($pattern),+] = previous $(
+ && $($guard)+
+ )? {
+ $instructions.tail_rewritten = true;
+ $body
+ }
}
- };
- ($instructions:ident, $read:ident, [$a:pat] if ($($guard:tt)+) => $out:expr $(,)?) => {
- rewrite!($instructions, $read, [$a] if ($($guard)+) => { replace!($instructions, $read, 1 => $out); })
- };
- ($instructions:ident, $read:ident, [$a:pat, $b:pat] if ($($guard:tt)+) => $out:expr $(,)?) => {
- rewrite!($instructions, $read, [$a, $b] if ($($guard)+) => { replace!($instructions, $read, 2 => $out); })
- };
- ($instructions:ident, $read:ident, [$a:pat, $b:pat, $c:pat] if ($($guard:tt)+) => $out:expr $(,)?) => {
- rewrite!($instructions, $read, [$a, $b, $c] if ($($guard)+) => { replace!($instructions, $read, 3 => $out); })
- };
- ($instructions:ident, $read:ident, [$a:pat] => $out:expr $(,)?) => {
- rewrite!($instructions, $read, [$a] => { replace!($instructions, $read, 1 => $out); })
- };
- ($instructions:ident, $read:ident, [$a:pat, $b:pat] => $out:expr $(,)?) => {
- rewrite!($instructions, $read, [$a, $b] => { replace!($instructions, $read, 2 => $out); })
- };
- ($instructions:ident, $read:ident, [$a:pat, $b:pat, $c:pat] => $out:expr $(,)?) => {
- rewrite!($instructions, $read, [$a, $b, $c] => { replace!($instructions, $read, 3 => $out); })
+ }};
+ ($instructions:ident, $read:ident, [$($pattern:pat),+] $(if ($($guard:tt)+))? => $out:expr $(,)?) => {
+ rewrite!($instructions, $read, [$($pattern),+] $(if ($($guard)+))? => {
+ replace!($instructions, $read, [$(stringify!($pattern)),+].len() => $out);
+ })
};
}
@@ -201,13 +199,13 @@ pub(crate) mod optimize {
binop_local_const_set = $lcset:ident
$(, load_local_tee = $loadtee:ident, load_local_set = $loadset:ident)?
) => {
- fn $name(instr: Instruction) -> Option<(Instruction, u16)> {
+ fn $name(instr: Instruction) -> Option<(Option<Instruction>, u16)> {
Some(match instr {
- Instruction::$get(local) => (Instruction::Nop, local),
- Instruction::$tee(local) => (Instruction::$set(local), local),
- Instruction::$lltee(op, a, b, local) => (Instruction::$llset(op, a, b, local), local),
- Instruction::$lctee(op, src, c, local) => (Instruction::$lcset(op, src, c, local), local),
- $(Instruction::$loadtee(memarg, addr, local) => (Instruction::$loadset(memarg, addr, local), local.into()),)?
+ Instruction::$get(local) => (None, local),
+ Instruction::$tee(local) => (Some(Instruction::$set(local)), local),
+ Instruction::$lltee(op, a, b, local) => (Some(Instruction::$llset(op, a, b, local)), local),
+ Instruction::$lctee(op, src, c, local) => (Some(Instruction::$lcset(op, src, c, local)), local),
+ $(Instruction::$loadtee(memarg, addr, local) => (Some(Instruction::$loadset(memarg, addr, local)), local.into()),)?
_ => return None,
})
}
@@ -223,21 +221,28 @@ pub(crate) mod optimize {
local_local = $local_local:ident,
local_const = $local_const:expr
) => {{
- if let Some([(lhs_idx, lhs_src), (rhs_idx, rhs_src), (op_idx, raw_op)]) =
- previous_non_nop::<3>($instrs, $read)
+ if !$instrs.tail_rewritten
+ && $read < $instrs.len()
+ && $read >= $instrs.block_start + 3
+ && let [lhs_src, rhs_src, raw_op] = [$instrs[$read - 3], $instrs[$read - 2], $instrs[$read - 1]]
&& let Some((lhs_instr, lhs)) = $source(lhs_src)
&& let Some(op) = $op(raw_op)
{
if let Some((rhs_instr, rhs)) = $source(rhs_src) {
- $instrs[lhs_idx] = lhs_instr;
- $instrs[rhs_idx] = rhs_instr;
- $instrs[op_idx] = Instruction::Nop;
- $instrs[$read] = Instruction::$local_local(op, lhs, rhs, $dst);
+ if rhs_instr.is_none() || rhs != lhs {
+ $instrs.tail_rewritten = true;
+ $instrs.truncate($read - 3);
+ $instrs.extend(lhs_instr);
+ $instrs.extend(rhs_instr);
+ $instrs.push(Instruction::$local_local(op, lhs, rhs, $dst));
+ $read = $instrs.len() - 1;
+ }
} else if let Some(imm) = $const(rhs_src, raw_op) {
- $instrs[lhs_idx] = lhs_instr;
- $instrs[rhs_idx] = Instruction::Nop;
- $instrs[op_idx] = Instruction::Nop;
- $instrs[$read] = $local_const($dst, lhs, op, imm);
+ $instrs.tail_rewritten = true;
+ $instrs.truncate($read - 3);
+ $instrs.extend(lhs_instr);
+ $instrs.push($local_const($dst, lhs, op, imm));
+ $read = $instrs.len() - 1;
}
}
}};
@@ -254,7 +259,17 @@ pub(crate) mod optimize {
binop_local_const_set = $lcset:expr
$(, const_instr = $const_instr:ident, set_local_const = $set_local_const:ident)?
) => {{
- rewrite!($instrs, $read, [$get(src)] => if src == $dst { Instruction::Nop } else { Instruction::$copy(src, $dst) });
+ rewrite!($instrs, $read, [$get(src)] if (src != $dst) => Instruction::$copy(src, $dst));
+ if !$instrs.tail_rewritten
+ && $read < $instrs.len()
+ && $read > $instrs.block_start
+ && let Instruction::$get(src) = $instrs[$read - 1]
+ && src == $dst
+ {
+ $instrs.tail_rewritten = true;
+ $instrs.truncate($read - 1);
+ $read = $instrs.len();
+ }
$(rewrite!($instrs, $read, [$const_instr(c)] => Instruction::$set_local_const($dst, c));)?
rewrite!($instrs, $read, [$ll(op, a, b)] => Instruction::$llset(op, a, b, $dst));
rewrite!($instrs, $read, [$lc(op, src, c)] => { replace!($instrs, $read, 1 => $lcset($dst, src, op, c)); });
@@ -270,7 +285,7 @@ pub(crate) mod optimize {
binop_local_const = $lc:ident,
binop_local_const_tee = $lctee:ident
) => {{
- rewrite!($instrs, $read, [$get(src)] if (src == $dst) => [Instruction::$get(src), Instruction::Nop]);
+ rewrite!($instrs, $read, [$get(src)] if (src == $dst) => Instruction::$get(src));
rewrite!($instrs, $read, [$ll(op, a, b)] => Instruction::$lltee(op, a, b, $dst));
rewrite!($instrs, $read, [$lc(op, src, c)] => Instruction::$lctee(op, src, c, $dst));
}};
@@ -286,7 +301,7 @@ pub(crate) mod optimize {
binop_local_const_tee = $lctee:ident,
binop_local_const_set = $lcset:ident
) => {{
- rewrite!($instrs, $read, [$tee(local)] => [Instruction::$set(local), Instruction::Nop]);
+ rewrite!($instrs, $read, [$tee(local)] => Instruction::$set(local));
rewrite!($instrs, $read, [$lltee(op, a, b, dst)] => Instruction::$llset(op, a, b, dst));
rewrite!($instrs, $read, [$lctee(op, src, c, dst)] => Instruction::$lcset(op, src, c, dst));
}};