@@ -388,7 +388,7 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
388388
389389 define_operands ! {
390390 // basic instructions
391- visit_global_get( GlobalGet , u32 ) , visit_i32_const( I32Const , i32 ) , visit_i64_const( I64Const , i64 ) , visit_call( Call , u32 ) , visit_return_call( ReturnCall , u32 ) , visit_memory_size( MemorySize , u32 ) , visit_memory_grow( MemoryGrow , u32 ) , visit_unreachable( Unreachable ) , visit_nop( Nop ) , visit_i32_eqz( I32Eqz ) , visit_i32_eq( I32Eq ) , visit_i32_ne( I32Ne ) , visit_i32_lt_s( I32LtS ) , visit_i32_lt_u( I32LtU ) , visit_i32_gt_s( I32GtS ) , visit_i32_gt_u( I32GtU ) , visit_i32_le_s( I32LeS ) , visit_i32_le_u( I32LeU ) , visit_i32_ge_s( I32GeS ) , visit_i32_ge_u( I32GeU ) , visit_i64_eqz( I64Eqz ) , visit_i64_eq( I64Eq ) , visit_i64_ne( I64Ne ) , visit_i64_lt_s( I64LtS ) , visit_i64_lt_u( I64LtU ) , visit_i64_gt_s( I64GtS ) , visit_i64_gt_u( I64GtU ) , visit_i64_le_s( I64LeS ) , visit_i64_le_u( I64LeU ) , visit_i64_ge_s( I64GeS ) , visit_i64_ge_u( I64GeU ) , visit_f32_eq( F32Eq ) , visit_f32_ne( F32Ne ) , visit_f32_lt( F32Lt ) , visit_f32_gt( F32Gt ) , visit_f32_le( F32Le ) , visit_f32_ge( F32Ge ) , visit_f64_eq( F64Eq ) , visit_f64_ne( F64Ne ) , visit_f64_lt( F64Lt ) , visit_f64_gt( F64Gt ) , visit_f64_le( F64Le ) , visit_f64_ge( F64Ge ) , visit_i32_clz( I32Clz ) , visit_i32_ctz( I32Ctz ) , visit_i32_popcnt( I32Popcnt ) , visit_i32_sub( I32Sub ) , visit_i32_mul( I32Mul ) , visit_i32_div_s( I32DivS ) , visit_i32_div_u( I32DivU ) , visit_i32_rem_s( I32RemS ) , visit_i32_rem_u( I32RemU ) , visit_i32_and( I32And ) , visit_i32_or( I32Or ) , visit_i32_xor( I32Xor ) , visit_i32_shl( I32Shl ) , visit_i32_shr_s( I32ShrS ) , visit_i32_shr_u( I32ShrU ) , visit_i32_rotl( I32Rotl ) , visit_i32_rotr( I32Rotr ) , visit_i64_clz( I64Clz ) , visit_i64_ctz( I64Ctz ) , visit_i64_popcnt( I64Popcnt ) , visit_i64_sub( I64Sub ) , visit_i64_mul( I64Mul ) , visit_i64_div_s( I64DivS ) , visit_i64_div_u( I64DivU ) , visit_i64_rem_s( I64RemS ) , visit_i64_rem_u( I64RemU ) , visit_i64_and( I64And ) , visit_i64_or( I64Or ) , visit_i64_xor( I64Xor ) , visit_i64_shl( I64Shl ) , visit_i64_shr_s( I64ShrS ) , visit_i64_shr_u( I64ShrU ) , visit_i64_rotr( I64Rotr ) , visit_f32_abs( F32Abs ) , visit_f32_neg( F32Neg ) , visit_f32_ceil( F32Ceil ) , visit_f32_floor( F32Floor ) , visit_f32_trunc( F32Trunc ) , visit_f32_nearest( F32Nearest ) , visit_f32_sqrt( F32Sqrt ) , visit_f32_add( F32Add ) , visit_f32_sub( F32Sub ) , visit_f32_mul( F32Mul ) , visit_f32_div( F32Div ) , visit_f32_min( F32Min ) , visit_f32_max( F32Max ) , visit_f32_copysign( F32Copysign ) , visit_f64_abs( F64Abs ) , visit_f64_neg( F64Neg ) , visit_f64_ceil( F64Ceil ) , visit_f64_floor( F64Floor ) , visit_f64_trunc( F64Trunc ) , visit_f64_nearest( F64Nearest ) , visit_f64_sqrt( F64Sqrt ) , visit_f64_add( F64Add ) , visit_f64_sub( F64Sub ) , visit_f64_mul( F64Mul ) , visit_f64_div( F64Div ) , visit_f64_min( F64Min ) , visit_f64_max( F64Max ) , visit_f64_copysign( F64Copysign ) , visit_i32_wrap_i64( I32WrapI64 ) , visit_i32_trunc_f32_s( I32TruncF32S ) , visit_i32_trunc_f32_u( I32TruncF32U ) , visit_i32_trunc_f64_s( I32TruncF64S ) , visit_i32_trunc_f64_u( I32TruncF64U ) , visit_i64_extend_i32_s( I64ExtendI32S ) , visit_i64_extend_i32_u( I64ExtendI32U ) , visit_i64_trunc_f32_s( I64TruncF32S ) , visit_i64_trunc_f32_u( I64TruncF32U ) , visit_i64_trunc_f64_s( I64TruncF64S ) , visit_i64_trunc_f64_u( I64TruncF64U ) , visit_f32_convert_i32_s( F32ConvertI32S ) , visit_f32_convert_i32_u( F32ConvertI32U ) , visit_f32_convert_i64_s( F32ConvertI64S ) , visit_f32_convert_i64_u( F32ConvertI64U ) , visit_f32_demote_f64( F32DemoteF64 ) , visit_f64_convert_i32_s( F64ConvertI32S ) , visit_f64_convert_i32_u( F64ConvertI32U ) , visit_f64_convert_i64_s( F64ConvertI64S ) , visit_f64_convert_i64_u( F64ConvertI64U ) , visit_f64_promote_f32( F64PromoteF32 ) , visit_i32_reinterpret_f32( I32ReinterpretF32 ) , visit_i64_reinterpret_f64( I64ReinterpretF64 ) , visit_f32_reinterpret_i32( F32ReinterpretI32 ) , visit_f64_reinterpret_i64( F64ReinterpretI64 ) ,
391+ visit_global_get( GlobalGet , u32 ) , visit_i32_const( I32Const , i32 ) , visit_i64_const( I64Const , i64 ) , visit_call( Call , u32 ) , visit_return_call( ReturnCall , u32 ) , visit_memory_size( MemorySize , u32 ) , visit_memory_grow( MemoryGrow , u32 ) , visit_unreachable( Unreachable ) , visit_nop( Nop ) , visit_i32_eqz( I32Eqz ) , visit_i32_eq( I32Eq ) , visit_i32_ne( I32Ne ) , visit_i32_lt_s( I32LtS ) , visit_i32_lt_u( I32LtU ) , visit_i32_gt_s( I32GtS ) , visit_i32_gt_u( I32GtU ) , visit_i32_le_s( I32LeS ) , visit_i32_le_u( I32LeU ) , visit_i32_ge_s( I32GeS ) , visit_i32_ge_u( I32GeU ) , visit_i64_eqz( I64Eqz ) , visit_i64_eq( I64Eq ) , visit_i64_ne( I64Ne ) , visit_i64_lt_s( I64LtS ) , visit_i64_lt_u( I64LtU ) , visit_i64_gt_s( I64GtS ) , visit_i64_gt_u( I64GtU ) , visit_i64_le_s( I64LeS ) , visit_i64_le_u( I64LeU ) , visit_i64_ge_s( I64GeS ) , visit_i64_ge_u( I64GeU ) , visit_f32_eq( F32Eq ) , visit_f32_ne( F32Ne ) , visit_f32_lt( F32Lt ) , visit_f32_gt( F32Gt ) , visit_f32_le( F32Le ) , visit_f32_ge( F32Ge ) , visit_f64_eq( F64Eq ) , visit_f64_ne( F64Ne ) , visit_f64_lt( F64Lt ) , visit_f64_gt( F64Gt ) , visit_f64_le( F64Le ) , visit_f64_ge( F64Ge ) , visit_i32_clz( I32Clz ) , visit_i32_ctz( I32Ctz ) , visit_i32_popcnt( I32Popcnt ) , visit_i32_sub( I32Sub ) , visit_i32_mul( I32Mul ) , visit_i32_div_s( I32DivS ) , visit_i32_div_u( I32DivU ) , visit_i32_rem_s( I32RemS ) , visit_i32_rem_u( I32RemU ) , visit_i32_and( I32And ) , visit_i32_or( I32Or ) , visit_i32_xor( I32Xor ) , visit_i32_shl( I32Shl ) , visit_i32_shr_s( I32ShrS ) , visit_i32_shr_u( I32ShrU ) , visit_i32_rotl( I32Rotl ) , visit_i32_rotr( I32Rotr ) , visit_i64_clz( I64Clz ) , visit_i64_ctz( I64Ctz ) , visit_i64_popcnt( I64Popcnt ) , visit_i64_sub( I64Sub ) , visit_i64_mul( I64Mul ) , visit_i64_div_s( I64DivS ) , visit_i64_div_u( I64DivU ) , visit_i64_rem_s( I64RemS ) , visit_i64_rem_u( I64RemU ) , visit_i64_and( I64And ) , visit_i64_or( I64Or ) , visit_i64_xor( I64Xor ) , visit_i64_shl( I64Shl ) , visit_i64_shr_s( I64ShrS ) , visit_i64_shr_u( I64ShrU ) , visit_i64_rotr( I64Rotr ) , visit_f32_abs( F32Abs ) , visit_f32_neg( F32Neg ) , visit_f32_ceil( F32Ceil ) , visit_f32_floor( F32Floor ) , visit_f32_trunc( F32Trunc ) , visit_f32_nearest( F32Nearest ) , visit_f32_sqrt( F32Sqrt ) , visit_f32_add( F32Add ) , visit_f32_sub( F32Sub ) , visit_f32_mul( F32Mul ) , visit_f32_div( F32Div ) , visit_f32_min( F32Min ) , visit_f32_max( F32Max ) , visit_f32_copysign( F32Copysign ) , visit_f64_abs( F64Abs ) , visit_f64_neg( F64Neg ) , visit_f64_ceil( F64Ceil ) , visit_f64_floor( F64Floor ) , visit_f64_trunc( F64Trunc ) , visit_f64_nearest( F64Nearest ) , visit_f64_sqrt( F64Sqrt ) , visit_f64_add( F64Add ) , visit_f64_sub( F64Sub ) , visit_f64_mul( F64Mul ) , visit_f64_div( F64Div ) , visit_f64_min( F64Min ) , visit_f64_max( F64Max ) , visit_f64_copysign( F64Copysign ) , visit_i32_wrap_i64( I32WrapI64 ) , visit_i32_trunc_f32_s( I32TruncF32S ) , visit_i32_trunc_f32_u( I32TruncF32U ) , visit_i32_trunc_f64_s( I32TruncF64S ) , visit_i32_trunc_f64_u( I32TruncF64U ) , visit_i64_extend_i32_s( I64ExtendI32S ) , visit_i64_extend_i32_u( I64ExtendI32U ) , visit_i64_trunc_f32_s( I64TruncF32S ) , visit_i64_trunc_f32_u( I64TruncF32U ) , visit_i64_trunc_f64_s( I64TruncF64S ) , visit_i64_trunc_f64_u( I64TruncF64U ) , visit_f32_convert_i32_s( F32ConvertI32S ) , visit_f32_convert_i32_u( F32ConvertI32U ) , visit_f32_convert_i64_s( F32ConvertI64S ) , visit_f32_convert_i64_u( F32ConvertI64U ) , visit_f32_demote_f64( F32DemoteF64 ) , visit_f64_convert_i32_s( F64ConvertI32S ) , visit_f64_convert_i32_u( F64ConvertI32U ) , visit_f64_convert_i64_s( F64ConvertI64S ) , visit_f64_convert_i64_u( F64ConvertI64U ) , visit_f64_promote_f32( F64PromoteF32 ) ,
392392
393393 // sign_extension
394394 visit_i32_extend8_s( I32Extend8S ) , visit_i32_extend16_s( I32Extend16S ) , visit_i64_extend8_s( I64Extend8S ) , visit_i64_extend16_s( I64Extend16S ) , visit_i64_extend32_s( I64Extend32S ) ,
@@ -446,6 +446,30 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
446446 }
447447
448448 fn visit_drop ( & mut self ) -> Self :: Output {
449+ match self . instructions . last ( ) . copied ( ) {
450+ Some ( Instruction :: LocalTee32 ( local) ) => {
451+ self . instructions . pop ( ) ;
452+ self . instructions . push ( Instruction :: LocalSet32 ( local) ) ;
453+ return ;
454+ }
455+ Some ( Instruction :: LocalTee64 ( local) ) => {
456+ self . instructions . pop ( ) ;
457+ self . instructions . push ( Instruction :: LocalSet64 ( local) ) ;
458+ return ;
459+ }
460+ Some ( Instruction :: LocalTee128 ( local) ) => {
461+ self . instructions . pop ( ) ;
462+ self . instructions . push ( Instruction :: LocalSet128 ( local) ) ;
463+ return ;
464+ }
465+ Some ( Instruction :: LocalTeeRef ( local) ) => {
466+ self . instructions . pop ( ) ;
467+ self . instructions . push ( Instruction :: LocalSetRef ( local) ) ;
468+ return ;
469+ }
470+ _ => { }
471+ }
472+
449473 match self . validator . get_operand_type ( 0 ) {
450474 Some ( Some ( t) ) => self . instructions . push ( match t {
451475 wasmparser:: ValType :: I32 => Instruction :: Drop32 ,
@@ -491,6 +515,18 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
491515 return ;
492516 }
493517
518+ if len >= 2 {
519+ let lhs = self . instructions [ len - 2 ] ;
520+ let rhs = self . instructions [ len - 1 ] ;
521+ if let ( Instruction :: I32Const ( c) , Instruction :: LocalGet32 ( local) ) = ( lhs, rhs) {
522+ self . instructions . pop ( ) ;
523+ self . instructions . pop ( ) ;
524+ self . instructions . push ( Instruction :: LocalGet32 ( local) ) ;
525+ self . instructions . push ( Instruction :: I32AddConst ( c) ) ;
526+ return ;
527+ }
528+ }
529+
494530 self . instructions . push ( Instruction :: I32Add ) ;
495531 }
496532
@@ -513,6 +549,18 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
513549 return ;
514550 }
515551
552+ if len >= 2 {
553+ let lhs = self . instructions [ len - 2 ] ;
554+ let rhs = self . instructions [ len - 1 ] ;
555+ if let ( Instruction :: I64Const ( c) , Instruction :: LocalGet64 ( local) ) = ( lhs, rhs) {
556+ self . instructions . pop ( ) ;
557+ self . instructions . pop ( ) ;
558+ self . instructions . push ( Instruction :: LocalGet64 ( local) ) ;
559+ self . instructions . push ( Instruction :: I64AddConst ( c) ) ;
560+ return ;
561+ }
562+ }
563+
516564 self . instructions . push ( Instruction :: I64Add ) ;
517565 }
518566
@@ -541,14 +589,44 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
541589 } ;
542590
543591 match self . validator . get_local_type ( idx) {
544- Some ( t) => self . instructions . push ( match t {
545- wasmparser:: ValType :: I32 => Instruction :: LocalGet32 ( resolved_idx) ,
546- wasmparser:: ValType :: F32 => Instruction :: LocalGet32 ( resolved_idx) ,
547- wasmparser:: ValType :: I64 => Instruction :: LocalGet64 ( resolved_idx) ,
548- wasmparser:: ValType :: F64 => Instruction :: LocalGet64 ( resolved_idx) ,
549- wasmparser:: ValType :: V128 => Instruction :: LocalGet128 ( resolved_idx) ,
550- wasmparser:: ValType :: Ref ( _) => Instruction :: LocalGetRef ( resolved_idx) ,
551- } ) ,
592+ Some ( t) => match t {
593+ wasmparser:: ValType :: I32 | wasmparser:: ValType :: F32 => {
594+ if matches ! ( self . instructions. last( ) , Some ( Instruction :: LocalSet32 ( local) ) if * local == resolved_idx)
595+ {
596+ self . instructions . pop ( ) ;
597+ self . instructions . push ( Instruction :: LocalTee32 ( resolved_idx) ) ;
598+ return ;
599+ }
600+ self . instructions . push ( Instruction :: LocalGet32 ( resolved_idx) ) ;
601+ }
602+ wasmparser:: ValType :: I64 | wasmparser:: ValType :: F64 => {
603+ if matches ! ( self . instructions. last( ) , Some ( Instruction :: LocalSet64 ( local) ) if * local == resolved_idx)
604+ {
605+ self . instructions . pop ( ) ;
606+ self . instructions . push ( Instruction :: LocalTee64 ( resolved_idx) ) ;
607+ return ;
608+ }
609+ self . instructions . push ( Instruction :: LocalGet64 ( resolved_idx) ) ;
610+ }
611+ wasmparser:: ValType :: V128 => {
612+ if matches ! ( self . instructions. last( ) , Some ( Instruction :: LocalSet128 ( local) ) if * local == resolved_idx)
613+ {
614+ self . instructions . pop ( ) ;
615+ self . instructions . push ( Instruction :: LocalTee128 ( resolved_idx) ) ;
616+ return ;
617+ }
618+ self . instructions . push ( Instruction :: LocalGet128 ( resolved_idx) ) ;
619+ }
620+ wasmparser:: ValType :: Ref ( _) => {
621+ if matches ! ( self . instructions. last( ) , Some ( Instruction :: LocalSetRef ( local) ) if * local == resolved_idx)
622+ {
623+ self . instructions . pop ( ) ;
624+ self . instructions . push ( Instruction :: LocalTeeRef ( resolved_idx) ) ;
625+ return ;
626+ }
627+ self . instructions . push ( Instruction :: LocalGetRef ( resolved_idx) ) ;
628+ }
629+ } ,
552630 _ => {
553631 self . visit_unreachable ( ) ;
554632 }
@@ -572,6 +650,12 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
572650 {
573651 let from = * from;
574652 self . instructions . pop ( ) ;
653+
654+ if from == resolved_idx {
655+ // local.set x (local.get x) is a no-op; drop it.
656+ return ;
657+ }
658+
575659 // validation will ensure that the last instruction is the correct local.get
576660 match self . validator . get_operand_type ( 0 ) {
577661 Some ( Some ( t) ) => self . instructions . push ( match t {
@@ -612,6 +696,35 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
612696 return ;
613697 } ;
614698
699+ if let Some ( Some ( t) ) = self . validator . get_operand_type ( 0 ) {
700+ match t {
701+ wasmparser:: ValType :: I32 | wasmparser:: ValType :: F32 => {
702+ if matches ! ( self . instructions. last( ) , Some ( Instruction :: LocalGet32 ( local) ) if * local == resolved_idx)
703+ {
704+ return ;
705+ }
706+ }
707+ wasmparser:: ValType :: I64 | wasmparser:: ValType :: F64 => {
708+ if matches ! ( self . instructions. last( ) , Some ( Instruction :: LocalGet64 ( local) ) if * local == resolved_idx)
709+ {
710+ return ;
711+ }
712+ }
713+ wasmparser:: ValType :: V128 => {
714+ if matches ! ( self . instructions. last( ) , Some ( Instruction :: LocalGet128 ( local) ) if * local == resolved_idx)
715+ {
716+ return ;
717+ }
718+ }
719+ wasmparser:: ValType :: Ref ( _) => {
720+ if matches ! ( self . instructions. last( ) , Some ( Instruction :: LocalGetRef ( local) ) if * local == resolved_idx)
721+ {
722+ return ;
723+ }
724+ }
725+ }
726+ }
727+
615728 if let Some ( Instruction :: I64XorRotlConst ( c) ) = self . instructions . last ( ) . copied ( ) {
616729 match self . validator . get_operand_type ( 0 ) {
617730 Some ( Some ( wasmparser:: ValType :: I64 ) ) | Some ( Some ( wasmparser:: ValType :: F64 ) ) => {
@@ -836,6 +949,11 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
836949 wasmparser:: ValType :: Ref ( _) => Instruction :: SelectRef ,
837950 } ) ;
838951 }
952+
953+ fn visit_f32_reinterpret_i32 ( & mut self ) -> Self :: Output { }
954+ fn visit_f64_reinterpret_i64 ( & mut self ) -> Self :: Output { }
955+ fn visit_i32_reinterpret_f32 ( & mut self ) -> Self :: Output { }
956+ fn visit_i64_reinterpret_f64 ( & mut self ) -> Self :: Output { }
839957}
840958
841959macro_rules! impl_visit_simd_operator {
0 commit comments