github.com/bananabytelabs/wazero@v0.0.0-20240105073314-54b22a776da8/internal/wazeroir/compiler_test.go (about)

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