@@ -11,9 +11,9 @@ use alloc::{
1111 vec:: Vec ,
1212} ;
1313use tinywasm_types:: {
14- BinOp , BinOp128 , CmpOp , ExceptionHandler , Global , Import , ImportKind , Instruction , MemoryType , Operand64 ,
15- Operand64Idx , Operand128 , Operand128Idx , StorageType , TableDefinition , TagType , TypeSection , ValueCounts ,
16- ValueLane , WasmFunctionData ,
14+ AtomicArg , AtomicOp , AtomicWidth , BinOp , BinOp128 , CmpOp , ExceptionHandler , Global , Import , ImportKind ,
15+ Instruction , MemoryType , Operand64 , Operand64Idx , Operand128 , Operand128Idx , StorageType , TableDefinition , TagType ,
16+ TypeSection , ValueCounts , ValueLane , WasmFunctionData ,
1717} ;
1818use wasmparser:: { FunctionBody , OperatorsReader , OperatorsReaderAllocations , VisitSimdOperator } ;
1919
@@ -497,6 +497,35 @@ pub(crate) fn process_operators_and_validate(
497497 Ok ( ( instructions, builder. data , builder. uses_local_memory , validator. into_allocations ( ) , reader. into_allocations ( ) ) )
498498}
499499
500+ macro_rules! atomic_visitors {
501+ ( $( $op: ident, $inputs: tt => $outputs: tt: $( ( $visit: ident, $width: literal) ) ,+; ) * ) => {
502+ $( atomic_visitors!( @group $op, $inputs => $outputs: $( ( $visit, $width) ) ,+) ; ) *
503+ } ;
504+ ( @group $op: ident, $inputs: tt => $outputs: tt: $( ( $visit: ident, $width: literal) ) ,+) => {
505+ $( atomic_visitors!( @one $op, $inputs => $outputs: $visit, $width) ; ) +
506+ } ;
507+ ( @one $op: ident, [ $( $input: ident) ,* ] => [ $( $output: ident) ,* ] : $visit: ident, $width: literal) => {
508+ fn $visit( & mut self , memarg: wasmparser:: MemArg ) -> Self :: Output {
509+ if memarg. align != ( $width as u32 ) . trailing_zeros( ) as u8 {
510+ return Err ( crate :: ParseError :: Other ( "invalid atomic alignment" . into( ) ) ) ;
511+ }
512+ let address = self . metadata. memory_size( memarg. memory) ?;
513+ self . mark_memory( memarg. memory) ;
514+ let memory = self . push128( Operand128 :: <tinywasm_types:: MemoryOperand >:: new( memarg. offset, memarg. memory) ) ?;
515+ self . emit(
516+ & [ $( atomic_visitors!( @size $input, address) ) ,* ] ,
517+ & [ $( atomic_visitors!( @size $output, address) ) ,* ] ,
518+ Instruction :: Atomic ( AtomicArg :: new( memory, AtomicWidth :: from_bytes( $width) , atomic_visitors!( @is64 [ $( $input) ,* ] [ $( $output) ,* ] ) , AtomicOp :: $op) ) ,
519+ )
520+ }
521+ } ;
522+ ( @size Addr , $address: ident) => { $address } ;
523+ ( @size $lane: ident, $address: ident) => { ValueLane :: $lane } ;
524+ ( @is64 [ Addr , S64 $( , S64 ) * ] $outputs: tt) => { true } ;
525+ ( @is64 [ Addr ] [ S64 ] ) => { true } ;
526+ ( @is64 $inputs: tt $outputs: tt) => { false } ;
527+ }
528+
500529impl < ' a > wasmparser:: VisitOperator < ' a > for FunctionBuilder < ' _ > {
501530 type Output = Result < ( ) > ;
502531
@@ -506,6 +535,41 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder<'_> {
506535
507536 wasmparser:: for_each_visit_operator!( impl_visit_operator) ;
508537
538+ fn visit_atomic_fence ( & mut self ) -> Self :: Output {
539+ self . emit ( & [ ] , & [ ] , Instruction :: AtomicFence )
540+ }
541+
542+ fn visit_memory_atomic_notify ( & mut self , _: wasmparser:: MemArg ) -> Self :: Output {
543+ Err ( crate :: ParseError :: UnsupportedOperator ( "memory.atomic.notify" . into ( ) ) )
544+ }
545+ fn visit_memory_atomic_wait32 ( & mut self , _: wasmparser:: MemArg ) -> Self :: Output {
546+ Err ( crate :: ParseError :: UnsupportedOperator ( "memory.atomic.wait32" . into ( ) ) )
547+ }
548+ fn visit_memory_atomic_wait64 ( & mut self , _: wasmparser:: MemArg ) -> Self :: Output {
549+ Err ( crate :: ParseError :: UnsupportedOperator ( "memory.atomic.wait64" . into ( ) ) )
550+ }
551+
552+ atomic_visitors ! {
553+ Load , [ Addr ] => [ S32 ] : ( visit_i32_atomic_load, 4 ) , ( visit_i32_atomic_load8_u, 1 ) , ( visit_i32_atomic_load16_u, 2 ) ;
554+ Load , [ Addr ] => [ S64 ] : ( visit_i64_atomic_load, 8 ) , ( visit_i64_atomic_load8_u, 1 ) , ( visit_i64_atomic_load16_u, 2 ) , ( visit_i64_atomic_load32_u, 4 ) ;
555+ Store , [ Addr , S32 ] => [ ] : ( visit_i32_atomic_store, 4 ) , ( visit_i32_atomic_store8, 1 ) , ( visit_i32_atomic_store16, 2 ) ;
556+ Store , [ Addr , S64 ] => [ ] : ( visit_i64_atomic_store, 8 ) , ( visit_i64_atomic_store8, 1 ) , ( visit_i64_atomic_store16, 2 ) , ( visit_i64_atomic_store32, 4 ) ;
557+ Add , [ Addr , S32 ] => [ S32 ] : ( visit_i32_atomic_rmw_add, 4 ) , ( visit_i32_atomic_rmw8_add_u, 1 ) , ( visit_i32_atomic_rmw16_add_u, 2 ) ;
558+ Add , [ Addr , S64 ] => [ S64 ] : ( visit_i64_atomic_rmw_add, 8 ) , ( visit_i64_atomic_rmw8_add_u, 1 ) , ( visit_i64_atomic_rmw16_add_u, 2 ) , ( visit_i64_atomic_rmw32_add_u, 4 ) ;
559+ Sub , [ Addr , S32 ] => [ S32 ] : ( visit_i32_atomic_rmw_sub, 4 ) , ( visit_i32_atomic_rmw8_sub_u, 1 ) , ( visit_i32_atomic_rmw16_sub_u, 2 ) ;
560+ Sub , [ Addr , S64 ] => [ S64 ] : ( visit_i64_atomic_rmw_sub, 8 ) , ( visit_i64_atomic_rmw8_sub_u, 1 ) , ( visit_i64_atomic_rmw16_sub_u, 2 ) , ( visit_i64_atomic_rmw32_sub_u, 4 ) ;
561+ And , [ Addr , S32 ] => [ S32 ] : ( visit_i32_atomic_rmw_and, 4 ) , ( visit_i32_atomic_rmw8_and_u, 1 ) , ( visit_i32_atomic_rmw16_and_u, 2 ) ;
562+ And , [ Addr , S64 ] => [ S64 ] : ( visit_i64_atomic_rmw_and, 8 ) , ( visit_i64_atomic_rmw8_and_u, 1 ) , ( visit_i64_atomic_rmw16_and_u, 2 ) , ( visit_i64_atomic_rmw32_and_u, 4 ) ;
563+ Or , [ Addr , S32 ] => [ S32 ] : ( visit_i32_atomic_rmw_or, 4 ) , ( visit_i32_atomic_rmw8_or_u, 1 ) , ( visit_i32_atomic_rmw16_or_u, 2 ) ;
564+ Or , [ Addr , S64 ] => [ S64 ] : ( visit_i64_atomic_rmw_or, 8 ) , ( visit_i64_atomic_rmw8_or_u, 1 ) , ( visit_i64_atomic_rmw16_or_u, 2 ) , ( visit_i64_atomic_rmw32_or_u, 4 ) ;
565+ Xor , [ Addr , S32 ] => [ S32 ] : ( visit_i32_atomic_rmw_xor, 4 ) , ( visit_i32_atomic_rmw8_xor_u, 1 ) , ( visit_i32_atomic_rmw16_xor_u, 2 ) ;
566+ Xor , [ Addr , S64 ] => [ S64 ] : ( visit_i64_atomic_rmw_xor, 8 ) , ( visit_i64_atomic_rmw8_xor_u, 1 ) , ( visit_i64_atomic_rmw16_xor_u, 2 ) , ( visit_i64_atomic_rmw32_xor_u, 4 ) ;
567+ Xchg , [ Addr , S32 ] => [ S32 ] : ( visit_i32_atomic_rmw_xchg, 4 ) , ( visit_i32_atomic_rmw8_xchg_u, 1 ) , ( visit_i32_atomic_rmw16_xchg_u, 2 ) ;
568+ Xchg , [ Addr , S64 ] => [ S64 ] : ( visit_i64_atomic_rmw_xchg, 8 ) , ( visit_i64_atomic_rmw8_xchg_u, 1 ) , ( visit_i64_atomic_rmw16_xchg_u, 2 ) , ( visit_i64_atomic_rmw32_xchg_u, 4 ) ;
569+ Cmpxchg , [ Addr , S32 , S32 ] => [ S32 ] : ( visit_i32_atomic_rmw_cmpxchg, 4 ) , ( visit_i32_atomic_rmw8_cmpxchg_u, 1 ) , ( visit_i32_atomic_rmw16_cmpxchg_u, 2 ) ;
570+ Cmpxchg , [ Addr , S64 , S64 ] => [ S64 ] : ( visit_i64_atomic_rmw_cmpxchg, 8 ) , ( visit_i64_atomic_rmw8_cmpxchg_u, 1 ) , ( visit_i64_atomic_rmw16_cmpxchg_u, 2 ) , ( visit_i64_atomic_rmw32_cmpxchg_u, 4 ) ;
571+ }
572+
509573 lowering_ops ! {
510574 memory [ Addr ] => [ S32 ] {
511575 visit_i32_load => I32Load [ load( Instruction :: LoadLocal32 ) ] ,
0 commit comments