github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/internal/wazeroir/compiler_test.go (about)

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