wa-lang.org/wazero@v1.0.2/internal/wazeroir/compiler_test.go (about)

     1  package wazeroir
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"math"
     7  	"testing"
     8  
     9  	"wa-lang.org/wazero/api"
    10  	"wa-lang.org/wazero/internal/leb128"
    11  	"wa-lang.org/wazero/internal/testing/require"
    12  	"wa-lang.org/wazero/internal/wasm"
    13  )
    14  
    15  // ctx is an arbitrary, non-default context.
    16  var ctx = context.WithValue(context.Background(), struct{}{}, "arbitrary")
    17  
    18  var (
    19  	f32, f64, i32 = wasm.ValueTypeF32, wasm.ValueTypeF64, wasm.ValueTypeI32
    20  	f32_i32       = &wasm.FunctionType{
    21  		Params: []wasm.ValueType{f32}, Results: []wasm.ValueType{i32},
    22  		ParamNumInUint64:  1,
    23  		ResultNumInUint64: 1,
    24  	}
    25  	i32_i32 = &wasm.FunctionType{
    26  		Params: []wasm.ValueType{i32}, Results: []wasm.ValueType{i32},
    27  		ParamNumInUint64:  1,
    28  		ResultNumInUint64: 1,
    29  	}
    30  	i32i32_i32 = &wasm.FunctionType{
    31  		Params: []wasm.ValueType{i32, i32}, Results: []wasm.ValueType{i32},
    32  		ParamNumInUint64:  2,
    33  		ResultNumInUint64: 1,
    34  	}
    35  	v_v      = &wasm.FunctionType{}
    36  	v_f64f64 = &wasm.FunctionType{Results: []wasm.ValueType{f64, f64}, ResultNumInUint64: 2}
    37  )
    38  
    39  func TestCompile(t *testing.T) {
    40  	tests := []struct {
    41  		name            string
    42  		module          *wasm.Module
    43  		expected        *CompilationResult
    44  		enabledFeatures api.CoreFeatures
    45  	}{
    46  		{
    47  			name: "nullary",
    48  			module: &wasm.Module{
    49  				TypeSection:     []*wasm.FunctionType{v_v},
    50  				FunctionSection: []wasm.Index{0},
    51  				CodeSection:     []*wasm.Code{{Body: []byte{wasm.OpcodeEnd}}},
    52  			},
    53  			expected: &CompilationResult{
    54  				Operations: []Operation{ // begin with params: []
    55  					&OperationBr{Target: &BranchTarget{}}, // return!
    56  				},
    57  				LabelCallers: map[string]uint32{},
    58  				Functions:    []uint32{0},
    59  				Types:        []*wasm.FunctionType{v_v},
    60  				Signature:    v_v,
    61  				TableTypes:   []wasm.RefType{},
    62  			},
    63  		},
    64  		{
    65  			name: "host wasm nullary",
    66  			module: &wasm.Module{
    67  				TypeSection:     []*wasm.FunctionType{v_v},
    68  				FunctionSection: []wasm.Index{0},
    69  				CodeSection:     []*wasm.Code{{IsHostFunction: true, Body: []byte{wasm.OpcodeEnd}}},
    70  			},
    71  			expected: &CompilationResult{
    72  				IsHostFunction: true,
    73  				Operations: []Operation{ // begin with params: []
    74  					&OperationBr{Target: &BranchTarget{}}, // return!
    75  				},
    76  				LabelCallers: map[string]uint32{},
    77  				Functions:    []uint32{0},
    78  				Types:        []*wasm.FunctionType{v_v},
    79  				Signature:    v_v,
    80  				TableTypes:   []wasm.RefType{},
    81  			},
    82  		},
    83  		{
    84  			name: "host go nullary",
    85  			module: &wasm.Module{
    86  				TypeSection:     []*wasm.FunctionType{v_v},
    87  				FunctionSection: []wasm.Index{0},
    88  				CodeSection:     []*wasm.Code{wasm.MustParseGoReflectFuncCode(func() {})},
    89  			},
    90  			expected: &CompilationResult{IsHostFunction: true},
    91  		},
    92  		{
    93  			name: "host go context.Context api.Module uses memory",
    94  			module: &wasm.Module{
    95  				TypeSection:     []*wasm.FunctionType{v_v},
    96  				FunctionSection: []wasm.Index{0},
    97  				CodeSection:     []*wasm.Code{wasm.MustParseGoReflectFuncCode(func(context.Context, api.Module) {})},
    98  			},
    99  			expected: &CompilationResult{IsHostFunction: true, UsesMemory: true},
   100  		},
   101  		{
   102  			name: "identity",
   103  			module: &wasm.Module{
   104  				TypeSection:     []*wasm.FunctionType{i32_i32},
   105  				FunctionSection: []wasm.Index{0},
   106  				CodeSection:     []*wasm.Code{{Body: []byte{wasm.OpcodeLocalGet, 0, wasm.OpcodeEnd}}},
   107  			},
   108  			expected: &CompilationResult{
   109  				Operations: []Operation{ // begin with params: [$x]
   110  					&OperationPick{Depth: 0},                                 // [$x, $x]
   111  					&OperationDrop{Depth: &InclusiveRange{Start: 1, End: 1}}, // [$x]
   112  					&OperationBr{Target: &BranchTarget{}},                    // return!
   113  				},
   114  				LabelCallers: map[string]uint32{},
   115  				Types: []*wasm.FunctionType{
   116  					{
   117  						Params: []wasm.ValueType{i32}, Results: []wasm.ValueType{i32},
   118  						ParamNumInUint64:  1,
   119  						ResultNumInUint64: 1,
   120  					},
   121  				},
   122  				Functions: []uint32{0},
   123  				Signature: &wasm.FunctionType{
   124  					Params: []wasm.ValueType{wasm.ValueTypeI32}, Results: []wasm.ValueType{wasm.ValueTypeI32},
   125  					ParamNumInUint64:  1,
   126  					ResultNumInUint64: 1,
   127  				},
   128  				TableTypes: []wasm.RefType{},
   129  			},
   130  		},
   131  		{
   132  			name: "uses memory",
   133  			module: &wasm.Module{
   134  				TypeSection:     []*wasm.FunctionType{v_v},
   135  				FunctionSection: []wasm.Index{0},
   136  				CodeSection: []*wasm.Code{{Body: []byte{
   137  					wasm.OpcodeI32Const, 8, // memory offset to load
   138  					wasm.OpcodeI32Load, 0x2, 0x0, // load alignment=2 (natural alignment) staticOffset=0
   139  					wasm.OpcodeDrop,
   140  					wasm.OpcodeEnd,
   141  				}}},
   142  			},
   143  			expected: &CompilationResult{
   144  				Operations: []Operation{ // begin with params: []
   145  					&OperationConstI32{Value: 8}, // [8]
   146  					&OperationLoad{Type: UnsignedTypeI32, Arg: &MemoryArg{Alignment: 2, Offset: 0}}, // [x]
   147  					&OperationDrop{Depth: &InclusiveRange{}},                                        // []
   148  					&OperationBr{Target: &BranchTarget{}},                                           // return!
   149  				},
   150  				LabelCallers: map[string]uint32{},
   151  				Types:        []*wasm.FunctionType{v_v},
   152  				Functions:    []uint32{0},
   153  				Signature:    v_v,
   154  				TableTypes:   []wasm.RefType{},
   155  				UsesMemory:   true,
   156  			},
   157  		},
   158  		{
   159  			name: "host uses memory",
   160  			module: &wasm.Module{
   161  				TypeSection:     []*wasm.FunctionType{v_v},
   162  				FunctionSection: []wasm.Index{0},
   163  				CodeSection: []*wasm.Code{{IsHostFunction: true, Body: []byte{
   164  					wasm.OpcodeI32Const, 8, // memory offset to load
   165  					wasm.OpcodeI32Load, 0x2, 0x0, // load alignment=2 (natural alignment) staticOffset=0
   166  					wasm.OpcodeDrop,
   167  					wasm.OpcodeEnd,
   168  				}}},
   169  			},
   170  			expected: &CompilationResult{
   171  				IsHostFunction: true,
   172  				Operations: []Operation{ // begin with params: []
   173  					&OperationConstI32{Value: 8}, // [8]
   174  					&OperationLoad{Type: UnsignedTypeI32, Arg: &MemoryArg{Alignment: 2, Offset: 0}}, // [x]
   175  					&OperationDrop{Depth: &InclusiveRange{}},                                        // []
   176  					&OperationBr{Target: &BranchTarget{}},                                           // return!
   177  				},
   178  				LabelCallers: map[string]uint32{},
   179  				Types:        []*wasm.FunctionType{v_v},
   180  				Functions:    []uint32{0},
   181  				Signature:    v_v,
   182  				TableTypes:   []wasm.RefType{},
   183  				UsesMemory:   true,
   184  			},
   185  		},
   186  		{
   187  			name: "memory.grow", // Ex to expose ops to grow memory
   188  			module: &wasm.Module{
   189  				TypeSection:     []*wasm.FunctionType{i32_i32},
   190  				FunctionSection: []wasm.Index{0},
   191  				CodeSection: []*wasm.Code{{Body: []byte{
   192  					wasm.OpcodeLocalGet, 0, wasm.OpcodeMemoryGrow, 0, wasm.OpcodeEnd,
   193  				}}},
   194  			},
   195  			expected: &CompilationResult{
   196  				Operations: []Operation{ // begin with params: [$delta]
   197  					&OperationPick{Depth: 0},                                 // [$delta, $delta]
   198  					&OperationMemoryGrow{},                                   // [$delta, $old_size]
   199  					&OperationDrop{Depth: &InclusiveRange{Start: 1, End: 1}}, // [$old_size]
   200  					&OperationBr{Target: &BranchTarget{}},                    // return!
   201  				},
   202  				LabelCallers: map[string]uint32{},
   203  				Types: []*wasm.FunctionType{{
   204  					Params: []wasm.ValueType{i32}, Results: []wasm.ValueType{i32},
   205  					ParamNumInUint64:  1,
   206  					ResultNumInUint64: 1,
   207  				}},
   208  				Functions: []uint32{0},
   209  				Signature: &wasm.FunctionType{
   210  					Params: []wasm.ValueType{wasm.ValueTypeI32}, Results: []wasm.ValueType{wasm.ValueTypeI32},
   211  					ParamNumInUint64:  1,
   212  					ResultNumInUint64: 1,
   213  				},
   214  				TableTypes: []wasm.RefType{},
   215  				UsesMemory: true,
   216  			},
   217  		},
   218  	}
   219  
   220  	for _, tt := range tests {
   221  		tc := tt
   222  
   223  		t.Run(tc.name, func(t *testing.T) {
   224  			enabledFeatures := tc.enabledFeatures
   225  			if enabledFeatures == 0 {
   226  				enabledFeatures = api.CoreFeaturesV2
   227  			}
   228  			for _, tp := range tc.module.TypeSection {
   229  				tp.CacheNumInUint64()
   230  			}
   231  			res, err := CompileFunctions(ctx, enabledFeatures, 0, tc.module)
   232  			require.NoError(t, err)
   233  
   234  			fn := res[0]
   235  			if fn.GoFunc != nil { // can't compare functions
   236  				// Special case because reflect.Value can't be compared with Equals
   237  				require.True(t, fn.IsHostFunction)
   238  				require.Equal(t, tc.expected.UsesMemory, fn.UsesMemory)
   239  				require.Equal(t, &tc.module.CodeSection[0].GoFunc, &fn.GoFunc)
   240  			} else {
   241  				require.Equal(t, tc.expected, fn)
   242  			}
   243  		})
   244  	}
   245  }
   246  
   247  func TestCompile_Block(t *testing.T) {
   248  	tests := []struct {
   249  		name            string
   250  		module          *wasm.Module
   251  		expected        *CompilationResult
   252  		enabledFeatures api.CoreFeatures
   253  	}{
   254  		{
   255  			name: "type-i32-i32",
   256  			module: &wasm.Module{
   257  				TypeSection:     []*wasm.FunctionType{v_v},
   258  				FunctionSection: []wasm.Index{0},
   259  				CodeSection: []*wasm.Code{{Body: []byte{
   260  					wasm.OpcodeBlock, 0x40,
   261  					wasm.OpcodeBr, 0,
   262  					wasm.OpcodeI32Add,
   263  					wasm.OpcodeDrop,
   264  					wasm.OpcodeEnd,
   265  					wasm.OpcodeEnd,
   266  				}}},
   267  			},
   268  			// Above set manually until the text compiler supports this:
   269  			// (func (export "type-i32-i32") (block (drop (i32.add (br 0)))))
   270  			expected: &CompilationResult{
   271  				Operations: []Operation{ // begin with params: []
   272  					&OperationBr{
   273  						Target: &BranchTarget{
   274  							Label: &Label{FrameID: 2, Kind: LabelKindContinuation}, // arbitrary FrameID
   275  						},
   276  					},
   277  					&OperationLabel{
   278  						Label: &Label{FrameID: 2, Kind: LabelKindContinuation}, // arbitrary FrameID
   279  					},
   280  					&OperationBr{Target: &BranchTarget{}}, // return!
   281  				},
   282  				// Note: i32.add comes after br 0 so is unreachable. Compilation succeeds when it feels like it
   283  				// shouldn't because the br instruction is stack-polymorphic. In other words, (br 0) substitutes for the
   284  				// two i32 parameters to add.
   285  				LabelCallers: map[string]uint32{".L2_cont": 1},
   286  				Functions:    []uint32{0},
   287  				Types:        []*wasm.FunctionType{v_v},
   288  				Signature:    v_v,
   289  				TableTypes:   []wasm.RefType{},
   290  			},
   291  		},
   292  	}
   293  
   294  	for _, tt := range tests {
   295  		tc := tt
   296  
   297  		t.Run(tc.name, func(t *testing.T) {
   298  			requireCompilationResult(t, tc.enabledFeatures, tc.expected, tc.module)
   299  		})
   300  	}
   301  }
   302  
   303  // TestCompile_BulkMemoryOperations uses the example from the "bulk-memory-operations" overview.
   304  func TestCompile_BulkMemoryOperations(t *testing.T) {
   305  	// Set manually until the text compiler supports this:
   306  	// (module
   307  	//  (memory 1)
   308  	//  (data (i32.const 0) "hello")   ;; data segment 0, is active so always copied
   309  	//  (data "goodbye")               ;; data segment 1, is passive
   310  	//
   311  	//  (func $start
   312  	//    ;; copy data segment 1 into memory 0 (the 0 is implicit)
   313  	//    (memory.init 1
   314  	//      (i32.const 16)    ;; target offset
   315  	//      (i32.const 0)     ;; source offset
   316  	//      (i32.const 7))    ;; length
   317  	//
   318  	//    ;; The memory used by this segment is no longer needed, so this segment can
   319  	//    ;; be dropped.
   320  	//    (data.drop 1)
   321  	//  )
   322  	//  (start $start)
   323  	// )
   324  	two := uint32(2)
   325  	module := &wasm.Module{
   326  		TypeSection:     []*wasm.FunctionType{v_v},
   327  		FunctionSection: []wasm.Index{0},
   328  		MemorySection:   &wasm.Memory{Min: 1},
   329  		DataSection: []*wasm.DataSegment{
   330  			{
   331  				OffsetExpression: &wasm.ConstantExpression{
   332  					Opcode: wasm.OpcodeI32Const,
   333  					Data:   []byte{0x00},
   334  				},
   335  				Init: []byte("hello"),
   336  			},
   337  			{
   338  				OffsetExpression: nil, // passive
   339  				Init:             []byte("goodbye"),
   340  			},
   341  		},
   342  		DataCountSection: &two,
   343  		CodeSection: []*wasm.Code{{Body: []byte{
   344  			wasm.OpcodeI32Const, 16,
   345  			wasm.OpcodeI32Const, 0,
   346  			wasm.OpcodeI32Const, 7,
   347  			wasm.OpcodeMiscPrefix, wasm.OpcodeMiscMemoryInit, 1, 0, // segment 1, memory 0
   348  			wasm.OpcodeMiscPrefix, wasm.OpcodeMiscDataDrop, 1,
   349  			wasm.OpcodeEnd,
   350  		}}},
   351  	}
   352  
   353  	expected := &CompilationResult{
   354  		Operations: []Operation{ // begin with params: []
   355  			&OperationConstI32{16},                // [16]
   356  			&OperationConstI32{0},                 // [16, 0]
   357  			&OperationConstI32{7},                 // [16, 0, 7]
   358  			&OperationMemoryInit{1},               // []
   359  			&OperationDataDrop{1},                 // []
   360  			&OperationBr{Target: &BranchTarget{}}, // return!
   361  		},
   362  		HasMemory:        true,
   363  		UsesMemory:       true,
   364  		HasDataInstances: true,
   365  		LabelCallers:     map[string]uint32{},
   366  		Signature:        v_v,
   367  		Functions:        []wasm.Index{0},
   368  		Types:            []*wasm.FunctionType{v_v},
   369  		TableTypes:       []wasm.RefType{},
   370  	}
   371  
   372  	res, err := CompileFunctions(ctx, api.CoreFeatureBulkMemoryOperations, 0, module)
   373  	require.NoError(t, err)
   374  	require.Equal(t, expected, res[0])
   375  }
   376  
   377  func TestCompile_MultiValue(t *testing.T) {
   378  	i32i32_i32i32 := &wasm.FunctionType{
   379  		Params:            []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32},
   380  		Results:           []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32},
   381  		ParamNumInUint64:  2,
   382  		ResultNumInUint64: 2,
   383  	}
   384  	_i32i64 := &wasm.FunctionType{
   385  		Results:           []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI64},
   386  		ParamNumInUint64:  0,
   387  		ResultNumInUint64: 2,
   388  	}
   389  
   390  	tests := []struct {
   391  		name            string
   392  		module          *wasm.Module
   393  		expected        *CompilationResult
   394  		enabledFeatures api.CoreFeatures
   395  	}{
   396  		{
   397  			name: "swap",
   398  			module: &wasm.Module{
   399  				TypeSection:     []*wasm.FunctionType{i32i32_i32i32},
   400  				FunctionSection: []wasm.Index{0},
   401  				CodeSection: []*wasm.Code{{Body: []byte{
   402  					// (func (param $x i32) (param $y i32) (result i32 i32) local.get 1 local.get 0)
   403  					wasm.OpcodeLocalGet, 1, wasm.OpcodeLocalGet, 0, wasm.OpcodeEnd,
   404  				}}},
   405  			},
   406  			expected: &CompilationResult{
   407  				Operations: []Operation{ // begin with params: [$x, $y]
   408  					&OperationPick{Depth: 0},                                 // [$x, $y, $y]
   409  					&OperationPick{Depth: 2},                                 // [$x, $y, $y, $x]
   410  					&OperationDrop{Depth: &InclusiveRange{Start: 2, End: 3}}, // [$y, $x]
   411  					&OperationBr{Target: &BranchTarget{}},                    // return!
   412  				},
   413  				LabelCallers: map[string]uint32{},
   414  				Signature:    i32i32_i32i32,
   415  				Functions:    []wasm.Index{0},
   416  				Types:        []*wasm.FunctionType{i32i32_i32i32},
   417  				TableTypes:   []wasm.RefType{},
   418  			},
   419  		},
   420  		{
   421  			name: "br.wast - type-f64-f64-value",
   422  			module: &wasm.Module{
   423  				TypeSection:     []*wasm.FunctionType{v_f64f64},
   424  				FunctionSection: []wasm.Index{0},
   425  				CodeSection: []*wasm.Code{{Body: []byte{
   426  					wasm.OpcodeBlock, 0, // (block (result f64 f64)
   427  					wasm.OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0x10, 0x40, // (f64.const 4)
   428  					wasm.OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0x14, 0x40, // (f64.const 5)
   429  					wasm.OpcodeBr, 0,
   430  					wasm.OpcodeF64Add,
   431  					wasm.OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0x18, 0x40, // (f64.const 6)
   432  					wasm.OpcodeEnd,
   433  					wasm.OpcodeEnd,
   434  				}}},
   435  			},
   436  			// Above set manually until the text compiler supports this:
   437  			// (func $type-f64-f64-value (result f64 f64)
   438  			//   (block (result f64 f64)
   439  			//     (f64.add (br 0 (f64.const 4) (f64.const 5))) (f64.const 6)
   440  			//   )
   441  			// )
   442  			expected: &CompilationResult{
   443  				Operations: []Operation{ // begin with params: []
   444  					&OperationConstF64{Value: 4}, // [4]
   445  					&OperationConstF64{Value: 5}, // [4, 5]
   446  					&OperationBr{
   447  						Target: &BranchTarget{
   448  							Label: &Label{FrameID: 2, Kind: LabelKindContinuation}, // arbitrary FrameID
   449  						},
   450  					},
   451  					&OperationLabel{
   452  						Label: &Label{FrameID: 2, Kind: LabelKindContinuation}, // arbitrary FrameID
   453  					},
   454  					&OperationBr{Target: &BranchTarget{}}, // return!
   455  				},
   456  				// Note: f64.add comes after br 0 so is unreachable. This is why neither the add, nor its other operand
   457  				// are in the above compilation result.
   458  				LabelCallers: map[string]uint32{".L2_cont": 1}, // arbitrary label
   459  				Signature:    v_f64f64,
   460  				Functions:    []wasm.Index{0},
   461  				Types:        []*wasm.FunctionType{v_f64f64},
   462  				TableTypes:   []wasm.RefType{},
   463  			},
   464  		},
   465  		{
   466  			name: "call.wast - $const-i32-i64",
   467  			module: &wasm.Module{
   468  				TypeSection:     []*wasm.FunctionType{_i32i64},
   469  				FunctionSection: []wasm.Index{0},
   470  				CodeSection: []*wasm.Code{{Body: []byte{
   471  					//  (func $const-i32-i64 (result i32 i64) i32.const 306 i64.const 356)
   472  					wasm.OpcodeI32Const, 0xb2, 0x2, wasm.OpcodeI64Const, 0xe4, 0x2, wasm.OpcodeEnd,
   473  				}}},
   474  			},
   475  			expected: &CompilationResult{
   476  				Operations: []Operation{ // begin with params: []
   477  					&OperationConstI32{Value: 306},        // [306]
   478  					&OperationConstI64{Value: 356},        // [306, 356]
   479  					&OperationBr{Target: &BranchTarget{}}, // return!
   480  				},
   481  				LabelCallers: map[string]uint32{},
   482  				Signature:    _i32i64,
   483  				Functions:    []wasm.Index{0},
   484  				Types:        []*wasm.FunctionType{_i32i64},
   485  				TableTypes:   []wasm.RefType{},
   486  			},
   487  		},
   488  		{
   489  			name: "if.wast - param",
   490  			module: &wasm.Module{
   491  				TypeSection:     []*wasm.FunctionType{i32_i32}, // (func (param i32) (result i32)
   492  				FunctionSection: []wasm.Index{0},
   493  				CodeSection: []*wasm.Code{{Body: []byte{
   494  					wasm.OpcodeI32Const, 1, // (i32.const 1)
   495  					wasm.OpcodeLocalGet, 0, wasm.OpcodeIf, 0, // (if (param i32) (result i32) (local.get 0)
   496  					wasm.OpcodeI32Const, 2, wasm.OpcodeI32Add, // (then (i32.const 2) (i32.add))
   497  					wasm.OpcodeElse, wasm.OpcodeI32Const, 0x7e, wasm.OpcodeI32Add, // (else (i32.const -2) (i32.add))
   498  					wasm.OpcodeEnd, // )
   499  					wasm.OpcodeEnd, // )
   500  				}}},
   501  			},
   502  			// Above set manually until the text compiler supports this:
   503  			//	(func (export "param") (param i32) (result i32)
   504  			//	  (i32.const 1)
   505  			//	  (if (param i32) (result i32) (local.get 0)
   506  			//	    (then (i32.const 2) (i32.add))
   507  			//	    (else (i32.const -2) (i32.add))
   508  			//	  )
   509  			//	)
   510  			expected: &CompilationResult{
   511  				Operations: []Operation{ // begin with params: [$0]
   512  					&OperationConstI32{Value: 1}, // [$0, 1]
   513  					&OperationPick{Depth: 1},     // [$0, 1, $0]
   514  					&OperationBrIf{ // [$0, 1]
   515  						Then: &BranchTargetDrop{Target: &BranchTarget{Label: &Label{FrameID: 2, Kind: LabelKindHeader}}},
   516  						Else: &BranchTargetDrop{Target: &BranchTarget{Label: &Label{FrameID: 2, Kind: LabelKindElse}}},
   517  					},
   518  					&OperationLabel{Label: &Label{FrameID: 2, Kind: LabelKindHeader}},
   519  					&OperationConstI32{Value: 2},         // [$0, 1, 2]
   520  					&OperationAdd{Type: UnsignedTypeI32}, // [$0, 3]
   521  					&OperationBr{Target: &BranchTarget{Label: &Label{FrameID: 2, Kind: LabelKindContinuation}}},
   522  					&OperationLabel{Label: &Label{FrameID: 2, Kind: LabelKindElse}},
   523  					&OperationConstI32{Value: uint32(api.EncodeI32(-2))}, // [$0, 1, -2]
   524  					&OperationAdd{Type: UnsignedTypeI32},                 // [$0, -1]
   525  					&OperationBr{Target: &BranchTarget{Label: &Label{FrameID: 2, Kind: LabelKindContinuation}}},
   526  					&OperationLabel{Label: &Label{FrameID: 2, Kind: LabelKindContinuation}},
   527  					&OperationDrop{Depth: &InclusiveRange{Start: 1, End: 1}}, // .L2 = [3], .L2_else = [-1]
   528  					&OperationBr{Target: &BranchTarget{}},
   529  				},
   530  				LabelCallers: map[string]uint32{
   531  					".L2":      1,
   532  					".L2_cont": 2,
   533  					".L2_else": 1,
   534  				},
   535  				Signature:  i32_i32,
   536  				Functions:  []wasm.Index{0},
   537  				Types:      []*wasm.FunctionType{i32_i32},
   538  				TableTypes: []wasm.RefType{},
   539  			},
   540  		},
   541  		{
   542  			name: "if.wast - params",
   543  			module: &wasm.Module{
   544  				TypeSection: []*wasm.FunctionType{
   545  					i32_i32,    // (func (param i32) (result i32)
   546  					i32i32_i32, // (if (param i32 i32) (result i32)
   547  				},
   548  				FunctionSection: []wasm.Index{0},
   549  				CodeSection: []*wasm.Code{{Body: []byte{
   550  					wasm.OpcodeI32Const, 1, // (i32.const 1)
   551  					wasm.OpcodeI32Const, 2, // (i32.const 2)
   552  					wasm.OpcodeLocalGet, 0, wasm.OpcodeIf, 1, // (if (param i32) (result i32) (local.get 0)
   553  					wasm.OpcodeI32Add,                  // (then (i32.add))
   554  					wasm.OpcodeElse, wasm.OpcodeI32Sub, // (else (i32.sub))
   555  					wasm.OpcodeEnd, // )
   556  					wasm.OpcodeEnd, // )
   557  				}}},
   558  			},
   559  			// Above set manually until the text compiler supports this:
   560  			//	(func (export "params") (param i32) (result i32)
   561  			//	  (i32.const 1)
   562  			//	  (i32.const 2)
   563  			//	  (if (param i32 i32) (result i32) (local.get 0)
   564  			//	    (then (i32.add))
   565  			//	    (else (i32.sub))
   566  			//	  )
   567  			//	)
   568  			expected: &CompilationResult{
   569  				Operations: []Operation{ // begin with params: [$0]
   570  					&OperationConstI32{Value: 1}, // [$0, 1]
   571  					&OperationConstI32{Value: 2}, // [$0, 1, 2]
   572  					&OperationPick{Depth: 2},     // [$0, 1, 2, $0]
   573  					&OperationBrIf{ // [$0, 1, 2]
   574  						Then: &BranchTargetDrop{Target: &BranchTarget{Label: &Label{FrameID: 2, Kind: LabelKindHeader}}},
   575  						Else: &BranchTargetDrop{Target: &BranchTarget{Label: &Label{FrameID: 2, Kind: LabelKindElse}}},
   576  					},
   577  					&OperationLabel{Label: &Label{FrameID: 2, Kind: LabelKindHeader}},
   578  					&OperationAdd{Type: UnsignedTypeI32}, // [$0, 3]
   579  					&OperationBr{Target: &BranchTarget{Label: &Label{FrameID: 2, Kind: LabelKindContinuation}}},
   580  					&OperationLabel{Label: &Label{FrameID: 2, Kind: LabelKindElse}},
   581  					&OperationSub{Type: UnsignedTypeI32}, // [$0, -1]
   582  					&OperationBr{Target: &BranchTarget{Label: &Label{FrameID: 2, Kind: LabelKindContinuation}}},
   583  					&OperationLabel{Label: &Label{FrameID: 2, Kind: LabelKindContinuation}},
   584  					&OperationDrop{Depth: &InclusiveRange{Start: 1, End: 1}}, // .L2 = [3], .L2_else = [-1]
   585  					&OperationBr{Target: &BranchTarget{}},
   586  				},
   587  				LabelCallers: map[string]uint32{
   588  					".L2":      1,
   589  					".L2_cont": 2,
   590  					".L2_else": 1,
   591  				},
   592  				Signature:  i32_i32,
   593  				Functions:  []wasm.Index{0},
   594  				Types:      []*wasm.FunctionType{i32_i32, i32i32_i32},
   595  				TableTypes: []wasm.RefType{},
   596  			},
   597  		},
   598  		{
   599  			name: "if.wast - params-break",
   600  			module: &wasm.Module{
   601  				TypeSection: []*wasm.FunctionType{
   602  					i32_i32,    // (func (param i32) (result i32)
   603  					i32i32_i32, // (if (param i32 i32) (result i32)
   604  				},
   605  				FunctionSection: []wasm.Index{0},
   606  				CodeSection: []*wasm.Code{{Body: []byte{
   607  					wasm.OpcodeI32Const, 1, // (i32.const 1)
   608  					wasm.OpcodeI32Const, 2, // (i32.const 2)
   609  					wasm.OpcodeLocalGet, 0, wasm.OpcodeIf, 1, // (if (param i32) (result i32) (local.get 0)
   610  					wasm.OpcodeI32Add, wasm.OpcodeBr, 0, // (then (i32.add) (br 0))
   611  					wasm.OpcodeElse, wasm.OpcodeI32Sub, wasm.OpcodeBr, 0, // (else (i32.sub) (br 0))
   612  					wasm.OpcodeEnd, // )
   613  					wasm.OpcodeEnd, // )
   614  				}}},
   615  			},
   616  			// Above set manually until the text compiler supports this:
   617  			//	(func (export "params-break") (param i32) (result i32)
   618  			//	  (i32.const 1)
   619  			//	  (i32.const 2)
   620  			//	  (if (param i32 i32) (result i32) (local.get 0)
   621  			//	    (then (i32.add) (br 0))
   622  			//	    (else (i32.sub) (br 0))
   623  			//	  )
   624  			//	)
   625  			expected: &CompilationResult{
   626  				Operations: []Operation{ // begin with params: [$0]
   627  					&OperationConstI32{Value: 1}, // [$0, 1]
   628  					&OperationConstI32{Value: 2}, // [$0, 1, 2]
   629  					&OperationPick{Depth: 2},     // [$0, 1, 2, $0]
   630  					&OperationBrIf{ // [$0, 1, 2]
   631  						Then: &BranchTargetDrop{Target: &BranchTarget{Label: &Label{FrameID: 2, Kind: LabelKindHeader}}},
   632  						Else: &BranchTargetDrop{Target: &BranchTarget{Label: &Label{FrameID: 2, Kind: LabelKindElse}}},
   633  					},
   634  					&OperationLabel{Label: &Label{FrameID: 2, Kind: LabelKindHeader}},
   635  					&OperationAdd{Type: UnsignedTypeI32}, // [$0, 3]
   636  					&OperationBr{Target: &BranchTarget{Label: &Label{FrameID: 2, Kind: LabelKindContinuation}}},
   637  					&OperationLabel{Label: &Label{FrameID: 2, Kind: LabelKindElse}},
   638  					&OperationSub{Type: UnsignedTypeI32}, // [$0, -1]
   639  					&OperationBr{Target: &BranchTarget{Label: &Label{FrameID: 2, Kind: LabelKindContinuation}}},
   640  					&OperationLabel{Label: &Label{FrameID: 2, Kind: LabelKindContinuation}},
   641  					&OperationDrop{Depth: &InclusiveRange{Start: 1, End: 1}}, // .L2 = [3], .L2_else = [-1]
   642  					&OperationBr{Target: &BranchTarget{}},
   643  				},
   644  				LabelCallers: map[string]uint32{
   645  					".L2":      1,
   646  					".L2_cont": 2,
   647  					".L2_else": 1,
   648  				},
   649  				Signature:  i32_i32,
   650  				Functions:  []wasm.Index{0},
   651  				Types:      []*wasm.FunctionType{i32_i32, i32i32_i32},
   652  				TableTypes: []wasm.RefType{},
   653  			},
   654  		},
   655  	}
   656  
   657  	for _, tt := range tests {
   658  		tc := tt
   659  
   660  		t.Run(tc.name, func(t *testing.T) {
   661  			enabledFeatures := tc.enabledFeatures
   662  			if enabledFeatures == 0 {
   663  				enabledFeatures = api.CoreFeaturesV2
   664  			}
   665  			for _, tp := range tc.module.TypeSection {
   666  				tp.CacheNumInUint64()
   667  			}
   668  			res, err := CompileFunctions(ctx, enabledFeatures, 0, tc.module)
   669  			require.NoError(t, err)
   670  			require.Equal(t, tc.expected, res[0])
   671  		})
   672  	}
   673  }
   674  
   675  // TestCompile_NonTrappingFloatToIntConversion picks an arbitrary operator from "nontrapping-float-to-int-conversion".
   676  func TestCompile_NonTrappingFloatToIntConversion(t *testing.T) {
   677  	module := &wasm.Module{
   678  		TypeSection:     []*wasm.FunctionType{f32_i32},
   679  		FunctionSection: []wasm.Index{0},
   680  		// (func (param f32) (result i32) local.get 0 i32.trunc_sat_f32_s)
   681  		CodeSection: []*wasm.Code{{Body: []byte{
   682  			wasm.OpcodeLocalGet, 0, wasm.OpcodeMiscPrefix, wasm.OpcodeMiscI32TruncSatF32S, wasm.OpcodeEnd,
   683  		}}},
   684  	}
   685  
   686  	expected := &CompilationResult{
   687  		Operations: []Operation{ // begin with params: [$0]
   688  			&OperationPick{Depth: 0}, // [$0, $0]
   689  			&OperationITruncFromF{ // [$0, i32.trunc_sat_f32_s($0)]
   690  				InputType:   Float32,
   691  				OutputType:  SignedInt32,
   692  				NonTrapping: true,
   693  			},
   694  			&OperationDrop{Depth: &InclusiveRange{Start: 1, End: 1}}, // [i32.trunc_sat_f32_s($0)]
   695  			&OperationBr{Target: &BranchTarget{}},                    // return!
   696  		},
   697  		LabelCallers: map[string]uint32{},
   698  		Signature:    f32_i32,
   699  		Functions:    []wasm.Index{0},
   700  		Types:        []*wasm.FunctionType{f32_i32},
   701  		TableTypes:   []wasm.RefType{},
   702  	}
   703  	for _, tp := range module.TypeSection {
   704  		tp.CacheNumInUint64()
   705  	}
   706  	res, err := CompileFunctions(ctx, api.CoreFeatureNonTrappingFloatToIntConversion, 0, module)
   707  	require.NoError(t, err)
   708  	require.Equal(t, expected, res[0])
   709  }
   710  
   711  // TestCompile_SignExtensionOps picks an arbitrary operator from "sign-extension-ops".
   712  func TestCompile_SignExtensionOps(t *testing.T) {
   713  	module := &wasm.Module{
   714  		TypeSection:     []*wasm.FunctionType{i32_i32},
   715  		FunctionSection: []wasm.Index{0},
   716  		CodeSection: []*wasm.Code{{Body: []byte{
   717  			wasm.OpcodeLocalGet, 0, wasm.OpcodeI32Extend8S, wasm.OpcodeEnd,
   718  		}}},
   719  	}
   720  
   721  	expected := &CompilationResult{
   722  		Operations: []Operation{ // begin with params: [$0]
   723  			&OperationPick{Depth: 0},                                 // [$0, $0]
   724  			&OperationSignExtend32From8{},                            // [$0, i32.extend8_s($0)]
   725  			&OperationDrop{Depth: &InclusiveRange{Start: 1, End: 1}}, // [i32.extend8_s($0)]
   726  			&OperationBr{Target: &BranchTarget{}},                    // return!
   727  		},
   728  		LabelCallers: map[string]uint32{},
   729  		Signature:    i32_i32,
   730  		Functions:    []wasm.Index{0},
   731  		Types:        []*wasm.FunctionType{i32_i32},
   732  		TableTypes:   []wasm.RefType{},
   733  	}
   734  	for _, tp := range module.TypeSection {
   735  		tp.CacheNumInUint64()
   736  	}
   737  	res, err := CompileFunctions(ctx, api.CoreFeatureSignExtensionOps, 0, module)
   738  	require.NoError(t, err)
   739  	require.Equal(t, expected, res[0])
   740  }
   741  
   742  func requireCompilationResult(t *testing.T, enabledFeatures api.CoreFeatures, expected *CompilationResult, module *wasm.Module) {
   743  	if enabledFeatures == 0 {
   744  		enabledFeatures = api.CoreFeaturesV2
   745  	}
   746  	res, err := CompileFunctions(ctx, enabledFeatures, 0, module)
   747  	require.NoError(t, err)
   748  	require.Equal(t, expected, res[0])
   749  }
   750  
   751  func TestCompile_CallIndirectNonZeroTableIndex(t *testing.T) {
   752  	module := &wasm.Module{
   753  		TypeSection:     []*wasm.FunctionType{v_v, v_v, v_v},
   754  		FunctionSection: []wasm.Index{0},
   755  		CodeSection: []*wasm.Code{{Body: []byte{
   756  			wasm.OpcodeI32Const, 0, // call indirect offset
   757  			wasm.OpcodeCallIndirect,
   758  			2, // Type index for call_indirect.
   759  			5, // Non-zero table index for call_indirect.
   760  			wasm.OpcodeEnd,
   761  		}}},
   762  		TableSection: []*wasm.Table{
   763  			{Type: wasm.RefTypeExternref},
   764  			{Type: wasm.RefTypeFuncref},
   765  			{Type: wasm.RefTypeFuncref},
   766  			{Type: wasm.RefTypeFuncref},
   767  			{Type: wasm.RefTypeFuncref},
   768  			{Type: wasm.RefTypeFuncref, Min: 100},
   769  		},
   770  	}
   771  
   772  	expected := &CompilationResult{
   773  		Operations: []Operation{ // begin with params: []
   774  			&OperationConstI32{},
   775  			&OperationCallIndirect{TypeIndex: 2, TableIndex: 5},
   776  			&OperationBr{Target: &BranchTarget{}}, // return!
   777  		},
   778  		HasTable:     true,
   779  		LabelCallers: map[string]uint32{},
   780  		Signature:    v_v,
   781  		Functions:    []wasm.Index{0},
   782  		TableTypes: []wasm.RefType{
   783  			wasm.RefTypeExternref, wasm.RefTypeFuncref, wasm.RefTypeFuncref, wasm.RefTypeFuncref, wasm.RefTypeFuncref, wasm.RefTypeFuncref,
   784  		},
   785  		Types: []*wasm.FunctionType{v_v, v_v, v_v},
   786  	}
   787  
   788  	res, err := CompileFunctions(ctx, api.CoreFeatureBulkMemoryOperations, 0, module)
   789  	require.NoError(t, err)
   790  	require.Equal(t, expected, res[0])
   791  }
   792  
   793  func TestCompile_Refs(t *testing.T) {
   794  	tests := []struct {
   795  		name     string
   796  		body     []byte
   797  		expected []Operation
   798  	}{
   799  		{
   800  			name: "ref.func",
   801  			body: []byte{
   802  				wasm.OpcodeRefFunc, 100,
   803  				wasm.OpcodeDrop,
   804  				wasm.OpcodeEnd,
   805  			},
   806  			expected: []Operation{
   807  				&OperationRefFunc{FunctionIndex: 100},
   808  				&OperationDrop{Depth: &InclusiveRange{Start: 0, End: 0}},
   809  				&OperationBr{Target: &BranchTarget{}}, // return!
   810  			},
   811  		},
   812  		{
   813  			name: "ref.null (externref)",
   814  			body: []byte{
   815  				wasm.OpcodeRefNull, wasm.ValueTypeExternref,
   816  				wasm.OpcodeDrop,
   817  				wasm.OpcodeEnd,
   818  			},
   819  			expected: []Operation{
   820  				&OperationConstI64{Value: 0},
   821  				&OperationDrop{Depth: &InclusiveRange{Start: 0, End: 0}},
   822  				&OperationBr{Target: &BranchTarget{}}, // return!
   823  			},
   824  		},
   825  		{
   826  			name: "ref.null (funcref)",
   827  			body: []byte{
   828  				wasm.OpcodeRefNull, wasm.ValueTypeFuncref,
   829  				wasm.OpcodeDrop,
   830  				wasm.OpcodeEnd,
   831  			},
   832  			expected: []Operation{
   833  				&OperationConstI64{Value: 0},
   834  				&OperationDrop{Depth: &InclusiveRange{Start: 0, End: 0}},
   835  				&OperationBr{Target: &BranchTarget{}}, // return!
   836  			},
   837  		},
   838  		{
   839  			name: "ref.is_null",
   840  			body: []byte{
   841  				wasm.OpcodeRefFunc, 100,
   842  				wasm.OpcodeRefIsNull,
   843  				wasm.OpcodeDrop,
   844  				wasm.OpcodeEnd,
   845  			},
   846  			expected: []Operation{
   847  				&OperationRefFunc{FunctionIndex: 100},
   848  				&OperationEqz{Type: UnsignedInt64},
   849  				&OperationDrop{Depth: &InclusiveRange{Start: 0, End: 0}},
   850  				&OperationBr{Target: &BranchTarget{}}, // return!
   851  			},
   852  		},
   853  		{
   854  			name: "ref.is_null (externref)",
   855  			body: []byte{
   856  				wasm.OpcodeRefNull, wasm.ValueTypeExternref,
   857  				wasm.OpcodeRefIsNull,
   858  				wasm.OpcodeDrop,
   859  				wasm.OpcodeEnd,
   860  			},
   861  			expected: []Operation{
   862  				&OperationConstI64{Value: 0},
   863  				&OperationEqz{Type: UnsignedInt64},
   864  				&OperationDrop{Depth: &InclusiveRange{Start: 0, End: 0}},
   865  				&OperationBr{Target: &BranchTarget{}}, // return!
   866  			},
   867  		},
   868  	}
   869  
   870  	for _, tt := range tests {
   871  		tc := tt
   872  		t.Run(tc.name, func(t *testing.T) {
   873  			module := &wasm.Module{
   874  				TypeSection:     []*wasm.FunctionType{v_v},
   875  				FunctionSection: []wasm.Index{0},
   876  				CodeSection:     []*wasm.Code{{Body: tc.body}},
   877  			}
   878  			res, err := CompileFunctions(ctx, api.CoreFeaturesV2, 0, module)
   879  			require.NoError(t, err)
   880  			require.Equal(t, tc.expected, res[0].Operations)
   881  		})
   882  	}
   883  }
   884  
   885  func TestCompile_TableGetOrSet(t *testing.T) {
   886  	tests := []struct {
   887  		name     string
   888  		body     []byte
   889  		expected []Operation
   890  	}{
   891  		{
   892  			name: "table.get",
   893  			body: []byte{
   894  				wasm.OpcodeI32Const, 10,
   895  				wasm.OpcodeTableGet, 0,
   896  				wasm.OpcodeDrop,
   897  				wasm.OpcodeEnd,
   898  			},
   899  			expected: []Operation{
   900  				&OperationConstI32{Value: 10},
   901  				&OperationTableGet{TableIndex: 0},
   902  				&OperationDrop{Depth: &InclusiveRange{Start: 0, End: 0}},
   903  				&OperationBr{Target: &BranchTarget{}}, // return!
   904  			},
   905  		},
   906  		{
   907  			name: "table.set (externref)",
   908  			body: []byte{
   909  				wasm.OpcodeI32Const, 10,
   910  				wasm.OpcodeRefNull, wasm.ValueTypeExternref,
   911  				wasm.OpcodeTableSet, 0,
   912  				wasm.OpcodeEnd,
   913  			},
   914  			expected: []Operation{
   915  				&OperationConstI32{Value: 10},
   916  				&OperationConstI64{Value: 0},
   917  				&OperationTableSet{TableIndex: 0},
   918  				&OperationBr{Target: &BranchTarget{}}, // return!
   919  			},
   920  		},
   921  		{
   922  			name: "table.set (funcref)",
   923  			body: []byte{
   924  				wasm.OpcodeI32Const, 10,
   925  				wasm.OpcodeRefFunc, 1,
   926  				wasm.OpcodeTableSet, 0,
   927  				wasm.OpcodeEnd,
   928  			},
   929  			expected: []Operation{
   930  				&OperationConstI32{Value: 10},
   931  				&OperationRefFunc{FunctionIndex: 1},
   932  				&OperationTableSet{TableIndex: 0},
   933  				&OperationBr{Target: &BranchTarget{}}, // return!
   934  			},
   935  		},
   936  	}
   937  
   938  	for _, tt := range tests {
   939  		tc := tt
   940  		t.Run(tc.name, func(t *testing.T) {
   941  			module := &wasm.Module{
   942  				TypeSection:     []*wasm.FunctionType{v_v},
   943  				FunctionSection: []wasm.Index{0},
   944  				CodeSection:     []*wasm.Code{{Body: tc.body}},
   945  				TableSection:    []*wasm.Table{{}},
   946  			}
   947  			res, err := CompileFunctions(ctx, api.CoreFeaturesV2, 0, module)
   948  			require.NoError(t, err)
   949  			require.Equal(t, tc.expected, res[0].Operations)
   950  		})
   951  	}
   952  }
   953  
   954  func TestCompile_TableGrowFillSize(t *testing.T) {
   955  	tests := []struct {
   956  		name     string
   957  		body     []byte
   958  		expected []Operation
   959  	}{
   960  		{
   961  			name: "table.grow",
   962  			body: []byte{
   963  				wasm.OpcodeRefNull, wasm.RefTypeFuncref,
   964  				wasm.OpcodeI32Const, 1,
   965  				wasm.OpcodeMiscPrefix, wasm.OpcodeMiscTableGrow, 1,
   966  				wasm.OpcodeEnd,
   967  			},
   968  			expected: []Operation{
   969  				&OperationConstI64{Value: 0}, // Null ref.
   970  				&OperationConstI32{Value: 1},
   971  				&OperationTableGrow{TableIndex: 1},
   972  				&OperationDrop{Depth: &InclusiveRange{Start: 0, End: 0}},
   973  				&OperationBr{Target: &BranchTarget{}}, // return!
   974  			},
   975  		},
   976  		{
   977  			name: "table.fill",
   978  			body: []byte{
   979  				wasm.OpcodeI32Const, 10,
   980  				wasm.OpcodeRefNull, wasm.RefTypeFuncref,
   981  				wasm.OpcodeI32Const, 1,
   982  				wasm.OpcodeMiscPrefix, wasm.OpcodeMiscTableFill, 1,
   983  				wasm.OpcodeEnd,
   984  			},
   985  			expected: []Operation{
   986  				&OperationConstI32{Value: 10},
   987  				&OperationConstI64{Value: 0}, // Null ref.
   988  				&OperationConstI32{Value: 1},
   989  				&OperationTableFill{TableIndex: 1},
   990  				&OperationBr{Target: &BranchTarget{}}, // return!
   991  			},
   992  		},
   993  		{
   994  			name: "table.size",
   995  			body: []byte{
   996  				wasm.OpcodeMiscPrefix, wasm.OpcodeMiscTableSize, 1,
   997  				wasm.OpcodeEnd,
   998  			},
   999  			expected: []Operation{
  1000  				&OperationTableSize{TableIndex: 1},
  1001  				&OperationDrop{Depth: &InclusiveRange{Start: 0, End: 0}},
  1002  				&OperationBr{Target: &BranchTarget{}}, // return!
  1003  			},
  1004  		},
  1005  	}
  1006  
  1007  	for _, tt := range tests {
  1008  		tc := tt
  1009  		t.Run(tc.name, func(t *testing.T) {
  1010  			module := &wasm.Module{
  1011  				TypeSection:     []*wasm.FunctionType{v_v},
  1012  				FunctionSection: []wasm.Index{0},
  1013  				CodeSection:     []*wasm.Code{{Body: tc.body}},
  1014  				TableSection:    []*wasm.Table{{}},
  1015  			}
  1016  			res, err := CompileFunctions(ctx, api.CoreFeaturesV2, 0, module)
  1017  			require.NoError(t, err)
  1018  			require.Equal(t, tc.expected, res[0].Operations)
  1019  			require.True(t, res[0].HasTable)
  1020  		})
  1021  	}
  1022  }
  1023  
  1024  func TestCompile_Locals(t *testing.T) {
  1025  	tests := []struct {
  1026  		name     string
  1027  		mod      *wasm.Module
  1028  		expected []Operation
  1029  	}{
  1030  		{
  1031  			name: "local.get - func param - v128",
  1032  			mod: &wasm.Module{
  1033  				TypeSection:     []*wasm.FunctionType{{Params: []wasm.ValueType{wasm.ValueTypeV128}}},
  1034  				FunctionSection: []wasm.Index{0},
  1035  				CodeSection: []*wasm.Code{{Body: []byte{
  1036  					wasm.OpcodeLocalGet, 0,
  1037  					wasm.OpcodeEnd,
  1038  				}}},
  1039  			},
  1040  			expected: []Operation{
  1041  				&OperationPick{Depth: 1, IsTargetVector: true}, // [param[0].low, param[0].high] -> [param[0].low, param[0].high, param[0].low, param[0].high]
  1042  				&OperationDrop{Depth: &InclusiveRange{Start: 0, End: 3}},
  1043  				&OperationBr{Target: &BranchTarget{}}, // return!
  1044  			},
  1045  		},
  1046  		{
  1047  			name: "local.get - func param - i64",
  1048  			mod: &wasm.Module{
  1049  				TypeSection:     []*wasm.FunctionType{{Params: []wasm.ValueType{wasm.ValueTypeI64}}},
  1050  				FunctionSection: []wasm.Index{0},
  1051  				CodeSection: []*wasm.Code{{Body: []byte{
  1052  					wasm.OpcodeLocalGet, 0,
  1053  					wasm.OpcodeEnd,
  1054  				}}},
  1055  			},
  1056  			expected: []Operation{
  1057  				&OperationPick{Depth: 0, IsTargetVector: false}, // [param[0]] -> [param[0], param[0]]
  1058  				&OperationDrop{Depth: &InclusiveRange{Start: 0, End: 1}},
  1059  				&OperationBr{Target: &BranchTarget{}}, // return!
  1060  			},
  1061  		},
  1062  		{
  1063  			name: "local.get - non func param - v128",
  1064  			mod: &wasm.Module{
  1065  				TypeSection:     []*wasm.FunctionType{v_v},
  1066  				FunctionSection: []wasm.Index{0},
  1067  				CodeSection: []*wasm.Code{{
  1068  					Body: []byte{
  1069  						wasm.OpcodeLocalGet, 0,
  1070  						wasm.OpcodeEnd,
  1071  					},
  1072  					LocalTypes: []wasm.ValueType{wasm.ValueTypeV128},
  1073  				}},
  1074  			},
  1075  			expected: []Operation{
  1076  				&OperationV128Const{Lo: 0, Hi: 0},
  1077  				&OperationPick{Depth: 1, IsTargetVector: true}, // [p[0].low, p[0].high] -> [p[0].low, p[0].high, p[0].low, p[0].high]
  1078  				&OperationDrop{Depth: &InclusiveRange{Start: 0, End: 3}},
  1079  				&OperationBr{Target: &BranchTarget{}}, // return!
  1080  			},
  1081  		},
  1082  		{
  1083  			name: "local.set - func param - v128",
  1084  			mod: &wasm.Module{
  1085  				TypeSection:     []*wasm.FunctionType{{Params: []wasm.ValueType{wasm.ValueTypeV128}}},
  1086  				FunctionSection: []wasm.Index{0},
  1087  				CodeSection: []*wasm.Code{{Body: []byte{
  1088  					wasm.OpcodeVecPrefix, wasm.OpcodeVecV128Const, // [] -> [0x01, 0x02]
  1089  					1, 0, 0, 0, 0, 0, 0, 0,
  1090  					2, 0, 0, 0, 0, 0, 0, 0,
  1091  					wasm.OpcodeLocalSet, 0, // [0x01, 0x02] -> []
  1092  					wasm.OpcodeEnd,
  1093  				}}},
  1094  			},
  1095  			expected: []Operation{
  1096  				// [p[0].lo, p[1].hi] -> [p[0].lo, p[1].hi, 0x01, 0x02]
  1097  				&OperationV128Const{Lo: 0x01, Hi: 0x02},
  1098  				// [p[0].lo, p[1].hi, 0x01, 0x02] -> [0x01, 0x02]
  1099  				&OperationSet{Depth: 3, IsTargetVector: true},
  1100  				&OperationDrop{Depth: &InclusiveRange{Start: 0, End: 1}},
  1101  				&OperationBr{Target: &BranchTarget{}}, // return!
  1102  			},
  1103  		},
  1104  		{
  1105  			name: "local.set - func param - i32",
  1106  			mod: &wasm.Module{
  1107  				TypeSection:     []*wasm.FunctionType{{Params: []wasm.ValueType{wasm.ValueTypeI32}}},
  1108  				FunctionSection: []wasm.Index{0},
  1109  				CodeSection: []*wasm.Code{{Body: []byte{
  1110  					wasm.OpcodeI32Const, 0x1, // [] -> [0x01]
  1111  					wasm.OpcodeLocalSet, 0, // [0x01] -> []
  1112  					wasm.OpcodeEnd,
  1113  				}}},
  1114  			},
  1115  			expected: []Operation{
  1116  				&OperationConstI32{Value: 0x1},
  1117  				&OperationSet{Depth: 1, IsTargetVector: false},
  1118  				&OperationDrop{Depth: &InclusiveRange{Start: 0, End: 0}},
  1119  				&OperationBr{Target: &BranchTarget{}}, // return!
  1120  			},
  1121  		},
  1122  		{
  1123  			name: "local.set - non func param - v128",
  1124  			mod: &wasm.Module{
  1125  				TypeSection:     []*wasm.FunctionType{v_v},
  1126  				FunctionSection: []wasm.Index{0},
  1127  				CodeSection: []*wasm.Code{{
  1128  					Body: []byte{
  1129  						wasm.OpcodeVecPrefix, wasm.OpcodeVecV128Const, // [] -> [0x01, 0x02]
  1130  						1, 0, 0, 0, 0, 0, 0, 0,
  1131  						2, 0, 0, 0, 0, 0, 0, 0,
  1132  						wasm.OpcodeLocalSet, 0, // [0x01, 0x02] -> []
  1133  						wasm.OpcodeEnd,
  1134  					},
  1135  					LocalTypes: []wasm.ValueType{wasm.ValueTypeV128},
  1136  				}},
  1137  			},
  1138  			expected: []Operation{
  1139  				&OperationV128Const{Lo: 0, Hi: 0},
  1140  				// [p[0].lo, p[1].hi] -> [p[0].lo, p[1].hi, 0x01, 0x02]
  1141  				&OperationV128Const{Lo: 0x01, Hi: 0x02},
  1142  				// [p[0].lo, p[1].hi, 0x01, 0x02] -> [0x01, 0x02]
  1143  				&OperationSet{Depth: 3, IsTargetVector: true},
  1144  				&OperationDrop{Depth: &InclusiveRange{Start: 0, End: 1}},
  1145  				&OperationBr{Target: &BranchTarget{}}, // return!
  1146  			},
  1147  		},
  1148  		{
  1149  			name: "local.tee - func param - v128",
  1150  			mod: &wasm.Module{
  1151  				TypeSection:     []*wasm.FunctionType{{Params: []wasm.ValueType{wasm.ValueTypeV128}}},
  1152  				FunctionSection: []wasm.Index{0},
  1153  				CodeSection: []*wasm.Code{{Body: []byte{
  1154  					wasm.OpcodeVecPrefix, wasm.OpcodeVecV128Const, // [] -> [0x01, 0x02]
  1155  					1, 0, 0, 0, 0, 0, 0, 0,
  1156  					2, 0, 0, 0, 0, 0, 0, 0,
  1157  					wasm.OpcodeLocalTee, 0, // [0x01, 0x02] ->  [0x01, 0x02]
  1158  					wasm.OpcodeEnd,
  1159  				}}},
  1160  			},
  1161  			expected: []Operation{
  1162  				// [p[0].lo, p[1].hi] -> [p[0].lo, p[1].hi, 0x01, 0x02]
  1163  				&OperationV128Const{Lo: 0x01, Hi: 0x02},
  1164  				// [p[0].lo, p[1].hi, 0x01, 0x02] -> [p[0].lo, p[1].hi, 0x01, 0x02, 0x01, 0x02]
  1165  				&OperationPick{Depth: 1, IsTargetVector: true},
  1166  				// [p[0].lo, p[1].hi, 0x01, 0x02, 0x01, 0x02] -> [0x01, 0x02, 0x01, 0x02]
  1167  				&OperationSet{Depth: 5, IsTargetVector: true},
  1168  				&OperationDrop{Depth: &InclusiveRange{Start: 0, End: 3}},
  1169  				&OperationBr{Target: &BranchTarget{}}, // return!
  1170  			},
  1171  		},
  1172  		{
  1173  			name: "local.tee - func param - f32",
  1174  			mod: &wasm.Module{
  1175  				TypeSection:     []*wasm.FunctionType{{Params: []wasm.ValueType{wasm.ValueTypeF32}}},
  1176  				FunctionSection: []wasm.Index{0},
  1177  				CodeSection: []*wasm.Code{{Body: []byte{
  1178  					wasm.OpcodeF32Const, 1, 0, 0, 0,
  1179  					wasm.OpcodeLocalTee, 0, // [0x01, 0x02] ->  [0x01, 0x02]
  1180  					wasm.OpcodeEnd,
  1181  				}}},
  1182  			},
  1183  			expected: []Operation{
  1184  				&OperationConstF32{math.Float32frombits(1)},
  1185  				&OperationPick{Depth: 0, IsTargetVector: false},
  1186  				&OperationSet{Depth: 2, IsTargetVector: false},
  1187  				&OperationDrop{Depth: &InclusiveRange{Start: 0, End: 1}},
  1188  				&OperationBr{Target: &BranchTarget{}}, // return!
  1189  			},
  1190  		},
  1191  		{
  1192  			name: "local.tee - non func param",
  1193  			mod: &wasm.Module{
  1194  				TypeSection:     []*wasm.FunctionType{v_v},
  1195  				FunctionSection: []wasm.Index{0},
  1196  				CodeSection: []*wasm.Code{{
  1197  					Body: []byte{
  1198  						wasm.OpcodeVecPrefix, wasm.OpcodeVecV128Const, // [] -> [0x01, 0x02]
  1199  						1, 0, 0, 0, 0, 0, 0, 0,
  1200  						2, 0, 0, 0, 0, 0, 0, 0,
  1201  						wasm.OpcodeLocalTee, 0, // [0x01, 0x02] ->  [0x01, 0x02]
  1202  						wasm.OpcodeEnd,
  1203  					},
  1204  					LocalTypes: []wasm.ValueType{wasm.ValueTypeV128},
  1205  				}},
  1206  			},
  1207  			expected: []Operation{
  1208  				&OperationV128Const{Lo: 0, Hi: 0},
  1209  				// [p[0].lo, p[1].hi] -> [p[0].lo, p[1].hi, 0x01, 0x02]
  1210  				&OperationV128Const{Lo: 0x01, Hi: 0x02},
  1211  				// [p[0].lo, p[1].hi, 0x01, 0x02] -> [p[0].lo, p[1].hi, 0x01, 0x02, 0x01, 0x02]
  1212  				&OperationPick{Depth: 1, IsTargetVector: true},
  1213  				// [p[0].lo, p[1].hi, 0x01, 0x02, 0x01, 0x2] -> [0x01, 0x02, 0x01, 0x02]
  1214  				&OperationSet{Depth: 5, IsTargetVector: true},
  1215  				&OperationDrop{Depth: &InclusiveRange{Start: 0, End: 3}},
  1216  				&OperationBr{Target: &BranchTarget{}}, // return!
  1217  			},
  1218  		},
  1219  	}
  1220  
  1221  	for _, tt := range tests {
  1222  		tc := tt
  1223  		t.Run(tc.name, func(t *testing.T) {
  1224  			res, err := CompileFunctions(ctx, api.CoreFeaturesV2, 0, tc.mod)
  1225  			require.NoError(t, err)
  1226  			msg := fmt.Sprintf("\nhave:\n\t%s\nwant:\n\t%s", Format(res[0].Operations), Format(tc.expected))
  1227  			require.Equal(t, tc.expected, res[0].Operations, msg)
  1228  		})
  1229  	}
  1230  }
  1231  
  1232  func TestCompile_Vec(t *testing.T) {
  1233  	addV128Const := func(in []byte) []byte {
  1234  		return append(in, wasm.OpcodeVecPrefix,
  1235  			wasm.OpcodeVecV128Const,
  1236  			1, 1, 1, 1, 1, 1, 1, 1,
  1237  			1, 1, 1, 1, 1, 1, 1, 1)
  1238  	}
  1239  
  1240  	vvv2v := func(vec wasm.OpcodeVec) (ret []byte) {
  1241  		ret = addV128Const(ret)
  1242  		ret = addV128Const(ret)
  1243  		ret = addV128Const(ret)
  1244  		return append(ret, wasm.OpcodeVecPrefix, vec, wasm.OpcodeDrop, wasm.OpcodeEnd)
  1245  	}
  1246  
  1247  	vv2v := func(vec wasm.OpcodeVec) (ret []byte) {
  1248  		ret = addV128Const(ret)
  1249  		ret = addV128Const(ret)
  1250  		return append(ret, wasm.OpcodeVecPrefix, vec, wasm.OpcodeDrop, wasm.OpcodeEnd)
  1251  	}
  1252  
  1253  	vi2v := func(vec wasm.OpcodeVec) (ret []byte) {
  1254  		ret = addV128Const(ret)
  1255  		return append(ret, wasm.OpcodeI32Const, 1,
  1256  			wasm.OpcodeVecPrefix, vec,
  1257  			wasm.OpcodeDrop, wasm.OpcodeEnd)
  1258  	}
  1259  
  1260  	v2v := func(vec wasm.OpcodeVec) (ret []byte) {
  1261  		ret = addV128Const(ret)
  1262  		return append(ret, wasm.OpcodeVecPrefix, vec, wasm.OpcodeDrop, wasm.OpcodeEnd)
  1263  	}
  1264  
  1265  	load := func(vec wasm.OpcodeVec, offset, align uint32) (ret []byte) {
  1266  		ret = []byte{wasm.OpcodeI32Const, 1, 1, 1, 1, wasm.OpcodeVecPrefix, vec}
  1267  		ret = append(ret, leb128.EncodeUint32(align)...)
  1268  		ret = append(ret, leb128.EncodeUint32(offset)...)
  1269  		ret = append(ret, wasm.OpcodeDrop, wasm.OpcodeEnd)
  1270  		return
  1271  	}
  1272  
  1273  	loadLane := func(vec wasm.OpcodeVec, offset, align uint32, lane byte) (ret []byte) {
  1274  		ret = addV128Const([]byte{wasm.OpcodeI32Const, 1, 1, 1, 1})
  1275  		ret = append(ret, wasm.OpcodeVecPrefix, vec)
  1276  		ret = append(ret, leb128.EncodeUint32(align)...)
  1277  		ret = append(ret, leb128.EncodeUint32(offset)...)
  1278  		ret = append(ret, lane, wasm.OpcodeDrop, wasm.OpcodeEnd)
  1279  		return
  1280  	}
  1281  
  1282  	storeLane := func(vec wasm.OpcodeVec, offset, align uint32, lane byte) (ret []byte) {
  1283  		ret = addV128Const([]byte{wasm.OpcodeI32Const, 0})
  1284  		ret = append(ret, wasm.OpcodeVecPrefix, vec)
  1285  		ret = append(ret, leb128.EncodeUint32(align)...)
  1286  		ret = append(ret, leb128.EncodeUint32(offset)...)
  1287  		ret = append(ret, lane, wasm.OpcodeEnd)
  1288  		return
  1289  	}
  1290  
  1291  	extractLane := func(vec wasm.OpcodeVec, lane byte) (ret []byte) {
  1292  		ret = addV128Const(ret)
  1293  		ret = append(ret, wasm.OpcodeVecPrefix, vec, lane, wasm.OpcodeDrop, wasm.OpcodeEnd)
  1294  		return
  1295  	}
  1296  
  1297  	replaceLane := func(vec wasm.OpcodeVec, lane byte) (ret []byte) {
  1298  		ret = addV128Const(ret)
  1299  
  1300  		switch vec {
  1301  		case wasm.OpcodeVecI8x16ReplaceLane, wasm.OpcodeVecI16x8ReplaceLane, wasm.OpcodeVecI32x4ReplaceLane:
  1302  			ret = append(ret, wasm.OpcodeI32Const, 0)
  1303  		case wasm.OpcodeVecI64x2ReplaceLane:
  1304  			ret = append(ret, wasm.OpcodeI64Const, 0)
  1305  		case wasm.OpcodeVecF32x4ReplaceLane:
  1306  			ret = append(ret, wasm.OpcodeF32Const, 0, 0, 0, 0)
  1307  		case wasm.OpcodeVecF64x2ReplaceLane:
  1308  			ret = append(ret, wasm.OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0, 0)
  1309  		}
  1310  
  1311  		ret = append(ret, wasm.OpcodeVecPrefix, vec, lane, wasm.OpcodeDrop, wasm.OpcodeEnd)
  1312  		return
  1313  	}
  1314  
  1315  	splat := func(vec wasm.OpcodeVec) (ret []byte) {
  1316  		switch vec {
  1317  		case wasm.OpcodeVecI8x16Splat, wasm.OpcodeVecI16x8Splat, wasm.OpcodeVecI32x4Splat:
  1318  			ret = append(ret, wasm.OpcodeI32Const, 0)
  1319  		case wasm.OpcodeVecI64x2Splat:
  1320  			ret = append(ret, wasm.OpcodeI64Const, 0)
  1321  		case wasm.OpcodeVecF32x4Splat:
  1322  			ret = append(ret, wasm.OpcodeF32Const, 0, 0, 0, 0)
  1323  		case wasm.OpcodeVecF64x2Splat:
  1324  			ret = append(ret, wasm.OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0, 0)
  1325  		}
  1326  		ret = append(ret, wasm.OpcodeVecPrefix, vec, wasm.OpcodeDrop, wasm.OpcodeEnd)
  1327  		return
  1328  	}
  1329  
  1330  	tests := []struct {
  1331  		name                 string
  1332  		body                 []byte
  1333  		expected             Operation
  1334  		needDropBeforeReturn bool
  1335  	}{
  1336  		{
  1337  			name:                 "i8x16 add",
  1338  			needDropBeforeReturn: true,
  1339  			body:                 vv2v(wasm.OpcodeVecI8x16Add),
  1340  			expected:             &OperationV128Add{Shape: ShapeI8x16},
  1341  		},
  1342  		{
  1343  			name:                 "i8x16 add",
  1344  			needDropBeforeReturn: true,
  1345  			body:                 vv2v(wasm.OpcodeVecI16x8Add),
  1346  			expected:             &OperationV128Add{Shape: ShapeI16x8},
  1347  		},
  1348  		{
  1349  			name:                 "i32x2 add",
  1350  			needDropBeforeReturn: true,
  1351  			body:                 vv2v(wasm.OpcodeVecI64x2Add),
  1352  			expected:             &OperationV128Add{Shape: ShapeI64x2},
  1353  		},
  1354  		{
  1355  			name:                 "i64x2 add",
  1356  			needDropBeforeReturn: true,
  1357  			body:                 vv2v(wasm.OpcodeVecI64x2Add),
  1358  			expected:             &OperationV128Add{Shape: ShapeI64x2},
  1359  		},
  1360  		{
  1361  			name:                 "i8x16 sub",
  1362  			needDropBeforeReturn: true,
  1363  			body:                 vv2v(wasm.OpcodeVecI8x16Sub),
  1364  			expected:             &OperationV128Sub{Shape: ShapeI8x16},
  1365  		},
  1366  		{
  1367  			name:                 "i16x8 sub",
  1368  			needDropBeforeReturn: true,
  1369  			body:                 vv2v(wasm.OpcodeVecI16x8Sub),
  1370  			expected:             &OperationV128Sub{Shape: ShapeI16x8},
  1371  		},
  1372  		{
  1373  			name:                 "i32x2 sub",
  1374  			needDropBeforeReturn: true,
  1375  			body:                 vv2v(wasm.OpcodeVecI64x2Sub),
  1376  			expected:             &OperationV128Sub{Shape: ShapeI64x2},
  1377  		},
  1378  		{
  1379  			name:                 "i64x2 sub",
  1380  			needDropBeforeReturn: true,
  1381  			body:                 vv2v(wasm.OpcodeVecI64x2Sub),
  1382  			expected:             &OperationV128Sub{Shape: ShapeI64x2},
  1383  		},
  1384  		{
  1385  			name: wasm.OpcodeVecV128LoadName, body: load(wasm.OpcodeVecV128Load, 0, 0),
  1386  			needDropBeforeReturn: true,
  1387  			expected:             &OperationV128Load{Type: V128LoadType128, Arg: &MemoryArg{Alignment: 0, Offset: 0}},
  1388  		},
  1389  		{
  1390  			name: wasm.OpcodeVecV128LoadName + "/align=4", body: load(wasm.OpcodeVecV128Load, 0, 4),
  1391  			needDropBeforeReturn: true,
  1392  			expected:             &OperationV128Load{Type: V128LoadType128, Arg: &MemoryArg{Alignment: 4, Offset: 0}},
  1393  		},
  1394  		{
  1395  			name: wasm.OpcodeVecV128Load8x8SName, body: load(wasm.OpcodeVecV128Load8x8s, 1, 0),
  1396  			needDropBeforeReturn: true,
  1397  			expected:             &OperationV128Load{Type: V128LoadType8x8s, Arg: &MemoryArg{Alignment: 0, Offset: 1}},
  1398  		},
  1399  		{
  1400  			name: wasm.OpcodeVecV128Load8x8SName + "/align=1", body: load(wasm.OpcodeVecV128Load8x8s, 0, 1),
  1401  			needDropBeforeReturn: true,
  1402  			expected:             &OperationV128Load{Type: V128LoadType8x8s, Arg: &MemoryArg{Alignment: 1, Offset: 0}},
  1403  		},
  1404  		{
  1405  			name: wasm.OpcodeVecV128Load8x8UName, body: load(wasm.OpcodeVecV128Load8x8u, 0, 0),
  1406  			needDropBeforeReturn: true,
  1407  			expected:             &OperationV128Load{Type: V128LoadType8x8u, Arg: &MemoryArg{Alignment: 0, Offset: 0}},
  1408  		},
  1409  		{
  1410  			name: wasm.OpcodeVecV128Load8x8UName + "/align=1", body: load(wasm.OpcodeVecV128Load8x8u, 0, 1),
  1411  			needDropBeforeReturn: true,
  1412  			expected:             &OperationV128Load{Type: V128LoadType8x8u, Arg: &MemoryArg{Alignment: 1, Offset: 0}},
  1413  		},
  1414  		{
  1415  			name: wasm.OpcodeVecV128Load16x4SName, body: load(wasm.OpcodeVecV128Load16x4s, 1, 0),
  1416  			needDropBeforeReturn: true,
  1417  			expected:             &OperationV128Load{Type: V128LoadType16x4s, Arg: &MemoryArg{Alignment: 0, Offset: 1}},
  1418  		},
  1419  		{
  1420  			name: wasm.OpcodeVecV128Load16x4SName + "/align=2", body: load(wasm.OpcodeVecV128Load16x4s, 0, 2),
  1421  			needDropBeforeReturn: true,
  1422  			expected:             &OperationV128Load{Type: V128LoadType16x4s, Arg: &MemoryArg{Alignment: 2, Offset: 0}},
  1423  		},
  1424  		{
  1425  			name: wasm.OpcodeVecV128Load16x4UName, body: load(wasm.OpcodeVecV128Load16x4u, 0, 0),
  1426  			needDropBeforeReturn: true,
  1427  			expected:             &OperationV128Load{Type: V128LoadType16x4u, Arg: &MemoryArg{Alignment: 0, Offset: 0}},
  1428  		},
  1429  		{
  1430  			name: wasm.OpcodeVecV128Load16x4UName + "/align=2", body: load(wasm.OpcodeVecV128Load16x4u, 0, 2),
  1431  			needDropBeforeReturn: true,
  1432  			expected:             &OperationV128Load{Type: V128LoadType16x4u, Arg: &MemoryArg{Alignment: 2, Offset: 0}},
  1433  		},
  1434  		{
  1435  			name: wasm.OpcodeVecV128Load32x2SName, body: load(wasm.OpcodeVecV128Load32x2s, 1, 0),
  1436  			needDropBeforeReturn: true,
  1437  			expected:             &OperationV128Load{Type: V128LoadType32x2s, Arg: &MemoryArg{Alignment: 0, Offset: 1}},
  1438  		},
  1439  		{
  1440  			name: wasm.OpcodeVecV128Load32x2SName + "/align=3", body: load(wasm.OpcodeVecV128Load32x2s, 0, 3),
  1441  			needDropBeforeReturn: true,
  1442  			expected:             &OperationV128Load{Type: V128LoadType32x2s, Arg: &MemoryArg{Alignment: 3, Offset: 0}},
  1443  		},
  1444  		{
  1445  			name: wasm.OpcodeVecV128Load32x2UName, body: load(wasm.OpcodeVecV128Load32x2u, 0, 0),
  1446  			needDropBeforeReturn: true,
  1447  			expected:             &OperationV128Load{Type: V128LoadType32x2u, Arg: &MemoryArg{Alignment: 0, Offset: 0}},
  1448  		},
  1449  		{
  1450  			name: wasm.OpcodeVecV128Load32x2UName + "/align=3", body: load(wasm.OpcodeVecV128Load32x2u, 0, 3),
  1451  			needDropBeforeReturn: true,
  1452  			expected:             &OperationV128Load{Type: V128LoadType32x2u, Arg: &MemoryArg{Alignment: 3, Offset: 0}},
  1453  		},
  1454  		{
  1455  			name: wasm.OpcodeVecV128Load8SplatName, body: load(wasm.OpcodeVecV128Load8Splat, 2, 0),
  1456  			needDropBeforeReturn: true,
  1457  			expected:             &OperationV128Load{Type: V128LoadType8Splat, Arg: &MemoryArg{Alignment: 0, Offset: 2}},
  1458  		},
  1459  		{
  1460  			name: wasm.OpcodeVecV128Load16SplatName, body: load(wasm.OpcodeVecV128Load16Splat, 0, 1),
  1461  			needDropBeforeReturn: true,
  1462  			expected:             &OperationV128Load{Type: V128LoadType16Splat, Arg: &MemoryArg{Alignment: 1, Offset: 0}},
  1463  		},
  1464  		{
  1465  			name: wasm.OpcodeVecV128Load32SplatName, body: load(wasm.OpcodeVecV128Load32Splat, 3, 2),
  1466  			needDropBeforeReturn: true,
  1467  			expected:             &OperationV128Load{Type: V128LoadType32Splat, Arg: &MemoryArg{Alignment: 2, Offset: 3}},
  1468  		},
  1469  		{
  1470  			name: wasm.OpcodeVecV128Load64SplatName, body: load(wasm.OpcodeVecV128Load64Splat, 0, 3),
  1471  			needDropBeforeReturn: true,
  1472  			expected:             &OperationV128Load{Type: V128LoadType64Splat, Arg: &MemoryArg{Alignment: 3, Offset: 0}},
  1473  		},
  1474  		{
  1475  			name: wasm.OpcodeVecV128Load32zeroName, body: load(wasm.OpcodeVecV128Load32zero, 0, 2),
  1476  			needDropBeforeReturn: true,
  1477  			expected:             &OperationV128Load{Type: V128LoadType32zero, Arg: &MemoryArg{Alignment: 2, Offset: 0}},
  1478  		},
  1479  		{
  1480  			name: wasm.OpcodeVecV128Load64zeroName, body: load(wasm.OpcodeVecV128Load64zero, 5, 3),
  1481  			needDropBeforeReturn: true,
  1482  			expected:             &OperationV128Load{Type: V128LoadType64zero, Arg: &MemoryArg{Alignment: 3, Offset: 5}},
  1483  		},
  1484  		{
  1485  			name: wasm.OpcodeVecV128Load8LaneName, needDropBeforeReturn: true,
  1486  			body:     loadLane(wasm.OpcodeVecV128Load8Lane, 5, 0, 10),
  1487  			expected: &OperationV128LoadLane{LaneIndex: 10, LaneSize: 8, Arg: &MemoryArg{Alignment: 0, Offset: 5}},
  1488  		},
  1489  		{
  1490  			name: wasm.OpcodeVecV128Load16LaneName, needDropBeforeReturn: true,
  1491  			body:     loadLane(wasm.OpcodeVecV128Load16Lane, 100, 1, 7),
  1492  			expected: &OperationV128LoadLane{LaneIndex: 7, LaneSize: 16, Arg: &MemoryArg{Alignment: 1, Offset: 100}},
  1493  		},
  1494  		{
  1495  			name: wasm.OpcodeVecV128Load32LaneName, needDropBeforeReturn: true,
  1496  			body:     loadLane(wasm.OpcodeVecV128Load32Lane, 0, 2, 3),
  1497  			expected: &OperationV128LoadLane{LaneIndex: 3, LaneSize: 32, Arg: &MemoryArg{Alignment: 2, Offset: 0}},
  1498  		},
  1499  		{
  1500  			name: wasm.OpcodeVecV128Load64LaneName, needDropBeforeReturn: true,
  1501  			body:     loadLane(wasm.OpcodeVecV128Load64Lane, 0, 3, 1),
  1502  			expected: &OperationV128LoadLane{LaneIndex: 1, LaneSize: 64, Arg: &MemoryArg{Alignment: 3, Offset: 0}},
  1503  		},
  1504  		{
  1505  			name: wasm.OpcodeVecV128StoreName, body: []byte{
  1506  				wasm.OpcodeI32Const,
  1507  				1, 1, 1, 1,
  1508  				wasm.OpcodeVecPrefix,
  1509  				wasm.OpcodeVecV128Const,
  1510  				1, 1, 1, 1, 1, 1, 1, 1,
  1511  				1, 1, 1, 1, 1, 1, 1, 1,
  1512  				wasm.OpcodeVecPrefix,
  1513  				wasm.OpcodeVecV128Store,
  1514  				4,  // alignment
  1515  				10, // offset
  1516  				wasm.OpcodeEnd,
  1517  			},
  1518  			expected: &OperationV128Store{Arg: &MemoryArg{Alignment: 4, Offset: 10}},
  1519  		},
  1520  		{
  1521  			name:     wasm.OpcodeVecV128Store8LaneName,
  1522  			body:     storeLane(wasm.OpcodeVecV128Store8Lane, 0, 0, 0),
  1523  			expected: &OperationV128StoreLane{LaneIndex: 0, LaneSize: 8, Arg: &MemoryArg{Alignment: 0, Offset: 0}},
  1524  		},
  1525  		{
  1526  			name:     wasm.OpcodeVecV128Store8LaneName + "/lane=15",
  1527  			body:     storeLane(wasm.OpcodeVecV128Store8Lane, 100, 0, 15),
  1528  			expected: &OperationV128StoreLane{LaneIndex: 15, LaneSize: 8, Arg: &MemoryArg{Alignment: 0, Offset: 100}},
  1529  		},
  1530  		{
  1531  			name:     wasm.OpcodeVecV128Store16LaneName,
  1532  			body:     storeLane(wasm.OpcodeVecV128Store16Lane, 0, 0, 0),
  1533  			expected: &OperationV128StoreLane{LaneIndex: 0, LaneSize: 16, Arg: &MemoryArg{Alignment: 0, Offset: 0}},
  1534  		},
  1535  		{
  1536  			name:     wasm.OpcodeVecV128Store16LaneName + "/lane=7/align=1",
  1537  			body:     storeLane(wasm.OpcodeVecV128Store16Lane, 100, 1, 7),
  1538  			expected: &OperationV128StoreLane{LaneIndex: 7, LaneSize: 16, Arg: &MemoryArg{Alignment: 1, Offset: 100}},
  1539  		},
  1540  		{
  1541  			name:     wasm.OpcodeVecV128Store32LaneName,
  1542  			body:     storeLane(wasm.OpcodeVecV128Store32Lane, 0, 0, 0),
  1543  			expected: &OperationV128StoreLane{LaneIndex: 0, LaneSize: 32, Arg: &MemoryArg{Alignment: 0, Offset: 0}},
  1544  		},
  1545  		{
  1546  			name:     wasm.OpcodeVecV128Store32LaneName + "/lane=3/align=2",
  1547  			body:     storeLane(wasm.OpcodeVecV128Store32Lane, 100, 2, 3),
  1548  			expected: &OperationV128StoreLane{LaneIndex: 3, LaneSize: 32, Arg: &MemoryArg{Alignment: 2, Offset: 100}},
  1549  		},
  1550  		{
  1551  			name:     wasm.OpcodeVecV128Store64LaneName,
  1552  			body:     storeLane(wasm.OpcodeVecV128Store64Lane, 0, 0, 0),
  1553  			expected: &OperationV128StoreLane{LaneIndex: 0, LaneSize: 64, Arg: &MemoryArg{Alignment: 0, Offset: 0}},
  1554  		},
  1555  		{
  1556  			name:     wasm.OpcodeVecV128Store64LaneName + "/lane=1/align=3",
  1557  			body:     storeLane(wasm.OpcodeVecV128Store64Lane, 50, 3, 1),
  1558  			expected: &OperationV128StoreLane{LaneIndex: 1, LaneSize: 64, Arg: &MemoryArg{Alignment: 3, Offset: 50}},
  1559  		},
  1560  		{
  1561  			name:                 wasm.OpcodeVecI8x16ExtractLaneSName,
  1562  			body:                 extractLane(wasm.OpcodeVecI8x16ExtractLaneS, 0),
  1563  			expected:             &OperationV128ExtractLane{LaneIndex: 0, Signed: true, Shape: ShapeI8x16},
  1564  			needDropBeforeReturn: true,
  1565  		},
  1566  		{
  1567  			name:                 wasm.OpcodeVecI8x16ExtractLaneSName + "/lane=15",
  1568  			body:                 extractLane(wasm.OpcodeVecI8x16ExtractLaneS, 15),
  1569  			expected:             &OperationV128ExtractLane{LaneIndex: 15, Signed: true, Shape: ShapeI8x16},
  1570  			needDropBeforeReturn: true,
  1571  		},
  1572  		{
  1573  			name:                 wasm.OpcodeVecI8x16ExtractLaneUName,
  1574  			body:                 extractLane(wasm.OpcodeVecI8x16ExtractLaneU, 0),
  1575  			expected:             &OperationV128ExtractLane{LaneIndex: 0, Signed: false, Shape: ShapeI8x16},
  1576  			needDropBeforeReturn: true,
  1577  		},
  1578  		{
  1579  			name:                 wasm.OpcodeVecI8x16ExtractLaneUName + "/lane=15",
  1580  			body:                 extractLane(wasm.OpcodeVecI8x16ExtractLaneU, 15),
  1581  			expected:             &OperationV128ExtractLane{LaneIndex: 15, Signed: false, Shape: ShapeI8x16},
  1582  			needDropBeforeReturn: true,
  1583  		},
  1584  		{
  1585  			name:                 wasm.OpcodeVecI16x8ExtractLaneSName,
  1586  			body:                 extractLane(wasm.OpcodeVecI16x8ExtractLaneS, 0),
  1587  			expected:             &OperationV128ExtractLane{LaneIndex: 0, Signed: true, Shape: ShapeI16x8},
  1588  			needDropBeforeReturn: true,
  1589  		},
  1590  		{
  1591  			name:                 wasm.OpcodeVecI16x8ExtractLaneSName + "/lane=7",
  1592  			body:                 extractLane(wasm.OpcodeVecI16x8ExtractLaneS, 7),
  1593  			expected:             &OperationV128ExtractLane{LaneIndex: 7, Signed: true, Shape: ShapeI16x8},
  1594  			needDropBeforeReturn: true,
  1595  		},
  1596  		{
  1597  			name:                 wasm.OpcodeVecI16x8ExtractLaneUName,
  1598  			body:                 extractLane(wasm.OpcodeVecI16x8ExtractLaneU, 0),
  1599  			expected:             &OperationV128ExtractLane{LaneIndex: 0, Signed: false, Shape: ShapeI16x8},
  1600  			needDropBeforeReturn: true,
  1601  		},
  1602  		{
  1603  			name:                 wasm.OpcodeVecI16x8ExtractLaneUName + "/lane=7",
  1604  			body:                 extractLane(wasm.OpcodeVecI16x8ExtractLaneU, 7),
  1605  			expected:             &OperationV128ExtractLane{LaneIndex: 7, Signed: false, Shape: ShapeI16x8},
  1606  			needDropBeforeReturn: true,
  1607  		},
  1608  		{
  1609  			name:                 wasm.OpcodeVecI32x4ExtractLaneName,
  1610  			body:                 extractLane(wasm.OpcodeVecI32x4ExtractLane, 0),
  1611  			expected:             &OperationV128ExtractLane{LaneIndex: 0, Shape: ShapeI32x4},
  1612  			needDropBeforeReturn: true,
  1613  		},
  1614  		{
  1615  			name:                 wasm.OpcodeVecI32x4ExtractLaneName + "/lane=3",
  1616  			body:                 extractLane(wasm.OpcodeVecI32x4ExtractLane, 3),
  1617  			expected:             &OperationV128ExtractLane{LaneIndex: 3, Shape: ShapeI32x4},
  1618  			needDropBeforeReturn: true,
  1619  		},
  1620  		{
  1621  			name:                 wasm.OpcodeVecI64x2ExtractLaneName,
  1622  			body:                 extractLane(wasm.OpcodeVecI64x2ExtractLane, 0),
  1623  			expected:             &OperationV128ExtractLane{LaneIndex: 0, Shape: ShapeI64x2},
  1624  			needDropBeforeReturn: true,
  1625  		},
  1626  		{
  1627  			name:                 wasm.OpcodeVecI64x2ExtractLaneName + "/lane=1",
  1628  			body:                 extractLane(wasm.OpcodeVecI64x2ExtractLane, 1),
  1629  			expected:             &OperationV128ExtractLane{LaneIndex: 1, Shape: ShapeI64x2},
  1630  			needDropBeforeReturn: true,
  1631  		},
  1632  		{
  1633  			name:                 wasm.OpcodeVecF32x4ExtractLaneName,
  1634  			body:                 extractLane(wasm.OpcodeVecF32x4ExtractLane, 0),
  1635  			expected:             &OperationV128ExtractLane{LaneIndex: 0, Shape: ShapeF32x4},
  1636  			needDropBeforeReturn: true,
  1637  		},
  1638  		{
  1639  			name:                 wasm.OpcodeVecF32x4ExtractLaneName + "/lane=3",
  1640  			body:                 extractLane(wasm.OpcodeVecF32x4ExtractLane, 3),
  1641  			expected:             &OperationV128ExtractLane{LaneIndex: 3, Shape: ShapeF32x4},
  1642  			needDropBeforeReturn: true,
  1643  		},
  1644  		{
  1645  			name:                 wasm.OpcodeVecF64x2ExtractLaneName,
  1646  			body:                 extractLane(wasm.OpcodeVecF64x2ExtractLane, 0),
  1647  			expected:             &OperationV128ExtractLane{LaneIndex: 0, Shape: ShapeF64x2},
  1648  			needDropBeforeReturn: true,
  1649  		},
  1650  		{
  1651  			name:                 wasm.OpcodeVecF64x2ExtractLaneName + "/lane=1",
  1652  			body:                 extractLane(wasm.OpcodeVecF64x2ExtractLane, 1),
  1653  			expected:             &OperationV128ExtractLane{LaneIndex: 1, Shape: ShapeF64x2},
  1654  			needDropBeforeReturn: true,
  1655  		},
  1656  
  1657  		{
  1658  			name:                 wasm.OpcodeVecI8x16ReplaceLaneName,
  1659  			body:                 replaceLane(wasm.OpcodeVecI8x16ReplaceLane, 0),
  1660  			expected:             &OperationV128ReplaceLane{LaneIndex: 0, Shape: ShapeI8x16},
  1661  			needDropBeforeReturn: true,
  1662  		},
  1663  		{
  1664  			name:                 wasm.OpcodeVecI8x16ReplaceLaneName + "/lane=15",
  1665  			body:                 replaceLane(wasm.OpcodeVecI8x16ReplaceLane, 15),
  1666  			expected:             &OperationV128ReplaceLane{LaneIndex: 15, Shape: ShapeI8x16},
  1667  			needDropBeforeReturn: true,
  1668  		},
  1669  		{
  1670  			name:                 wasm.OpcodeVecI16x8ReplaceLaneName,
  1671  			body:                 replaceLane(wasm.OpcodeVecI16x8ReplaceLane, 0),
  1672  			expected:             &OperationV128ReplaceLane{LaneIndex: 0, Shape: ShapeI16x8},
  1673  			needDropBeforeReturn: true,
  1674  		},
  1675  		{
  1676  			name:                 wasm.OpcodeVecI16x8ReplaceLaneName + "/lane=7",
  1677  			body:                 replaceLane(wasm.OpcodeVecI16x8ReplaceLane, 7),
  1678  			expected:             &OperationV128ReplaceLane{LaneIndex: 7, Shape: ShapeI16x8},
  1679  			needDropBeforeReturn: true,
  1680  		},
  1681  		{
  1682  			name:                 wasm.OpcodeVecI32x4ReplaceLaneName,
  1683  			body:                 replaceLane(wasm.OpcodeVecI32x4ReplaceLane, 0),
  1684  			expected:             &OperationV128ReplaceLane{LaneIndex: 0, Shape: ShapeI32x4},
  1685  			needDropBeforeReturn: true,
  1686  		},
  1687  		{
  1688  			name:                 wasm.OpcodeVecI32x4ReplaceLaneName + "/lane=3",
  1689  			body:                 replaceLane(wasm.OpcodeVecI32x4ReplaceLane, 3),
  1690  			expected:             &OperationV128ReplaceLane{LaneIndex: 3, Shape: ShapeI32x4},
  1691  			needDropBeforeReturn: true,
  1692  		},
  1693  		{
  1694  			name:                 wasm.OpcodeVecI64x2ReplaceLaneName,
  1695  			body:                 replaceLane(wasm.OpcodeVecI64x2ReplaceLane, 0),
  1696  			expected:             &OperationV128ReplaceLane{LaneIndex: 0, Shape: ShapeI64x2},
  1697  			needDropBeforeReturn: true,
  1698  		},
  1699  		{
  1700  			name:                 wasm.OpcodeVecI64x2ReplaceLaneName + "/lane=1",
  1701  			body:                 replaceLane(wasm.OpcodeVecI64x2ReplaceLane, 1),
  1702  			expected:             &OperationV128ReplaceLane{LaneIndex: 1, Shape: ShapeI64x2},
  1703  			needDropBeforeReturn: true,
  1704  		},
  1705  		{
  1706  			name:                 wasm.OpcodeVecF32x4ReplaceLaneName,
  1707  			body:                 replaceLane(wasm.OpcodeVecF32x4ReplaceLane, 0),
  1708  			expected:             &OperationV128ReplaceLane{LaneIndex: 0, Shape: ShapeF32x4},
  1709  			needDropBeforeReturn: true,
  1710  		},
  1711  		{
  1712  			name:                 wasm.OpcodeVecF32x4ReplaceLaneName + "/lane=3",
  1713  			body:                 replaceLane(wasm.OpcodeVecF32x4ReplaceLane, 3),
  1714  			expected:             &OperationV128ReplaceLane{LaneIndex: 3, Shape: ShapeF32x4},
  1715  			needDropBeforeReturn: true,
  1716  		},
  1717  		{
  1718  			name:                 wasm.OpcodeVecF64x2ReplaceLaneName,
  1719  			body:                 replaceLane(wasm.OpcodeVecF64x2ReplaceLane, 0),
  1720  			expected:             &OperationV128ReplaceLane{LaneIndex: 0, Shape: ShapeF64x2},
  1721  			needDropBeforeReturn: true,
  1722  		},
  1723  		{
  1724  			name:                 wasm.OpcodeVecF64x2ReplaceLaneName + "/lane=1",
  1725  			body:                 replaceLane(wasm.OpcodeVecF64x2ReplaceLane, 1),
  1726  			expected:             &OperationV128ReplaceLane{LaneIndex: 1, Shape: ShapeF64x2},
  1727  			needDropBeforeReturn: true,
  1728  		},
  1729  		{
  1730  			name: wasm.OpcodeVecI8x16SplatName, body: splat(wasm.OpcodeVecI8x16Splat),
  1731  			expected:             &OperationV128Splat{Shape: ShapeI8x16},
  1732  			needDropBeforeReturn: true,
  1733  		},
  1734  		{
  1735  			name: wasm.OpcodeVecI16x8SplatName, body: splat(wasm.OpcodeVecI16x8Splat),
  1736  			expected:             &OperationV128Splat{Shape: ShapeI16x8},
  1737  			needDropBeforeReturn: true,
  1738  		},
  1739  		{
  1740  			name: wasm.OpcodeVecI32x4SplatName, body: splat(wasm.OpcodeVecI32x4Splat),
  1741  			expected:             &OperationV128Splat{Shape: ShapeI32x4},
  1742  			needDropBeforeReturn: true,
  1743  		},
  1744  		{
  1745  			name: wasm.OpcodeVecI64x2SplatName, body: splat(wasm.OpcodeVecI64x2Splat),
  1746  			expected:             &OperationV128Splat{Shape: ShapeI64x2},
  1747  			needDropBeforeReturn: true,
  1748  		},
  1749  		{
  1750  			name: wasm.OpcodeVecF32x4SplatName, body: splat(wasm.OpcodeVecF32x4Splat),
  1751  			expected:             &OperationV128Splat{Shape: ShapeF32x4},
  1752  			needDropBeforeReturn: true,
  1753  		},
  1754  		{
  1755  			name: wasm.OpcodeVecF64x2SplatName, body: splat(wasm.OpcodeVecF64x2Splat),
  1756  			expected:             &OperationV128Splat{Shape: ShapeF64x2},
  1757  			needDropBeforeReturn: true,
  1758  		},
  1759  		{
  1760  			name: wasm.OpcodeVecI8x16SwizzleName, body: vv2v(wasm.OpcodeVecI8x16Swizzle),
  1761  			expected:             &OperationV128Swizzle{},
  1762  			needDropBeforeReturn: true,
  1763  		},
  1764  		{
  1765  			name: wasm.OpcodeVecV128i8x16ShuffleName, body: []byte{
  1766  				wasm.OpcodeVecPrefix,
  1767  				wasm.OpcodeVecV128Const, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  1768  				wasm.OpcodeVecPrefix,
  1769  				wasm.OpcodeVecV128Const, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  1770  				wasm.OpcodeVecPrefix,
  1771  				wasm.OpcodeVecV128i8x16Shuffle,
  1772  				1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
  1773  				wasm.OpcodeDrop,
  1774  				wasm.OpcodeEnd,
  1775  			},
  1776  			expected: &OperationV128Shuffle{Lanes: [16]byte{
  1777  				1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
  1778  			}},
  1779  			needDropBeforeReturn: true,
  1780  		},
  1781  		{
  1782  			name: wasm.OpcodeVecV128NotName, body: v2v(wasm.OpcodeVecV128Not),
  1783  			needDropBeforeReturn: true,
  1784  			expected:             &OperationV128Not{},
  1785  		},
  1786  		{
  1787  			name: wasm.OpcodeVecV128AndName, body: vv2v(wasm.OpcodeVecV128And),
  1788  			needDropBeforeReturn: true,
  1789  			expected:             &OperationV128And{},
  1790  		},
  1791  		{
  1792  			name: wasm.OpcodeVecV128AndNotName, body: vv2v(wasm.OpcodeVecV128AndNot),
  1793  			needDropBeforeReturn: true,
  1794  			expected:             &OperationV128AndNot{},
  1795  		},
  1796  		{
  1797  			name: wasm.OpcodeVecV128OrName, body: vv2v(wasm.OpcodeVecV128Or),
  1798  			needDropBeforeReturn: true,
  1799  			expected:             &OperationV128Or{},
  1800  		},
  1801  		{
  1802  			name: wasm.OpcodeVecV128XorName, body: vv2v(wasm.OpcodeVecV128Xor),
  1803  			needDropBeforeReturn: true,
  1804  			expected:             &OperationV128Xor{},
  1805  		},
  1806  		{
  1807  			name: wasm.OpcodeVecV128BitselectName, body: vvv2v(wasm.OpcodeVecV128Bitselect),
  1808  			needDropBeforeReturn: true,
  1809  			expected:             &OperationV128Bitselect{},
  1810  		},
  1811  		{
  1812  			name: wasm.OpcodeVecI8x16ShlName, body: vi2v(wasm.OpcodeVecI8x16Shl),
  1813  			needDropBeforeReturn: true,
  1814  			expected:             &OperationV128Shl{Shape: ShapeI8x16},
  1815  		},
  1816  		{
  1817  			name: wasm.OpcodeVecI8x16ShrSName, body: vi2v(wasm.OpcodeVecI8x16ShrS),
  1818  			needDropBeforeReturn: true,
  1819  			expected:             &OperationV128Shr{Shape: ShapeI8x16, Signed: true},
  1820  		},
  1821  		{
  1822  			name: wasm.OpcodeVecI8x16ShrUName, body: vi2v(wasm.OpcodeVecI8x16ShrU),
  1823  			needDropBeforeReturn: true,
  1824  			expected:             &OperationV128Shr{Shape: ShapeI8x16, Signed: false},
  1825  		},
  1826  		{
  1827  			name: wasm.OpcodeVecI16x8ShlName, body: vi2v(wasm.OpcodeVecI16x8Shl),
  1828  			needDropBeforeReturn: true,
  1829  			expected:             &OperationV128Shl{Shape: ShapeI16x8},
  1830  		},
  1831  		{
  1832  			name: wasm.OpcodeVecI16x8ShrSName, body: vi2v(wasm.OpcodeVecI16x8ShrS),
  1833  			needDropBeforeReturn: true,
  1834  			expected:             &OperationV128Shr{Shape: ShapeI16x8, Signed: true},
  1835  		},
  1836  		{
  1837  			name: wasm.OpcodeVecI16x8ShrUName, body: vi2v(wasm.OpcodeVecI16x8ShrU),
  1838  			needDropBeforeReturn: true,
  1839  			expected:             &OperationV128Shr{Shape: ShapeI16x8, Signed: false},
  1840  		},
  1841  		{
  1842  			name: wasm.OpcodeVecI32x4ShlName, body: vi2v(wasm.OpcodeVecI32x4Shl),
  1843  			needDropBeforeReturn: true,
  1844  			expected:             &OperationV128Shl{Shape: ShapeI32x4},
  1845  		},
  1846  		{
  1847  			name: wasm.OpcodeVecI32x4ShrSName, body: vi2v(wasm.OpcodeVecI32x4ShrS),
  1848  			needDropBeforeReturn: true,
  1849  			expected:             &OperationV128Shr{Shape: ShapeI32x4, Signed: true},
  1850  		},
  1851  		{
  1852  			name: wasm.OpcodeVecI32x4ShrUName, body: vi2v(wasm.OpcodeVecI32x4ShrU),
  1853  			needDropBeforeReturn: true,
  1854  			expected:             &OperationV128Shr{Shape: ShapeI32x4, Signed: false},
  1855  		},
  1856  		{
  1857  			name: wasm.OpcodeVecI64x2ShlName, body: vi2v(wasm.OpcodeVecI64x2Shl),
  1858  			needDropBeforeReturn: true,
  1859  			expected:             &OperationV128Shl{Shape: ShapeI64x2},
  1860  		},
  1861  		{
  1862  			name: wasm.OpcodeVecI64x2ShrSName, body: vi2v(wasm.OpcodeVecI64x2ShrS),
  1863  			needDropBeforeReturn: true,
  1864  			expected:             &OperationV128Shr{Shape: ShapeI64x2, Signed: true},
  1865  		},
  1866  		{
  1867  			name: wasm.OpcodeVecI64x2ShrUName, body: vi2v(wasm.OpcodeVecI64x2ShrU),
  1868  			needDropBeforeReturn: true,
  1869  			expected:             &OperationV128Shr{Shape: ShapeI64x2, Signed: false},
  1870  		},
  1871  		{
  1872  			name: wasm.OpcodeVecI8x16EqName, body: vv2v(wasm.OpcodeVecI8x16Eq),
  1873  			needDropBeforeReturn: true,
  1874  			expected:             &OperationV128Cmp{Type: V128CmpTypeI8x16Eq},
  1875  		},
  1876  		{
  1877  			name: wasm.OpcodeVecI8x16NeName, body: vv2v(wasm.OpcodeVecI8x16Ne),
  1878  			needDropBeforeReturn: true,
  1879  			expected:             &OperationV128Cmp{Type: V128CmpTypeI8x16Ne},
  1880  		},
  1881  		{
  1882  			name: wasm.OpcodeVecI8x16LtSName, body: vv2v(wasm.OpcodeVecI8x16LtS),
  1883  			needDropBeforeReturn: true,
  1884  			expected:             &OperationV128Cmp{Type: V128CmpTypeI8x16LtS},
  1885  		},
  1886  		{
  1887  			name: wasm.OpcodeVecI8x16LtUName, body: vv2v(wasm.OpcodeVecI8x16LtU),
  1888  			needDropBeforeReturn: true,
  1889  			expected:             &OperationV128Cmp{Type: V128CmpTypeI8x16LtU},
  1890  		},
  1891  		{
  1892  			name: wasm.OpcodeVecI8x16GtSName, body: vv2v(wasm.OpcodeVecI8x16GtS),
  1893  			needDropBeforeReturn: true,
  1894  			expected:             &OperationV128Cmp{Type: V128CmpTypeI8x16GtS},
  1895  		},
  1896  		{
  1897  			name: wasm.OpcodeVecI8x16GtUName, body: vv2v(wasm.OpcodeVecI8x16GtU),
  1898  			needDropBeforeReturn: true,
  1899  			expected:             &OperationV128Cmp{Type: V128CmpTypeI8x16GtU},
  1900  		},
  1901  		{
  1902  			name: wasm.OpcodeVecI8x16LeSName, body: vv2v(wasm.OpcodeVecI8x16LeS),
  1903  			needDropBeforeReturn: true,
  1904  			expected:             &OperationV128Cmp{Type: V128CmpTypeI8x16LeS},
  1905  		},
  1906  		{
  1907  			name: wasm.OpcodeVecI8x16LeUName, body: vv2v(wasm.OpcodeVecI8x16LeU),
  1908  			needDropBeforeReturn: true,
  1909  			expected:             &OperationV128Cmp{Type: V128CmpTypeI8x16LeU},
  1910  		},
  1911  		{
  1912  			name: wasm.OpcodeVecI8x16GeSName, body: vv2v(wasm.OpcodeVecI8x16GeS),
  1913  			needDropBeforeReturn: true,
  1914  			expected:             &OperationV128Cmp{Type: V128CmpTypeI8x16GeS},
  1915  		},
  1916  		{
  1917  			name: wasm.OpcodeVecI8x16GeUName, body: vv2v(wasm.OpcodeVecI8x16GeU),
  1918  			needDropBeforeReturn: true,
  1919  			expected:             &OperationV128Cmp{Type: V128CmpTypeI8x16GeU},
  1920  		},
  1921  		{
  1922  			name: wasm.OpcodeVecI16x8EqName, body: vv2v(wasm.OpcodeVecI16x8Eq),
  1923  			needDropBeforeReturn: true,
  1924  			expected:             &OperationV128Cmp{Type: V128CmpTypeI16x8Eq},
  1925  		},
  1926  		{
  1927  			name: wasm.OpcodeVecI16x8NeName, body: vv2v(wasm.OpcodeVecI16x8Ne),
  1928  			needDropBeforeReturn: true,
  1929  			expected:             &OperationV128Cmp{Type: V128CmpTypeI16x8Ne},
  1930  		},
  1931  		{
  1932  			name: wasm.OpcodeVecI16x8LtSName, body: vv2v(wasm.OpcodeVecI16x8LtS),
  1933  			needDropBeforeReturn: true,
  1934  			expected:             &OperationV128Cmp{Type: V128CmpTypeI16x8LtS},
  1935  		},
  1936  		{
  1937  			name: wasm.OpcodeVecI16x8LtUName, body: vv2v(wasm.OpcodeVecI16x8LtU),
  1938  			needDropBeforeReturn: true,
  1939  			expected:             &OperationV128Cmp{Type: V128CmpTypeI16x8LtU},
  1940  		},
  1941  		{
  1942  			name: wasm.OpcodeVecI16x8GtSName, body: vv2v(wasm.OpcodeVecI16x8GtS),
  1943  			needDropBeforeReturn: true,
  1944  			expected:             &OperationV128Cmp{Type: V128CmpTypeI16x8GtS},
  1945  		},
  1946  		{
  1947  			name: wasm.OpcodeVecI16x8GtUName, body: vv2v(wasm.OpcodeVecI16x8GtU),
  1948  			needDropBeforeReturn: true,
  1949  			expected:             &OperationV128Cmp{Type: V128CmpTypeI16x8GtU},
  1950  		},
  1951  		{
  1952  			name: wasm.OpcodeVecI16x8LeSName, body: vv2v(wasm.OpcodeVecI16x8LeS),
  1953  			needDropBeforeReturn: true,
  1954  			expected:             &OperationV128Cmp{Type: V128CmpTypeI16x8LeS},
  1955  		},
  1956  		{
  1957  			name: wasm.OpcodeVecI16x8LeUName, body: vv2v(wasm.OpcodeVecI16x8LeU),
  1958  			needDropBeforeReturn: true,
  1959  			expected:             &OperationV128Cmp{Type: V128CmpTypeI16x8LeU},
  1960  		},
  1961  		{
  1962  			name: wasm.OpcodeVecI16x8GeSName, body: vv2v(wasm.OpcodeVecI16x8GeS),
  1963  			needDropBeforeReturn: true,
  1964  			expected:             &OperationV128Cmp{Type: V128CmpTypeI16x8GeS},
  1965  		},
  1966  		{
  1967  			name: wasm.OpcodeVecI16x8GeUName, body: vv2v(wasm.OpcodeVecI16x8GeU),
  1968  			needDropBeforeReturn: true,
  1969  			expected:             &OperationV128Cmp{Type: V128CmpTypeI16x8GeU},
  1970  		},
  1971  		{
  1972  			name: wasm.OpcodeVecI32x4EqName, body: vv2v(wasm.OpcodeVecI32x4Eq),
  1973  			needDropBeforeReturn: true,
  1974  			expected:             &OperationV128Cmp{Type: V128CmpTypeI32x4Eq},
  1975  		},
  1976  		{
  1977  			name: wasm.OpcodeVecI32x4NeName, body: vv2v(wasm.OpcodeVecI32x4Ne),
  1978  			needDropBeforeReturn: true,
  1979  			expected:             &OperationV128Cmp{Type: V128CmpTypeI32x4Ne},
  1980  		},
  1981  		{
  1982  			name: wasm.OpcodeVecI32x4LtSName, body: vv2v(wasm.OpcodeVecI32x4LtS),
  1983  			needDropBeforeReturn: true,
  1984  			expected:             &OperationV128Cmp{Type: V128CmpTypeI32x4LtS},
  1985  		},
  1986  		{
  1987  			name: wasm.OpcodeVecI32x4LtUName, body: vv2v(wasm.OpcodeVecI32x4LtU),
  1988  			needDropBeforeReturn: true,
  1989  			expected:             &OperationV128Cmp{Type: V128CmpTypeI32x4LtU},
  1990  		},
  1991  		{
  1992  			name: wasm.OpcodeVecI32x4GtSName, body: vv2v(wasm.OpcodeVecI32x4GtS),
  1993  			needDropBeforeReturn: true,
  1994  			expected:             &OperationV128Cmp{Type: V128CmpTypeI32x4GtS},
  1995  		},
  1996  		{
  1997  			name: wasm.OpcodeVecI32x4GtUName, body: vv2v(wasm.OpcodeVecI32x4GtU),
  1998  			needDropBeforeReturn: true,
  1999  			expected:             &OperationV128Cmp{Type: V128CmpTypeI32x4GtU},
  2000  		},
  2001  		{
  2002  			name: wasm.OpcodeVecI32x4LeSName, body: vv2v(wasm.OpcodeVecI32x4LeS),
  2003  			needDropBeforeReturn: true,
  2004  			expected:             &OperationV128Cmp{Type: V128CmpTypeI32x4LeS},
  2005  		},
  2006  		{
  2007  			name: wasm.OpcodeVecI32x4LeUName, body: vv2v(wasm.OpcodeVecI32x4LeU),
  2008  			needDropBeforeReturn: true,
  2009  			expected:             &OperationV128Cmp{Type: V128CmpTypeI32x4LeU},
  2010  		},
  2011  		{
  2012  			name: wasm.OpcodeVecI32x4GeSName, body: vv2v(wasm.OpcodeVecI32x4GeS),
  2013  			needDropBeforeReturn: true,
  2014  			expected:             &OperationV128Cmp{Type: V128CmpTypeI32x4GeS},
  2015  		},
  2016  		{
  2017  			name: wasm.OpcodeVecI32x4GeUName, body: vv2v(wasm.OpcodeVecI32x4GeU),
  2018  			needDropBeforeReturn: true,
  2019  			expected:             &OperationV128Cmp{Type: V128CmpTypeI32x4GeU},
  2020  		},
  2021  		{
  2022  			name: wasm.OpcodeVecI64x2EqName, body: vv2v(wasm.OpcodeVecI64x2Eq),
  2023  			needDropBeforeReturn: true,
  2024  			expected:             &OperationV128Cmp{Type: V128CmpTypeI64x2Eq},
  2025  		},
  2026  		{
  2027  			name: wasm.OpcodeVecI64x2NeName, body: vv2v(wasm.OpcodeVecI64x2Ne),
  2028  			needDropBeforeReturn: true,
  2029  			expected:             &OperationV128Cmp{Type: V128CmpTypeI64x2Ne},
  2030  		},
  2031  		{
  2032  			name: wasm.OpcodeVecI64x2LtSName, body: vv2v(wasm.OpcodeVecI64x2LtS),
  2033  			needDropBeforeReturn: true,
  2034  			expected:             &OperationV128Cmp{Type: V128CmpTypeI64x2LtS},
  2035  		},
  2036  		{
  2037  			name: wasm.OpcodeVecI64x2GtSName, body: vv2v(wasm.OpcodeVecI64x2GtS),
  2038  			needDropBeforeReturn: true,
  2039  			expected:             &OperationV128Cmp{Type: V128CmpTypeI64x2GtS},
  2040  		},
  2041  		{
  2042  			name: wasm.OpcodeVecI64x2LeSName, body: vv2v(wasm.OpcodeVecI64x2LeS),
  2043  			needDropBeforeReturn: true,
  2044  			expected:             &OperationV128Cmp{Type: V128CmpTypeI64x2LeS},
  2045  		},
  2046  		{
  2047  			name: wasm.OpcodeVecI64x2GeSName, body: vv2v(wasm.OpcodeVecI64x2GeS),
  2048  			needDropBeforeReturn: true,
  2049  			expected:             &OperationV128Cmp{Type: V128CmpTypeI64x2GeS},
  2050  		},
  2051  		{
  2052  			name: wasm.OpcodeVecF32x4EqName, body: vv2v(wasm.OpcodeVecF32x4Eq),
  2053  			needDropBeforeReturn: true,
  2054  			expected:             &OperationV128Cmp{Type: V128CmpTypeF32x4Eq},
  2055  		},
  2056  		{
  2057  			name: wasm.OpcodeVecF32x4NeName, body: vv2v(wasm.OpcodeVecF32x4Ne),
  2058  			needDropBeforeReturn: true,
  2059  			expected:             &OperationV128Cmp{Type: V128CmpTypeF32x4Ne},
  2060  		},
  2061  		{
  2062  			name: wasm.OpcodeVecF32x4LtName, body: vv2v(wasm.OpcodeVecF32x4Lt),
  2063  			needDropBeforeReturn: true,
  2064  			expected:             &OperationV128Cmp{Type: V128CmpTypeF32x4Lt},
  2065  		},
  2066  		{
  2067  			name: wasm.OpcodeVecF32x4GtName, body: vv2v(wasm.OpcodeVecF32x4Gt),
  2068  			needDropBeforeReturn: true,
  2069  			expected:             &OperationV128Cmp{Type: V128CmpTypeF32x4Gt},
  2070  		},
  2071  		{
  2072  			name: wasm.OpcodeVecF32x4LeName, body: vv2v(wasm.OpcodeVecF32x4Le),
  2073  			needDropBeforeReturn: true,
  2074  			expected:             &OperationV128Cmp{Type: V128CmpTypeF32x4Le},
  2075  		},
  2076  		{
  2077  			name: wasm.OpcodeVecF32x4GeName, body: vv2v(wasm.OpcodeVecF32x4Ge),
  2078  			needDropBeforeReturn: true,
  2079  			expected:             &OperationV128Cmp{Type: V128CmpTypeF32x4Ge},
  2080  		},
  2081  		{
  2082  			name: wasm.OpcodeVecF64x2EqName, body: vv2v(wasm.OpcodeVecF64x2Eq),
  2083  			needDropBeforeReturn: true,
  2084  			expected:             &OperationV128Cmp{Type: V128CmpTypeF64x2Eq},
  2085  		},
  2086  		{
  2087  			name: wasm.OpcodeVecF64x2NeName, body: vv2v(wasm.OpcodeVecF64x2Ne),
  2088  			needDropBeforeReturn: true,
  2089  			expected:             &OperationV128Cmp{Type: V128CmpTypeF64x2Ne},
  2090  		},
  2091  		{
  2092  			name: wasm.OpcodeVecF64x2LtName, body: vv2v(wasm.OpcodeVecF64x2Lt),
  2093  			needDropBeforeReturn: true,
  2094  			expected:             &OperationV128Cmp{Type: V128CmpTypeF64x2Lt},
  2095  		},
  2096  		{
  2097  			name: wasm.OpcodeVecF64x2GtName, body: vv2v(wasm.OpcodeVecF64x2Gt),
  2098  			needDropBeforeReturn: true,
  2099  			expected:             &OperationV128Cmp{Type: V128CmpTypeF64x2Gt},
  2100  		},
  2101  		{
  2102  			name: wasm.OpcodeVecF64x2LeName, body: vv2v(wasm.OpcodeVecF64x2Le),
  2103  			needDropBeforeReturn: true,
  2104  			expected:             &OperationV128Cmp{Type: V128CmpTypeF64x2Le},
  2105  		},
  2106  		{
  2107  			name: wasm.OpcodeVecF64x2GeName, body: vv2v(wasm.OpcodeVecF64x2Ge),
  2108  			needDropBeforeReturn: true,
  2109  			expected:             &OperationV128Cmp{Type: V128CmpTypeF64x2Ge},
  2110  		},
  2111  		{
  2112  			name: wasm.OpcodeVecI8x16AllTrueName, body: v2v(wasm.OpcodeVecI8x16AllTrue),
  2113  			needDropBeforeReturn: true,
  2114  			expected:             &OperationV128AllTrue{Shape: ShapeI8x16},
  2115  		},
  2116  		{
  2117  			name: wasm.OpcodeVecI16x8AllTrueName, body: v2v(wasm.OpcodeVecI16x8AllTrue),
  2118  			needDropBeforeReturn: true,
  2119  			expected:             &OperationV128AllTrue{Shape: ShapeI16x8},
  2120  		},
  2121  		{
  2122  			name: wasm.OpcodeVecI32x4AllTrueName, body: v2v(wasm.OpcodeVecI32x4AllTrue),
  2123  			needDropBeforeReturn: true,
  2124  			expected:             &OperationV128AllTrue{Shape: ShapeI32x4},
  2125  		},
  2126  		{
  2127  			name: wasm.OpcodeVecI64x2AllTrueName, body: v2v(wasm.OpcodeVecI64x2AllTrue),
  2128  			needDropBeforeReturn: true,
  2129  			expected:             &OperationV128AllTrue{Shape: ShapeI64x2},
  2130  		},
  2131  		{
  2132  			name: wasm.OpcodeVecI8x16BitMaskName, body: v2v(wasm.OpcodeVecI8x16BitMask),
  2133  			needDropBeforeReturn: true, expected: &OperationV128BitMask{Shape: ShapeI8x16},
  2134  		},
  2135  		{
  2136  			name: wasm.OpcodeVecI16x8BitMaskName, body: v2v(wasm.OpcodeVecI16x8BitMask),
  2137  			needDropBeforeReturn: true, expected: &OperationV128BitMask{Shape: ShapeI16x8},
  2138  		},
  2139  		{
  2140  			name: wasm.OpcodeVecI32x4BitMaskName, body: v2v(wasm.OpcodeVecI32x4BitMask),
  2141  			needDropBeforeReturn: true, expected: &OperationV128BitMask{Shape: ShapeI32x4},
  2142  		},
  2143  		{
  2144  			name: wasm.OpcodeVecI64x2BitMaskName, body: v2v(wasm.OpcodeVecI64x2BitMask),
  2145  			needDropBeforeReturn: true, expected: &OperationV128BitMask{Shape: ShapeI64x2},
  2146  		},
  2147  		{
  2148  			name: wasm.OpcodeVecV128AnyTrueName, body: v2v(wasm.OpcodeVecV128AnyTrue),
  2149  			needDropBeforeReturn: true,
  2150  			expected:             &OperationV128AnyTrue{},
  2151  		},
  2152  		{
  2153  			name: wasm.OpcodeVecI8x16AddName, body: vv2v(wasm.OpcodeVecI8x16Add),
  2154  			needDropBeforeReturn: true,
  2155  			expected:             &OperationV128Add{Shape: ShapeI8x16},
  2156  		},
  2157  		{
  2158  			name: wasm.OpcodeVecI8x16AddSatSName, body: vv2v(wasm.OpcodeVecI8x16AddSatS),
  2159  			needDropBeforeReturn: true,
  2160  			expected:             &OperationV128AddSat{Shape: ShapeI8x16, Signed: true},
  2161  		},
  2162  		{
  2163  			name: wasm.OpcodeVecI8x16AddSatUName, body: vv2v(wasm.OpcodeVecI8x16AddSatU),
  2164  			needDropBeforeReturn: true,
  2165  			expected:             &OperationV128AddSat{Shape: ShapeI8x16, Signed: false},
  2166  		},
  2167  		{
  2168  			name: wasm.OpcodeVecI8x16SubName, body: vv2v(wasm.OpcodeVecI8x16Sub),
  2169  			needDropBeforeReturn: true,
  2170  			expected:             &OperationV128Sub{Shape: ShapeI8x16},
  2171  		},
  2172  		{
  2173  			name: wasm.OpcodeVecI8x16SubSatSName, body: vv2v(wasm.OpcodeVecI8x16SubSatS),
  2174  			needDropBeforeReturn: true,
  2175  			expected:             &OperationV128SubSat{Shape: ShapeI8x16, Signed: true},
  2176  		},
  2177  		{
  2178  			name: wasm.OpcodeVecI8x16SubSatUName, body: vv2v(wasm.OpcodeVecI8x16SubSatU),
  2179  			needDropBeforeReturn: true,
  2180  			expected:             &OperationV128SubSat{Shape: ShapeI8x16, Signed: false},
  2181  		},
  2182  		{
  2183  			name: wasm.OpcodeVecI16x8AddName, body: vv2v(wasm.OpcodeVecI16x8Add),
  2184  			needDropBeforeReturn: true,
  2185  			expected:             &OperationV128Add{Shape: ShapeI16x8},
  2186  		},
  2187  		{
  2188  			name: wasm.OpcodeVecI16x8AddSatSName, body: vv2v(wasm.OpcodeVecI16x8AddSatS),
  2189  			needDropBeforeReturn: true,
  2190  			expected:             &OperationV128AddSat{Shape: ShapeI16x8, Signed: true},
  2191  		},
  2192  		{
  2193  			name: wasm.OpcodeVecI16x8AddSatUName, body: vv2v(wasm.OpcodeVecI16x8AddSatU),
  2194  			needDropBeforeReturn: true,
  2195  			expected:             &OperationV128AddSat{Shape: ShapeI16x8, Signed: false},
  2196  		},
  2197  		{
  2198  			name: wasm.OpcodeVecI16x8SubName, body: vv2v(wasm.OpcodeVecI16x8Sub),
  2199  			needDropBeforeReturn: true,
  2200  			expected:             &OperationV128Sub{Shape: ShapeI16x8},
  2201  		},
  2202  		{
  2203  			name: wasm.OpcodeVecI16x8SubSatSName, body: vv2v(wasm.OpcodeVecI16x8SubSatS),
  2204  			needDropBeforeReturn: true,
  2205  			expected:             &OperationV128SubSat{Shape: ShapeI16x8, Signed: true},
  2206  		},
  2207  		{
  2208  			name: wasm.OpcodeVecI16x8SubSatUName, body: vv2v(wasm.OpcodeVecI16x8SubSatU),
  2209  			needDropBeforeReturn: true,
  2210  			expected:             &OperationV128SubSat{Shape: ShapeI16x8, Signed: false},
  2211  		},
  2212  		{
  2213  			name: wasm.OpcodeVecI16x8MulName, body: vv2v(wasm.OpcodeVecI16x8Mul),
  2214  			needDropBeforeReturn: true,
  2215  			expected:             &OperationV128Mul{Shape: ShapeI16x8},
  2216  		},
  2217  		{
  2218  			name: wasm.OpcodeVecI32x4AddName, body: vv2v(wasm.OpcodeVecI32x4Add),
  2219  			needDropBeforeReturn: true,
  2220  			expected:             &OperationV128Add{Shape: ShapeI32x4},
  2221  		},
  2222  		{
  2223  			name: wasm.OpcodeVecI32x4SubName, body: vv2v(wasm.OpcodeVecI32x4Sub),
  2224  			needDropBeforeReturn: true,
  2225  			expected:             &OperationV128Sub{Shape: ShapeI32x4},
  2226  		},
  2227  		{
  2228  			name: wasm.OpcodeVecI32x4MulName, body: vv2v(wasm.OpcodeVecI32x4Mul),
  2229  			needDropBeforeReturn: true,
  2230  			expected:             &OperationV128Mul{Shape: ShapeI32x4},
  2231  		},
  2232  		{
  2233  			name: wasm.OpcodeVecI64x2AddName, body: vv2v(wasm.OpcodeVecI64x2Add),
  2234  			needDropBeforeReturn: true,
  2235  			expected:             &OperationV128Add{Shape: ShapeI64x2},
  2236  		},
  2237  		{
  2238  			name: wasm.OpcodeVecI64x2SubName, body: vv2v(wasm.OpcodeVecI64x2Sub),
  2239  			needDropBeforeReturn: true,
  2240  			expected:             &OperationV128Sub{Shape: ShapeI64x2},
  2241  		},
  2242  		{
  2243  			name: wasm.OpcodeVecI64x2MulName, body: vv2v(wasm.OpcodeVecI64x2Mul),
  2244  			needDropBeforeReturn: true,
  2245  			expected:             &OperationV128Mul{Shape: ShapeI64x2},
  2246  		},
  2247  		{
  2248  			name: wasm.OpcodeVecF32x4AddName, body: vv2v(wasm.OpcodeVecF32x4Add),
  2249  			needDropBeforeReturn: true,
  2250  			expected:             &OperationV128Add{Shape: ShapeF32x4},
  2251  		},
  2252  		{
  2253  			name: wasm.OpcodeVecF32x4SubName, body: vv2v(wasm.OpcodeVecF32x4Sub),
  2254  			needDropBeforeReturn: true,
  2255  			expected:             &OperationV128Sub{Shape: ShapeF32x4},
  2256  		},
  2257  		{
  2258  			name: wasm.OpcodeVecF32x4MulName, body: vv2v(wasm.OpcodeVecF32x4Mul),
  2259  			needDropBeforeReturn: true,
  2260  			expected:             &OperationV128Mul{Shape: ShapeF32x4},
  2261  		},
  2262  		{
  2263  			name: wasm.OpcodeVecF32x4DivName, body: vv2v(wasm.OpcodeVecF32x4Div),
  2264  			needDropBeforeReturn: true,
  2265  			expected:             &OperationV128Div{Shape: ShapeF32x4},
  2266  		},
  2267  		{
  2268  			name: wasm.OpcodeVecF64x2AddName, body: vv2v(wasm.OpcodeVecF64x2Add),
  2269  			needDropBeforeReturn: true,
  2270  			expected:             &OperationV128Add{Shape: ShapeF64x2},
  2271  		},
  2272  		{
  2273  			name: wasm.OpcodeVecF64x2SubName, body: vv2v(wasm.OpcodeVecF64x2Sub),
  2274  			needDropBeforeReturn: true,
  2275  			expected:             &OperationV128Sub{Shape: ShapeF64x2},
  2276  		},
  2277  		{
  2278  			name: wasm.OpcodeVecF64x2MulName, body: vv2v(wasm.OpcodeVecF64x2Mul),
  2279  			needDropBeforeReturn: true,
  2280  			expected:             &OperationV128Mul{Shape: ShapeF64x2},
  2281  		},
  2282  		{
  2283  			name: wasm.OpcodeVecF64x2DivName, body: vv2v(wasm.OpcodeVecF64x2Div),
  2284  			needDropBeforeReturn: true,
  2285  			expected:             &OperationV128Div{Shape: ShapeF64x2},
  2286  		},
  2287  		{
  2288  			name: wasm.OpcodeVecI8x16MinSName, body: vv2v(wasm.OpcodeVecI8x16MinS),
  2289  			needDropBeforeReturn: true,
  2290  			expected:             &OperationV128Min{Shape: ShapeI8x16, Signed: true},
  2291  		},
  2292  		{
  2293  			name: wasm.OpcodeVecI8x16MinUName, body: vv2v(wasm.OpcodeVecI8x16MinU),
  2294  			needDropBeforeReturn: true,
  2295  			expected:             &OperationV128Min{Shape: ShapeI8x16},
  2296  		},
  2297  		{
  2298  			name: wasm.OpcodeVecI8x16MaxSName, body: vv2v(wasm.OpcodeVecI8x16MaxS),
  2299  			needDropBeforeReturn: true,
  2300  			expected:             &OperationV128Max{Shape: ShapeI8x16, Signed: true},
  2301  		},
  2302  		{
  2303  			name: wasm.OpcodeVecI8x16MaxUName, body: vv2v(wasm.OpcodeVecI8x16MaxU),
  2304  			needDropBeforeReturn: true,
  2305  			expected:             &OperationV128Max{Shape: ShapeI8x16},
  2306  		},
  2307  		{
  2308  			name: wasm.OpcodeVecI8x16AvgrUName, body: vv2v(wasm.OpcodeVecI8x16AvgrU),
  2309  			needDropBeforeReturn: true,
  2310  			expected:             &OperationV128AvgrU{Shape: ShapeI8x16},
  2311  		},
  2312  		{
  2313  			name: wasm.OpcodeVecI16x8MinSName, body: vv2v(wasm.OpcodeVecI16x8MinS),
  2314  			needDropBeforeReturn: true,
  2315  			expected:             &OperationV128Min{Shape: ShapeI16x8, Signed: true},
  2316  		},
  2317  		{
  2318  			name: wasm.OpcodeVecI16x8MinUName, body: vv2v(wasm.OpcodeVecI16x8MinU),
  2319  			needDropBeforeReturn: true,
  2320  			expected:             &OperationV128Min{Shape: ShapeI16x8},
  2321  		},
  2322  		{
  2323  			name: wasm.OpcodeVecI16x8MaxSName, body: vv2v(wasm.OpcodeVecI16x8MaxS),
  2324  			needDropBeforeReturn: true,
  2325  			expected:             &OperationV128Max{Shape: ShapeI16x8, Signed: true},
  2326  		},
  2327  		{
  2328  			name: wasm.OpcodeVecI16x8MaxUName, body: vv2v(wasm.OpcodeVecI16x8MaxU),
  2329  			needDropBeforeReturn: true,
  2330  			expected:             &OperationV128Max{Shape: ShapeI16x8},
  2331  		},
  2332  		{
  2333  			name: wasm.OpcodeVecI16x8AvgrUName, body: vv2v(wasm.OpcodeVecI16x8AvgrU),
  2334  			needDropBeforeReturn: true,
  2335  			expected:             &OperationV128AvgrU{Shape: ShapeI16x8},
  2336  		},
  2337  		{
  2338  			name: wasm.OpcodeVecI32x4MinSName, body: vv2v(wasm.OpcodeVecI32x4MinS),
  2339  			needDropBeforeReturn: true,
  2340  			expected:             &OperationV128Min{Shape: ShapeI32x4, Signed: true},
  2341  		},
  2342  		{
  2343  			name: wasm.OpcodeVecI32x4MinUName, body: vv2v(wasm.OpcodeVecI32x4MinU),
  2344  			needDropBeforeReturn: true,
  2345  			expected:             &OperationV128Min{Shape: ShapeI32x4},
  2346  		},
  2347  		{
  2348  			name: wasm.OpcodeVecI32x4MaxSName, body: vv2v(wasm.OpcodeVecI32x4MaxS),
  2349  			needDropBeforeReturn: true,
  2350  			expected:             &OperationV128Max{Shape: ShapeI32x4, Signed: true},
  2351  		},
  2352  		{
  2353  			name: wasm.OpcodeVecI32x4MaxUName, body: vv2v(wasm.OpcodeVecI32x4MaxU),
  2354  			needDropBeforeReturn: true,
  2355  			expected:             &OperationV128Max{Shape: ShapeI32x4},
  2356  		},
  2357  		{
  2358  			name: wasm.OpcodeVecF32x4MinName, body: vv2v(wasm.OpcodeVecF32x4Min),
  2359  			needDropBeforeReturn: true,
  2360  			expected:             &OperationV128Min{Shape: ShapeF32x4},
  2361  		},
  2362  		{
  2363  			name: wasm.OpcodeVecF32x4MaxName, body: vv2v(wasm.OpcodeVecF32x4Max),
  2364  			needDropBeforeReturn: true,
  2365  			expected:             &OperationV128Max{Shape: ShapeF32x4},
  2366  		},
  2367  		{
  2368  			name: wasm.OpcodeVecF64x2MinName, body: vv2v(wasm.OpcodeVecF64x2Min),
  2369  			needDropBeforeReturn: true,
  2370  			expected:             &OperationV128Min{Shape: ShapeF64x2},
  2371  		},
  2372  		{
  2373  			name: wasm.OpcodeVecF64x2MaxName, body: vv2v(wasm.OpcodeVecF64x2Max),
  2374  			needDropBeforeReturn: true,
  2375  			expected:             &OperationV128Max{Shape: ShapeF64x2},
  2376  		},
  2377  		{
  2378  			name: wasm.OpcodeVecI8x16AbsName, body: v2v(wasm.OpcodeVecI8x16Abs),
  2379  			needDropBeforeReturn: true,
  2380  			expected:             &OperationV128Abs{Shape: ShapeI8x16},
  2381  		},
  2382  		{
  2383  			name: wasm.OpcodeVecI8x16PopcntName, body: v2v(wasm.OpcodeVecI8x16Popcnt),
  2384  			needDropBeforeReturn: true,
  2385  			expected:             &OperationV128Popcnt{},
  2386  		},
  2387  		{
  2388  			name: wasm.OpcodeVecI16x8AbsName, body: v2v(wasm.OpcodeVecI16x8Abs),
  2389  			needDropBeforeReturn: true,
  2390  			expected:             &OperationV128Abs{Shape: ShapeI16x8},
  2391  		},
  2392  		{
  2393  			name: wasm.OpcodeVecI32x4AbsName, body: v2v(wasm.OpcodeVecI32x4Abs),
  2394  			needDropBeforeReturn: true,
  2395  			expected:             &OperationV128Abs{Shape: ShapeI32x4},
  2396  		},
  2397  		{
  2398  			name: wasm.OpcodeVecI64x2AbsName, body: v2v(wasm.OpcodeVecI64x2Abs),
  2399  			needDropBeforeReturn: true,
  2400  			expected:             &OperationV128Abs{Shape: ShapeI64x2},
  2401  		},
  2402  		{
  2403  			name: wasm.OpcodeVecF32x4AbsName, body: v2v(wasm.OpcodeVecF32x4Abs),
  2404  			needDropBeforeReturn: true,
  2405  			expected:             &OperationV128Abs{Shape: ShapeF32x4},
  2406  		},
  2407  		{
  2408  			name: wasm.OpcodeVecF64x2AbsName, body: v2v(wasm.OpcodeVecF64x2Abs),
  2409  			needDropBeforeReturn: true,
  2410  			expected:             &OperationV128Abs{Shape: ShapeF64x2},
  2411  		},
  2412  		{
  2413  			name: wasm.OpcodeVecF32x4CeilName, body: v2v(wasm.OpcodeVecF32x4Ceil),
  2414  			needDropBeforeReturn: true,
  2415  			expected:             &OperationV128Ceil{Shape: ShapeF32x4},
  2416  		},
  2417  		{
  2418  			name: wasm.OpcodeVecF32x4FloorName, body: v2v(wasm.OpcodeVecF32x4Floor),
  2419  			needDropBeforeReturn: true,
  2420  			expected:             &OperationV128Floor{Shape: ShapeF32x4},
  2421  		},
  2422  		{
  2423  			name: wasm.OpcodeVecF32x4TruncName, body: v2v(wasm.OpcodeVecF32x4Trunc),
  2424  			needDropBeforeReturn: true,
  2425  			expected:             &OperationV128Trunc{Shape: ShapeF32x4},
  2426  		},
  2427  		{
  2428  			name: wasm.OpcodeVecF32x4NearestName, body: v2v(wasm.OpcodeVecF32x4Nearest),
  2429  			needDropBeforeReturn: true,
  2430  			expected:             &OperationV128Nearest{Shape: ShapeF32x4},
  2431  		},
  2432  		{
  2433  			name: wasm.OpcodeVecF64x2CeilName, body: v2v(wasm.OpcodeVecF64x2Ceil),
  2434  			needDropBeforeReturn: true,
  2435  			expected:             &OperationV128Ceil{Shape: ShapeF64x2},
  2436  		},
  2437  		{
  2438  			name: wasm.OpcodeVecF64x2FloorName, body: v2v(wasm.OpcodeVecF64x2Floor),
  2439  			needDropBeforeReturn: true,
  2440  			expected:             &OperationV128Floor{Shape: ShapeF64x2},
  2441  		},
  2442  		{
  2443  			name: wasm.OpcodeVecF64x2TruncName, body: v2v(wasm.OpcodeVecF64x2Trunc),
  2444  			needDropBeforeReturn: true,
  2445  			expected:             &OperationV128Trunc{Shape: ShapeF64x2},
  2446  		},
  2447  		{
  2448  			name: wasm.OpcodeVecF64x2NearestName, body: v2v(wasm.OpcodeVecF64x2Nearest),
  2449  			needDropBeforeReturn: true,
  2450  			expected:             &OperationV128Nearest{Shape: ShapeF64x2},
  2451  		},
  2452  		{
  2453  			name: wasm.OpcodeVecF32x4PminName, body: vv2v(wasm.OpcodeVecF32x4Pmin),
  2454  			needDropBeforeReturn: true,
  2455  			expected:             &OperationV128Pmin{Shape: ShapeF32x4},
  2456  		},
  2457  		{
  2458  			name: wasm.OpcodeVecF32x4PmaxName, body: vv2v(wasm.OpcodeVecF32x4Pmax),
  2459  			needDropBeforeReturn: true,
  2460  			expected:             &OperationV128Pmax{Shape: ShapeF32x4},
  2461  		},
  2462  		{
  2463  			name: wasm.OpcodeVecF64x2PminName, body: vv2v(wasm.OpcodeVecF64x2Pmin),
  2464  			needDropBeforeReturn: true,
  2465  			expected:             &OperationV128Pmin{Shape: ShapeF64x2},
  2466  		},
  2467  		{
  2468  			name: wasm.OpcodeVecF64x2PmaxName, body: vv2v(wasm.OpcodeVecF64x2Pmax),
  2469  			needDropBeforeReturn: true,
  2470  			expected:             &OperationV128Pmax{Shape: ShapeF64x2},
  2471  		},
  2472  		{
  2473  			name: wasm.OpcodeVecI16x8Q15mulrSatSName, body: vv2v(wasm.OpcodeVecI16x8Q15mulrSatS),
  2474  			needDropBeforeReturn: true,
  2475  			expected:             &OperationV128Q15mulrSatS{},
  2476  		},
  2477  		{
  2478  			name: wasm.OpcodeVecI16x8ExtMulLowI8x16SName, body: vv2v(wasm.OpcodeVecI16x8ExtMulLowI8x16S),
  2479  			needDropBeforeReturn: true,
  2480  			expected: &OperationV128ExtMul{
  2481  				OriginShape: ShapeI8x16,
  2482  				Signed:      true,
  2483  				UseLow:      true,
  2484  			},
  2485  		},
  2486  		{
  2487  			name: wasm.OpcodeVecI16x8ExtMulHighI8x16SName, body: vv2v(wasm.OpcodeVecI16x8ExtMulHighI8x16S),
  2488  			needDropBeforeReturn: true,
  2489  			expected: &OperationV128ExtMul{
  2490  				OriginShape: ShapeI8x16,
  2491  				Signed:      true,
  2492  				UseLow:      false,
  2493  			},
  2494  		},
  2495  		{
  2496  			name: wasm.OpcodeVecI16x8ExtMulLowI8x16UName, body: vv2v(wasm.OpcodeVecI16x8ExtMulLowI8x16U),
  2497  			needDropBeforeReturn: true,
  2498  			expected: &OperationV128ExtMul{
  2499  				OriginShape: ShapeI8x16,
  2500  				Signed:      false,
  2501  				UseLow:      true,
  2502  			},
  2503  		},
  2504  		{
  2505  			name: wasm.OpcodeVecI16x8ExtMulHighI8x16UName, body: vv2v(wasm.OpcodeVecI16x8ExtMulHighI8x16U),
  2506  			needDropBeforeReturn: true,
  2507  			expected: &OperationV128ExtMul{
  2508  				OriginShape: ShapeI8x16,
  2509  				Signed:      false,
  2510  				UseLow:      false,
  2511  			},
  2512  		},
  2513  		{
  2514  			name: wasm.OpcodeVecI32x4ExtMulLowI16x8SName, body: vv2v(wasm.OpcodeVecI32x4ExtMulLowI16x8S),
  2515  			needDropBeforeReturn: true,
  2516  			expected: &OperationV128ExtMul{
  2517  				OriginShape: ShapeI16x8,
  2518  				Signed:      true,
  2519  				UseLow:      true,
  2520  			},
  2521  		},
  2522  		{
  2523  			name: wasm.OpcodeVecI32x4ExtMulHighI16x8SName, body: vv2v(wasm.OpcodeVecI32x4ExtMulHighI16x8S),
  2524  			needDropBeforeReturn: true,
  2525  			expected: &OperationV128ExtMul{
  2526  				OriginShape: ShapeI16x8,
  2527  				Signed:      true,
  2528  				UseLow:      false,
  2529  			},
  2530  		},
  2531  		{
  2532  			name: wasm.OpcodeVecI32x4ExtMulLowI16x8UName, body: vv2v(wasm.OpcodeVecI32x4ExtMulLowI16x8U),
  2533  			needDropBeforeReturn: true,
  2534  			expected: &OperationV128ExtMul{
  2535  				OriginShape: ShapeI16x8,
  2536  				Signed:      false,
  2537  				UseLow:      true,
  2538  			},
  2539  		},
  2540  		{
  2541  			name: wasm.OpcodeVecI32x4ExtMulHighI16x8UName, body: vv2v(wasm.OpcodeVecI32x4ExtMulHighI16x8U),
  2542  			needDropBeforeReturn: true,
  2543  			expected: &OperationV128ExtMul{
  2544  				OriginShape: ShapeI16x8,
  2545  				Signed:      false,
  2546  				UseLow:      false,
  2547  			},
  2548  		},
  2549  		{
  2550  			name: wasm.OpcodeVecI64x2ExtMulLowI32x4SName, body: vv2v(wasm.OpcodeVecI64x2ExtMulLowI32x4S),
  2551  			needDropBeforeReturn: true,
  2552  			expected: &OperationV128ExtMul{
  2553  				OriginShape: ShapeI32x4,
  2554  				Signed:      true,
  2555  				UseLow:      true,
  2556  			},
  2557  		},
  2558  		{
  2559  			name: wasm.OpcodeVecI64x2ExtMulHighI32x4SName, body: vv2v(wasm.OpcodeVecI64x2ExtMulHighI32x4S),
  2560  			needDropBeforeReturn: true,
  2561  			expected: &OperationV128ExtMul{
  2562  				OriginShape: ShapeI32x4,
  2563  				Signed:      true,
  2564  				UseLow:      false,
  2565  			},
  2566  		},
  2567  		{
  2568  			name: wasm.OpcodeVecI64x2ExtMulLowI32x4UName, body: vv2v(wasm.OpcodeVecI64x2ExtMulLowI32x4U),
  2569  			needDropBeforeReturn: true,
  2570  			expected: &OperationV128ExtMul{
  2571  				OriginShape: ShapeI32x4,
  2572  				Signed:      false,
  2573  				UseLow:      true,
  2574  			},
  2575  		},
  2576  		{
  2577  			name: wasm.OpcodeVecI64x2ExtMulHighI32x4UName, body: vv2v(wasm.OpcodeVecI64x2ExtMulHighI32x4U),
  2578  			needDropBeforeReturn: true,
  2579  			expected: &OperationV128ExtMul{
  2580  				OriginShape: ShapeI32x4,
  2581  				Signed:      false,
  2582  				UseLow:      false,
  2583  			},
  2584  		},
  2585  		{
  2586  			name: wasm.OpcodeVecI16x8ExtendLowI8x16SName, body: v2v(wasm.OpcodeVecI16x8ExtendLowI8x16S),
  2587  			needDropBeforeReturn: true,
  2588  			expected: &OperationV128Extend{
  2589  				OriginShape: ShapeI8x16,
  2590  				Signed:      true,
  2591  				UseLow:      true,
  2592  			},
  2593  		},
  2594  		{
  2595  			name: wasm.OpcodeVecI16x8ExtendHighI8x16SName, body: v2v(wasm.OpcodeVecI16x8ExtendHighI8x16S),
  2596  			needDropBeforeReturn: true,
  2597  			expected: &OperationV128Extend{
  2598  				OriginShape: ShapeI8x16,
  2599  				Signed:      true,
  2600  				UseLow:      false,
  2601  			},
  2602  		},
  2603  		{
  2604  			name: wasm.OpcodeVecI16x8ExtendLowI8x16UName, body: v2v(wasm.OpcodeVecI16x8ExtendLowI8x16U),
  2605  			needDropBeforeReturn: true,
  2606  			expected: &OperationV128Extend{
  2607  				OriginShape: ShapeI8x16,
  2608  				Signed:      false,
  2609  				UseLow:      true,
  2610  			},
  2611  		},
  2612  		{
  2613  			name: wasm.OpcodeVecI16x8ExtendHighI8x16UName, body: v2v(wasm.OpcodeVecI16x8ExtendHighI8x16U),
  2614  			needDropBeforeReturn: true,
  2615  			expected: &OperationV128Extend{
  2616  				OriginShape: ShapeI8x16,
  2617  				Signed:      false,
  2618  				UseLow:      false,
  2619  			},
  2620  		},
  2621  		{
  2622  			name: wasm.OpcodeVecI32x4ExtendLowI16x8SName, body: v2v(wasm.OpcodeVecI32x4ExtendLowI16x8S),
  2623  			needDropBeforeReturn: true,
  2624  			expected: &OperationV128Extend{
  2625  				OriginShape: ShapeI16x8,
  2626  				Signed:      true,
  2627  				UseLow:      true,
  2628  			},
  2629  		},
  2630  		{
  2631  			name: wasm.OpcodeVecI32x4ExtendHighI16x8SName, body: v2v(wasm.OpcodeVecI32x4ExtendHighI16x8S),
  2632  			needDropBeforeReturn: true,
  2633  			expected: &OperationV128Extend{
  2634  				OriginShape: ShapeI16x8,
  2635  				Signed:      true,
  2636  				UseLow:      false,
  2637  			},
  2638  		},
  2639  		{
  2640  			name: wasm.OpcodeVecI32x4ExtendLowI16x8UName, body: v2v(wasm.OpcodeVecI32x4ExtendLowI16x8U),
  2641  			needDropBeforeReturn: true,
  2642  			expected: &OperationV128Extend{
  2643  				OriginShape: ShapeI16x8,
  2644  				Signed:      false,
  2645  				UseLow:      true,
  2646  			},
  2647  		},
  2648  		{
  2649  			name: wasm.OpcodeVecI32x4ExtendHighI16x8UName, body: v2v(wasm.OpcodeVecI32x4ExtendHighI16x8U),
  2650  			needDropBeforeReturn: true,
  2651  			expected: &OperationV128Extend{
  2652  				OriginShape: ShapeI16x8,
  2653  				Signed:      false,
  2654  				UseLow:      false,
  2655  			},
  2656  		},
  2657  		{
  2658  			name: wasm.OpcodeVecI64x2ExtendLowI32x4SName, body: v2v(wasm.OpcodeVecI64x2ExtendLowI32x4S),
  2659  			needDropBeforeReturn: true,
  2660  			expected: &OperationV128Extend{
  2661  				OriginShape: ShapeI32x4,
  2662  				Signed:      true,
  2663  				UseLow:      true,
  2664  			},
  2665  		},
  2666  		{
  2667  			name: wasm.OpcodeVecI64x2ExtendHighI32x4SName, body: v2v(wasm.OpcodeVecI64x2ExtendHighI32x4S),
  2668  			needDropBeforeReturn: true,
  2669  			expected: &OperationV128Extend{
  2670  				OriginShape: ShapeI32x4,
  2671  				Signed:      true,
  2672  				UseLow:      false,
  2673  			},
  2674  		},
  2675  		{
  2676  			name: wasm.OpcodeVecI64x2ExtendLowI32x4UName, body: v2v(wasm.OpcodeVecI64x2ExtendLowI32x4U),
  2677  			needDropBeforeReturn: true,
  2678  			expected: &OperationV128Extend{
  2679  				OriginShape: ShapeI32x4,
  2680  				Signed:      false,
  2681  				UseLow:      true,
  2682  			},
  2683  		},
  2684  		{
  2685  			name: wasm.OpcodeVecI64x2ExtendHighI32x4UName, body: v2v(wasm.OpcodeVecI64x2ExtendHighI32x4U),
  2686  			needDropBeforeReturn: true,
  2687  			expected: &OperationV128Extend{
  2688  				OriginShape: ShapeI32x4,
  2689  				Signed:      false,
  2690  				UseLow:      false,
  2691  			},
  2692  		},
  2693  
  2694  		{
  2695  			name: wasm.OpcodeVecI16x8ExtaddPairwiseI8x16SName, body: v2v(wasm.OpcodeVecI16x8ExtaddPairwiseI8x16S),
  2696  			needDropBeforeReturn: true,
  2697  			expected:             &OperationV128ExtAddPairwise{OriginShape: ShapeI8x16, Signed: true},
  2698  		},
  2699  		{
  2700  			name: wasm.OpcodeVecI16x8ExtaddPairwiseI8x16UName, body: v2v(wasm.OpcodeVecI16x8ExtaddPairwiseI8x16U),
  2701  			needDropBeforeReturn: true,
  2702  			expected:             &OperationV128ExtAddPairwise{OriginShape: ShapeI8x16, Signed: false},
  2703  		},
  2704  		{
  2705  			name: wasm.OpcodeVecI32x4ExtaddPairwiseI16x8SName, body: v2v(wasm.OpcodeVecI32x4ExtaddPairwiseI16x8S),
  2706  			needDropBeforeReturn: true,
  2707  			expected:             &OperationV128ExtAddPairwise{OriginShape: ShapeI16x8, Signed: true},
  2708  		},
  2709  		{
  2710  			name: wasm.OpcodeVecI32x4ExtaddPairwiseI16x8UName, body: v2v(wasm.OpcodeVecI32x4ExtaddPairwiseI16x8U),
  2711  			needDropBeforeReturn: true,
  2712  			expected:             &OperationV128ExtAddPairwise{OriginShape: ShapeI16x8, Signed: false},
  2713  		},
  2714  		{
  2715  			name: wasm.OpcodeVecF64x2PromoteLowF32x4ZeroName, body: v2v(wasm.OpcodeVecF64x2PromoteLowF32x4Zero),
  2716  			needDropBeforeReturn: true,
  2717  			expected:             &OperationV128FloatPromote{},
  2718  		},
  2719  		{
  2720  			name: wasm.OpcodeVecF32x4DemoteF64x2ZeroName, body: v2v(wasm.OpcodeVecF32x4DemoteF64x2Zero),
  2721  			needDropBeforeReturn: true,
  2722  			expected:             &OperationV128FloatDemote{},
  2723  		},
  2724  		{
  2725  			name: wasm.OpcodeVecF32x4ConvertI32x4SName, body: v2v(wasm.OpcodeVecF32x4ConvertI32x4S),
  2726  			needDropBeforeReturn: true,
  2727  			expected:             &OperationV128FConvertFromI{DestinationShape: ShapeF32x4, Signed: true},
  2728  		},
  2729  		{
  2730  			name: wasm.OpcodeVecF32x4ConvertI32x4UName, body: v2v(wasm.OpcodeVecF32x4ConvertI32x4U),
  2731  			needDropBeforeReturn: true,
  2732  			expected:             &OperationV128FConvertFromI{DestinationShape: ShapeF32x4, Signed: false},
  2733  		},
  2734  		{
  2735  			name: wasm.OpcodeVecF64x2ConvertLowI32x4SName, body: v2v(wasm.OpcodeVecF64x2ConvertLowI32x4S),
  2736  			needDropBeforeReturn: true,
  2737  			expected:             &OperationV128FConvertFromI{DestinationShape: ShapeF64x2, Signed: true},
  2738  		},
  2739  		{
  2740  			name: wasm.OpcodeVecF64x2ConvertLowI32x4UName, body: v2v(wasm.OpcodeVecF64x2ConvertLowI32x4U),
  2741  			needDropBeforeReturn: true,
  2742  			expected:             &OperationV128FConvertFromI{DestinationShape: ShapeF64x2, Signed: false},
  2743  		},
  2744  		{
  2745  			name: wasm.OpcodeVecI32x4DotI16x8SName, body: vv2v(wasm.OpcodeVecI32x4DotI16x8S),
  2746  			needDropBeforeReturn: true,
  2747  			expected:             &OperationV128Dot{},
  2748  		},
  2749  		{
  2750  			name: wasm.OpcodeVecI8x16NarrowI16x8SName, body: vv2v(wasm.OpcodeVecI8x16NarrowI16x8S),
  2751  			needDropBeforeReturn: true,
  2752  			expected:             &OperationV128Narrow{OriginShape: ShapeI16x8, Signed: true},
  2753  		},
  2754  		{
  2755  			name: wasm.OpcodeVecI8x16NarrowI16x8UName, body: vv2v(wasm.OpcodeVecI8x16NarrowI16x8U),
  2756  			needDropBeforeReturn: true,
  2757  			expected:             &OperationV128Narrow{OriginShape: ShapeI16x8, Signed: false},
  2758  		},
  2759  		{
  2760  			name: wasm.OpcodeVecI16x8NarrowI32x4SName, body: vv2v(wasm.OpcodeVecI16x8NarrowI32x4S),
  2761  			needDropBeforeReturn: true,
  2762  			expected:             &OperationV128Narrow{OriginShape: ShapeI32x4, Signed: true},
  2763  		},
  2764  		{
  2765  			name: wasm.OpcodeVecI16x8NarrowI32x4UName, body: vv2v(wasm.OpcodeVecI16x8NarrowI32x4U),
  2766  			needDropBeforeReturn: true,
  2767  			expected:             &OperationV128Narrow{OriginShape: ShapeI32x4, Signed: false},
  2768  		},
  2769  		{
  2770  			name: wasm.OpcodeVecI32x4TruncSatF32x4SName, body: v2v(wasm.OpcodeVecI32x4TruncSatF32x4S),
  2771  			needDropBeforeReturn: true,
  2772  			expected:             &OperationV128ITruncSatFromF{OriginShape: ShapeF32x4, Signed: true},
  2773  		},
  2774  		{
  2775  			name: wasm.OpcodeVecI32x4TruncSatF32x4UName, body: v2v(wasm.OpcodeVecI32x4TruncSatF32x4U),
  2776  			needDropBeforeReturn: true,
  2777  			expected:             &OperationV128ITruncSatFromF{OriginShape: ShapeF32x4, Signed: false},
  2778  		},
  2779  		{
  2780  			name: wasm.OpcodeVecI32x4TruncSatF64x2SZeroName, body: v2v(wasm.OpcodeVecI32x4TruncSatF64x2SZero),
  2781  			needDropBeforeReturn: true,
  2782  			expected:             &OperationV128ITruncSatFromF{OriginShape: ShapeF64x2, Signed: true},
  2783  		},
  2784  		{
  2785  			name: wasm.OpcodeVecI32x4TruncSatF64x2UZeroName, body: v2v(wasm.OpcodeVecI32x4TruncSatF64x2UZero),
  2786  			needDropBeforeReturn: true,
  2787  			expected:             &OperationV128ITruncSatFromF{OriginShape: ShapeF64x2, Signed: false},
  2788  		},
  2789  	}
  2790  
  2791  	for _, tt := range tests {
  2792  		tc := tt
  2793  		t.Run(tc.name, func(t *testing.T) {
  2794  			module := &wasm.Module{
  2795  				TypeSection:     []*wasm.FunctionType{v_v},
  2796  				FunctionSection: []wasm.Index{0},
  2797  				MemorySection:   &wasm.Memory{},
  2798  				CodeSection:     []*wasm.Code{{Body: tc.body}},
  2799  			}
  2800  			res, err := CompileFunctions(ctx, api.CoreFeaturesV2, 0, module)
  2801  			require.NoError(t, err)
  2802  
  2803  			var actual Operation
  2804  			if tc.needDropBeforeReturn {
  2805  				// If the drop operation is inserted, the target op exits at -3
  2806  				// as the operations looks like: [... target, drop, br(to return)].
  2807  				actual = res[0].Operations[len(res[0].Operations)-3]
  2808  			} else {
  2809  				// If the drop operation is not inserted, the target op exits at -2
  2810  				// as the operations looks like: [... target, br(to return)].
  2811  				actual = res[0].Operations[len(res[0].Operations)-2]
  2812  			}
  2813  
  2814  			require.Equal(t, tc.expected, actual)
  2815  		})
  2816  	}
  2817  }
  2818  
  2819  // TestCompile_unreachable_Br_BrIf_BrTable ensures that unreachable br/br_if/br_table instructions are correctly ignored.
  2820  func TestCompile_unreachable_Br_BrIf_BrTable(t *testing.T) {
  2821  	tests := []struct {
  2822  		name     string
  2823  		mod      *wasm.Module
  2824  		expected []Operation
  2825  	}{
  2826  		{
  2827  			name: "br",
  2828  			mod: &wasm.Module{
  2829  				TypeSection:     []*wasm.FunctionType{v_v},
  2830  				FunctionSection: []wasm.Index{0},
  2831  				CodeSection: []*wasm.Code{{Body: []byte{
  2832  					wasm.OpcodeBr, 0, // Return the function -> the followings are unreachable.
  2833  					wasm.OpcodeBlock, 0,
  2834  					wasm.OpcodeBr, 1,
  2835  					wasm.OpcodeEnd, // End the block.
  2836  					wasm.OpcodeEnd, // End the function.
  2837  				}}},
  2838  			},
  2839  			expected: []Operation{&OperationBr{Target: &BranchTarget{}}},
  2840  		},
  2841  		{
  2842  			name: "br_if",
  2843  			mod: &wasm.Module{
  2844  				TypeSection:     []*wasm.FunctionType{v_v},
  2845  				FunctionSection: []wasm.Index{0},
  2846  				CodeSection: []*wasm.Code{{Body: []byte{
  2847  					wasm.OpcodeBr, 0, // Return the function -> the followings are unreachable.
  2848  					wasm.OpcodeBlock, 0,
  2849  					wasm.OpcodeI32Const, 1,
  2850  					wasm.OpcodeBrIf, 1,
  2851  					wasm.OpcodeEnd, // End the block.
  2852  					wasm.OpcodeEnd, // End the function.
  2853  				}}},
  2854  			},
  2855  			expected: []Operation{&OperationBr{Target: &BranchTarget{}}},
  2856  		},
  2857  		{
  2858  			name: "br_table",
  2859  			mod: &wasm.Module{
  2860  				TypeSection:     []*wasm.FunctionType{v_v},
  2861  				FunctionSection: []wasm.Index{0},
  2862  				CodeSection: []*wasm.Code{{Body: []byte{
  2863  					wasm.OpcodeBr, 0, // Return the function -> the followings are unreachable.
  2864  					wasm.OpcodeBlock, 0,
  2865  					wasm.OpcodeBrTable, 2, 2, 3,
  2866  					wasm.OpcodeEnd, // End the block.
  2867  					wasm.OpcodeEnd, // End the function.
  2868  				}}},
  2869  			},
  2870  			expected: []Operation{&OperationBr{Target: &BranchTarget{}}},
  2871  		},
  2872  	}
  2873  
  2874  	for _, tt := range tests {
  2875  		tc := tt
  2876  		t.Run(tc.name, func(t *testing.T) {
  2877  			res, err := CompileFunctions(ctx, api.CoreFeaturesV2, 0, tc.mod)
  2878  			require.NoError(t, err)
  2879  			require.Equal(t, tc.expected, res[0].Operations)
  2880  		})
  2881  	}
  2882  }
  2883  
  2884  // TestCompile_drop_vectors ensures that wasm.OpcodeDrop on vector values is correctly compiled,
  2885  // which is not covered by spectest.
  2886  func TestCompile_drop_vectors(t *testing.T) {
  2887  	tests := []struct {
  2888  		name     string
  2889  		mod      *wasm.Module
  2890  		expected []Operation
  2891  	}{
  2892  		{
  2893  			name: "basic",
  2894  			mod: &wasm.Module{
  2895  				TypeSection:     []*wasm.FunctionType{v_v},
  2896  				FunctionSection: []wasm.Index{0},
  2897  				CodeSection: []*wasm.Code{{Body: []byte{
  2898  					wasm.OpcodeVecPrefix,
  2899  					wasm.OpcodeVecV128Const, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
  2900  					wasm.OpcodeDrop,
  2901  					wasm.OpcodeEnd,
  2902  				}}},
  2903  			},
  2904  			expected: []Operation{
  2905  				&OperationV128Const{Lo: 0x1, Hi: 0x2},
  2906  				// InclusiveRange is the range in uint64 representation, so dropping a vector value on top
  2907  				// should be translated as drop [0..1] inclusively.
  2908  				&OperationDrop{Depth: &InclusiveRange{Start: 0, End: 1}},
  2909  				&OperationBr{Target: &BranchTarget{}},
  2910  			},
  2911  		},
  2912  	}
  2913  
  2914  	for _, tt := range tests {
  2915  		tc := tt
  2916  		t.Run(tc.name, func(t *testing.T) {
  2917  			res, err := CompileFunctions(ctx, api.CoreFeaturesV2, 0, tc.mod)
  2918  			require.NoError(t, err)
  2919  			require.Equal(t, tc.expected, res[0].Operations)
  2920  		})
  2921  	}
  2922  }
  2923  
  2924  func TestCompile_select_vectors(t *testing.T) {
  2925  	tests := []struct {
  2926  		name     string
  2927  		mod      *wasm.Module
  2928  		expected []Operation
  2929  	}{
  2930  		{
  2931  			name: "non typed",
  2932  			mod: &wasm.Module{
  2933  				TypeSection:     []*wasm.FunctionType{v_v},
  2934  				FunctionSection: []wasm.Index{0},
  2935  				CodeSection: []*wasm.Code{{Body: []byte{
  2936  					wasm.OpcodeVecPrefix,
  2937  					wasm.OpcodeVecV128Const, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
  2938  					wasm.OpcodeVecPrefix,
  2939  					wasm.OpcodeVecV128Const, 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0,
  2940  					wasm.OpcodeI32Const, 0,
  2941  					wasm.OpcodeSelect,
  2942  					wasm.OpcodeDrop,
  2943  					wasm.OpcodeEnd,
  2944  				}}},
  2945  				FunctionDefinitionSection: []*wasm.FunctionDefinition{{}},
  2946  			},
  2947  			expected: []Operation{
  2948  				&OperationV128Const{Lo: 0x1, Hi: 0x2},
  2949  				&OperationV128Const{Lo: 0x3, Hi: 0x4},
  2950  				&OperationConstI32{Value: 0},
  2951  				&OperationSelect{IsTargetVector: true},
  2952  				&OperationDrop{Depth: &InclusiveRange{Start: 0, End: 1}},
  2953  				&OperationBr{Target: &BranchTarget{}},
  2954  			},
  2955  		},
  2956  		{
  2957  			name: "typed",
  2958  			mod: &wasm.Module{
  2959  				TypeSection:     []*wasm.FunctionType{v_v},
  2960  				FunctionSection: []wasm.Index{0},
  2961  				CodeSection: []*wasm.Code{{Body: []byte{
  2962  					wasm.OpcodeVecPrefix,
  2963  					wasm.OpcodeVecV128Const, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
  2964  					wasm.OpcodeVecPrefix,
  2965  					wasm.OpcodeVecV128Const, 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0,
  2966  					wasm.OpcodeI32Const, 0,
  2967  					wasm.OpcodeTypedSelect, 0x1, wasm.ValueTypeV128,
  2968  					wasm.OpcodeDrop,
  2969  					wasm.OpcodeEnd,
  2970  				}}},
  2971  				FunctionDefinitionSection: []*wasm.FunctionDefinition{{}},
  2972  			},
  2973  			expected: []Operation{
  2974  				&OperationV128Const{Lo: 0x1, Hi: 0x2},
  2975  				&OperationV128Const{Lo: 0x3, Hi: 0x4},
  2976  				&OperationConstI32{Value: 0},
  2977  				&OperationSelect{IsTargetVector: true},
  2978  				&OperationDrop{Depth: &InclusiveRange{Start: 0, End: 1}},
  2979  				&OperationBr{Target: &BranchTarget{}},
  2980  			},
  2981  		},
  2982  	}
  2983  
  2984  	for _, tt := range tests {
  2985  		tc := tt
  2986  		t.Run(tc.name, func(t *testing.T) {
  2987  			res, err := CompileFunctions(ctx, api.CoreFeaturesV2, 0, tc.mod)
  2988  			require.NoError(t, err)
  2989  			require.Equal(t, tc.expected, res[0].Operations)
  2990  		})
  2991  	}
  2992  }
  2993  
  2994  func TestCompiler_initializeStack(t *testing.T) {
  2995  	const v128 = wasm.ValueTypeV128
  2996  	tests := []struct {
  2997  		name                               string
  2998  		sig                                *wasm.FunctionType
  2999  		functionLocalTypes                 []wasm.ValueType
  3000  		callFrameStackSizeInUint64         int
  3001  		expLocalIndexToStackHeightInUint64 map[uint32]int
  3002  	}{
  3003  		{
  3004  			name: "no function local, args>results",
  3005  			sig: &wasm.FunctionType{
  3006  				Params:            []wasm.ValueType{i32, f32},
  3007  				Results:           []wasm.ValueType{i32},
  3008  				ParamNumInUint64:  2,
  3009  				ResultNumInUint64: 1,
  3010  			},
  3011  			expLocalIndexToStackHeightInUint64: map[uint32]int{
  3012  				0: 0,
  3013  				1: 1,
  3014  			},
  3015  		},
  3016  		{
  3017  			name: "no function local, args=results",
  3018  			sig: &wasm.FunctionType{
  3019  				Params:            []wasm.ValueType{i32},
  3020  				Results:           []wasm.ValueType{i32},
  3021  				ParamNumInUint64:  1,
  3022  				ResultNumInUint64: 1,
  3023  			},
  3024  			expLocalIndexToStackHeightInUint64: map[uint32]int{
  3025  				0: 0,
  3026  			},
  3027  		},
  3028  		{
  3029  			name: "no function local, args>results, with vector",
  3030  			sig: &wasm.FunctionType{
  3031  				Params:            []wasm.ValueType{i32, v128, f32},
  3032  				Results:           []wasm.ValueType{i32},
  3033  				ParamNumInUint64:  4,
  3034  				ResultNumInUint64: 1,
  3035  			},
  3036  			expLocalIndexToStackHeightInUint64: map[uint32]int{
  3037  				0: 0,
  3038  				1: 1,
  3039  				2: 3,
  3040  			},
  3041  		},
  3042  		{
  3043  			name: "no function local, args<results",
  3044  			sig: &wasm.FunctionType{
  3045  				Params:            []wasm.ValueType{},
  3046  				Results:           []wasm.ValueType{i32},
  3047  				ParamNumInUint64:  0,
  3048  				ResultNumInUint64: 1,
  3049  			},
  3050  			callFrameStackSizeInUint64:         4,
  3051  			expLocalIndexToStackHeightInUint64: map[uint32]int{},
  3052  		},
  3053  		{
  3054  			name: "no function local, args<results",
  3055  			sig: &wasm.FunctionType{
  3056  				Params:            []wasm.ValueType{i32},
  3057  				Results:           []wasm.ValueType{i32, f32},
  3058  				ParamNumInUint64:  1,
  3059  				ResultNumInUint64: 2,
  3060  			},
  3061  			callFrameStackSizeInUint64:         4,
  3062  			expLocalIndexToStackHeightInUint64: map[uint32]int{0: 0},
  3063  		},
  3064  		{
  3065  			name: "no function local, args<results, with vector",
  3066  			sig: &wasm.FunctionType{
  3067  				Params:            []wasm.ValueType{i32},
  3068  				Results:           []wasm.ValueType{i32, v128, f32},
  3069  				ParamNumInUint64:  1,
  3070  				ResultNumInUint64: 4,
  3071  			},
  3072  			callFrameStackSizeInUint64:         4,
  3073  			expLocalIndexToStackHeightInUint64: map[uint32]int{0: 0},
  3074  		},
  3075  
  3076  		// With function locals
  3077  		{
  3078  			name: "function locals, args>results",
  3079  			sig: &wasm.FunctionType{
  3080  				Params:            []wasm.ValueType{i32, f32},
  3081  				Results:           []wasm.ValueType{i32},
  3082  				ParamNumInUint64:  2,
  3083  				ResultNumInUint64: 1,
  3084  			},
  3085  			functionLocalTypes:         []wasm.ValueType{f64},
  3086  			callFrameStackSizeInUint64: 4,
  3087  			// [i32, f32, callframe.0, callframe.1, callframe.2, callframe.3, f64]
  3088  			expLocalIndexToStackHeightInUint64: map[uint32]int{
  3089  				0: 0,
  3090  				1: 1,
  3091  				// Function local comes after call frame.
  3092  				2: 6,
  3093  			},
  3094  		},
  3095  		{
  3096  			name: "function locals, args>results, with vector",
  3097  			sig: &wasm.FunctionType{
  3098  				Params:            []wasm.ValueType{i32, v128, f32},
  3099  				Results:           []wasm.ValueType{i32},
  3100  				ParamNumInUint64:  4,
  3101  				ResultNumInUint64: 1,
  3102  			},
  3103  			functionLocalTypes:         []wasm.ValueType{v128, v128},
  3104  			callFrameStackSizeInUint64: 4,
  3105  			// [i32, v128.lo, v128.hi, f32, callframe.0, callframe.1, callframe.2, callframe.3, v128.lo, v128.hi, v128.lo, v128.hi]
  3106  			expLocalIndexToStackHeightInUint64: map[uint32]int{
  3107  				0: 0,
  3108  				1: 1,
  3109  				2: 3,
  3110  				// Function local comes after call frame.
  3111  				3: 8,
  3112  				4: 10,
  3113  			},
  3114  		},
  3115  		{
  3116  			name: "function locals, args<results",
  3117  			sig: &wasm.FunctionType{
  3118  				Params:            []wasm.ValueType{i32},
  3119  				Results:           []wasm.ValueType{i32, i32, i32, i32},
  3120  				ParamNumInUint64:  1,
  3121  				ResultNumInUint64: 4,
  3122  			},
  3123  			functionLocalTypes:         []wasm.ValueType{f64},
  3124  			callFrameStackSizeInUint64: 4,
  3125  			// [i32, _, _, _, callframe.0, callframe.1, callframe.2, callframe.3, f64]
  3126  			expLocalIndexToStackHeightInUint64: map[uint32]int{
  3127  				0: 0,
  3128  				1: 8,
  3129  			},
  3130  		},
  3131  		{
  3132  			name: "function locals, args<results with vector",
  3133  			sig: &wasm.FunctionType{
  3134  				Params:            []wasm.ValueType{v128, f64},
  3135  				Results:           []wasm.ValueType{v128, i32, i32, v128},
  3136  				ParamNumInUint64:  3,
  3137  				ResultNumInUint64: 6,
  3138  			},
  3139  			functionLocalTypes:         []wasm.ValueType{f64},
  3140  			callFrameStackSizeInUint64: 4,
  3141  			// [v128.lo, v128.hi, f64, _, _, _, callframe.0, callframe.1, callframe.2, callframe.3, f64]
  3142  			expLocalIndexToStackHeightInUint64: map[uint32]int{
  3143  				0: 0,
  3144  				1: 2,
  3145  				2: 10,
  3146  			},
  3147  		},
  3148  	}
  3149  
  3150  	for _, tc := range tests {
  3151  		tc := tc
  3152  		t.Run(tc.name, func(t *testing.T) {
  3153  			c := &compiler{
  3154  				sig: tc.sig, localTypes: tc.functionLocalTypes,
  3155  				callFrameStackSizeInUint64: tc.callFrameStackSizeInUint64,
  3156  			}
  3157  
  3158  			c.initializeStack()
  3159  			require.Equal(t, tc.expLocalIndexToStackHeightInUint64, c.localIndexToStackHeightInUint64)
  3160  		})
  3161  
  3162  	}
  3163  }