wa-lang.org/wazero@v1.0.2/internal/engine/compiler/compiler_vec_test.go (about)

     1  package compiler
     2  
     3  import (
     4  	"encoding/binary"
     5  	"math"
     6  	"testing"
     7  
     8  	"wa-lang.org/wazero/internal/moremath"
     9  	"wa-lang.org/wazero/internal/testing/require"
    10  	"wa-lang.org/wazero/internal/wasm"
    11  	"wa-lang.org/wazero/internal/wazeroir"
    12  )
    13  
    14  func TestCompiler_compileV128Add(t *testing.T) {
    15  	tests := []struct {
    16  		name        string
    17  		shape       wazeroir.Shape
    18  		x1, x2, exp [16]byte
    19  	}{
    20  		{
    21  			name:  "i8x16",
    22  			shape: wazeroir.ShapeI8x16,
    23  			x1:    [16]byte{0: 1, 2: 10, 10: 10},
    24  			x2:    [16]byte{0: 10, 4: 5, 10: 5},
    25  			exp:   [16]byte{0: 11, 2: 10, 4: 5, 10: 15},
    26  		},
    27  		{
    28  			name:  "i16x8",
    29  			shape: wazeroir.ShapeI16x8,
    30  			x1:    i16x8(1123, 0, 123, 1, 1, 5, 8, 1),
    31  			x2:    i16x8(0, 123, 123, 0, 1, 5, 9, 1),
    32  			exp:   i16x8(1123, 123, 246, 1, 2, 10, 17, 2),
    33  		},
    34  		{
    35  			name:  "i32x4",
    36  			shape: wazeroir.ShapeI32x4,
    37  			x1:    i32x4(i32ToU32(-123), 5, 4, math.MaxUint32),
    38  			x2:    i32x4(i32ToU32(-10), 1, i32ToU32(-104), math.MaxUint32),
    39  			exp:   i32x4(i32ToU32(-133), 6, i32ToU32(-100), math.MaxUint32-1),
    40  		},
    41  		{
    42  			name:  "i64x2",
    43  			shape: wazeroir.ShapeI64x2,
    44  			x1:    i64x2(i64ToU64(math.MinInt64), 12345),
    45  			x2:    i64x2(i64ToU64(-1), i64ToU64(-12345)),
    46  			exp:   i64x2(i64ToU64(math.MinInt64)+i64ToU64(-1), 0),
    47  		},
    48  		{
    49  			name:  "f32x4",
    50  			shape: wazeroir.ShapeF32x4,
    51  			x1:    f32x4(1.0, 123, float32(math.Inf(1)), float32(math.Inf(-1))),
    52  			x2:    f32x4(51234.12341, 123, math.MaxFloat32, -123),
    53  			exp:   f32x4(51235.12341, 246, float32(math.Inf(1)), float32(math.Inf(-1))),
    54  		},
    55  		{
    56  			name:  "f64x2",
    57  			shape: wazeroir.ShapeF64x2,
    58  			x1:    f64x2(1.123, math.Inf(1)),
    59  			x2:    f64x2(1.123, math.MinInt64),
    60  			exp:   f64x2(2.246, math.Inf(1)),
    61  		},
    62  	}
    63  
    64  	for _, tc := range tests {
    65  		tc := tc
    66  		t.Run(tc.name, func(t *testing.T) {
    67  			env := newCompilerEnvironment()
    68  			compiler := env.requireNewCompiler(t, newCompiler,
    69  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
    70  
    71  			err := compiler.compilePreamble()
    72  			require.NoError(t, err)
    73  
    74  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
    75  				Lo: binary.LittleEndian.Uint64(tc.x1[:8]),
    76  				Hi: binary.LittleEndian.Uint64(tc.x1[8:]),
    77  			})
    78  			require.NoError(t, err)
    79  
    80  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
    81  				Lo: binary.LittleEndian.Uint64(tc.x2[:8]),
    82  				Hi: binary.LittleEndian.Uint64(tc.x2[8:]),
    83  			})
    84  			require.NoError(t, err)
    85  
    86  			err = compiler.compileV128Add(&wazeroir.OperationV128Add{Shape: tc.shape})
    87  			require.NoError(t, err)
    88  
    89  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
    90  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
    91  
    92  			err = compiler.compileReturnFunction()
    93  			require.NoError(t, err)
    94  
    95  			// Generate and run the code under test.
    96  			code, _, err := compiler.compile()
    97  			require.NoError(t, err)
    98  			env.exec(code)
    99  
   100  			require.Equal(t, nativeCallStatusCodeReturned, env.callEngine().statusCode)
   101  
   102  			lo, hi := env.stackTopAsV128()
   103  			var actual [16]byte
   104  			binary.LittleEndian.PutUint64(actual[:8], lo)
   105  			binary.LittleEndian.PutUint64(actual[8:], hi)
   106  			require.Equal(t, tc.exp, actual)
   107  		})
   108  	}
   109  }
   110  
   111  func TestCompiler_compileV128Sub(t *testing.T) {
   112  	tests := []struct {
   113  		name        string
   114  		shape       wazeroir.Shape
   115  		x1, x2, exp [16]byte
   116  	}{
   117  		{
   118  			name:  "i8x16",
   119  			shape: wazeroir.ShapeI8x16,
   120  			x1:    [16]byte{0: 1, 2: 10, 10: 10},
   121  			x2:    [16]byte{0: 10, 4: 5, 10: 5},
   122  			exp:   [16]byte{0: i8ToU8(-9), 2: 10, 4: i8ToU8(-5), 10: 5},
   123  		},
   124  		{
   125  			name:  "i16x8",
   126  			shape: wazeroir.ShapeI16x8,
   127  			x1:    i16x8(1123, 0, 123, 1, 1, 5, 8, 1),
   128  			x2:    i16x8(0, 123, 123, 0, 1, 5, 9, 1),
   129  			exp:   i16x8(1123, i16ToU16(-123), 0, 1, 0, 0, i16ToU16(-1), 0),
   130  		},
   131  		{
   132  			name:  "i32x4",
   133  			shape: wazeroir.ShapeI32x4,
   134  			x1:    i32x4(i32ToU32(-123), 5, 4, math.MaxUint32),
   135  			x2:    i32x4(i32ToU32(-10), 1, i32ToU32(-104), math.MaxUint32),
   136  			exp:   i32x4(i32ToU32(-113), 4, 108, 0),
   137  		},
   138  		{
   139  			name:  "i64x2",
   140  			shape: wazeroir.ShapeI64x2,
   141  			x1:    i64x2(i64ToU64(math.MinInt64), 12345),
   142  			x2:    i64x2(i64ToU64(-1), i64ToU64(-12345)),
   143  			exp:   i64x2(i64ToU64(math.MinInt64+1), 12345*2),
   144  		},
   145  		{
   146  			name:  "f32x4",
   147  			shape: wazeroir.ShapeF32x4,
   148  			x1:    f32x4(1.0, 123, float32(math.Inf(1)), float32(math.Inf(-1))),
   149  			x2:    f32x4(51234.12341, 123, math.MaxFloat32, -123),
   150  			exp:   f32x4(-51233.12341, 0, float32(math.Inf(1)), float32(math.Inf(-1))),
   151  		},
   152  		{
   153  			name:  "f64x2",
   154  			shape: wazeroir.ShapeF64x2,
   155  			x1:    f64x2(1.123, math.Inf(1)),
   156  			x2:    f64x2(1.123, math.MinInt64),
   157  			exp:   f64x2(0, math.Inf(1)),
   158  		},
   159  	}
   160  
   161  	for _, tc := range tests {
   162  		tc := tc
   163  		t.Run(tc.name, func(t *testing.T) {
   164  			env := newCompilerEnvironment()
   165  			compiler := env.requireNewCompiler(t, newCompiler,
   166  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
   167  
   168  			err := compiler.compilePreamble()
   169  			require.NoError(t, err)
   170  
   171  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
   172  				Lo: binary.LittleEndian.Uint64(tc.x1[:8]),
   173  				Hi: binary.LittleEndian.Uint64(tc.x1[8:]),
   174  			})
   175  			require.NoError(t, err)
   176  
   177  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
   178  				Lo: binary.LittleEndian.Uint64(tc.x2[:8]),
   179  				Hi: binary.LittleEndian.Uint64(tc.x2[8:]),
   180  			})
   181  			require.NoError(t, err)
   182  
   183  			err = compiler.compileV128Sub(&wazeroir.OperationV128Sub{Shape: tc.shape})
   184  			require.NoError(t, err)
   185  
   186  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
   187  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
   188  
   189  			err = compiler.compileReturnFunction()
   190  			require.NoError(t, err)
   191  
   192  			// Generate and run the code under test.
   193  			code, _, err := compiler.compile()
   194  			require.NoError(t, err)
   195  			env.exec(code)
   196  
   197  			require.Equal(t, nativeCallStatusCodeReturned, env.callEngine().statusCode)
   198  
   199  			lo, hi := env.stackTopAsV128()
   200  			var actual [16]byte
   201  			binary.LittleEndian.PutUint64(actual[:8], lo)
   202  			binary.LittleEndian.PutUint64(actual[8:], hi)
   203  			require.Equal(t, tc.exp, actual)
   204  		})
   205  	}
   206  }
   207  
   208  func TestCompiler_compileV128Load(t *testing.T) {
   209  	tests := []struct {
   210  		name       string
   211  		memSetupFn func(buf []byte)
   212  		loadType   wazeroir.V128LoadType
   213  		offset     uint32
   214  		exp        [16]byte
   215  	}{
   216  		{
   217  			name: "v128 offset=0", loadType: wazeroir.V128LoadType128, offset: 0,
   218  			memSetupFn: func(buf []byte) {
   219  				copy(buf, []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20})
   220  			},
   221  			exp: [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
   222  		},
   223  		{
   224  			name: "v128 offset=2", loadType: wazeroir.V128LoadType128, offset: 2,
   225  			memSetupFn: func(buf []byte) {
   226  				copy(buf, []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20})
   227  			},
   228  			exp: [16]byte{3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18},
   229  		},
   230  		{
   231  			name: "8x8s offset=0", loadType: wazeroir.V128LoadType8x8s, offset: 0,
   232  			memSetupFn: func(buf []byte) {
   233  				copy(buf, []byte{
   234  					1, 0xff, 3, 0xff, 5, 0xff, 7, 0xff, 9, 10,
   235  					11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
   236  				})
   237  			},
   238  			exp: [16]byte{
   239  				1, 0, 0xff, 0xff, 3, 0, 0xff, 0xff, 5, 0, 0xff, 0xff, 7, 0, 0xff, 0xff,
   240  			},
   241  		},
   242  		{
   243  			name: "8x8s offset=3", loadType: wazeroir.V128LoadType8x8s, offset: 3,
   244  			memSetupFn: func(buf []byte) {
   245  				copy(buf, []byte{
   246  					1, 0xff, 3, 0xff, 5, 0xff, 7, 0xff, 9, 10,
   247  					11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
   248  				})
   249  			},
   250  			exp: [16]byte{
   251  				0xff, 0xff, 5, 0, 0xff, 0xff, 7, 0, 0xff, 0xff, 9, 0, 10, 0, 11, 0,
   252  			},
   253  		},
   254  		{
   255  			name: "8x8u offset=0", loadType: wazeroir.V128LoadType8x8u, offset: 0,
   256  			memSetupFn: func(buf []byte) {
   257  				copy(buf, []byte{
   258  					1, 0xff, 3, 0xff, 5, 0xff, 7, 0xff, 9, 10,
   259  					11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
   260  				})
   261  			},
   262  			exp: [16]byte{
   263  				1, 0, 0xff, 0, 3, 0, 0xff, 0, 5, 0, 0xff, 0, 7, 0, 0xff, 0,
   264  			},
   265  		},
   266  		{
   267  			name: "8x8i offset=3", loadType: wazeroir.V128LoadType8x8u, offset: 3,
   268  			memSetupFn: func(buf []byte) {
   269  				copy(buf, []byte{
   270  					1, 0xff, 3, 0xff, 5, 0xff, 7, 0xff, 9, 10,
   271  					11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
   272  				})
   273  			},
   274  			exp: [16]byte{
   275  				0xff, 0, 5, 0, 0xff, 0, 7, 0, 0xff, 0, 9, 0, 10, 0, 11, 0,
   276  			},
   277  		},
   278  		{
   279  			name: "16x4s offset=0", loadType: wazeroir.V128LoadType16x4s, offset: 0,
   280  			memSetupFn: func(buf []byte) {
   281  				copy(buf, []byte{
   282  					1, 0xff, 3, 0xff, 5, 0xff, 7, 0xff, 9, 10,
   283  					11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
   284  				})
   285  			},
   286  			exp: [16]byte{
   287  				1, 0xff, 0xff, 0xff,
   288  				3, 0xff, 0xff, 0xff,
   289  				5, 0xff, 0xff, 0xff,
   290  				7, 0xff, 0xff, 0xff,
   291  			},
   292  		},
   293  		{
   294  			name: "16x4s offset=3", loadType: wazeroir.V128LoadType16x4s, offset: 3,
   295  			memSetupFn: func(buf []byte) {
   296  				copy(buf, []byte{
   297  					1, 0xff, 3, 0xff, 5, 6, 0xff, 0xff, 9, 10,
   298  					11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
   299  				})
   300  			},
   301  			exp: [16]byte{
   302  				0xff, 5, 0, 0,
   303  				6, 0xff, 0xff, 0xff,
   304  				0xff, 9, 0, 0,
   305  				10, 11, 0, 0,
   306  			},
   307  		},
   308  		{
   309  			name: "16x4u offset=0", loadType: wazeroir.V128LoadType16x4u, offset: 0,
   310  			memSetupFn: func(buf []byte) {
   311  				copy(buf, []byte{
   312  					1, 0xff, 3, 0xff, 5, 0xff, 7, 0xff, 9, 10,
   313  					11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
   314  				})
   315  			},
   316  			exp: [16]byte{
   317  				1, 0xff, 0, 0,
   318  				3, 0xff, 0, 0,
   319  				5, 0xff, 0, 0,
   320  				7, 0xff, 0, 0,
   321  			},
   322  		},
   323  		{
   324  			name: "16x4u offset=3", loadType: wazeroir.V128LoadType16x4u, offset: 3,
   325  			memSetupFn: func(buf []byte) {
   326  				copy(buf, []byte{
   327  					1, 0xff, 3, 0xff, 5, 6, 0xff, 0xff, 9, 10,
   328  					11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
   329  				})
   330  			},
   331  			exp: [16]byte{
   332  				0xff, 5, 0, 0,
   333  				6, 0xff, 0, 0,
   334  				0xff, 9, 0, 0,
   335  				10, 11, 0, 0,
   336  			},
   337  		},
   338  		{
   339  			name: "32x2s offset=0", loadType: wazeroir.V128LoadType32x2s, offset: 0,
   340  			memSetupFn: func(buf []byte) {
   341  				copy(buf, []byte{
   342  					1, 0xff, 3, 0xff, 5, 6, 7, 0xff, 9, 10,
   343  					11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
   344  				})
   345  			},
   346  			exp: [16]byte{
   347  				1, 0xff, 3, 0xff, 0xff, 0xff, 0xff, 0xff,
   348  				5, 6, 7, 0xff, 0xff, 0xff, 0xff, 0xff,
   349  			},
   350  		},
   351  		{
   352  			name: "32x2s offset=2", loadType: wazeroir.V128LoadType32x2s, offset: 2,
   353  			memSetupFn: func(buf []byte) {
   354  				copy(buf, []byte{
   355  					1, 0xff, 3, 0xff, 5, 6, 7, 0xff, 9, 0xff,
   356  					11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
   357  				})
   358  			},
   359  			exp: [16]byte{
   360  				3, 0xff, 5, 6, 0, 0, 0, 0,
   361  				7, 0xff, 9, 0xff, 0xff, 0xff, 0xff, 0xff,
   362  			},
   363  		},
   364  		{
   365  			name: "32x2u offset=0", loadType: wazeroir.V128LoadType32x2u, offset: 0,
   366  			memSetupFn: func(buf []byte) {
   367  				copy(buf, []byte{
   368  					1, 0xff, 3, 0xff, 5, 6, 7, 0xff, 9, 10,
   369  					11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
   370  				})
   371  			},
   372  			exp: [16]byte{
   373  				1, 0xff, 3, 0xff, 0, 0, 0, 0,
   374  				5, 6, 7, 0xff, 0, 0, 0, 0,
   375  			},
   376  		},
   377  		{
   378  			name: "32x2u offset=2", loadType: wazeroir.V128LoadType32x2u, offset: 2,
   379  			memSetupFn: func(buf []byte) {
   380  				copy(buf, []byte{
   381  					1, 0xff, 3, 0xff, 5, 6, 7, 0xff, 9, 0xff,
   382  					11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
   383  				})
   384  			},
   385  			exp: [16]byte{
   386  				3, 0xff, 5, 6, 0, 0, 0, 0,
   387  				7, 0xff, 9, 0xff, 0, 0, 0, 0,
   388  			},
   389  		},
   390  		{
   391  			name: "32zero offset=0", loadType: wazeroir.V128LoadType32zero, offset: 0,
   392  			memSetupFn: func(buf []byte) {
   393  				copy(buf, []byte{
   394  					1, 0xff, 3, 0xff, 5, 6, 7, 0xff, 9, 0xff,
   395  					11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
   396  				})
   397  			},
   398  			exp: [16]byte{
   399  				1, 0xff, 3, 0xff, 0, 0, 0, 0,
   400  				0, 0, 0, 0, 0, 0, 0, 0,
   401  			},
   402  		},
   403  		{
   404  			name: "32zero offset=3", loadType: wazeroir.V128LoadType32zero, offset: 3,
   405  			memSetupFn: func(buf []byte) {
   406  				copy(buf, []byte{
   407  					1, 0xff, 3, 0xff, 5, 6, 0xff, 8, 9, 0xff,
   408  					11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
   409  				})
   410  			},
   411  			exp: [16]byte{
   412  				0xff, 5, 6, 0xff, 0, 0, 0, 0,
   413  				0, 0, 0, 0, 0, 0, 0, 0,
   414  			},
   415  		},
   416  		{
   417  			name: "32zero on ceil", loadType: wazeroir.V128LoadType32zero,
   418  			offset: wasm.MemoryPageSize - 4,
   419  			memSetupFn: func(buf []byte) {
   420  				copy(buf[wasm.MemoryPageSize-8:], []byte{
   421  					1, 0xff, 3, 0xff,
   422  					5, 6, 0xff, 8,
   423  				})
   424  			},
   425  			exp: [16]byte{5, 6, 0xff, 8},
   426  		},
   427  		{
   428  			name: "64zero offset=0", loadType: wazeroir.V128LoadType64zero, offset: 0,
   429  			memSetupFn: func(buf []byte) {
   430  				copy(buf, []byte{
   431  					1, 0xff, 3, 0xff, 5, 6, 7, 0xff, 9, 0xff,
   432  					11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
   433  				})
   434  			},
   435  			exp: [16]byte{
   436  				1, 0xff, 3, 0xff, 5, 6, 7, 0xff,
   437  				0, 0, 0, 0, 0, 0, 0, 0,
   438  			},
   439  		},
   440  		{
   441  			name: "64zero offset=2", loadType: wazeroir.V128LoadType64zero, offset: 2,
   442  			memSetupFn: func(buf []byte) {
   443  				copy(buf, []byte{
   444  					1, 0xff, 3, 0xff, 5, 6, 7, 0xff, 9, 0xff,
   445  					11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
   446  				})
   447  			},
   448  			exp: [16]byte{
   449  				3, 0xff, 5, 6, 7, 0xff, 9, 0xff,
   450  				0, 0, 0, 0, 0, 0, 0, 0,
   451  			},
   452  		},
   453  		{
   454  			name: "64zero on ceil", loadType: wazeroir.V128LoadType64zero,
   455  			offset: wasm.MemoryPageSize - 8,
   456  			memSetupFn: func(buf []byte) {
   457  				copy(buf[wasm.MemoryPageSize-16:], []byte{
   458  					1, 0xff, 3, 0xff, 5, 6, 7, 0xff,
   459  					9, 0xff, 11, 12, 13, 14, 15,
   460  				})
   461  			},
   462  			exp: [16]byte{9, 0xff, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0},
   463  		},
   464  		{
   465  			name: "8splat offset=0", loadType: wazeroir.V128LoadType8Splat, offset: 0,
   466  			memSetupFn: func(buf []byte) {
   467  				copy(buf, []byte{
   468  					1, 0xff, 3, 0xff, 5, 6, 7, 0xff, 9, 0xff,
   469  				})
   470  			},
   471  			exp: [16]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
   472  		},
   473  		{
   474  			name: "8splat offset=1", loadType: wazeroir.V128LoadType8Splat, offset: 1,
   475  			memSetupFn: func(buf []byte) {
   476  				copy(buf, []byte{
   477  					1, 0xff, 3, 0xff, 5, 6, 7, 0xff, 9, 0xff,
   478  				})
   479  			},
   480  			exp: [16]byte{
   481  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   482  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   483  			},
   484  		},
   485  		{
   486  			name: "16splat offset=0", loadType: wazeroir.V128LoadType16Splat, offset: 0,
   487  			memSetupFn: func(buf []byte) {
   488  				copy(buf, []byte{
   489  					1, 0xff, 3, 0xff, 5, 6, 7, 0xff, 9, 0xff,
   490  				})
   491  			},
   492  			exp: [16]byte{1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff},
   493  		},
   494  		{
   495  			name: "16splat offset=5", loadType: wazeroir.V128LoadType16Splat, offset: 5,
   496  			memSetupFn: func(buf []byte) {
   497  				copy(buf, []byte{
   498  					1, 0xff, 3, 0xff, 5, 6, 7, 0xff, 9, 0xff,
   499  				})
   500  			},
   501  			exp: [16]byte{6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7},
   502  		},
   503  		{
   504  			name: "32splat offset=0", loadType: wazeroir.V128LoadType32Splat, offset: 0,
   505  			memSetupFn: func(buf []byte) {
   506  				copy(buf, []byte{
   507  					1, 0xff, 3, 0xff, 5, 6, 7, 0xff, 9, 0xff,
   508  				})
   509  			},
   510  			exp: [16]byte{1, 0xff, 3, 0xff, 1, 0xff, 3, 0xff, 1, 0xff, 3, 0xff, 1, 0xff, 3, 0xff},
   511  		},
   512  		{
   513  			name: "32splat offset=1", loadType: wazeroir.V128LoadType32Splat, offset: 1,
   514  			memSetupFn: func(buf []byte) {
   515  				copy(buf, []byte{
   516  					1, 0xff, 3, 0xff, 5, 6, 7, 0xff, 9, 0xff,
   517  				})
   518  			},
   519  			exp: [16]byte{0xff, 3, 0xff, 5, 0xff, 3, 0xff, 5, 0xff, 3, 0xff, 5, 0xff, 3, 0xff, 5},
   520  		},
   521  		{
   522  			name: "64splat offset=0", loadType: wazeroir.V128LoadType64Splat, offset: 0,
   523  			memSetupFn: func(buf []byte) {
   524  				copy(buf, []byte{
   525  					1, 0xff, 3, 0xff, 5, 6, 7, 0xff, 9, 0xff,
   526  				})
   527  			},
   528  			exp: [16]byte{1, 0xff, 3, 0xff, 5, 6, 7, 0xff, 1, 0xff, 3, 0xff, 5, 6, 7, 0xff},
   529  		},
   530  		{
   531  			name: "64splat offset=1", loadType: wazeroir.V128LoadType64Splat, offset: 1,
   532  			memSetupFn: func(buf []byte) {
   533  				copy(buf, []byte{
   534  					1, 0xff, 3, 0xff, 5, 6, 7, 0xff, 9, 0xff,
   535  				})
   536  			},
   537  			exp: [16]byte{0xff, 3, 0xff, 5, 6, 7, 0xff, 9, 0xff, 3, 0xff, 5, 6, 7, 0xff, 9},
   538  		},
   539  	}
   540  
   541  	for _, tc := range tests {
   542  		tc := tc
   543  		t.Run(tc.name, func(t *testing.T) {
   544  			env := newCompilerEnvironment()
   545  			tc.memSetupFn(env.memory())
   546  
   547  			compiler := env.requireNewCompiler(t, newCompiler,
   548  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
   549  
   550  			err := compiler.compilePreamble()
   551  			require.NoError(t, err)
   552  
   553  			err = compiler.compileConstI32(&wazeroir.OperationConstI32{Value: tc.offset})
   554  			require.NoError(t, err)
   555  
   556  			err = compiler.compileV128Load(&wazeroir.OperationV128Load{
   557  				Type: tc.loadType, Arg: &wazeroir.MemoryArg{},
   558  			})
   559  			require.NoError(t, err)
   560  
   561  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
   562  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
   563  			loadedLocation := compiler.runtimeValueLocationStack().peek()
   564  			require.True(t, loadedLocation.onRegister())
   565  
   566  			err = compiler.compileReturnFunction()
   567  			require.NoError(t, err)
   568  
   569  			// Generate and run the code under test.
   570  			code, _, err := compiler.compile()
   571  			require.NoError(t, err)
   572  			env.exec(code)
   573  
   574  			require.Equal(t, nativeCallStatusCodeReturned, env.callEngine().statusCode)
   575  
   576  			require.Equal(t, uint64(2), env.stackPointer())
   577  			lo, hi := env.stackTopAsV128()
   578  
   579  			var actual [16]byte
   580  			binary.LittleEndian.PutUint64(actual[:8], lo)
   581  			binary.LittleEndian.PutUint64(actual[8:], hi)
   582  			require.Equal(t, tc.exp, actual)
   583  		})
   584  	}
   585  }
   586  
   587  func TestCompiler_compileV128LoadLane(t *testing.T) {
   588  	originalVecLo, originalVecHi := uint64(0), uint64(0)
   589  	tests := []struct {
   590  		name                string
   591  		memSetupFn          func(buf []byte)
   592  		laneIndex, laneSize byte
   593  		offset              uint32
   594  		exp                 [16]byte
   595  	}{
   596  		{
   597  			name: "8_lane offset=0 laneIndex=0",
   598  			memSetupFn: func(buf []byte) {
   599  				copy(buf, []byte{
   600  					1, 0xff,
   601  				})
   602  			},
   603  			laneSize:  8,
   604  			laneIndex: 0,
   605  			offset:    0,
   606  			exp:       [16]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
   607  		},
   608  		{
   609  			name: "8_lane offset=1 laneIndex=0",
   610  			memSetupFn: func(buf []byte) {
   611  				copy(buf, []byte{
   612  					1, 0xff,
   613  				})
   614  			},
   615  			laneSize:  8,
   616  			laneIndex: 0,
   617  			offset:    1,
   618  			exp:       [16]byte{0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
   619  		},
   620  		{
   621  			name: "8_lane offset=1 laneIndex=5",
   622  			memSetupFn: func(buf []byte) {
   623  				copy(buf, []byte{
   624  					1, 0xff,
   625  				})
   626  			},
   627  			laneSize:  8,
   628  			laneIndex: 5,
   629  			offset:    1,
   630  			exp:       [16]byte{0, 0, 0, 0, 0, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
   631  		},
   632  		{
   633  			name: "16_lane offset=0 laneIndex=0",
   634  			memSetupFn: func(buf []byte) {
   635  				copy(buf, []byte{
   636  					1, 0xff, 1, 0xa,
   637  				})
   638  			},
   639  			laneSize:  16,
   640  			laneIndex: 0,
   641  			offset:    0,
   642  			exp:       [16]byte{1, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
   643  		},
   644  		{
   645  			name: "16_lane offset=1 laneIndex=0",
   646  			memSetupFn: func(buf []byte) {
   647  				copy(buf, []byte{
   648  					1, 0xff, 1, 0xa,
   649  				})
   650  			},
   651  			laneSize:  16,
   652  			laneIndex: 0,
   653  			offset:    1,
   654  			exp:       [16]byte{0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
   655  		},
   656  		{
   657  			name: "16_lane offset=1 laneIndex=5",
   658  			memSetupFn: func(buf []byte) {
   659  				copy(buf, []byte{
   660  					1, 0xff, 1, 0xa,
   661  				})
   662  			},
   663  			laneSize:  16,
   664  			laneIndex: 5,
   665  			offset:    1,
   666  			exp:       [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 1, 0, 0, 0, 0},
   667  		},
   668  		{
   669  			name: "32_lane offset=0 laneIndex=0",
   670  			memSetupFn: func(buf []byte) {
   671  				copy(buf, []byte{
   672  					1, 0xff, 1, 0xa, 0x9, 0x8,
   673  				})
   674  			},
   675  			laneSize:  32,
   676  			laneIndex: 0,
   677  			offset:    0,
   678  			exp:       [16]byte{1, 0xff, 1, 0xa, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
   679  		},
   680  		{
   681  			name: "32_lane offset=1 laneIndex=0",
   682  			memSetupFn: func(buf []byte) {
   683  				copy(buf, []byte{
   684  					1, 0xff, 1, 0xa, 0x9, 0x8,
   685  				})
   686  			},
   687  			laneSize:  32,
   688  			laneIndex: 0,
   689  			offset:    1,
   690  			exp:       [16]byte{0xff, 1, 0xa, 0x9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
   691  		},
   692  		{
   693  			name: "32_lane offset=1 laneIndex=3",
   694  			memSetupFn: func(buf []byte) {
   695  				copy(buf, []byte{
   696  					1, 0xff, 1, 0xa, 0x9, 0x8,
   697  				})
   698  			},
   699  			laneSize:  32,
   700  			laneIndex: 3,
   701  			offset:    1,
   702  			exp:       [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 1, 0xa, 0x9},
   703  		},
   704  
   705  		{
   706  			name: "64_lane offset=0 laneIndex=0",
   707  			memSetupFn: func(buf []byte) {
   708  				copy(buf, []byte{
   709  					1, 0xff, 1, 0xa, 0x9, 0x8, 0x1, 0x2, 0x3, 0x4,
   710  				})
   711  			},
   712  			laneSize:  64,
   713  			laneIndex: 0,
   714  			offset:    0,
   715  			exp:       [16]byte{1, 0xff, 1, 0xa, 0x9, 0x8, 0x1, 0x2, 0, 0, 0, 0, 0, 0, 0, 0},
   716  		},
   717  		{
   718  			name: "64_lane offset=1 laneIndex=0",
   719  			memSetupFn: func(buf []byte) {
   720  				copy(buf, []byte{
   721  					1, 0xff, 1, 0xa, 0x9, 0x8, 0x1, 0x2, 0x3, 0x4,
   722  				})
   723  			},
   724  			laneSize:  64,
   725  			laneIndex: 0,
   726  			offset:    1,
   727  			exp:       [16]byte{0xff, 1, 0xa, 0x9, 0x8, 0x1, 0x2, 0x3, 0, 0, 0, 0, 0, 0, 0, 0},
   728  		},
   729  		{
   730  			name: "64_lane offset=3 laneIndex=1",
   731  			memSetupFn: func(buf []byte) {
   732  				copy(buf, []byte{
   733  					1, 0xff, 1, 0xa, 0x9, 0x8, 0x1, 0x2, 0x3, 0x4, 0xa,
   734  				})
   735  			},
   736  			laneSize:  64,
   737  			laneIndex: 1,
   738  			offset:    3,
   739  			exp:       [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0xa, 0x9, 0x8, 0x1, 0x2, 0x3, 0x4, 0xa},
   740  		},
   741  	}
   742  
   743  	for _, tc := range tests {
   744  		tc := tc
   745  		t.Run(tc.name, func(t *testing.T) {
   746  			env := newCompilerEnvironment()
   747  			tc.memSetupFn(env.memory())
   748  
   749  			compiler := env.requireNewCompiler(t, newCompiler,
   750  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
   751  
   752  			err := compiler.compilePreamble()
   753  			require.NoError(t, err)
   754  
   755  			err = compiler.compileConstI32(&wazeroir.OperationConstI32{Value: tc.offset})
   756  			require.NoError(t, err)
   757  
   758  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
   759  				Lo: originalVecLo,
   760  				Hi: originalVecHi,
   761  			})
   762  			require.NoError(t, err)
   763  
   764  			err = compiler.compileV128LoadLane(&wazeroir.OperationV128LoadLane{
   765  				LaneIndex: tc.laneIndex, LaneSize: tc.laneSize, Arg: &wazeroir.MemoryArg{},
   766  			})
   767  			require.NoError(t, err)
   768  
   769  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
   770  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
   771  			loadedLocation := compiler.runtimeValueLocationStack().peek()
   772  			require.True(t, loadedLocation.onRegister())
   773  
   774  			err = compiler.compileReturnFunction()
   775  			require.NoError(t, err)
   776  
   777  			// Generate and run the code under test.
   778  			code, _, err := compiler.compile()
   779  			require.NoError(t, err)
   780  			env.exec(code)
   781  
   782  			require.Equal(t, uint64(2), env.stackPointer())
   783  			lo, hi := env.stackTopAsV128()
   784  
   785  			var actual [16]byte
   786  			binary.LittleEndian.PutUint64(actual[:8], lo)
   787  			binary.LittleEndian.PutUint64(actual[8:], hi)
   788  			require.Equal(t, tc.exp, actual)
   789  		})
   790  	}
   791  }
   792  
   793  func TestCompiler_compileV128Store(t *testing.T) {
   794  	tests := []struct {
   795  		name   string
   796  		offset uint32
   797  	}{
   798  		{name: "offset=1", offset: 1},
   799  		{name: "offset=5", offset: 5},
   800  		{name: "offset=10", offset: 10},
   801  	}
   802  
   803  	for _, tc := range tests {
   804  		tc := tc
   805  		t.Run(tc.name, func(t *testing.T) {
   806  			env := newCompilerEnvironment()
   807  
   808  			compiler := env.requireNewCompiler(t, newCompiler,
   809  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
   810  
   811  			err := compiler.compilePreamble()
   812  			require.NoError(t, err)
   813  
   814  			err = compiler.compileConstI32(&wazeroir.OperationConstI32{Value: tc.offset})
   815  			require.NoError(t, err)
   816  
   817  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{Lo: ^uint64(0), Hi: ^uint64(0)})
   818  			require.NoError(t, err)
   819  
   820  			err = compiler.compileV128Store(&wazeroir.OperationV128Store{Arg: &wazeroir.MemoryArg{}})
   821  			require.NoError(t, err)
   822  
   823  			requireRuntimeLocationStackPointerEqual(t, uint64(0), compiler)
   824  			require.Equal(t, 0, len(compiler.runtimeValueLocationStack().usedRegisters))
   825  
   826  			err = compiler.compileReturnFunction()
   827  			require.NoError(t, err)
   828  
   829  			// Generate and run the code under test.
   830  			code, _, err := compiler.compile()
   831  			require.NoError(t, err)
   832  			env.exec(code)
   833  
   834  			require.Equal(t, uint64(0), env.stackPointer())
   835  
   836  			mem := env.memory()
   837  			require.Equal(t, []byte{
   838  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   839  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   840  			},
   841  				mem[tc.offset:tc.offset+16])
   842  		})
   843  	}
   844  }
   845  
   846  func TestCompiler_compileV128StoreLane(t *testing.T) {
   847  	vecBytes := [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
   848  	tests := []struct {
   849  		name                string
   850  		laneIndex, laneSize byte
   851  		offset              uint32
   852  		exp                 [16]byte
   853  	}{
   854  		{
   855  			name:      "8_lane offset=0 laneIndex=0",
   856  			laneSize:  8,
   857  			laneIndex: 0,
   858  			offset:    0,
   859  			exp:       [16]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
   860  		},
   861  		{
   862  			name:      "8_lane offset=1 laneIndex=0",
   863  			laneSize:  8,
   864  			laneIndex: 0,
   865  			offset:    1,
   866  			exp:       [16]byte{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
   867  		},
   868  		{
   869  			name:      "8_lane offset=3 laneIndex=5",
   870  			laneSize:  8,
   871  			laneIndex: 5,
   872  			offset:    3,
   873  			exp:       [16]byte{0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
   874  		},
   875  		{
   876  			name:      "16_lane offset=0 laneIndex=0",
   877  			laneSize:  16,
   878  			laneIndex: 0,
   879  			offset:    0,
   880  			exp:       [16]byte{1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
   881  		},
   882  		{
   883  			name:      "16_lane offset=1 laneIndex=0",
   884  			laneSize:  16,
   885  			laneIndex: 0,
   886  			offset:    1,
   887  			exp:       [16]byte{0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
   888  		},
   889  		{
   890  			name:      "16_lane offset=5 laneIndex=7",
   891  			laneSize:  16,
   892  			laneIndex: 7,
   893  			offset:    5,
   894  			exp:       [16]byte{0, 0, 0, 0, 0, 15, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0},
   895  		},
   896  
   897  		{
   898  			name:      "32_lane offset=0 laneIndex=0",
   899  			laneSize:  32,
   900  			laneIndex: 0,
   901  			offset:    0,
   902  			exp:       [16]byte{1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
   903  		},
   904  		{
   905  			name:      "32_lane offset=1 laneIndex=0",
   906  			laneSize:  32,
   907  			laneIndex: 0,
   908  			offset:    1,
   909  			exp:       [16]byte{0, 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
   910  		},
   911  		{
   912  			name:      "32_lane offset=5 laneIndex=3",
   913  			laneSize:  32,
   914  			laneIndex: 3,
   915  			offset:    5,
   916  			exp:       [16]byte{0, 0, 0, 0, 0, 13, 14, 15, 16, 0, 0, 0, 0, 0, 0, 0},
   917  		},
   918  
   919  		{
   920  			name:      "64_lane offset=0 laneIndex=0",
   921  			laneSize:  64,
   922  			laneIndex: 0,
   923  			offset:    0,
   924  			exp:       [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0},
   925  		},
   926  		{
   927  			name:      "64_lane offset=1 laneIndex=0",
   928  			laneSize:  64,
   929  			laneIndex: 0,
   930  			offset:    1,
   931  			exp:       [16]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0},
   932  		},
   933  		{
   934  			name:      "64_lane offset=5 laneIndex=3",
   935  			laneSize:  64,
   936  			laneIndex: 1,
   937  			offset:    6,
   938  			exp:       [16]byte{0, 0, 0, 0, 0, 0, 9, 10, 11, 12, 13, 14, 15, 16, 0, 0},
   939  		},
   940  	}
   941  
   942  	for _, tc := range tests {
   943  		tc := tc
   944  		t.Run(tc.name, func(t *testing.T) {
   945  			env := newCompilerEnvironment()
   946  
   947  			compiler := env.requireNewCompiler(t, newCompiler,
   948  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
   949  
   950  			err := compiler.compilePreamble()
   951  			require.NoError(t, err)
   952  
   953  			err = compiler.compileConstI32(&wazeroir.OperationConstI32{Value: tc.offset})
   954  			require.NoError(t, err)
   955  
   956  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
   957  				Lo: binary.LittleEndian.Uint64(vecBytes[:8]),
   958  				Hi: binary.LittleEndian.Uint64(vecBytes[8:]),
   959  			})
   960  			require.NoError(t, err)
   961  
   962  			err = compiler.compileV128StoreLane(&wazeroir.OperationV128StoreLane{
   963  				LaneIndex: tc.laneIndex, LaneSize: tc.laneSize, Arg: &wazeroir.MemoryArg{},
   964  			})
   965  			require.NoError(t, err)
   966  
   967  			requireRuntimeLocationStackPointerEqual(t, uint64(0), compiler)
   968  			require.Equal(t, 0, len(compiler.runtimeValueLocationStack().usedRegisters))
   969  
   970  			err = compiler.compileReturnFunction()
   971  			require.NoError(t, err)
   972  
   973  			// Generate and run the code under test.
   974  			code, _, err := compiler.compile()
   975  			require.NoError(t, err)
   976  			env.exec(code)
   977  
   978  			require.Equal(t, tc.exp[:], env.memory()[:16])
   979  		})
   980  	}
   981  }
   982  
   983  func TestCompiler_compileV128ExtractLane(t *testing.T) {
   984  	tests := []struct {
   985  		name      string
   986  		vecBytes  [16]byte
   987  		shape     wazeroir.Shape
   988  		signed    bool
   989  		laneIndex byte
   990  		exp       uint64
   991  	}{
   992  		{
   993  			name:      "i8x16 unsigned index=0",
   994  			vecBytes:  [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
   995  			shape:     wazeroir.ShapeI8x16,
   996  			signed:    false,
   997  			laneIndex: 0,
   998  			exp:       uint64(byte(1)),
   999  		},
  1000  		{
  1001  			name:      "i8x16 unsigned index=15",
  1002  			vecBytes:  [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0xff},
  1003  			shape:     wazeroir.ShapeI8x16,
  1004  			signed:    false,
  1005  			laneIndex: 15,
  1006  			exp:       uint64(byte(0xff)),
  1007  		},
  1008  		{
  1009  			name:      "i8x16 signed index=0",
  1010  			vecBytes:  [16]byte{0xf1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
  1011  			shape:     wazeroir.ShapeI8x16,
  1012  			signed:    true,
  1013  			laneIndex: 0,
  1014  			exp:       uint64(0xff_ff_ff_f1),
  1015  		},
  1016  		{
  1017  			name:      "i8x16 signed index=1",
  1018  			vecBytes:  [16]byte{0xf0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
  1019  			shape:     wazeroir.ShapeI8x16,
  1020  			signed:    true,
  1021  			laneIndex: 1,
  1022  			exp:       uint64(2),
  1023  		},
  1024  		{
  1025  			name:      "i16x8 unsigned index=0",
  1026  			vecBytes:  [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
  1027  			shape:     wazeroir.ShapeI16x8,
  1028  			signed:    false,
  1029  			laneIndex: 0,
  1030  			exp:       uint64(uint16(0x2<<8 | 0x1)),
  1031  		},
  1032  		{
  1033  			name:      "i16x8 unsigned index=7",
  1034  			vecBytes:  [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0xff},
  1035  			shape:     wazeroir.ShapeI16x8,
  1036  			signed:    false,
  1037  			laneIndex: 7,
  1038  			exp:       uint64(uint16(0xff<<8 | 15)),
  1039  		},
  1040  		{
  1041  			name:      "i16x8 signed index=0",
  1042  			vecBytes:  [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
  1043  			shape:     wazeroir.ShapeI16x8,
  1044  			signed:    true,
  1045  			laneIndex: 0,
  1046  			exp:       uint64(uint16(0x2<<8 | 0x1)),
  1047  		},
  1048  		{
  1049  			name:      "i16x8 signed index=7",
  1050  			vecBytes:  [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0xf1},
  1051  			shape:     wazeroir.ShapeI16x8,
  1052  			signed:    true,
  1053  			laneIndex: 7,
  1054  			exp:       uint64(uint32(0xffff<<16) | uint32(uint16(0xf1<<8|15))),
  1055  		},
  1056  		{
  1057  			name:      "i32x4 index=0",
  1058  			vecBytes:  [16]byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16},
  1059  			shape:     wazeroir.ShapeI32x4,
  1060  			laneIndex: 0,
  1061  			exp:       uint64(uint32(0x04_03_02_01)),
  1062  		},
  1063  		{
  1064  			name:      "i32x4 index=3",
  1065  			vecBytes:  [16]byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16},
  1066  			shape:     wazeroir.ShapeI32x4,
  1067  			laneIndex: 3,
  1068  			exp:       uint64(uint32(0x16_15_14_13)),
  1069  		},
  1070  		{
  1071  			name:      "i64x4 index=0",
  1072  			vecBytes:  [16]byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16},
  1073  			shape:     wazeroir.ShapeI64x2,
  1074  			laneIndex: 0,
  1075  			exp:       uint64(0x08_07_06_05_04_03_02_01),
  1076  		},
  1077  		{
  1078  			name:      "i64x4 index=1",
  1079  			vecBytes:  [16]byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16},
  1080  			shape:     wazeroir.ShapeI64x2,
  1081  			laneIndex: 1,
  1082  			exp:       uint64(0x16_15_14_13_12_11_10_09),
  1083  		},
  1084  		{
  1085  			name:      "f32x4 index=0",
  1086  			vecBytes:  [16]byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16},
  1087  			shape:     wazeroir.ShapeF32x4,
  1088  			laneIndex: 0,
  1089  			exp:       uint64(uint32(0x04_03_02_01)),
  1090  		},
  1091  		{
  1092  			name:      "f32x4 index=3",
  1093  			vecBytes:  [16]byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16},
  1094  			shape:     wazeroir.ShapeF32x4,
  1095  			laneIndex: 3,
  1096  			exp:       uint64(uint32(0x16_15_14_13)),
  1097  		},
  1098  		{
  1099  			name:      "f64x4 index=0",
  1100  			vecBytes:  [16]byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16},
  1101  			shape:     wazeroir.ShapeF64x2,
  1102  			laneIndex: 0,
  1103  			exp:       uint64(0x08_07_06_05_04_03_02_01),
  1104  		},
  1105  		{
  1106  			name:      "f64x4 index=1",
  1107  			vecBytes:  [16]byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16},
  1108  			shape:     wazeroir.ShapeF64x2,
  1109  			laneIndex: 1,
  1110  			exp:       uint64(0x16_15_14_13_12_11_10_09),
  1111  		},
  1112  	}
  1113  
  1114  	for _, tc := range tests {
  1115  		tc := tc
  1116  		t.Run(tc.name, func(t *testing.T) {
  1117  			env := newCompilerEnvironment()
  1118  
  1119  			compiler := env.requireNewCompiler(t, newCompiler,
  1120  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  1121  
  1122  			err := compiler.compilePreamble()
  1123  			require.NoError(t, err)
  1124  
  1125  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  1126  				Lo: binary.LittleEndian.Uint64(tc.vecBytes[:8]),
  1127  				Hi: binary.LittleEndian.Uint64(tc.vecBytes[8:]),
  1128  			})
  1129  			require.NoError(t, err)
  1130  
  1131  			err = compiler.compileV128ExtractLane(&wazeroir.OperationV128ExtractLane{
  1132  				LaneIndex: tc.laneIndex,
  1133  				Signed:    tc.signed,
  1134  				Shape:     tc.shape,
  1135  			})
  1136  			require.NoError(t, err)
  1137  
  1138  			requireRuntimeLocationStackPointerEqual(t, uint64(1), compiler)
  1139  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  1140  
  1141  			vt := compiler.runtimeValueLocationStack().peek().valueType
  1142  			switch tc.shape {
  1143  			case wazeroir.ShapeI8x16, wazeroir.ShapeI16x8, wazeroir.ShapeI32x4:
  1144  				require.Equal(t, runtimeValueTypeI32, vt)
  1145  			case wazeroir.ShapeI64x2:
  1146  				require.Equal(t, runtimeValueTypeI64, vt)
  1147  			case wazeroir.ShapeF32x4:
  1148  				require.Equal(t, runtimeValueTypeF32, vt)
  1149  			case wazeroir.ShapeF64x2:
  1150  				require.Equal(t, runtimeValueTypeF64, vt)
  1151  			}
  1152  
  1153  			err = compiler.compileReturnFunction()
  1154  			require.NoError(t, err)
  1155  
  1156  			// Generate and run the code under test.
  1157  			code, _, err := compiler.compile()
  1158  			require.NoError(t, err)
  1159  			env.exec(code)
  1160  
  1161  			switch tc.shape {
  1162  			case wazeroir.ShapeI8x16, wazeroir.ShapeI16x8, wazeroir.ShapeI32x4, wazeroir.ShapeF32x4:
  1163  				require.Equal(t, uint32(tc.exp), env.stackTopAsUint32())
  1164  			case wazeroir.ShapeI64x2, wazeroir.ShapeF64x2:
  1165  				require.Equal(t, tc.exp, env.stackTopAsUint64())
  1166  			}
  1167  		})
  1168  	}
  1169  }
  1170  
  1171  func TestCompiler_compileV128ReplaceLane(t *testing.T) {
  1172  	tests := []struct {
  1173  		name               string
  1174  		originValueSetupFn func(*testing.T, compilerImpl)
  1175  		shape              wazeroir.Shape
  1176  		laneIndex          byte
  1177  		exp                [16]byte
  1178  		lo, hi             uint64
  1179  	}{
  1180  		{
  1181  			name:      "i8x16 index=0",
  1182  			shape:     wazeroir.ShapeI8x16,
  1183  			laneIndex: 5,
  1184  			originValueSetupFn: func(t *testing.T, c compilerImpl) {
  1185  				err := c.compileConstI32(&wazeroir.OperationConstI32{Value: 0xff})
  1186  				require.NoError(t, err)
  1187  			},
  1188  			exp: [16]byte{5: 0xff},
  1189  		},
  1190  		{
  1191  			name:      "i8x16 index=3",
  1192  			shape:     wazeroir.ShapeI8x16,
  1193  			laneIndex: 5,
  1194  			originValueSetupFn: func(t *testing.T, c compilerImpl) {
  1195  				err := c.compileConstI32(&wazeroir.OperationConstI32{Value: 0xff << 8})
  1196  				require.NoError(t, err)
  1197  			},
  1198  			exp: [16]byte{},
  1199  		},
  1200  		{
  1201  			name:      "i8x16 index=5",
  1202  			shape:     wazeroir.ShapeI8x16,
  1203  			laneIndex: 5,
  1204  			originValueSetupFn: func(t *testing.T, c compilerImpl) {
  1205  				err := c.compileConstI32(&wazeroir.OperationConstI32{Value: 0xff})
  1206  				require.NoError(t, err)
  1207  			},
  1208  			exp: [16]byte{5: 0xff},
  1209  		},
  1210  		{
  1211  			name:      "i16x8 index=0",
  1212  			shape:     wazeroir.ShapeI16x8,
  1213  			laneIndex: 0,
  1214  			originValueSetupFn: func(t *testing.T, c compilerImpl) {
  1215  				err := c.compileConstI32(&wazeroir.OperationConstI32{Value: 0xee_ff})
  1216  				require.NoError(t, err)
  1217  			},
  1218  			exp: [16]byte{0: 0xff, 1: 0xee},
  1219  		},
  1220  		{
  1221  			name:      "i16x8 index=3",
  1222  			shape:     wazeroir.ShapeI16x8,
  1223  			laneIndex: 3,
  1224  			originValueSetupFn: func(t *testing.T, c compilerImpl) {
  1225  				err := c.compileConstI32(&wazeroir.OperationConstI32{Value: 0xaa_00})
  1226  				require.NoError(t, err)
  1227  			},
  1228  			exp: [16]byte{7: 0xaa},
  1229  		},
  1230  		{
  1231  			name:      "i16x8 index=7",
  1232  			shape:     wazeroir.ShapeI16x8,
  1233  			laneIndex: 3,
  1234  			originValueSetupFn: func(t *testing.T, c compilerImpl) {
  1235  				err := c.compileConstI32(&wazeroir.OperationConstI32{Value: 0xaa_bb << 16})
  1236  				require.NoError(t, err)
  1237  			},
  1238  			exp: [16]byte{},
  1239  		},
  1240  		{
  1241  			name:      "i32x4 index=0",
  1242  			shape:     wazeroir.ShapeI32x4,
  1243  			laneIndex: 0,
  1244  			originValueSetupFn: func(t *testing.T, c compilerImpl) {
  1245  				err := c.compileConstI32(&wazeroir.OperationConstI32{Value: 0xaa_bb_cc_dd})
  1246  				require.NoError(t, err)
  1247  			},
  1248  			exp: [16]byte{0: 0xdd, 1: 0xcc, 2: 0xbb, 3: 0xaa},
  1249  		},
  1250  		{
  1251  			name:      "i32x4 index=3",
  1252  			shape:     wazeroir.ShapeI32x4,
  1253  			laneIndex: 3,
  1254  			originValueSetupFn: func(t *testing.T, c compilerImpl) {
  1255  				err := c.compileConstI32(&wazeroir.OperationConstI32{Value: 0xaa_bb_cc_dd})
  1256  				require.NoError(t, err)
  1257  			},
  1258  			exp: [16]byte{12: 0xdd, 13: 0xcc, 14: 0xbb, 15: 0xaa},
  1259  		},
  1260  		{
  1261  			name:      "i64x2 index=0",
  1262  			shape:     wazeroir.ShapeI64x2,
  1263  			laneIndex: 0,
  1264  			originValueSetupFn: func(t *testing.T, c compilerImpl) {
  1265  				err := c.compileConstI64(&wazeroir.OperationConstI64{Value: 0xaa_bb_cc_dd_01_02_03_04})
  1266  				require.NoError(t, err)
  1267  			},
  1268  			exp: [16]byte{0: 0x04, 1: 0x03, 2: 0x02, 3: 0x01, 4: 0xdd, 5: 0xcc, 6: 0xbb, 7: 0xaa},
  1269  		},
  1270  		{
  1271  			name:      "i64x2 index=1",
  1272  			shape:     wazeroir.ShapeI64x2,
  1273  			laneIndex: 1,
  1274  			originValueSetupFn: func(t *testing.T, c compilerImpl) {
  1275  				err := c.compileConstI64(&wazeroir.OperationConstI64{Value: 0xaa_bb_cc_dd_01_02_03_04})
  1276  				require.NoError(t, err)
  1277  			},
  1278  			exp: [16]byte{8: 0x04, 9: 0x03, 10: 0x02, 11: 0x01, 12: 0xdd, 13: 0xcc, 14: 0xbb, 15: 0xaa},
  1279  		},
  1280  		{
  1281  			name:      "f32x4 index=0",
  1282  			shape:     wazeroir.ShapeF32x4,
  1283  			laneIndex: 0,
  1284  			originValueSetupFn: func(t *testing.T, c compilerImpl) {
  1285  				err := c.compileConstF32(&wazeroir.OperationConstF32{Value: math.Float32frombits(0xaa_bb_cc_dd)})
  1286  				require.NoError(t, err)
  1287  			},
  1288  			exp: [16]byte{0: 0xdd, 1: 0xcc, 2: 0xbb, 3: 0xaa},
  1289  		},
  1290  		{
  1291  			name:      "f32x4 index=1",
  1292  			shape:     wazeroir.ShapeF32x4,
  1293  			laneIndex: 1,
  1294  			originValueSetupFn: func(t *testing.T, c compilerImpl) {
  1295  				err := c.compileConstF32(&wazeroir.OperationConstF32{Value: math.Float32frombits(0xaa_bb_cc_dd)})
  1296  				require.NoError(t, err)
  1297  			},
  1298  			exp: [16]byte{4: 0xdd, 5: 0xcc, 6: 0xbb, 7: 0xaa},
  1299  		},
  1300  		{
  1301  			name:      "f32x4 index=2",
  1302  			shape:     wazeroir.ShapeF32x4,
  1303  			laneIndex: 2,
  1304  			originValueSetupFn: func(t *testing.T, c compilerImpl) {
  1305  				err := c.compileConstF32(&wazeroir.OperationConstF32{Value: math.Float32frombits(0xaa_bb_cc_dd)})
  1306  				require.NoError(t, err)
  1307  			},
  1308  			exp: [16]byte{8: 0xdd, 9: 0xcc, 10: 0xbb, 11: 0xaa},
  1309  		},
  1310  		{
  1311  			name:      "f32x4 index=3",
  1312  			shape:     wazeroir.ShapeF32x4,
  1313  			laneIndex: 3,
  1314  			originValueSetupFn: func(t *testing.T, c compilerImpl) {
  1315  				err := c.compileConstF32(&wazeroir.OperationConstF32{Value: math.Float32frombits(0xaa_bb_cc_dd)})
  1316  				require.NoError(t, err)
  1317  			},
  1318  			exp: [16]byte{12: 0xdd, 13: 0xcc, 14: 0xbb, 15: 0xaa},
  1319  		},
  1320  		{
  1321  			name:      "f64x2 index=0",
  1322  			shape:     wazeroir.ShapeF64x2,
  1323  			laneIndex: 0,
  1324  			originValueSetupFn: func(t *testing.T, c compilerImpl) {
  1325  				err := c.compileConstF64(&wazeroir.OperationConstF64{Value: math.Float64frombits(0xaa_bb_cc_dd_01_02_03_04)})
  1326  				require.NoError(t, err)
  1327  			},
  1328  			exp: [16]byte{0: 0x04, 1: 0x03, 2: 0x02, 3: 0x01, 4: 0xdd, 5: 0xcc, 6: 0xbb, 7: 0xaa},
  1329  		},
  1330  		{
  1331  			name:      "f64x2 index=1",
  1332  			shape:     wazeroir.ShapeF64x2,
  1333  			laneIndex: 1,
  1334  			originValueSetupFn: func(t *testing.T, c compilerImpl) {
  1335  				err := c.compileConstF64(&wazeroir.OperationConstF64{Value: math.Float64frombits(0xaa_bb_cc_dd_01_02_03_04)})
  1336  				require.NoError(t, err)
  1337  			},
  1338  			exp: [16]byte{8: 0x04, 9: 0x03, 10: 0x02, 11: 0x01, 12: 0xdd, 13: 0xcc, 14: 0xbb, 15: 0xaa},
  1339  		},
  1340  		{
  1341  			name:      "f64x2 index=0 / lo,hi = 1.0",
  1342  			shape:     wazeroir.ShapeF64x2,
  1343  			laneIndex: 0,
  1344  			originValueSetupFn: func(t *testing.T, c compilerImpl) {
  1345  				err := c.compileConstF64(&wazeroir.OperationConstF64{Value: math.Float64frombits(0.0)})
  1346  				require.NoError(t, err)
  1347  			},
  1348  			lo:  math.Float64bits(1.0),
  1349  			hi:  math.Float64bits(1.0),
  1350  			exp: [16]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf0, 0x3f},
  1351  		},
  1352  		{
  1353  			name:      "f64x2 index=1 / lo,hi = 1.0",
  1354  			shape:     wazeroir.ShapeF64x2,
  1355  			laneIndex: 1,
  1356  			originValueSetupFn: func(t *testing.T, c compilerImpl) {
  1357  				err := c.compileConstF64(&wazeroir.OperationConstF64{Value: math.Float64frombits(0.0)})
  1358  				require.NoError(t, err)
  1359  			},
  1360  			lo:  math.Float64bits(1.0),
  1361  			hi:  math.Float64bits(1.0),
  1362  			exp: [16]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf0, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
  1363  		},
  1364  	}
  1365  
  1366  	for _, tc := range tests {
  1367  		tc := tc
  1368  		t.Run(tc.name, func(t *testing.T) {
  1369  			env := newCompilerEnvironment()
  1370  			compiler := env.requireNewCompiler(t, newCompiler,
  1371  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  1372  
  1373  			err := compiler.compilePreamble()
  1374  			require.NoError(t, err)
  1375  
  1376  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{Lo: tc.lo, Hi: tc.hi})
  1377  			require.NoError(t, err)
  1378  
  1379  			tc.originValueSetupFn(t, compiler)
  1380  
  1381  			err = compiler.compileV128ReplaceLane(&wazeroir.OperationV128ReplaceLane{
  1382  				LaneIndex: tc.laneIndex,
  1383  				Shape:     tc.shape,
  1384  			})
  1385  			require.NoError(t, err)
  1386  
  1387  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  1388  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  1389  
  1390  			err = compiler.compileReturnFunction()
  1391  			require.NoError(t, err)
  1392  
  1393  			// Generate and run the code under test.
  1394  			code, _, err := compiler.compile()
  1395  			require.NoError(t, err)
  1396  			env.exec(code)
  1397  
  1398  			lo, hi := env.stackTopAsV128()
  1399  			var actual [16]byte
  1400  			binary.LittleEndian.PutUint64(actual[:8], lo)
  1401  			binary.LittleEndian.PutUint64(actual[8:], hi)
  1402  			require.Equal(t, tc.exp, actual)
  1403  		})
  1404  	}
  1405  }
  1406  
  1407  func TestCompiler_compileV128Splat(t *testing.T) {
  1408  	tests := []struct {
  1409  		name               string
  1410  		originValueSetupFn func(*testing.T, compilerImpl)
  1411  		shape              wazeroir.Shape
  1412  		exp                [16]byte
  1413  	}{
  1414  		{
  1415  			name: "i8x16",
  1416  			originValueSetupFn: func(t *testing.T, c compilerImpl) {
  1417  				err := c.compileConstI32(&wazeroir.OperationConstI32{Value: 0x1})
  1418  				require.NoError(t, err)
  1419  			},
  1420  			shape: wazeroir.ShapeI8x16,
  1421  			exp:   [16]byte{0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1},
  1422  		},
  1423  		{
  1424  			name: "i16x8",
  1425  			originValueSetupFn: func(t *testing.T, c compilerImpl) {
  1426  				err := c.compileConstI32(&wazeroir.OperationConstI32{Value: 0xff_11})
  1427  				require.NoError(t, err)
  1428  			},
  1429  			shape: wazeroir.ShapeI16x8,
  1430  			exp:   [16]byte{0x11, 0xff, 0x11, 0xff, 0x11, 0xff, 0x11, 0xff, 0x11, 0xff, 0x11, 0xff, 0x11, 0xff, 0x11, 0xff},
  1431  		},
  1432  		{
  1433  			name: "i32x4",
  1434  			originValueSetupFn: func(t *testing.T, c compilerImpl) {
  1435  				err := c.compileConstI32(&wazeroir.OperationConstI32{Value: 0xff_11_ee_22})
  1436  				require.NoError(t, err)
  1437  			},
  1438  			shape: wazeroir.ShapeI32x4,
  1439  			exp:   [16]byte{0x22, 0xee, 0x11, 0xff, 0x22, 0xee, 0x11, 0xff, 0x22, 0xee, 0x11, 0xff, 0x22, 0xee, 0x11, 0xff},
  1440  		},
  1441  		{
  1442  			name: "i64x2",
  1443  			originValueSetupFn: func(t *testing.T, c compilerImpl) {
  1444  				err := c.compileConstI64(&wazeroir.OperationConstI64{Value: 0xff_00_ee_00_11_00_22_00})
  1445  				require.NoError(t, err)
  1446  			},
  1447  			shape: wazeroir.ShapeI64x2,
  1448  			exp:   [16]byte{0x00, 0x22, 0x00, 0x11, 0x00, 0xee, 0x00, 0xff, 0x00, 0x22, 0x00, 0x11, 0x00, 0xee, 0x00, 0xff},
  1449  		},
  1450  		{
  1451  			name: "f32x4",
  1452  			originValueSetupFn: func(t *testing.T, c compilerImpl) {
  1453  				err := c.compileConstF32(&wazeroir.OperationConstF32{Value: math.Float32frombits(0xff_11_ee_22)})
  1454  				require.NoError(t, err)
  1455  			},
  1456  			shape: wazeroir.ShapeF32x4,
  1457  			exp:   [16]byte{0x22, 0xee, 0x11, 0xff, 0x22, 0xee, 0x11, 0xff, 0x22, 0xee, 0x11, 0xff, 0x22, 0xee, 0x11, 0xff},
  1458  		},
  1459  		{
  1460  			name: "f64x2",
  1461  			originValueSetupFn: func(t *testing.T, c compilerImpl) {
  1462  				err := c.compileConstF64(&wazeroir.OperationConstF64{Value: math.Float64frombits(0xff_00_ee_00_11_00_22_00)})
  1463  				require.NoError(t, err)
  1464  			},
  1465  			shape: wazeroir.ShapeF64x2,
  1466  			exp:   [16]byte{0x00, 0x22, 0x00, 0x11, 0x00, 0xee, 0x00, 0xff, 0x00, 0x22, 0x00, 0x11, 0x00, 0xee, 0x00, 0xff},
  1467  		},
  1468  	}
  1469  
  1470  	for _, tc := range tests {
  1471  		tc := tc
  1472  		t.Run(tc.name, func(t *testing.T) {
  1473  			env := newCompilerEnvironment()
  1474  			compiler := env.requireNewCompiler(t, newCompiler,
  1475  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  1476  
  1477  			err := compiler.compilePreamble()
  1478  			require.NoError(t, err)
  1479  
  1480  			tc.originValueSetupFn(t, compiler)
  1481  
  1482  			err = compiler.compileV128Splat(&wazeroir.OperationV128Splat{Shape: tc.shape})
  1483  			require.NoError(t, err)
  1484  
  1485  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  1486  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  1487  
  1488  			err = compiler.compileReturnFunction()
  1489  			require.NoError(t, err)
  1490  
  1491  			// Generate and run the code under test.
  1492  			code, _, err := compiler.compile()
  1493  			require.NoError(t, err)
  1494  			env.exec(code)
  1495  
  1496  			lo, hi := env.stackTopAsV128()
  1497  			var actual [16]byte
  1498  			binary.LittleEndian.PutUint64(actual[:8], lo)
  1499  			binary.LittleEndian.PutUint64(actual[8:], hi)
  1500  			require.Equal(t, tc.exp, actual)
  1501  		})
  1502  	}
  1503  }
  1504  
  1505  func TestCompiler_compileV128AnyTrue(t *testing.T) {
  1506  	tests := []struct {
  1507  		name   string
  1508  		lo, hi uint64
  1509  		exp    uint32
  1510  	}{
  1511  		{name: "lo == 0 && hi == 0", lo: 0, hi: 0, exp: 0},
  1512  		{name: "lo != 0", lo: 1, exp: 1},
  1513  		{name: "hi != 0", hi: 1, exp: 1},
  1514  		{name: "lo != 0 && hi != 0", lo: 1, hi: 1, exp: 1},
  1515  	}
  1516  
  1517  	for _, tc := range tests {
  1518  		tc := tc
  1519  		t.Run(tc.name, func(t *testing.T) {
  1520  			env := newCompilerEnvironment()
  1521  			compiler := env.requireNewCompiler(t, newCompiler,
  1522  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  1523  
  1524  			err := compiler.compilePreamble()
  1525  			require.NoError(t, err)
  1526  
  1527  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{Lo: tc.lo, Hi: tc.hi})
  1528  			require.NoError(t, err)
  1529  
  1530  			err = compiler.compileV128AnyTrue(&wazeroir.OperationV128AnyTrue{})
  1531  			require.NoError(t, err)
  1532  
  1533  			requireRuntimeLocationStackPointerEqual(t, uint64(1), compiler)
  1534  
  1535  			err = compiler.compileReturnFunction()
  1536  			require.NoError(t, err)
  1537  
  1538  			// Generate and run the code under test.
  1539  			code, _, err := compiler.compile()
  1540  			require.NoError(t, err)
  1541  			env.exec(code)
  1542  
  1543  			require.Equal(t, nativeCallStatusCodeReturned, env.callEngine().statusCode)
  1544  			require.Equal(t, uint64(1), env.stackPointer())
  1545  			require.Equal(t, tc.exp, env.stackTopAsUint32())
  1546  		})
  1547  	}
  1548  }
  1549  
  1550  func TestCompiler_compileV128AllTrue(t *testing.T) {
  1551  	tests := []struct {
  1552  		name   string
  1553  		shape  wazeroir.Shape
  1554  		lo, hi uint64
  1555  		exp    uint32
  1556  	}{
  1557  		{
  1558  			name:  "i8x16 - true",
  1559  			shape: wazeroir.ShapeI8x16,
  1560  			lo:    0xffff_ffff_ffff_ffff,
  1561  			hi:    0x0101_0101_0101_0101,
  1562  			exp:   1,
  1563  		},
  1564  		{
  1565  			name:  "i8x16 - false on lo",
  1566  			shape: wazeroir.ShapeI8x16,
  1567  			lo:    0xffff_ffff_ffff_ffff,
  1568  			hi:    0x1111_1111_0011_1111,
  1569  			exp:   0,
  1570  		},
  1571  		{
  1572  			name:  "i8x16 - false on hi",
  1573  			shape: wazeroir.ShapeI8x16,
  1574  			lo:    0xffff_00ff_ffff_ffff,
  1575  			hi:    0x1111_1111_1111_1111,
  1576  			exp:   0,
  1577  		},
  1578  		{
  1579  			name:  "i16x8 - true",
  1580  			shape: wazeroir.ShapeI16x8,
  1581  			lo:    0x1000_0100_0010_0001,
  1582  			hi:    0x0101_0101_0101_0101,
  1583  			exp:   1,
  1584  		},
  1585  		{
  1586  			name:  "i16x8 - false on hi",
  1587  			shape: wazeroir.ShapeI16x8,
  1588  			lo:    0x1000_0100_0010_0001,
  1589  			hi:    0x1111_1111_0000_1111,
  1590  			exp:   0,
  1591  		},
  1592  		{
  1593  			name:  "i16x8 - false on lo",
  1594  			shape: wazeroir.ShapeI16x8,
  1595  			lo:    0xffff_0000_ffff_ffff,
  1596  			hi:    0x1111_1111_1111_1111,
  1597  			exp:   0,
  1598  		},
  1599  		{
  1600  			name:  "i32x4 - true",
  1601  			shape: wazeroir.ShapeI32x4,
  1602  			lo:    0x1000_0000_0010_0000,
  1603  			hi:    0x0000_0001_0000_1000,
  1604  			exp:   1,
  1605  		},
  1606  		{
  1607  			name:  "i32x4 - true",
  1608  			shape: wazeroir.ShapeI32x4,
  1609  			lo:    0x0000_1111_1111_0000,
  1610  			hi:    0x0000_0001_1000_0000,
  1611  			exp:   1,
  1612  		},
  1613  		{
  1614  			name:  "i32x4 - false on lo",
  1615  			shape: wazeroir.ShapeI32x4,
  1616  			lo:    0x1111_1111_0000_0000,
  1617  			hi:    0x1111_1111_1111_1111,
  1618  			exp:   0,
  1619  		},
  1620  		{
  1621  			name:  "i32x4 - false on lo",
  1622  			shape: wazeroir.ShapeI32x4,
  1623  			lo:    0x0000_0000_1111_1111,
  1624  			hi:    0x1111_1111_1111_1111,
  1625  			exp:   0,
  1626  		},
  1627  		{
  1628  			name:  "i32x4 - false on hi",
  1629  			shape: wazeroir.ShapeI32x4,
  1630  			lo:    0x1111_1111_1111_1111,
  1631  			hi:    0x1111_1111_0000_0000,
  1632  			exp:   0,
  1633  		},
  1634  		{
  1635  			name:  "i32x4 - false on hi",
  1636  			shape: wazeroir.ShapeI32x4,
  1637  			lo:    0x1111_1111_1111_1111,
  1638  			hi:    0x0000_0000_1111_1111,
  1639  			exp:   0,
  1640  		},
  1641  
  1642  		{
  1643  			name:  "i64x2 - true",
  1644  			shape: wazeroir.ShapeI64x2,
  1645  			lo:    0x1000_0000_0000_0000,
  1646  			hi:    0x0000_0001_0000_0000,
  1647  			exp:   1,
  1648  		},
  1649  		{
  1650  			name:  "i64x2 - true",
  1651  			shape: wazeroir.ShapeI64x2,
  1652  			lo:    0x0000_0000_0010_0000,
  1653  			hi:    0x0000_0000_0000_0100,
  1654  			exp:   1,
  1655  		},
  1656  		{
  1657  			name:  "i64x2 - true",
  1658  			shape: wazeroir.ShapeI64x2,
  1659  			lo:    0x0000_0000_0000_1000,
  1660  			hi:    0x1000_0000_0000_0000,
  1661  			exp:   1,
  1662  		},
  1663  		{
  1664  			name:  "i64x2 - false on lo",
  1665  			shape: wazeroir.ShapeI64x2,
  1666  			lo:    0,
  1667  			hi:    0x1111_1111_1111_1111,
  1668  			exp:   0,
  1669  		},
  1670  		{
  1671  			name:  "i64x2 - false on hi",
  1672  			shape: wazeroir.ShapeI64x2,
  1673  			lo:    0x1111_1111_1111_1111,
  1674  			hi:    0,
  1675  			exp:   0,
  1676  		},
  1677  	}
  1678  
  1679  	for _, tc := range tests {
  1680  		tc := tc
  1681  		t.Run(tc.name, func(t *testing.T) {
  1682  			env := newCompilerEnvironment()
  1683  			compiler := env.requireNewCompiler(t, newCompiler,
  1684  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  1685  
  1686  			err := compiler.compilePreamble()
  1687  			require.NoError(t, err)
  1688  
  1689  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{Lo: tc.lo, Hi: tc.hi})
  1690  			require.NoError(t, err)
  1691  
  1692  			err = compiler.compileV128AllTrue(&wazeroir.OperationV128AllTrue{Shape: tc.shape})
  1693  			require.NoError(t, err)
  1694  
  1695  			require.Equal(t, 0, len(compiler.runtimeValueLocationStack().usedRegisters))
  1696  
  1697  			err = compiler.compileReturnFunction()
  1698  			require.NoError(t, err)
  1699  
  1700  			// Generate and run the code under test.
  1701  			code, _, err := compiler.compile()
  1702  			require.NoError(t, err)
  1703  			env.exec(code)
  1704  
  1705  			require.Equal(t, nativeCallStatusCodeReturned, env.callEngine().statusCode)
  1706  			require.Equal(t, uint64(1), env.stackPointer())
  1707  			require.Equal(t, tc.exp, env.stackTopAsUint32())
  1708  		})
  1709  	}
  1710  }
  1711  
  1712  func i8ToU8(v int8) byte {
  1713  	return byte(v)
  1714  }
  1715  
  1716  func i16ToU16(v int16) uint16 {
  1717  	return uint16(v)
  1718  }
  1719  
  1720  func i32ToU32(v int32) uint32 {
  1721  	return uint32(v)
  1722  }
  1723  
  1724  func i64ToU64(v int64) uint64 {
  1725  	return uint64(v)
  1726  }
  1727  
  1728  func TestCompiler_compileV128Swizzle(t *testing.T) {
  1729  	tests := []struct {
  1730  		name              string
  1731  		indexVec, baseVec [16]byte
  1732  		expVec            [16]byte
  1733  	}{
  1734  		{
  1735  			name:     "1",
  1736  			baseVec:  [16]byte{16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31},
  1737  			indexVec: [16]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
  1738  			expVec:   [16]byte{16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31},
  1739  		},
  1740  		{
  1741  			name: "2",
  1742  			baseVec: [16]byte{
  1743  				i8ToU8(-16), i8ToU8(-15), i8ToU8(-14), i8ToU8(-13), i8ToU8(-12),
  1744  				i8ToU8(-11), i8ToU8(-10), i8ToU8(-9), i8ToU8(-8), i8ToU8(-7), i8ToU8(-6), i8ToU8(-5),
  1745  				i8ToU8(-4), i8ToU8(-3), i8ToU8(-2), i8ToU8(-1),
  1746  			},
  1747  			indexVec: [16]byte{
  1748  				i8ToU8(-8), i8ToU8(-7), i8ToU8(-6), i8ToU8(-5), i8ToU8(-4),
  1749  				i8ToU8(-3), i8ToU8(-2), i8ToU8(-1), 16, 17, 18, 19, 20, 21, 22, 23,
  1750  			},
  1751  			expVec: [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  1752  		},
  1753  		{
  1754  			name:     "3",
  1755  			baseVec:  [16]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115},
  1756  			indexVec: [16]byte{15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0},
  1757  			expVec:   [16]byte{115, 114, 113, 112, 111, 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, 100},
  1758  		},
  1759  		{
  1760  			name:    "4",
  1761  			baseVec: [16]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115},
  1762  			indexVec: [16]byte{
  1763  				9, 16, 10, 17, 11, 18, 12, 19, 13, 20, 14, 21, 15, 22, 16, 23,
  1764  			},
  1765  			expVec: [16]byte{109, 0, 110, 0, 111, 0, 112, 0, 113, 0, 114, 0, 115, 0, 0, 0},
  1766  		},
  1767  		{
  1768  			name:     "5",
  1769  			baseVec:  [16]byte{0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73},
  1770  			indexVec: [16]byte{9, 16, 10, 17, 11, 18, 12, 19, 13, 20, 14, 21, 15, 22, 16, 23},
  1771  			expVec:   [16]byte{0x6d, 0, 0x6e, 0, 0x6f, 0, 0x70, 0, 0x71, 0, 0x72, 0, 0x73, 0, 0, 0},
  1772  		},
  1773  	}
  1774  
  1775  	for _, tc := range tests {
  1776  		tc := tc
  1777  		t.Run(tc.name, func(t *testing.T) {
  1778  			env := newCompilerEnvironment()
  1779  			compiler := env.requireNewCompiler(t, newCompiler,
  1780  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  1781  
  1782  			err := compiler.compilePreamble()
  1783  			require.NoError(t, err)
  1784  
  1785  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  1786  				Lo: binary.LittleEndian.Uint64(tc.baseVec[:8]),
  1787  				Hi: binary.LittleEndian.Uint64(tc.baseVec[8:]),
  1788  			})
  1789  			require.NoError(t, err)
  1790  
  1791  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  1792  				Lo: binary.LittleEndian.Uint64(tc.indexVec[:8]),
  1793  				Hi: binary.LittleEndian.Uint64(tc.indexVec[8:]),
  1794  			})
  1795  			require.NoError(t, err)
  1796  
  1797  			err = compiler.compileV128Swizzle(&wazeroir.OperationV128Swizzle{})
  1798  			require.NoError(t, err)
  1799  
  1800  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  1801  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  1802  
  1803  			err = compiler.compileReturnFunction()
  1804  			require.NoError(t, err)
  1805  
  1806  			// Generate and run the code under test.
  1807  			code, _, err := compiler.compile()
  1808  			require.NoError(t, err)
  1809  			env.exec(code)
  1810  
  1811  			require.Equal(t, nativeCallStatusCodeReturned, env.callEngine().statusCode)
  1812  
  1813  			lo, hi := env.stackTopAsV128()
  1814  			var actual [16]byte
  1815  			binary.LittleEndian.PutUint64(actual[:8], lo)
  1816  			binary.LittleEndian.PutUint64(actual[8:], hi)
  1817  			require.Equal(t, tc.expVec, actual)
  1818  		})
  1819  	}
  1820  }
  1821  
  1822  func TestCompiler_compileV128Shuffle(t *testing.T) {
  1823  	tests := []struct {
  1824  		name             string
  1825  		lanes, w, v, exp [16]byte
  1826  	}{
  1827  		{
  1828  			name:  "v only",
  1829  			lanes: [16]byte{1, 1, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 0},
  1830  			v:     [16]byte{0: 0xa, 1: 0xb, 10: 0xc},
  1831  			w:     [16]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
  1832  			exp: [16]byte{
  1833  				0xb, 0xb, 0xb, 0xb,
  1834  				0xa, 0xa, 0xa, 0xa,
  1835  				0xc, 0xc, 0xc, 0xc,
  1836  				0xa, 0xa, 0xa, 0xa,
  1837  			},
  1838  		},
  1839  		{
  1840  			name:  "w only",
  1841  			lanes: [16]byte{17, 17, 17, 17, 16, 16, 16, 16, 26, 26, 26, 26, 16, 16, 16, 16},
  1842  			v:     [16]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
  1843  			w:     [16]byte{0: 0xa, 1: 0xb, 10: 0xc},
  1844  			exp: [16]byte{
  1845  				0xb, 0xb, 0xb, 0xb,
  1846  				0xa, 0xa, 0xa, 0xa,
  1847  				0xc, 0xc, 0xc, 0xc,
  1848  				0xa, 0xa, 0xa, 0xa,
  1849  			},
  1850  		},
  1851  		{
  1852  			name:  "mix",
  1853  			lanes: [16]byte{0, 17, 2, 19, 4, 21, 6, 23, 8, 25, 10, 27, 12, 29, 14, 31},
  1854  			v: [16]byte{
  1855  				0x1, 0xff, 0x2, 0xff, 0x3, 0xff, 0x4, 0xff,
  1856  				0x5, 0xff, 0x6, 0xff, 0x7, 0xff, 0x8, 0xff,
  1857  			},
  1858  			w: [16]byte{
  1859  				0xff, 0x11, 0xff, 0x12, 0xff, 0x13, 0xff, 0x14,
  1860  				0xff, 0x15, 0xff, 0x16, 0xff, 0x17, 0xff, 0x18,
  1861  			},
  1862  			exp: [16]byte{
  1863  				0x1, 0x11, 0x2, 0x12, 0x3, 0x13, 0x4, 0x14,
  1864  				0x5, 0x15, 0x6, 0x16, 0x7, 0x17, 0x8, 0x18,
  1865  			},
  1866  		},
  1867  		{
  1868  			name:  "mix",
  1869  			lanes: [16]byte{0, 17, 2, 19, 4, 21, 6, 23, 8, 25, 10, 27, 12, 29, 14, 31},
  1870  			v: [16]byte{
  1871  				0x1, 0xff, 0x2, 0xff, 0x3, 0xff, 0x4, 0xff,
  1872  				0x5, 0xff, 0x6, 0xff, 0x7, 0xff, 0x8, 0xff,
  1873  			},
  1874  			w: [16]byte{
  1875  				0xff, 0x11, 0xff, 0x12, 0xff, 0x13, 0xff, 0x14,
  1876  				0xff, 0x15, 0xff, 0x16, 0xff, 0x17, 0xff, 0x18,
  1877  			},
  1878  			exp: [16]byte{
  1879  				0x1, 0x11, 0x2, 0x12, 0x3, 0x13, 0x4, 0x14,
  1880  				0x5, 0x15, 0x6, 0x16, 0x7, 0x17, 0x8, 0x18,
  1881  			},
  1882  		},
  1883  	}
  1884  
  1885  	for _, tc := range tests {
  1886  		tc := tc
  1887  		t.Run(tc.name, func(t *testing.T) {
  1888  			env := newCompilerEnvironment()
  1889  			compiler := env.requireNewCompiler(t, newCompiler,
  1890  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  1891  
  1892  			err := compiler.compilePreamble()
  1893  			require.NoError(t, err)
  1894  
  1895  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  1896  				Lo: binary.LittleEndian.Uint64(tc.v[:8]),
  1897  				Hi: binary.LittleEndian.Uint64(tc.v[8:]),
  1898  			})
  1899  			require.NoError(t, err)
  1900  
  1901  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  1902  				Lo: binary.LittleEndian.Uint64(tc.w[:8]),
  1903  				Hi: binary.LittleEndian.Uint64(tc.w[8:]),
  1904  			})
  1905  			require.NoError(t, err)
  1906  
  1907  			err = compiler.compileV128Shuffle(&wazeroir.OperationV128Shuffle{Lanes: tc.lanes})
  1908  			require.NoError(t, err)
  1909  
  1910  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  1911  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  1912  
  1913  			err = compiler.compileReturnFunction()
  1914  			require.NoError(t, err)
  1915  
  1916  			// Generate and run the code under test.
  1917  			code, _, err := compiler.compile()
  1918  			require.NoError(t, err)
  1919  			env.exec(code)
  1920  
  1921  			lo, hi := env.stackTopAsV128()
  1922  			var actual [16]byte
  1923  			binary.LittleEndian.PutUint64(actual[:8], lo)
  1924  			binary.LittleEndian.PutUint64(actual[8:], hi)
  1925  			require.Equal(t, tc.exp, actual)
  1926  		})
  1927  	}
  1928  }
  1929  
  1930  func TestCompiler_compileV128Bitmask(t *testing.T) {
  1931  	u16x8 := func(u1, u2, u3, u4, u5, u6, u7, u8 uint16) (ret [16]byte) {
  1932  		binary.LittleEndian.PutUint16(ret[0:], u1)
  1933  		binary.LittleEndian.PutUint16(ret[2:], u2)
  1934  		binary.LittleEndian.PutUint16(ret[4:], u3)
  1935  		binary.LittleEndian.PutUint16(ret[6:], u4)
  1936  		binary.LittleEndian.PutUint16(ret[8:], u5)
  1937  		binary.LittleEndian.PutUint16(ret[10:], u6)
  1938  		binary.LittleEndian.PutUint16(ret[12:], u7)
  1939  		binary.LittleEndian.PutUint16(ret[14:], u8)
  1940  		return
  1941  	}
  1942  	u32x4 := func(u1, u2, u3, u4 uint32) (ret [16]byte) {
  1943  		binary.LittleEndian.PutUint32(ret[0:], u1)
  1944  		binary.LittleEndian.PutUint32(ret[4:], u2)
  1945  		binary.LittleEndian.PutUint32(ret[8:], u3)
  1946  		binary.LittleEndian.PutUint32(ret[12:], u4)
  1947  		return
  1948  	}
  1949  	u64x2 := func(u1, u2 uint64) (ret [16]byte) {
  1950  		binary.LittleEndian.PutUint64(ret[0:], u1)
  1951  		binary.LittleEndian.PutUint64(ret[8:], u2)
  1952  		return
  1953  	}
  1954  
  1955  	tests := []struct {
  1956  		name  string
  1957  		shape wazeroir.Shape
  1958  		v     [16]byte
  1959  		exp   uint32
  1960  	}{
  1961  		{
  1962  			name: wasm.OpcodeVecI8x16BitMaskName,
  1963  			v: [16]byte{
  1964  				i8ToU8(-1), 1, i8ToU8(-1), 1, i8ToU8(-1), 1, i8ToU8(-1), 1,
  1965  				i8ToU8(-1), 1, i8ToU8(-1), 1, i8ToU8(-1), 1, i8ToU8(-1), 1,
  1966  			},
  1967  			shape: wazeroir.ShapeI8x16,
  1968  			exp:   0b0101_0101_0101_0101,
  1969  		},
  1970  		{
  1971  			name: wasm.OpcodeVecI8x16BitMaskName,
  1972  			v: [16]byte{
  1973  				i8ToU8(-1), 1, i8ToU8(-1), 1, i8ToU8(-1), 1, i8ToU8(-1), 1,
  1974  				0, 0, 0, 0, 0, 0, 0, 0,
  1975  			},
  1976  			shape: wazeroir.ShapeI8x16,
  1977  			exp:   0b0000_0000_0101_0101,
  1978  		},
  1979  		{
  1980  			name: wasm.OpcodeVecI8x16BitMaskName,
  1981  			v: [16]byte{
  1982  				0, 0, 0, 0, 0, 0, 0, 0,
  1983  				i8ToU8(-1), 1, i8ToU8(-1), 1, i8ToU8(-1), 1, i8ToU8(-1), 1,
  1984  			},
  1985  			shape: wazeroir.ShapeI8x16,
  1986  			exp:   0b0101_0101_0000_0000,
  1987  		},
  1988  		{
  1989  			name:  wasm.OpcodeVecI16x8BitMaskName,
  1990  			v:     u16x8(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff),
  1991  			shape: wazeroir.ShapeI16x8,
  1992  			exp:   0b1111_1111,
  1993  		},
  1994  		{
  1995  			name:  wasm.OpcodeVecI16x8BitMaskName,
  1996  			v:     u16x8(0, 0xffff, 0, 0xffff, 0, 0xffff, 0, 0xffff),
  1997  			shape: wazeroir.ShapeI16x8,
  1998  			exp:   0b1010_1010,
  1999  		},
  2000  		{
  2001  			name:  wasm.OpcodeVecI32x4BitMaskName,
  2002  			v:     u32x4(0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff),
  2003  			shape: wazeroir.ShapeI32x4,
  2004  			exp:   0b1111,
  2005  		},
  2006  		{
  2007  			name:  wasm.OpcodeVecI32x4BitMaskName,
  2008  			v:     u32x4(0, 0xffffffff, 0xffffffff, 0),
  2009  			shape: wazeroir.ShapeI32x4,
  2010  			exp:   0b0110,
  2011  		},
  2012  		{
  2013  			name:  wasm.OpcodeVecI64x2BitMaskName,
  2014  			v:     u64x2(0, 0xffffffffffffffff),
  2015  			shape: wazeroir.ShapeI64x2,
  2016  			exp:   0b10,
  2017  		},
  2018  		{
  2019  			name:  wasm.OpcodeVecI64x2BitMaskName,
  2020  			v:     u64x2(0xffffffffffffffff, 0xffffffffffffffff),
  2021  			shape: wazeroir.ShapeI64x2,
  2022  			exp:   0b11,
  2023  		},
  2024  	}
  2025  
  2026  	for _, tc := range tests {
  2027  		tc := tc
  2028  		t.Run(tc.name, func(t *testing.T) {
  2029  			env := newCompilerEnvironment()
  2030  			compiler := env.requireNewCompiler(t, newCompiler,
  2031  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  2032  
  2033  			err := compiler.compilePreamble()
  2034  			require.NoError(t, err)
  2035  
  2036  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  2037  				Lo: binary.LittleEndian.Uint64(tc.v[:8]),
  2038  				Hi: binary.LittleEndian.Uint64(tc.v[8:]),
  2039  			})
  2040  			require.NoError(t, err)
  2041  
  2042  			err = compiler.compileV128BitMask(&wazeroir.OperationV128BitMask{Shape: tc.shape})
  2043  			require.NoError(t, err)
  2044  
  2045  			requireRuntimeLocationStackPointerEqual(t, uint64(1), compiler)
  2046  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  2047  
  2048  			err = compiler.compileReturnFunction()
  2049  			require.NoError(t, err)
  2050  
  2051  			// Generate and run the code under test.
  2052  
  2053  			code, _, err := compiler.compile()
  2054  			require.NoError(t, err)
  2055  			env.exec(code)
  2056  
  2057  			actual := env.stackTopAsUint32()
  2058  			require.Equal(t, tc.exp, actual)
  2059  		})
  2060  	}
  2061  }
  2062  
  2063  func TestCompiler_compileV128_Not(t *testing.T) {
  2064  	env := newCompilerEnvironment()
  2065  	compiler := env.requireNewCompiler(t, newCompiler,
  2066  		&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  2067  
  2068  	err := compiler.compilePreamble()
  2069  	require.NoError(t, err)
  2070  
  2071  	var originalLo, originalHi uint64 = 0xffff_0000_ffff_0000, 0x0000_ffff_0000_ffff
  2072  
  2073  	err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  2074  		Lo: originalLo,
  2075  		Hi: originalHi,
  2076  	})
  2077  	require.NoError(t, err)
  2078  
  2079  	err = compiler.compileV128Not(&wazeroir.OperationV128Not{})
  2080  	require.NoError(t, err)
  2081  
  2082  	requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  2083  	require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  2084  
  2085  	err = compiler.compileReturnFunction()
  2086  	require.NoError(t, err)
  2087  
  2088  	// Generate and run the code under test.
  2089  	code, _, err := compiler.compile()
  2090  	require.NoError(t, err)
  2091  	env.exec(code)
  2092  
  2093  	lo, hi := env.stackTopAsV128()
  2094  	require.Equal(t, ^originalLo, lo)
  2095  	require.Equal(t, ^originalHi, hi)
  2096  }
  2097  
  2098  func TestCompiler_compileV128_And_Or_Xor_AndNot(t *testing.T) {
  2099  	tests := []struct {
  2100  		name        string
  2101  		op          wazeroir.OperationKind
  2102  		x1, x2, exp [16]byte
  2103  	}{
  2104  		{
  2105  			name: "AND",
  2106  			op:   wazeroir.OperationKindV128And,
  2107  			x1: [16]byte{
  2108  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2109  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2110  			},
  2111  			x2:  [16]byte{},
  2112  			exp: [16]byte{},
  2113  		},
  2114  		{
  2115  			name: "AND",
  2116  			op:   wazeroir.OperationKindV128And,
  2117  			x2: [16]byte{
  2118  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2119  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2120  			},
  2121  			x1:  [16]byte{},
  2122  			exp: [16]byte{},
  2123  		},
  2124  		{
  2125  			name: "AND",
  2126  			op:   wazeroir.OperationKindV128And,
  2127  			x2: [16]byte{
  2128  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2129  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2130  			},
  2131  			x1:  [16]byte{0: 0x1, 5: 0x1, 15: 0x1},
  2132  			exp: [16]byte{0: 0x1, 5: 0x1, 15: 0x1},
  2133  		},
  2134  		{
  2135  			name: "OR",
  2136  			op:   wazeroir.OperationKindV128Or,
  2137  			x1: [16]byte{
  2138  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2139  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2140  			},
  2141  			x2: [16]byte{},
  2142  			exp: [16]byte{
  2143  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2144  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2145  			},
  2146  		},
  2147  		{
  2148  			name: "OR",
  2149  			op:   wazeroir.OperationKindV128Or,
  2150  			x2: [16]byte{
  2151  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2152  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2153  			},
  2154  			x1: [16]byte{},
  2155  			exp: [16]byte{
  2156  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2157  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2158  			},
  2159  		},
  2160  		{
  2161  			name: "OR",
  2162  			op:   wazeroir.OperationKindV128Or,
  2163  			x2:   [16]byte{},
  2164  			x1:   [16]byte{0: 0x1, 5: 0x1, 15: 0x1},
  2165  			exp:  [16]byte{0: 0x1, 5: 0x1, 15: 0x1},
  2166  		},
  2167  		{
  2168  			name: "OR",
  2169  			op:   wazeroir.OperationKindV128Or,
  2170  			x2:   [16]byte{8: 0x1, 10: 0x1},
  2171  			x1:   [16]byte{0: 0x1},
  2172  			exp:  [16]byte{0: 0x1, 8: 0x1, 10: 0x1},
  2173  		},
  2174  		{
  2175  			name: "XOR",
  2176  			op:   wazeroir.OperationKindV128Xor,
  2177  			x1: [16]byte{
  2178  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2179  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2180  			},
  2181  			x2: [16]byte{},
  2182  			exp: [16]byte{
  2183  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2184  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2185  			},
  2186  		},
  2187  		{
  2188  			name: "XOR",
  2189  			op:   wazeroir.OperationKindV128Xor,
  2190  			x2: [16]byte{
  2191  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2192  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2193  			},
  2194  			x1: [16]byte{},
  2195  			exp: [16]byte{
  2196  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2197  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2198  			},
  2199  		},
  2200  		{
  2201  			name: "XOR",
  2202  			op:   wazeroir.OperationKindV128Xor,
  2203  			x2: [16]byte{
  2204  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2205  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2206  			},
  2207  			x1: [16]byte{
  2208  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2209  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2210  			},
  2211  			exp: [16]byte{},
  2212  		},
  2213  		{
  2214  			name: "XOR",
  2215  			op:   wazeroir.OperationKindV128Xor,
  2216  			x2: [16]byte{
  2217  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2218  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2219  			},
  2220  			x1: [16]byte{0: 0x1, 15: 0x2},
  2221  			exp: [16]byte{
  2222  				0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2223  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd,
  2224  			},
  2225  		},
  2226  
  2227  		{
  2228  			name: "AndNot",
  2229  			op:   wazeroir.OperationKindV128AndNot,
  2230  			x2:   [16]byte{},
  2231  			x1: [16]byte{
  2232  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2233  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2234  			},
  2235  			exp: [16]byte{
  2236  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2237  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2238  			},
  2239  		},
  2240  		{
  2241  			name: "AndNot",
  2242  			op:   wazeroir.OperationKindV128AndNot,
  2243  			x2: [16]byte{
  2244  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2245  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2246  			},
  2247  			x1:  [16]byte{},
  2248  			exp: [16]byte{},
  2249  		},
  2250  		{
  2251  			name: "AndNot",
  2252  			op:   wazeroir.OperationKindV128AndNot,
  2253  			x2: [16]byte{
  2254  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2255  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2256  			},
  2257  			x1: [16]byte{
  2258  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2259  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2260  			},
  2261  			exp: [16]byte{},
  2262  		},
  2263  		{
  2264  			name: "AndNot",
  2265  			op:   wazeroir.OperationKindV128AndNot,
  2266  			x2: [16]byte{
  2267  				0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2268  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd,
  2269  			},
  2270  			x1:  [16]byte{0: 0x1, 15: 0x2},
  2271  			exp: [16]byte{0: 0x1, 15: 0x2},
  2272  		},
  2273  	}
  2274  
  2275  	for _, tc := range tests {
  2276  		tc := tc
  2277  		t.Run(tc.name, func(t *testing.T) {
  2278  			env := newCompilerEnvironment()
  2279  			compiler := env.requireNewCompiler(t, newCompiler,
  2280  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  2281  
  2282  			err := compiler.compilePreamble()
  2283  			require.NoError(t, err)
  2284  
  2285  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  2286  				Lo: binary.LittleEndian.Uint64(tc.x1[:8]),
  2287  				Hi: binary.LittleEndian.Uint64(tc.x1[8:]),
  2288  			})
  2289  			require.NoError(t, err)
  2290  
  2291  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  2292  				Lo: binary.LittleEndian.Uint64(tc.x2[:8]),
  2293  				Hi: binary.LittleEndian.Uint64(tc.x2[8:]),
  2294  			})
  2295  			require.NoError(t, err)
  2296  
  2297  			switch tc.op {
  2298  			case wazeroir.OperationKindV128And:
  2299  				err = compiler.compileV128And(nil) // And doesn't use the param.
  2300  			case wazeroir.OperationKindV128Or:
  2301  				err = compiler.compileV128Or(nil) // Or doesn't use the param.
  2302  			case wazeroir.OperationKindV128Xor:
  2303  				err = compiler.compileV128Xor(nil) // Xor doesn't use the param.
  2304  			case wazeroir.OperationKindV128AndNot:
  2305  				err = compiler.compileV128AndNot(nil) // AndNot doesn't use the param.
  2306  			}
  2307  			require.NoError(t, err)
  2308  
  2309  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  2310  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  2311  
  2312  			err = compiler.compileReturnFunction()
  2313  			require.NoError(t, err)
  2314  
  2315  			// Generate and run the code under test.
  2316  			code, _, err := compiler.compile()
  2317  			require.NoError(t, err)
  2318  			env.exec(code)
  2319  
  2320  			lo, hi := env.stackTopAsV128()
  2321  			var actual [16]byte
  2322  			binary.LittleEndian.PutUint64(actual[:8], lo)
  2323  			binary.LittleEndian.PutUint64(actual[8:], hi)
  2324  			require.Equal(t, tc.exp, actual)
  2325  		})
  2326  	}
  2327  }
  2328  
  2329  func TestCompiler_compileV128Bitselect(t *testing.T) {
  2330  	tests := []struct {
  2331  		name                  string
  2332  		selector, x1, x2, exp [16]byte
  2333  	}{
  2334  		{
  2335  			name: "all x1",
  2336  			selector: [16]byte{
  2337  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2338  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2339  			},
  2340  			x1:  [16]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
  2341  			x2:  [16]byte{2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2},
  2342  			exp: [16]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
  2343  		},
  2344  		{
  2345  			name:     "all x2",
  2346  			selector: [16]byte{},
  2347  			x1:       [16]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
  2348  			x2:       [16]byte{2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2},
  2349  			exp:      [16]byte{2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2},
  2350  		},
  2351  		{
  2352  			name: "mix",
  2353  			selector: [16]byte{
  2354  				0b1111_0000, 0b1111_0000, 0b1111_0000, 0b1111_0000, 0b1111_0000, 0b1111_0000, 0b1111_0000, 0b1111_0000,
  2355  				0b0000_0000, 0b0000_0000, 0b0000_0000, 0b0000_0000, 0b1111_1111, 0b1111_1111, 0b1111_1111, 0b1111_1111,
  2356  			},
  2357  			x1: [16]byte{
  2358  				0b1010_1010, 0b1010_1010, 0b1010_1010, 0b1010_1010, 0b1010_1010, 0b1010_1010, 0b1010_1010, 0b1010_1010,
  2359  				0b1010_1010, 0b1010_1010, 0b1010_1010, 0b1010_1010, 0b1010_1010, 0b1010_1010, 0b1010_1010, 0b1010_1010,
  2360  			},
  2361  			x2: [16]byte{
  2362  				0b0101_0101, 0b0101_0101, 0b0101_0101, 0b0101_0101, 0b0101_0101, 0b0101_0101, 0b0101_0101, 0b0101_0101,
  2363  				0b0101_0101, 0b0101_0101, 0b0101_0101, 0b0101_0101, 0b0101_0101, 0b0101_0101, 0b0101_0101, 0b0101_0101,
  2364  			},
  2365  			exp: [16]byte{
  2366  				0b1010_0101, 0b1010_0101, 0b1010_0101, 0b1010_0101, 0b1010_0101, 0b1010_0101, 0b1010_0101, 0b1010_0101,
  2367  				0b0101_0101, 0b0101_0101, 0b0101_0101, 0b0101_0101, 0b1010_1010, 0b1010_1010, 0b1010_1010, 0b1010_1010,
  2368  			},
  2369  		},
  2370  	}
  2371  
  2372  	for _, tc := range tests {
  2373  		tc := tc
  2374  		t.Run(tc.name, func(t *testing.T) {
  2375  			env := newCompilerEnvironment()
  2376  			compiler := env.requireNewCompiler(t, newCompiler,
  2377  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  2378  
  2379  			err := compiler.compilePreamble()
  2380  			require.NoError(t, err)
  2381  
  2382  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  2383  				Lo: binary.LittleEndian.Uint64(tc.x1[:8]),
  2384  				Hi: binary.LittleEndian.Uint64(tc.x1[8:]),
  2385  			})
  2386  			require.NoError(t, err)
  2387  
  2388  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  2389  				Lo: binary.LittleEndian.Uint64(tc.x2[:8]),
  2390  				Hi: binary.LittleEndian.Uint64(tc.x2[8:]),
  2391  			})
  2392  			require.NoError(t, err)
  2393  
  2394  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  2395  				Lo: binary.LittleEndian.Uint64(tc.selector[:8]),
  2396  				Hi: binary.LittleEndian.Uint64(tc.selector[8:]),
  2397  			})
  2398  			require.NoError(t, err)
  2399  
  2400  			err = compiler.compileV128Bitselect(nil)
  2401  			require.NoError(t, err)
  2402  
  2403  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  2404  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  2405  
  2406  			err = compiler.compileReturnFunction()
  2407  			require.NoError(t, err)
  2408  
  2409  			// Generate and run the code under test.
  2410  			code, _, err := compiler.compile()
  2411  			require.NoError(t, err)
  2412  			env.exec(code)
  2413  
  2414  			lo, hi := env.stackTopAsV128()
  2415  			var actual [16]byte
  2416  			binary.LittleEndian.PutUint64(actual[:8], lo)
  2417  			binary.LittleEndian.PutUint64(actual[8:], hi)
  2418  			require.Equal(t, tc.exp, actual)
  2419  		})
  2420  	}
  2421  }
  2422  
  2423  func TestCompiler_compileV128Shl(t *testing.T) {
  2424  	tests := []struct {
  2425  		name   string
  2426  		shape  wazeroir.Shape
  2427  		s      uint32
  2428  		x, exp [16]byte
  2429  	}{
  2430  		{
  2431  			name:  "i8x16/shift=0",
  2432  			shape: wazeroir.ShapeI8x16,
  2433  			x: [16]byte{
  2434  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2435  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2436  			},
  2437  			exp: [16]byte{
  2438  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2439  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2440  			},
  2441  			s: 0,
  2442  		},
  2443  		{
  2444  			name:  "i8x16/shift=1",
  2445  			shape: wazeroir.ShapeI8x16,
  2446  			x: [16]byte{
  2447  				1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff,
  2448  				1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff,
  2449  			},
  2450  			exp: [16]byte{
  2451  				2, 0xfe, 2, 0xfe, 2, 0xfe, 2, 0xfe,
  2452  				2, 0xfe, 2, 0xfe, 2, 0xfe, 2, 0xfe,
  2453  			},
  2454  			s: 1,
  2455  		},
  2456  		{
  2457  			name:  "i8x16/shift=2",
  2458  			shape: wazeroir.ShapeI8x16,
  2459  			x: [16]byte{
  2460  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2461  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2462  			},
  2463  			exp: [16]byte{
  2464  				4, 0, 4, 0, 4, 0, 4, 0,
  2465  				4, 0, 4, 0, 4, 0, 4, 0,
  2466  			},
  2467  			s: 2,
  2468  		},
  2469  		{
  2470  			name:  "i8x16/shift=3",
  2471  			shape: wazeroir.ShapeI8x16,
  2472  			x: [16]byte{
  2473  				1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff,
  2474  				1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff,
  2475  			},
  2476  			exp: [16]byte{
  2477  				8, 0xff & ^0b111, 8, 0xff & ^0b111, 8, 0xff & ^0b111, 8, 0xff & ^0b111,
  2478  				8, 0xff & ^0b111, 8, 0xff & ^0b111, 8, 0xff & ^0b111, 8, 0xff & ^0b111,
  2479  			},
  2480  			s: 3,
  2481  		},
  2482  		{
  2483  			name:  "i8x16/shift=4",
  2484  			shape: wazeroir.ShapeI8x16,
  2485  			x: [16]byte{
  2486  				0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1,
  2487  				0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1,
  2488  			},
  2489  			exp: [16]byte{
  2490  				0xff & ^0b1111, 16, 0xff & ^0b1111, 16, 0xff & ^0b1111, 16, 0xff & ^0b1111, 16,
  2491  				0xff & ^0b1111, 16, 0xff & ^0b1111, 16, 0xff & ^0b1111, 16, 0xff & ^0b1111, 16,
  2492  			},
  2493  			s: 4,
  2494  		},
  2495  		{
  2496  			name:  "i8x16/shift=5",
  2497  			shape: wazeroir.ShapeI8x16,
  2498  			x: [16]byte{
  2499  				0xff, 0xff, 0xff, 0xff, 1, 1, 1, 1,
  2500  				0xff, 0xff, 0xff, 0xff, 1, 1, 1, 1,
  2501  			},
  2502  			exp: [16]byte{
  2503  				0xff & ^0b11111, 0xff & ^0b11111, 0xff & ^0b11111, 0xff & ^0b11111, 32, 32, 32, 32,
  2504  				0xff & ^0b11111, 0xff & ^0b11111, 0xff & ^0b11111, 0xff & ^0b11111, 32, 32, 32, 32,
  2505  			},
  2506  			s: 5,
  2507  		},
  2508  		{
  2509  			name:  "i8x16/shift=6",
  2510  			shape: wazeroir.ShapeI8x16,
  2511  			x: [16]byte{
  2512  				0xff, 0x81, 0xff, 0x81, 0xff, 0x81, 0xff, 0x81,
  2513  				0xff, 0x81, 0xff, 0x81, 0xff, 0x81, 0xff, 0x81,
  2514  			},
  2515  			exp: [16]byte{
  2516  				0xc0, 1 << 6, 0xc0, 1 << 6, 0xc0, 1 << 6, 0xc0, 1 << 6,
  2517  				0xc0, 1 << 6, 0xc0, 1 << 6, 0xc0, 1 << 6, 0xc0, 1 << 6,
  2518  			},
  2519  			s: 6,
  2520  		},
  2521  		{
  2522  			name:  "i8x16/shift=7",
  2523  			shape: wazeroir.ShapeI8x16,
  2524  			x: [16]byte{
  2525  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2526  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2527  			},
  2528  			exp: [16]byte{
  2529  				0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
  2530  				0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
  2531  			},
  2532  			s: 7,
  2533  		},
  2534  		{
  2535  			name:  "i16x8/shift=0",
  2536  			shape: wazeroir.ShapeI16x8,
  2537  			x: [16]byte{
  2538  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2539  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2540  			},
  2541  			exp: [16]byte{
  2542  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2543  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2544  			},
  2545  			s: 0,
  2546  		},
  2547  		{
  2548  			name:  "i16x8/shift=1",
  2549  			shape: wazeroir.ShapeI16x8,
  2550  			x: [16]byte{
  2551  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2552  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2553  			},
  2554  			exp: [16]byte{
  2555  				2, 0, 2, 0, 2, 0, 2, 0,
  2556  				2, 0, 2, 0, 2, 0, 2, 0,
  2557  			},
  2558  			s: 1,
  2559  		},
  2560  		{
  2561  			name:  "i16x8/shift=7",
  2562  			shape: wazeroir.ShapeI16x8,
  2563  			x: [16]byte{
  2564  				1, 1, 1, 1, 0x80, 0x80, 0x80, 0x80,
  2565  				0, 0x80, 0, 0x80, 0b11, 0b11, 0b11, 0b11,
  2566  			},
  2567  			exp: [16]byte{
  2568  				0, 1, 0, 1, 0, 0x80, 0, 0x80,
  2569  				0, 0, 0, 0, 0, 0b11, 0, 0b11,
  2570  			},
  2571  			s: 8,
  2572  		},
  2573  		{
  2574  			name:  "i16x8/shift=15",
  2575  			shape: wazeroir.ShapeI16x8,
  2576  			x: [16]byte{
  2577  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2578  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2579  			},
  2580  			exp: [16]byte{
  2581  				0, 0x80, 0, 0x80, 0, 0x80, 0, 0x80,
  2582  				0, 0x80, 0, 0x80, 0, 0x80, 0, 0x80,
  2583  			},
  2584  			s: 15,
  2585  		},
  2586  		{
  2587  			name:  "i32x4/shift=0",
  2588  			shape: wazeroir.ShapeI32x4,
  2589  			x: [16]byte{
  2590  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2591  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2592  			},
  2593  			exp: [16]byte{
  2594  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2595  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2596  			},
  2597  			s: 0,
  2598  		},
  2599  		{
  2600  			name:  "i32x4/shift=1",
  2601  			shape: wazeroir.ShapeI32x4,
  2602  			x: [16]byte{
  2603  				1, 0x80, 0, 0x80, 1, 0x80, 0, 0x80,
  2604  				1, 0x80, 0, 0x80, 1, 0x80, 0, 0x80,
  2605  			},
  2606  			exp: [16]byte{
  2607  				2, 0, 1, 0, 2, 0, 1, 0,
  2608  				2, 0, 1, 0, 2, 0, 1, 0,
  2609  			},
  2610  			s: 1,
  2611  		},
  2612  		{
  2613  			name:  "i32x4/shift=31",
  2614  			shape: wazeroir.ShapeI32x4,
  2615  			x: [16]byte{
  2616  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2617  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2618  			},
  2619  			exp: [16]byte{
  2620  				0, 0, 0, 0x80, 0, 0, 0, 0x80,
  2621  				0, 0, 0, 0x80, 0, 0, 0, 0x80,
  2622  			},
  2623  			s: 31,
  2624  		},
  2625  		{
  2626  			name:  "i64x2/shift=0",
  2627  			shape: wazeroir.ShapeI64x2,
  2628  			x: [16]byte{
  2629  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2630  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2631  			},
  2632  			exp: [16]byte{
  2633  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2634  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2635  			},
  2636  			s: 0,
  2637  		},
  2638  		{
  2639  			name:  "i64x2/shift=5",
  2640  			shape: wazeroir.ShapeI64x2,
  2641  			x: [16]byte{
  2642  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2643  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2644  			},
  2645  			exp: [16]byte{
  2646  				1 << 5, 0, 1<<4 | 1<<5, 0, 1<<4 | 1<<5, 0, 1<<4 | 1<<5, 0,
  2647  				1 << 5, 0, 1<<4 | 1<<5, 0, 1<<4 | 1<<5, 0, 1<<4 | 1<<5, 0,
  2648  			},
  2649  			s: 5,
  2650  		},
  2651  		{
  2652  			name:  "i64x2/shift=63",
  2653  			shape: wazeroir.ShapeI64x2,
  2654  			x: [16]byte{
  2655  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2656  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  2657  			},
  2658  			exp: [16]byte{
  2659  				0, 0, 0, 0, 0, 0, 0, 0x80,
  2660  				0, 0, 0, 0, 0, 0, 0, 0x80,
  2661  			},
  2662  			s: 63,
  2663  		},
  2664  	}
  2665  
  2666  	for _, tc := range tests {
  2667  		tc := tc
  2668  		t.Run(tc.name, func(t *testing.T) {
  2669  			env := newCompilerEnvironment()
  2670  			compiler := env.requireNewCompiler(t, newCompiler,
  2671  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  2672  
  2673  			err := compiler.compilePreamble()
  2674  			require.NoError(t, err)
  2675  
  2676  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  2677  				Lo: binary.LittleEndian.Uint64(tc.x[:8]),
  2678  				Hi: binary.LittleEndian.Uint64(tc.x[8:]),
  2679  			})
  2680  			require.NoError(t, err)
  2681  
  2682  			err = compiler.compileConstI32(&wazeroir.OperationConstI32{Value: tc.s})
  2683  			require.NoError(t, err)
  2684  
  2685  			err = compiler.compileV128Shl(&wazeroir.OperationV128Shl{Shape: tc.shape})
  2686  			require.NoError(t, err)
  2687  
  2688  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  2689  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  2690  
  2691  			err = compiler.compileReturnFunction()
  2692  			require.NoError(t, err)
  2693  
  2694  			// Generate and run the code under test.
  2695  			code, _, err := compiler.compile()
  2696  			require.NoError(t, err)
  2697  			env.exec(code)
  2698  
  2699  			lo, hi := env.stackTopAsV128()
  2700  			var actual [16]byte
  2701  			binary.LittleEndian.PutUint64(actual[:8], lo)
  2702  			binary.LittleEndian.PutUint64(actual[8:], hi)
  2703  			require.Equal(t, tc.exp, actual)
  2704  		})
  2705  	}
  2706  }
  2707  
  2708  func TestCompiler_compileV128Shr(t *testing.T) {
  2709  	tests := []struct {
  2710  		name   string
  2711  		signed bool
  2712  		shape  wazeroir.Shape
  2713  		s      uint32
  2714  		x, exp [16]byte
  2715  	}{
  2716  		{
  2717  			name:  "i8x16/shift=0/signed=false",
  2718  			shape: wazeroir.ShapeI8x16,
  2719  			x: [16]byte{
  2720  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2721  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2722  			},
  2723  			exp: [16]byte{
  2724  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2725  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2726  			},
  2727  			s:      0,
  2728  			signed: false,
  2729  		},
  2730  		{
  2731  			name:  "i8x16/shift=7/signed=false",
  2732  			shape: wazeroir.ShapeI8x16,
  2733  			x: [16]byte{
  2734  				0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
  2735  				0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
  2736  			},
  2737  			exp: [16]byte{
  2738  				1, 1, 1, 1, 1, 1, 1, 1,
  2739  				1, 1, 1, 1, 1, 1, 1, 1,
  2740  			},
  2741  			s:      7,
  2742  			signed: false,
  2743  		},
  2744  		{
  2745  			name:  "i8x16/shift=0/signed=false",
  2746  			shape: wazeroir.ShapeI8x16,
  2747  			x: [16]byte{
  2748  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2749  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2750  			},
  2751  			exp: [16]byte{
  2752  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2753  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2754  			},
  2755  			s:      0,
  2756  			signed: true,
  2757  		},
  2758  		{
  2759  			name:  "i8x16/shift=7/signed=false",
  2760  			shape: wazeroir.ShapeI8x16,
  2761  			x: [16]byte{
  2762  				1, 0x80, 0x7e, 0x80, 1, 0x80, 0x7e, 0x80,
  2763  				1, 0x80, 0x7e, 0x80, 1, 0x80, 0x7e, 0x80,
  2764  			},
  2765  			exp: [16]byte{
  2766  				0, 0xff, 0, 0xff, 0, 0xff, 0, 0xff,
  2767  				0, 0xff, 0, 0xff, 0, 0xff, 0, 0xff,
  2768  			},
  2769  			s:      7,
  2770  			signed: true,
  2771  		},
  2772  		{
  2773  			name:  "i16x8/shift=0/signed=false",
  2774  			shape: wazeroir.ShapeI16x8,
  2775  			x: [16]byte{
  2776  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2777  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2778  			},
  2779  			exp: [16]byte{
  2780  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2781  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2782  			},
  2783  			s:      0,
  2784  			signed: false,
  2785  		},
  2786  		{
  2787  			name:  "i16x8/shift=8/signed=false",
  2788  			shape: wazeroir.ShapeI16x8,
  2789  			x: [16]byte{
  2790  				0xff, 0x80, 0xff, 0x80, 0xff, 0x80, 0xff, 0x80,
  2791  				0xff, 0x80, 0xff, 0x80, 0xff, 0x80, 0xff, 0x80,
  2792  			},
  2793  			exp: [16]byte{
  2794  				0x80, 0, 0x80, 0, 0x80, 0, 0x80, 0,
  2795  				0x80, 0, 0x80, 0, 0x80, 0, 0x80, 0,
  2796  			},
  2797  			s:      8,
  2798  			signed: false,
  2799  		},
  2800  		{
  2801  			name:  "i16x8/shift=0/signed=true",
  2802  			shape: wazeroir.ShapeI16x8,
  2803  			x: [16]byte{
  2804  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2805  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2806  			},
  2807  			exp: [16]byte{
  2808  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2809  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2810  			},
  2811  			s:      0,
  2812  			signed: true,
  2813  		},
  2814  		{
  2815  			name:  "i16x8/shift=8/signed=true",
  2816  			shape: wazeroir.ShapeI16x8,
  2817  			x: [16]byte{
  2818  				0xff, 0x80, 0xff, 0x80, 0xff, 0x80, 0xff, 0x80,
  2819  				0xff, 0x80, 0xff, 0x80, 0xff, 0x80, 0xff, 0x80,
  2820  			},
  2821  			exp: [16]byte{
  2822  				0x80, 0xff, 0x80, 0xff, 0x80, 0xff, 0x80, 0xff,
  2823  				0x80, 0xff, 0x80, 0xff, 0x80, 0xff, 0x80, 0xff,
  2824  			},
  2825  			s:      8,
  2826  			signed: true,
  2827  		},
  2828  		{
  2829  			name:  "i32x4/shift=0/signed=false",
  2830  			shape: wazeroir.ShapeI32x4,
  2831  			x: [16]byte{
  2832  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2833  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2834  			},
  2835  			exp: [16]byte{
  2836  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2837  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2838  			},
  2839  			s:      0,
  2840  			signed: false,
  2841  		},
  2842  		{
  2843  			name:  "i32x4/shift=16/signed=false",
  2844  			shape: wazeroir.ShapeI32x4,
  2845  			x: [16]byte{
  2846  				0, 0, 0, 0x80, 0, 0, 0, 0x80,
  2847  				0, 0, 0, 0x80, 0, 0, 0, 0x80,
  2848  			},
  2849  			exp: [16]byte{
  2850  				0, 0x80, 0, 0, 0, 0x80, 0, 0,
  2851  				0, 0x80, 0, 0, 0, 0x80, 0, 0,
  2852  			},
  2853  			s:      16,
  2854  			signed: false,
  2855  		},
  2856  		{
  2857  			name:  "i32x4/shift=0/signed=true",
  2858  			shape: wazeroir.ShapeI32x4,
  2859  			x: [16]byte{
  2860  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2861  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2862  			},
  2863  			exp: [16]byte{
  2864  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2865  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2866  			},
  2867  			s:      0,
  2868  			signed: true,
  2869  		},
  2870  		{
  2871  			name:  "i32x4/shift=16/signed=true",
  2872  			shape: wazeroir.ShapeI32x4,
  2873  			x: [16]byte{
  2874  				0, 0, 0, 0x80, 0, 0, 0, 0x80,
  2875  				0, 0, 0, 0x80, 0, 0, 0, 0x80,
  2876  			},
  2877  			exp: [16]byte{
  2878  				0, 0x80, 0xff, 0xff, 0, 0x80, 0xff, 0xff,
  2879  				0, 0x80, 0xff, 0xff, 0, 0x80, 0xff, 0xff,
  2880  			},
  2881  			s:      16,
  2882  			signed: true,
  2883  		},
  2884  		{
  2885  			name:  "i64x2/shift=0/signed=false",
  2886  			shape: wazeroir.ShapeI32x4,
  2887  			x: [16]byte{
  2888  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2889  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2890  			},
  2891  			exp: [16]byte{
  2892  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2893  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2894  			},
  2895  			s:      0,
  2896  			signed: false,
  2897  		},
  2898  		{
  2899  			name:  "i64x2/shift=16/signed=false",
  2900  			shape: wazeroir.ShapeI64x2,
  2901  			x: [16]byte{
  2902  				0, 0, 0, 0x80, 0, 0, 0, 0x80,
  2903  				0, 0, 0, 0x80, 0, 0, 0, 0x80,
  2904  			},
  2905  			exp: [16]byte{
  2906  				0, 0x80, 0, 0, 0, 0x80, 0, 0,
  2907  				0, 0x80, 0, 0, 0, 0x80, 0, 0,
  2908  			},
  2909  			s:      16,
  2910  			signed: false,
  2911  		},
  2912  		{
  2913  			name:  "i64x2/shift=0/signed=true",
  2914  			shape: wazeroir.ShapeI64x2,
  2915  			x: [16]byte{
  2916  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2917  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2918  			},
  2919  			exp: [16]byte{
  2920  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2921  				1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80,
  2922  			},
  2923  			s:      0,
  2924  			signed: true,
  2925  		},
  2926  		{
  2927  			name:  "i64x2/shift=16/signed=true",
  2928  			shape: wazeroir.ShapeI64x2,
  2929  			x: [16]byte{
  2930  				0, 0, 0, 0x80, 0, 0, 0, 0x80,
  2931  				0, 0, 0, 0x80, 0, 0, 0, 0x80,
  2932  			},
  2933  			exp: [16]byte{
  2934  				0, 0x80, 0, 0, 0, 0x80, 0xff, 0xff,
  2935  				0, 0x80, 0, 0, 0, 0x80, 0xff, 0xff,
  2936  			},
  2937  			s:      16,
  2938  			signed: true,
  2939  		},
  2940  	}
  2941  
  2942  	for _, tc := range tests {
  2943  		tc := tc
  2944  		t.Run(tc.name, func(t *testing.T) {
  2945  			env := newCompilerEnvironment()
  2946  			compiler := env.requireNewCompiler(t, newCompiler,
  2947  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  2948  
  2949  			err := compiler.compilePreamble()
  2950  			require.NoError(t, err)
  2951  
  2952  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  2953  				Lo: binary.LittleEndian.Uint64(tc.x[:8]),
  2954  				Hi: binary.LittleEndian.Uint64(tc.x[8:]),
  2955  			})
  2956  			require.NoError(t, err)
  2957  
  2958  			err = compiler.compileConstI32(&wazeroir.OperationConstI32{Value: tc.s})
  2959  			require.NoError(t, err)
  2960  
  2961  			err = compiler.compileV128Shr(&wazeroir.OperationV128Shr{Shape: tc.shape, Signed: tc.signed})
  2962  			require.NoError(t, err)
  2963  
  2964  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  2965  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  2966  
  2967  			err = compiler.compileReturnFunction()
  2968  			require.NoError(t, err)
  2969  
  2970  			// Generate and run the code under test.
  2971  			code, _, err := compiler.compile()
  2972  			require.NoError(t, err)
  2973  			env.exec(code)
  2974  
  2975  			lo, hi := env.stackTopAsV128()
  2976  			var actual [16]byte
  2977  			binary.LittleEndian.PutUint64(actual[:8], lo)
  2978  			binary.LittleEndian.PutUint64(actual[8:], hi)
  2979  			require.Equal(t, tc.exp, actual)
  2980  		})
  2981  	}
  2982  }
  2983  
  2984  func i16x8(i1, i2, i3, i4, i5, i6, i7, i8 uint16) (ret [16]byte) {
  2985  	binary.LittleEndian.PutUint16(ret[0:], i1)
  2986  	binary.LittleEndian.PutUint16(ret[2:], i2)
  2987  	binary.LittleEndian.PutUint16(ret[4:], i3)
  2988  	binary.LittleEndian.PutUint16(ret[6:], i4)
  2989  	binary.LittleEndian.PutUint16(ret[8:], i5)
  2990  	binary.LittleEndian.PutUint16(ret[10:], i6)
  2991  	binary.LittleEndian.PutUint16(ret[12:], i7)
  2992  	binary.LittleEndian.PutUint16(ret[14:], i8)
  2993  	return
  2994  }
  2995  
  2996  func i32x4(i1, i2, i3, i4 uint32) (ret [16]byte) {
  2997  	binary.LittleEndian.PutUint32(ret[0:], i1)
  2998  	binary.LittleEndian.PutUint32(ret[4:], i2)
  2999  	binary.LittleEndian.PutUint32(ret[8:], i3)
  3000  	binary.LittleEndian.PutUint32(ret[12:], i4)
  3001  	return
  3002  }
  3003  
  3004  func f32x4(f1, f2, f3, f4 float32) (ret [16]byte) {
  3005  	binary.LittleEndian.PutUint32(ret[0:], math.Float32bits(f1))
  3006  	binary.LittleEndian.PutUint32(ret[4:], math.Float32bits(f2))
  3007  	binary.LittleEndian.PutUint32(ret[8:], math.Float32bits(f3))
  3008  	binary.LittleEndian.PutUint32(ret[12:], math.Float32bits(f4))
  3009  	return
  3010  }
  3011  
  3012  func i64x2(i1, i2 uint64) (ret [16]byte) {
  3013  	binary.LittleEndian.PutUint64(ret[0:], i1)
  3014  	binary.LittleEndian.PutUint64(ret[8:], i2)
  3015  	return
  3016  }
  3017  
  3018  func f64x2(f1, f2 float64) (ret [16]byte) {
  3019  	binary.LittleEndian.PutUint64(ret[0:], math.Float64bits(f1))
  3020  	binary.LittleEndian.PutUint64(ret[8:], math.Float64bits(f2))
  3021  	return
  3022  }
  3023  
  3024  func TestCompiler_compileV128Cmp(t *testing.T) {
  3025  	tests := []struct {
  3026  		name        string
  3027  		cmpType     wazeroir.V128CmpType
  3028  		x1, x2, exp [16]byte
  3029  	}{
  3030  		{
  3031  			name:    "f32x4 eq",
  3032  			cmpType: wazeroir.V128CmpTypeF32x4Eq,
  3033  			x1:      f32x4(1.0, -123.123, 0, 3214231),
  3034  			x2:      f32x4(0, 0, 0, 0),
  3035  			exp:     [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0},
  3036  		},
  3037  		{
  3038  			name:    "f32x4 ne",
  3039  			cmpType: wazeroir.V128CmpTypeF32x4Ne,
  3040  			x1:      f32x4(1.0, -123.123, 123, 3214231),
  3041  			x2:      f32x4(2.0, 213123123.1231, 123, 0),
  3042  			exp:     [16]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff},
  3043  		},
  3044  		{
  3045  			name:    "f32x4 lt",
  3046  			cmpType: wazeroir.V128CmpTypeF32x4Lt,
  3047  			x1:      f32x4(2.0, -123.123, 1234, 3214231),
  3048  			x2:      f32x4(2.0, 213123123.1231, 123, 0),
  3049  			exp:     [16]byte{0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0},
  3050  		},
  3051  		{
  3052  			name:    "f32x4 le",
  3053  			cmpType: wazeroir.V128CmpTypeF32x4Le,
  3054  			x1:      f32x4(2.0, -123.123, 1234, 3214231),
  3055  			x2:      f32x4(2.0, 213123123.1231, 123, 0),
  3056  			exp:     [16]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0},
  3057  		},
  3058  		{
  3059  			name:    "f32x4 gt",
  3060  			cmpType: wazeroir.V128CmpTypeF32x4Gt,
  3061  			x1:      f32x4(2.0, -123.123, 1234, 3214231),
  3062  			x2:      f32x4(2.0, 213123123.1231, 123, 0),
  3063  			exp:     [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
  3064  		},
  3065  		{
  3066  			name:    "f32x4 ge",
  3067  			cmpType: wazeroir.V128CmpTypeF32x4Ge,
  3068  			x1:      f32x4(2.0, -123.123, 1234, 3214231),
  3069  			x2:      f32x4(2.0, 213123123.1231, 123, 0),
  3070  			exp:     [16]byte{0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
  3071  		},
  3072  		{
  3073  			name:    "f64x2 eq",
  3074  			cmpType: wazeroir.V128CmpTypeF64x2Eq,
  3075  			x1:      f64x2(1.0, -123.12412),
  3076  			x2:      f64x2(1.0, 123.123124),
  3077  			exp:     [16]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0},
  3078  		},
  3079  		{
  3080  			name:    "f64x2 ne",
  3081  			cmpType: wazeroir.V128CmpTypeF64x2Ne,
  3082  			x1:      f64x2(1.0, -123.12412),
  3083  			x2:      f64x2(1.0, 123.123124),
  3084  			exp:     [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
  3085  		},
  3086  		{
  3087  			name:    "f64x2 lt",
  3088  			cmpType: wazeroir.V128CmpTypeF64x2Lt,
  3089  			x1:      f64x2(-123, math.Inf(-1)),
  3090  			x2:      f64x2(-123, -1234515),
  3091  			exp:     [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
  3092  		},
  3093  		{
  3094  			name:    "f64x2 le",
  3095  			cmpType: wazeroir.V128CmpTypeF64x2Le,
  3096  			x1:      f64x2(-123, 123),
  3097  			x2:      f64x2(-123, math.MaxFloat64),
  3098  			exp:     [16]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
  3099  		},
  3100  		{
  3101  			name:    "f64x2 gt",
  3102  			cmpType: wazeroir.V128CmpTypeF64x2Gt,
  3103  			x1:      f64x2(math.MaxFloat64, -123.0),
  3104  			x2:      f64x2(123, -123.0),
  3105  			exp: [16]byte{
  3106  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  3107  				0, 0, 0, 0, 0, 0, 0, 0,
  3108  			},
  3109  		},
  3110  		{
  3111  			name:    "f64x2 ge",
  3112  			cmpType: wazeroir.V128CmpTypeF64x2Ge,
  3113  			x1:      f64x2(math.MaxFloat64, -123.0),
  3114  			x2:      f64x2(123, -123.0),
  3115  			exp: [16]byte{
  3116  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  3117  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  3118  			},
  3119  		},
  3120  		{
  3121  			name:    "i8x16 eq",
  3122  			cmpType: wazeroir.V128CmpTypeI8x16Eq,
  3123  			x1:      [16]byte{0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1},
  3124  			x2:      [16]byte{1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0},
  3125  			exp:     [16]byte{0, 0xff, 0, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0xff, 0xff, 0},
  3126  		},
  3127  		{
  3128  			name:    "i8x16 ne",
  3129  			cmpType: wazeroir.V128CmpTypeI8x16Ne,
  3130  			x1:      [16]byte{0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1},
  3131  			x2:      [16]byte{1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0},
  3132  			exp:     [16]byte{0xff, 0, 0xff, 0, 0, 0xff, 0, 0, 0, 0, 0, 0, 0xff, 0, 0, 0xff},
  3133  		},
  3134  		{
  3135  			name:    "i8x16 lt_s",
  3136  			cmpType: wazeroir.V128CmpTypeI8x16LtS,
  3137  			x1:      [16]byte{0: i8ToU8(-1), 15: 0},
  3138  			x2:      [16]byte{0: 0x7f, 15: i8ToU8(-1)},
  3139  			exp:     [16]byte{0: 0xff},
  3140  		},
  3141  		{
  3142  			name:    "i8x16 lt_u",
  3143  			cmpType: wazeroir.V128CmpTypeI8x16LtU,
  3144  			x1:      [16]byte{0: 0xff, 15: 0},
  3145  			x2:      [16]byte{0: 0x7f, 15: 0xff},
  3146  			exp:     [16]byte{15: 0xff},
  3147  		},
  3148  		{
  3149  			name:    "i8x16 gt_s",
  3150  			cmpType: wazeroir.V128CmpTypeI8x16GtS,
  3151  			x1:      [16]byte{0: i8ToU8(-1), 15: 0},
  3152  			x2:      [16]byte{0: 0x7f, 15: i8ToU8(-1)},
  3153  			exp:     [16]byte{15: 0xff},
  3154  		},
  3155  		{
  3156  			name:    "i8x16 gt_u",
  3157  			cmpType: wazeroir.V128CmpTypeI8x16GtU,
  3158  			x1:      [16]byte{0: 0xff, 15: 0},
  3159  			x2:      [16]byte{0: 0x7f, 15: 0xff},
  3160  			exp:     [16]byte{0: 0xff},
  3161  		},
  3162  		{
  3163  			name:    "i8x16 le_s",
  3164  			cmpType: wazeroir.V128CmpTypeI8x16LeS,
  3165  			x1:      [16]byte{i8ToU8(-1), 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, i8ToU8(-1)},
  3166  			x2:      [16]byte{0: 0x7f, 15: i8ToU8(-1)},
  3167  			exp:     [16]byte{0: 0xff, 15: 0xff},
  3168  		},
  3169  		{
  3170  			name:    "i8x16 le_u",
  3171  			cmpType: wazeroir.V128CmpTypeI8x16LeU,
  3172  			x1:      [16]byte{0x80, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0xff},
  3173  			x2:      [16]byte{0: 0x7f, 5: 0x1, 15: 0xff},
  3174  			exp:     [16]byte{5: 0xff, 15: 0xff},
  3175  		},
  3176  		{
  3177  			name:    "i8x16 ge_s",
  3178  			cmpType: wazeroir.V128CmpTypeI8x16GeS,
  3179  			x1:      [16]byte{0: 0x7f, 15: i8ToU8(-1)},
  3180  			x2:      [16]byte{i8ToU8(-1), 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, i8ToU8(-1)},
  3181  			exp:     [16]byte{0: 0xff, 15: 0xff},
  3182  		},
  3183  		{
  3184  			name:    "i8x16 ge_u",
  3185  			cmpType: wazeroir.V128CmpTypeI8x16GeU,
  3186  			x1:      [16]byte{0: 0x7f, 3: 0xe, 15: 0xff},
  3187  			x2:      [16]byte{0xff, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0xff},
  3188  			exp:     [16]byte{3: 0xff, 15: 0xff},
  3189  		},
  3190  		{
  3191  			name:    "i16x8 eq",
  3192  			cmpType: wazeroir.V128CmpTypeI16x8Eq,
  3193  			x1:      i16x8(0, 1, 0, 1, 0, 1, 0, 1),
  3194  			x2:      i16x8(0, 0, 0, 1, 1, 1, 0, 0),
  3195  			exp:     i16x8(0xffff, 0, 0xffff, 0xffff, 0, 0xffff, 0xffff, 0),
  3196  		},
  3197  		{
  3198  			name:    "i8x16 ne",
  3199  			cmpType: wazeroir.V128CmpTypeI16x8Ne,
  3200  			x1:      i16x8(0, 1, 0, 1, 0, 1, 0, 1),
  3201  			x2:      i16x8(0, 0, 0, 1, 1, 1, 0, 0),
  3202  			exp:     i16x8(0, 0xffff, 0, 0, 0xffff, 0, 0, 0xffff),
  3203  		},
  3204  		{
  3205  			name:    "i8x16 lt_s",
  3206  			cmpType: wazeroir.V128CmpTypeI16x8LtS,
  3207  			x1:      i16x8(0xffff, 1, 0, 1, 0, 1, 0, 1),
  3208  			x2:      i16x8(0, 0, 0, 1, 1, 1, 0, 0),
  3209  			exp:     i16x8(0xffff, 0, 0, 0, 0xffff, 0, 0, 0),
  3210  		},
  3211  		{
  3212  			name:    "i8x16 lt_u",
  3213  			cmpType: wazeroir.V128CmpTypeI16x8LtU,
  3214  			x1:      i16x8(0xffff, 1, 0, 1, 0, 1, 0, 1),
  3215  			x2:      i16x8(0, 0, 0, 1, 1, 1, 0, 0),
  3216  			exp:     i16x8(0, 0, 0, 0, 0xffff, 0, 0, 0),
  3217  		},
  3218  		{
  3219  			name:    "i8x16 gt_s",
  3220  			cmpType: wazeroir.V128CmpTypeI16x8GtS,
  3221  			x1:      i16x8(0, 1, 0, 1, 0, 1, 0, 1),
  3222  			x2:      i16x8(0xffff, 0, 0, 1, 1, 1, 0, 0),
  3223  			exp:     i16x8(0xffff, 0xffff, 0, 0, 0, 0, 0, 0xffff),
  3224  		},
  3225  		{
  3226  			name:    "i8x16 gt_u",
  3227  			cmpType: wazeroir.V128CmpTypeI16x8GtU,
  3228  			x1:      i16x8(0, 1, 0, 1, 0, 1, 0, 1),
  3229  			x2:      i16x8(0xffff, 0, 0, 1, 1, 1, 0, 0),
  3230  			exp:     i16x8(0, 0xffff, 0, 0, 0, 0, 0, 0xffff),
  3231  		},
  3232  		{
  3233  			name:    "i8x16 le_s",
  3234  			cmpType: wazeroir.V128CmpTypeI16x8LeS,
  3235  			x1:      i16x8(0xffff, 1, 0, 1, 0, 1, 0, 1),
  3236  			x2:      i16x8(0, 0, 0, 1, 1, 1, 0, 0),
  3237  			exp:     i16x8(0xffff, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0),
  3238  		},
  3239  		{
  3240  			name:    "i8x16 le_u",
  3241  			cmpType: wazeroir.V128CmpTypeI16x8LeU,
  3242  			x1:      i16x8(0xffff, 1, 0, 1, 0, 1, 0, 1),
  3243  			x2:      i16x8(0, 0, 0, 1, 1, 1, 0, 0),
  3244  			exp:     i16x8(0, 0, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0),
  3245  		},
  3246  		{
  3247  			name:    "i8x16 ge_s",
  3248  			cmpType: wazeroir.V128CmpTypeI16x8GeS,
  3249  			x1:      i16x8(0, 1, 0, 1, 0, 1, 0, 1),
  3250  			x2:      i16x8(0xffff, 0, 0, 1, 1, 1, 0, 0),
  3251  			exp:     i16x8(0xffff, 0xffff, 0xffff, 0xffff, 0, 0xffff, 0xffff, 0xffff),
  3252  		},
  3253  		{
  3254  			name:    "i8x16 ge_u",
  3255  			cmpType: wazeroir.V128CmpTypeI16x8GeU,
  3256  			x1:      i16x8(0, 1, 0, 1, 0, 1, 0, 1),
  3257  			x2:      i16x8(0xffff, 0, 0, 1, 1, 1, 0, 0),
  3258  			exp:     i16x8(0, 0xffff, 0xffff, 0xffff, 0, 0xffff, 0xffff, 0xffff),
  3259  		},
  3260  		{
  3261  			name:    "i32x4 eq",
  3262  			cmpType: wazeroir.V128CmpTypeI32x4Eq,
  3263  			x1:      i32x4(0, 1, 1, 0),
  3264  			x2:      i32x4(0, 1, 0, 1),
  3265  			exp:     i32x4(0xffffffff, 0xffffffff, 0, 0),
  3266  		},
  3267  		{
  3268  			name:    "i32x4 ne",
  3269  			cmpType: wazeroir.V128CmpTypeI32x4Ne,
  3270  			x1:      i32x4(0, 1, 1, 0),
  3271  			x2:      i32x4(0, 1, 0, 1),
  3272  			exp:     i32x4(0, 0, 0xffffffff, 0xffffffff),
  3273  		},
  3274  		{
  3275  			name:    "i32x4 lt_s",
  3276  			cmpType: wazeroir.V128CmpTypeI32x4LtS,
  3277  			x1:      i32x4(0xffffffff, 1, 1, 0),
  3278  			x2:      i32x4(0, 1, 0, 1),
  3279  			exp:     i32x4(0xffffffff, 0, 0, 0xffffffff),
  3280  		},
  3281  		{
  3282  			name:    "i32x4 lt_u",
  3283  			cmpType: wazeroir.V128CmpTypeI32x4LtU,
  3284  			x1:      i32x4(0xffffffff, 1, 1, 0),
  3285  			x2:      i32x4(0, 1, 0, 1),
  3286  			exp:     i32x4(0, 0, 0, 0xffffffff),
  3287  		},
  3288  		{
  3289  			name:    "i32x4 gt_s",
  3290  			cmpType: wazeroir.V128CmpTypeI32x4GtS,
  3291  			x1:      i32x4(0, 1, 1, 1),
  3292  			x2:      i32x4(0xffffffff, 1, 0, 0),
  3293  			exp:     i32x4(0xffffffff, 0, 0xffffffff, 0xffffffff),
  3294  		},
  3295  		{
  3296  			name:    "i32x4 gt_u",
  3297  			cmpType: wazeroir.V128CmpTypeI32x4GtU,
  3298  			x1:      i32x4(0, 1, 1, 1),
  3299  			x2:      i32x4(0xffffffff, 1, 0, 0),
  3300  			exp:     i32x4(0, 0, 0xffffffff, 0xffffffff),
  3301  		},
  3302  		{
  3303  			name:    "i32x4 le_s",
  3304  			cmpType: wazeroir.V128CmpTypeI32x4LeS,
  3305  			x1:      i32x4(0xffffffff, 1, 1, 0),
  3306  			x2:      i32x4(0, 1, 0, 1),
  3307  			exp:     i32x4(0xffffffff, 0xffffffff, 0, 0xffffffff),
  3308  		},
  3309  		{
  3310  			name:    "i32x4 le_u",
  3311  			cmpType: wazeroir.V128CmpTypeI32x4LeU,
  3312  			x1:      i32x4(0xffffffff, 1, 1, 0),
  3313  			x2:      i32x4(0, 1, 0, 1),
  3314  			exp:     i32x4(0, 0xffffffff, 0, 0xffffffff),
  3315  		},
  3316  		{
  3317  			name:    "i32x4 ge_s",
  3318  			cmpType: wazeroir.V128CmpTypeI32x4GeS,
  3319  			x1:      i32x4(0, 1, 1, 0),
  3320  			x2:      i32x4(0xffffffff, 1, 0, 1),
  3321  			exp:     i32x4(0xffffffff, 0xffffffff, 0xffffffff, 0),
  3322  		},
  3323  		{
  3324  			name:    "i32x4 ge_u",
  3325  			cmpType: wazeroir.V128CmpTypeI32x4GeU,
  3326  			x1:      i32x4(0, 1, 1, 0),
  3327  			x2:      i32x4(0xffffffff, 1, 0, 1),
  3328  			exp:     i32x4(0, 0xffffffff, 0xffffffff, 0),
  3329  		},
  3330  		{
  3331  			name:    "i64x2 eq",
  3332  			cmpType: wazeroir.V128CmpTypeI64x2Eq,
  3333  			x1:      i64x2(1, 0),
  3334  			x2:      i64x2(0, 0),
  3335  			exp:     i64x2(0, 0xffffffffffffffff),
  3336  		},
  3337  		{
  3338  			name:    "i64x2 ne",
  3339  			cmpType: wazeroir.V128CmpTypeI64x2Ne,
  3340  			x1:      i64x2(1, 0),
  3341  			x2:      i64x2(0, 0),
  3342  			exp:     i64x2(0xffffffffffffffff, 0),
  3343  		},
  3344  		{
  3345  			name:    "i64x2 lt_s",
  3346  			cmpType: wazeroir.V128CmpTypeI64x2LtS,
  3347  			x1:      i64x2(0xffffffffffffffff, 0),
  3348  			x2:      i64x2(0, 0),
  3349  			exp:     i64x2(0xffffffffffffffff, 0),
  3350  		},
  3351  		{
  3352  			name:    "i64x2 gt_s",
  3353  			cmpType: wazeroir.V128CmpTypeI64x2GtS,
  3354  			x1:      i64x2(123, 0),
  3355  			x2:      i64x2(123, 0xffffffffffffffff),
  3356  			exp:     i64x2(0, 0xffffffffffffffff),
  3357  		},
  3358  		{
  3359  			name:    "i64x2 le_s",
  3360  			cmpType: wazeroir.V128CmpTypeI64x2LeS,
  3361  			x1:      i64x2(123, 0xffffffffffffffff),
  3362  			x2:      i64x2(123, 0),
  3363  			exp:     i64x2(0xffffffffffffffff, 0xffffffffffffffff),
  3364  		},
  3365  		{
  3366  			name:    "i64x2 ge_s",
  3367  			cmpType: wazeroir.V128CmpTypeI64x2GeS,
  3368  			x1:      i64x2(123, 0),
  3369  			x2:      i64x2(123, 0xffffffffffffffff),
  3370  			exp:     i64x2(0xffffffffffffffff, 0xffffffffffffffff),
  3371  		},
  3372  	}
  3373  
  3374  	for _, tc := range tests {
  3375  		tc := tc
  3376  		t.Run(tc.name, func(t *testing.T) {
  3377  			env := newCompilerEnvironment()
  3378  			compiler := env.requireNewCompiler(t, newCompiler,
  3379  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  3380  
  3381  			err := compiler.compilePreamble()
  3382  			require.NoError(t, err)
  3383  
  3384  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  3385  				Lo: binary.LittleEndian.Uint64(tc.x1[:8]),
  3386  				Hi: binary.LittleEndian.Uint64(tc.x1[8:]),
  3387  			})
  3388  			require.NoError(t, err)
  3389  
  3390  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  3391  				Lo: binary.LittleEndian.Uint64(tc.x2[:8]),
  3392  				Hi: binary.LittleEndian.Uint64(tc.x2[8:]),
  3393  			})
  3394  			require.NoError(t, err)
  3395  
  3396  			err = compiler.compileV128Cmp(&wazeroir.OperationV128Cmp{Type: tc.cmpType})
  3397  			require.NoError(t, err)
  3398  
  3399  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  3400  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  3401  
  3402  			err = compiler.compileReturnFunction()
  3403  			require.NoError(t, err)
  3404  
  3405  			// Generate and run the code under test.
  3406  			code, _, err := compiler.compile()
  3407  			require.NoError(t, err)
  3408  			env.exec(code)
  3409  
  3410  			lo, hi := env.stackTopAsV128()
  3411  			var actual [16]byte
  3412  			binary.LittleEndian.PutUint64(actual[:8], lo)
  3413  			binary.LittleEndian.PutUint64(actual[8:], hi)
  3414  			require.Equal(t, tc.exp, actual)
  3415  		})
  3416  	}
  3417  }
  3418  
  3419  func TestCompiler_compileV128AvgrU(t *testing.T) {
  3420  	tests := []struct {
  3421  		name        string
  3422  		shape       wazeroir.Shape
  3423  		x1, x2, exp [16]byte
  3424  	}{
  3425  		{
  3426  			name:  "i8x16",
  3427  			shape: wazeroir.ShapeI8x16,
  3428  			x1:    [16]byte{0: 1, 2: 10, 10: 10, 15: math.MaxUint8},
  3429  			x2:    [16]byte{0: 10, 4: 5, 10: 5, 15: 10},
  3430  			exp: [16]byte{
  3431  				0:  byte((uint16(1) + uint16(10) + 1) / 2),
  3432  				2:  byte((uint16(10) + 1) / 2),
  3433  				4:  byte((uint16(5) + 1) / 2),
  3434  				10: byte((uint16(10) + uint16(5) + 1) / 2),
  3435  				15: byte((uint16(math.MaxUint8) + uint16(10) + 1) / 2),
  3436  			},
  3437  		},
  3438  		{
  3439  			name:  "i16x8",
  3440  			shape: wazeroir.ShapeI16x8,
  3441  			x1:    i16x8(1, 0, 100, 0, 0, math.MaxUint16, 0, 0),
  3442  			x2:    i16x8(10, 0, math.MaxUint16, 0, 0, 1, 0, 0),
  3443  			exp: i16x8(
  3444  				uint16((uint32(1)+uint32(10)+1)/2),
  3445  				0,
  3446  				uint16((uint32(100)+uint32(math.MaxUint16)+1)/2),
  3447  				0,
  3448  				0,
  3449  				uint16((uint32(1)+uint32(math.MaxUint16)+1)/2),
  3450  				0, 0,
  3451  			),
  3452  		},
  3453  	}
  3454  
  3455  	for _, tc := range tests {
  3456  		tc := tc
  3457  		t.Run(tc.name, func(t *testing.T) {
  3458  			env := newCompilerEnvironment()
  3459  			compiler := env.requireNewCompiler(t, newCompiler,
  3460  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  3461  
  3462  			err := compiler.compilePreamble()
  3463  			require.NoError(t, err)
  3464  
  3465  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  3466  				Lo: binary.LittleEndian.Uint64(tc.x1[:8]),
  3467  				Hi: binary.LittleEndian.Uint64(tc.x1[8:]),
  3468  			})
  3469  			require.NoError(t, err)
  3470  
  3471  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  3472  				Lo: binary.LittleEndian.Uint64(tc.x2[:8]),
  3473  				Hi: binary.LittleEndian.Uint64(tc.x2[8:]),
  3474  			})
  3475  			require.NoError(t, err)
  3476  
  3477  			err = compiler.compileV128AvgrU(&wazeroir.OperationV128AvgrU{Shape: tc.shape})
  3478  			require.NoError(t, err)
  3479  
  3480  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  3481  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  3482  
  3483  			err = compiler.compileReturnFunction()
  3484  			require.NoError(t, err)
  3485  
  3486  			// Generate and run the code under test.
  3487  			code, _, err := compiler.compile()
  3488  			require.NoError(t, err)
  3489  			env.exec(code)
  3490  
  3491  			require.Equal(t, nativeCallStatusCodeReturned, env.callEngine().statusCode)
  3492  
  3493  			lo, hi := env.stackTopAsV128()
  3494  			var actual [16]byte
  3495  			binary.LittleEndian.PutUint64(actual[:8], lo)
  3496  			binary.LittleEndian.PutUint64(actual[8:], hi)
  3497  			require.Equal(t, tc.exp, actual)
  3498  		})
  3499  	}
  3500  }
  3501  
  3502  func TestCompiler_compileV128Sqrt(t *testing.T) {
  3503  	tests := []struct {
  3504  		name   string
  3505  		shape  wazeroir.Shape
  3506  		v, exp [16]byte
  3507  	}{
  3508  		{
  3509  			name:  "f32x4",
  3510  			shape: wazeroir.ShapeF32x4,
  3511  			v:     f32x4(1.23, -123.1231, math.MaxFloat32, float32(math.Inf(1))),
  3512  			exp: f32x4(
  3513  				float32(math.Sqrt(float64(float32(1.23)))),
  3514  				float32(math.Sqrt(float64(float32(-123.1231)))),
  3515  				float32(math.Sqrt(float64(float32(math.MaxFloat32)))),
  3516  				float32(math.Sqrt(float64(float32(math.Inf(1))))),
  3517  			),
  3518  		},
  3519  		{
  3520  			name:  "f64x2",
  3521  			shape: wazeroir.ShapeF64x2,
  3522  			v:     f64x2(1.2314, math.MaxFloat64),
  3523  			exp:   f64x2(math.Sqrt(1.2314), math.Sqrt(math.MaxFloat64)),
  3524  		},
  3525  	}
  3526  
  3527  	for _, tc := range tests {
  3528  		tc := tc
  3529  		t.Run(tc.name, func(t *testing.T) {
  3530  			env := newCompilerEnvironment()
  3531  			compiler := env.requireNewCompiler(t, newCompiler,
  3532  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  3533  
  3534  			err := compiler.compilePreamble()
  3535  			require.NoError(t, err)
  3536  
  3537  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  3538  				Lo: binary.LittleEndian.Uint64(tc.v[:8]),
  3539  				Hi: binary.LittleEndian.Uint64(tc.v[8:]),
  3540  			})
  3541  			require.NoError(t, err)
  3542  
  3543  			err = compiler.compileV128Sqrt(&wazeroir.OperationV128Sqrt{Shape: tc.shape})
  3544  			require.NoError(t, err)
  3545  
  3546  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  3547  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  3548  
  3549  			err = compiler.compileReturnFunction()
  3550  			require.NoError(t, err)
  3551  
  3552  			// Generate and run the code under test.
  3553  			code, _, err := compiler.compile()
  3554  			require.NoError(t, err)
  3555  			env.exec(code)
  3556  
  3557  			require.Equal(t, nativeCallStatusCodeReturned, env.callEngine().statusCode)
  3558  
  3559  			lo, hi := env.stackTopAsV128()
  3560  			var actual [16]byte
  3561  			binary.LittleEndian.PutUint64(actual[:8], lo)
  3562  			binary.LittleEndian.PutUint64(actual[8:], hi)
  3563  			require.Equal(t, tc.exp, actual)
  3564  		})
  3565  	}
  3566  }
  3567  
  3568  func TestCompiler_compileV128Mul(t *testing.T) {
  3569  	tests := []struct {
  3570  		name        string
  3571  		shape       wazeroir.Shape
  3572  		x1, x2, exp [16]byte
  3573  	}{
  3574  		{
  3575  			name:  "i16x8",
  3576  			shape: wazeroir.ShapeI16x8,
  3577  			x1:    i16x8(1123, 0, 123, 1, 1, 5, 8, 1),
  3578  			x2:    i16x8(0, 123, 123, 0, 1, 5, 9, 1),
  3579  			exp:   i16x8(0, 0, 123*123, 0, 1, 25, 8*9, 1),
  3580  		},
  3581  		{
  3582  			name:  "i32x4",
  3583  			shape: wazeroir.ShapeI32x4,
  3584  			x1:    i32x4(i32ToU32(-123), 5, 4, math.MaxUint32),
  3585  			x2:    i32x4(i32ToU32(-10), 1, i32ToU32(-104), 0),
  3586  			exp:   i32x4(1230, 5, i32ToU32(-416), 0),
  3587  		},
  3588  		{
  3589  			name:  "i64x2",
  3590  			shape: wazeroir.ShapeI64x2,
  3591  			x1:    i64x2(1, 12345),
  3592  			x2:    i64x2(100, i64ToU64(-10)),
  3593  			exp:   i64x2(100, i64ToU64(-123450)),
  3594  		},
  3595  		{
  3596  			name:  "f32x4",
  3597  			shape: wazeroir.ShapeF32x4,
  3598  			x1:    f32x4(1.0, 123, float32(math.Inf(1)), float32(math.Inf(-1))),
  3599  			x2:    f32x4(51234.12341, 123, math.MaxFloat32, -123),
  3600  			exp:   f32x4(51234.12341, 123*123, float32(math.Inf(1)), float32(math.Inf(1))),
  3601  		},
  3602  		{
  3603  			name:  "f64x2",
  3604  			shape: wazeroir.ShapeF64x2,
  3605  			x1:    f64x2(1.123, math.Inf(1)),
  3606  			x2:    f64x2(1.123, math.MinInt64),
  3607  			exp:   f64x2(1.123*1.123, math.Inf(-1)),
  3608  		},
  3609  	}
  3610  
  3611  	for _, tc := range tests {
  3612  		tc := tc
  3613  		t.Run(tc.name, func(t *testing.T) {
  3614  			env := newCompilerEnvironment()
  3615  			compiler := env.requireNewCompiler(t, newCompiler,
  3616  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  3617  
  3618  			err := compiler.compilePreamble()
  3619  			require.NoError(t, err)
  3620  
  3621  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  3622  				Lo: binary.LittleEndian.Uint64(tc.x1[:8]),
  3623  				Hi: binary.LittleEndian.Uint64(tc.x1[8:]),
  3624  			})
  3625  			require.NoError(t, err)
  3626  
  3627  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  3628  				Lo: binary.LittleEndian.Uint64(tc.x2[:8]),
  3629  				Hi: binary.LittleEndian.Uint64(tc.x2[8:]),
  3630  			})
  3631  			require.NoError(t, err)
  3632  
  3633  			err = compiler.compileV128Mul(&wazeroir.OperationV128Mul{Shape: tc.shape})
  3634  			require.NoError(t, err)
  3635  
  3636  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  3637  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  3638  
  3639  			err = compiler.compileReturnFunction()
  3640  			require.NoError(t, err)
  3641  
  3642  			// Generate and run the code under test.
  3643  			code, _, err := compiler.compile()
  3644  			require.NoError(t, err)
  3645  			env.exec(code)
  3646  
  3647  			require.Equal(t, nativeCallStatusCodeReturned, env.callEngine().statusCode)
  3648  
  3649  			lo, hi := env.stackTopAsV128()
  3650  			var actual [16]byte
  3651  			binary.LittleEndian.PutUint64(actual[:8], lo)
  3652  			binary.LittleEndian.PutUint64(actual[8:], hi)
  3653  			require.Equal(t, tc.exp, actual)
  3654  		})
  3655  	}
  3656  }
  3657  
  3658  func TestCompiler_compileV128Neg(t *testing.T) {
  3659  	tests := []struct {
  3660  		name   string
  3661  		shape  wazeroir.Shape
  3662  		v, exp [16]byte
  3663  	}{
  3664  		{
  3665  			name:  "i8x16",
  3666  			shape: wazeroir.ShapeI8x16,
  3667  			v:     [16]byte{1: 123, 5: i8ToU8(-1), 15: i8ToU8(-125)},
  3668  			exp:   [16]byte{1: i8ToU8(-123), 5: 1, 15: 125},
  3669  		},
  3670  		{
  3671  			name:  "i16x8",
  3672  			shape: wazeroir.ShapeI16x8,
  3673  			v:     i16x8(0, 0, i16ToU16(-123), 0, 1, 25, 8, i16ToU16(-1)),
  3674  			exp:   i16x8(0, 0, 123, 0, i16ToU16(-1), i16ToU16(-25), i16ToU16(-8), 1),
  3675  		},
  3676  		{
  3677  			name:  "i32x4",
  3678  			shape: wazeroir.ShapeI32x4,
  3679  			v:     i32x4(1230, 5, i32ToU32(-416), 0),
  3680  			exp:   i32x4(i32ToU32(-1230), i32ToU32(-5), 416, 0),
  3681  		},
  3682  		{
  3683  			name:  "i64x2",
  3684  			shape: wazeroir.ShapeI64x2,
  3685  			v:     i64x2(100, i64ToU64(-123450)),
  3686  			exp:   i64x2(i64ToU64(-100), 123450),
  3687  		},
  3688  		{
  3689  			name:  "f32x4",
  3690  			shape: wazeroir.ShapeF32x4,
  3691  			v:     f32x4(51234.12341, -123, float32(math.Inf(1)), 0.1),
  3692  			exp:   f32x4(-51234.12341, 123, float32(math.Inf(-1)), -0.1),
  3693  		},
  3694  		{
  3695  			name:  "f32x4",
  3696  			shape: wazeroir.ShapeF32x4,
  3697  			v:     f32x4(51234.12341, 0, float32(math.Inf(1)), 0.1),
  3698  			exp:   f32x4(-51234.12341, float32(math.Copysign(0, -1)), float32(math.Inf(-1)), -0.1),
  3699  		},
  3700  		{
  3701  			name:  "f64x2",
  3702  			shape: wazeroir.ShapeF64x2,
  3703  			v:     f64x2(1.123, math.Inf(-1)),
  3704  			exp:   f64x2(-1.123, math.Inf(1)),
  3705  		},
  3706  		{
  3707  			name:  "f64x2",
  3708  			shape: wazeroir.ShapeF64x2,
  3709  			v:     f64x2(0, math.Inf(-1)),
  3710  			exp:   f64x2(math.Copysign(0, -1), math.Inf(1)),
  3711  		},
  3712  	}
  3713  
  3714  	for _, tc := range tests {
  3715  		tc := tc
  3716  		t.Run(tc.name, func(t *testing.T) {
  3717  			env := newCompilerEnvironment()
  3718  			compiler := env.requireNewCompiler(t, newCompiler,
  3719  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  3720  
  3721  			err := compiler.compilePreamble()
  3722  			require.NoError(t, err)
  3723  
  3724  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  3725  				Lo: binary.LittleEndian.Uint64(tc.v[:8]),
  3726  				Hi: binary.LittleEndian.Uint64(tc.v[8:]),
  3727  			})
  3728  			require.NoError(t, err)
  3729  
  3730  			err = compiler.compileV128Neg(&wazeroir.OperationV128Neg{Shape: tc.shape})
  3731  			require.NoError(t, err)
  3732  
  3733  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  3734  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  3735  
  3736  			err = compiler.compileReturnFunction()
  3737  			require.NoError(t, err)
  3738  
  3739  			// Generate and run the code under test.
  3740  			code, _, err := compiler.compile()
  3741  			require.NoError(t, err)
  3742  			env.exec(code)
  3743  
  3744  			require.Equal(t, nativeCallStatusCodeReturned, env.callEngine().statusCode)
  3745  
  3746  			lo, hi := env.stackTopAsV128()
  3747  			var actual [16]byte
  3748  			binary.LittleEndian.PutUint64(actual[:8], lo)
  3749  			binary.LittleEndian.PutUint64(actual[8:], hi)
  3750  			require.Equal(t, tc.exp, actual)
  3751  		})
  3752  	}
  3753  }
  3754  
  3755  func TestCompiler_compileV128Abs(t *testing.T) {
  3756  	tests := []struct {
  3757  		name   string
  3758  		shape  wazeroir.Shape
  3759  		v, exp [16]byte
  3760  	}{
  3761  		{
  3762  			name:  "i8x16",
  3763  			shape: wazeroir.ShapeI8x16,
  3764  			v:     [16]byte{1: 123, 5: i8ToU8(-1), 15: i8ToU8(-125)},
  3765  			exp:   [16]byte{1: 123, 5: 1, 15: 125},
  3766  		},
  3767  		{
  3768  			name:  "i16x8",
  3769  			shape: wazeroir.ShapeI16x8,
  3770  			v:     i16x8(0, 0, i16ToU16(-123), 0, 1, 25, 8, i16ToU16(-1)),
  3771  			exp:   i16x8(0, 0, 123, 0, 1, 25, 8, 1),
  3772  		},
  3773  		{
  3774  			name:  "i32x4",
  3775  			shape: wazeroir.ShapeI32x4,
  3776  			v:     i32x4(i32ToU32(-1230), 5, i32ToU32(-416), 0),
  3777  			exp:   i32x4(1230, 5, 416, 0),
  3778  		},
  3779  		{
  3780  			name:  "i64x2",
  3781  			shape: wazeroir.ShapeI64x2,
  3782  			v:     i64x2(i64ToU64(-100), i64ToU64(-123450)),
  3783  			exp:   i64x2(100, 123450),
  3784  		},
  3785  		{
  3786  			name:  "f32x4",
  3787  			shape: wazeroir.ShapeF32x4,
  3788  			v:     f32x4(51234.12341, -123, float32(math.Inf(1)), 0.1),
  3789  			exp:   f32x4(51234.12341, 123, float32(math.Inf(1)), 0.1),
  3790  		},
  3791  		{
  3792  			name:  "f32x4",
  3793  			shape: wazeroir.ShapeF32x4,
  3794  			v:     f32x4(51234.12341, 0, float32(math.Inf(1)), -0.1),
  3795  			exp:   f32x4(51234.12341, 0, float32(math.Inf(1)), 0.1),
  3796  		},
  3797  		{
  3798  			name:  "f64x2",
  3799  			shape: wazeroir.ShapeF64x2,
  3800  			v:     f64x2(-1.123, math.Inf(-1)),
  3801  			exp:   f64x2(1.123, math.Inf(1)),
  3802  		},
  3803  		{
  3804  			name:  "f64x2",
  3805  			shape: wazeroir.ShapeF64x2,
  3806  			v:     f64x2(0, math.Inf(-1)),
  3807  			exp:   f64x2(0, math.Inf(1)),
  3808  		},
  3809  	}
  3810  
  3811  	for _, tc := range tests {
  3812  		tc := tc
  3813  		t.Run(tc.name, func(t *testing.T) {
  3814  			env := newCompilerEnvironment()
  3815  			compiler := env.requireNewCompiler(t, newCompiler,
  3816  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  3817  
  3818  			err := compiler.compilePreamble()
  3819  			require.NoError(t, err)
  3820  
  3821  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  3822  				Lo: binary.LittleEndian.Uint64(tc.v[:8]),
  3823  				Hi: binary.LittleEndian.Uint64(tc.v[8:]),
  3824  			})
  3825  			require.NoError(t, err)
  3826  
  3827  			err = compiler.compileV128Abs(&wazeroir.OperationV128Abs{Shape: tc.shape})
  3828  			require.NoError(t, err)
  3829  
  3830  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  3831  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  3832  
  3833  			err = compiler.compileReturnFunction()
  3834  			require.NoError(t, err)
  3835  
  3836  			// Generate and run the code under test.
  3837  			code, _, err := compiler.compile()
  3838  			require.NoError(t, err)
  3839  			env.exec(code)
  3840  
  3841  			require.Equal(t, nativeCallStatusCodeReturned, env.callEngine().statusCode)
  3842  
  3843  			lo, hi := env.stackTopAsV128()
  3844  			var actual [16]byte
  3845  			binary.LittleEndian.PutUint64(actual[:8], lo)
  3846  			binary.LittleEndian.PutUint64(actual[8:], hi)
  3847  			require.Equal(t, tc.exp, actual)
  3848  		})
  3849  	}
  3850  }
  3851  
  3852  func TestCompiler_compileV128Div(t *testing.T) {
  3853  	tests := []struct {
  3854  		name        string
  3855  		shape       wazeroir.Shape
  3856  		x1, x2, exp [16]byte
  3857  	}{
  3858  		{
  3859  			name:  "f32x4",
  3860  			shape: wazeroir.ShapeF32x4,
  3861  			x1:    f32x4(1.0, 123, float32(math.Inf(1)), float32(math.Inf(-1))),
  3862  			x2:    f32x4(123.12, 123, math.MaxFloat32, -123),
  3863  			exp:   f32x4(float32(1.0)/float32(123.12), 1, float32(math.Inf(1)), float32(math.Inf(1))),
  3864  		},
  3865  		{
  3866  			name:  "f64x2",
  3867  			shape: wazeroir.ShapeF64x2,
  3868  			x1:    f64x2(1.123, math.Inf(1)),
  3869  			x2:    f64x2(1.123, math.MinInt64),
  3870  			exp:   f64x2(1.0, math.Inf(-1)),
  3871  		},
  3872  		{
  3873  			name:  "f64x2",
  3874  			shape: wazeroir.ShapeF64x2,
  3875  			x1:    f64x2(0, math.Inf(1)),
  3876  			x2:    f64x2(1.123, math.MaxInt64),
  3877  			exp:   f64x2(0, math.Inf(1)),
  3878  		},
  3879  	}
  3880  
  3881  	for _, tc := range tests {
  3882  		tc := tc
  3883  		t.Run(tc.name, func(t *testing.T) {
  3884  			env := newCompilerEnvironment()
  3885  			compiler := env.requireNewCompiler(t, newCompiler,
  3886  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  3887  
  3888  			err := compiler.compilePreamble()
  3889  			require.NoError(t, err)
  3890  
  3891  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  3892  				Lo: binary.LittleEndian.Uint64(tc.x1[:8]),
  3893  				Hi: binary.LittleEndian.Uint64(tc.x1[8:]),
  3894  			})
  3895  			require.NoError(t, err)
  3896  
  3897  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  3898  				Lo: binary.LittleEndian.Uint64(tc.x2[:8]),
  3899  				Hi: binary.LittleEndian.Uint64(tc.x2[8:]),
  3900  			})
  3901  			require.NoError(t, err)
  3902  
  3903  			err = compiler.compileV128Div(&wazeroir.OperationV128Div{Shape: tc.shape})
  3904  			require.NoError(t, err)
  3905  
  3906  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  3907  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  3908  
  3909  			err = compiler.compileReturnFunction()
  3910  			require.NoError(t, err)
  3911  
  3912  			// Generate and run the code under test.
  3913  			code, _, err := compiler.compile()
  3914  			require.NoError(t, err)
  3915  			env.exec(code)
  3916  
  3917  			require.Equal(t, nativeCallStatusCodeReturned, env.callEngine().statusCode)
  3918  
  3919  			lo, hi := env.stackTopAsV128()
  3920  			var actual [16]byte
  3921  			binary.LittleEndian.PutUint64(actual[:8], lo)
  3922  			binary.LittleEndian.PutUint64(actual[8:], hi)
  3923  			require.Equal(t, tc.exp, actual)
  3924  		})
  3925  	}
  3926  }
  3927  
  3928  func TestCompiler_compileV128Min(t *testing.T) {
  3929  	tests := []struct {
  3930  		name        string
  3931  		shape       wazeroir.Shape
  3932  		signed      bool
  3933  		x1, x2, exp [16]byte
  3934  	}{
  3935  		{
  3936  			name:   "i8x16s",
  3937  			shape:  wazeroir.ShapeI8x16,
  3938  			signed: true,
  3939  			x1:     [16]byte{0: 123, 5: i8ToU8(-1), 15: 2},
  3940  			x2:     [16]byte{0: 1, 5: 0, 15: i8ToU8(-1)},
  3941  			exp:    [16]byte{0: 1, 5: i8ToU8(-1), 15: i8ToU8(-1)},
  3942  		},
  3943  		{
  3944  			name:   "i8x16u",
  3945  			shape:  wazeroir.ShapeI8x16,
  3946  			signed: false,
  3947  			x1:     [16]byte{0: 123, 5: i8ToU8(-1), 15: 2},
  3948  			x2:     [16]byte{0: 1, 5: 0, 15: i8ToU8(-1)},
  3949  			exp:    [16]byte{0: 1, 5: 0, 15: 2},
  3950  		},
  3951  		{
  3952  			name:   "i16x8s",
  3953  			shape:  wazeroir.ShapeI16x8,
  3954  			signed: true,
  3955  			x1:     i16x8(1123, 0, 123, 1, 1, 6, i16ToU16(-123), 1),
  3956  			x2:     i16x8(0, 123, i16ToU16(-123), 3, 1, 4, 5, 1),
  3957  			exp:    i16x8(0, 0, i16ToU16(-123), 1, 1, 4, i16ToU16(-123), 1),
  3958  		},
  3959  		{
  3960  			name:   "i16x8u",
  3961  			shape:  wazeroir.ShapeI16x8,
  3962  			signed: false,
  3963  			x1:     i16x8(1123, 0, 123, 1, 1, 6, i16ToU16(-123), 1),
  3964  			x2:     i16x8(0, 123, i16ToU16(-123), 3, 1, 4, 5, 1),
  3965  			exp:    i16x8(0, 0, 123, 1, 1, 4, 5, 1),
  3966  		},
  3967  		{
  3968  			name:   "i32x4s",
  3969  			shape:  wazeroir.ShapeI32x4,
  3970  			signed: true,
  3971  			x1:     i32x4(i32ToU32(-123), 0, 1, i32ToU32(math.MinInt32)),
  3972  			x2:     i32x4(123, 5, 1, 0),
  3973  			exp:    i32x4(i32ToU32(-123), 0, 1, i32ToU32(math.MinInt32)),
  3974  		},
  3975  		{
  3976  			name:   "i32x4u",
  3977  			shape:  wazeroir.ShapeI32x4,
  3978  			signed: false,
  3979  			x1:     i32x4(i32ToU32(-123), 0, 1, i32ToU32(math.MinInt32)),
  3980  			x2:     i32x4(123, 5, 1, 0),
  3981  			exp:    i32x4(123, 0, 1, 0),
  3982  		},
  3983  		{
  3984  			name:  "f32x4",
  3985  			shape: wazeroir.ShapeF32x4,
  3986  			// If the sign of zeros are different, negative zeros must be returned according to the spec.
  3987  			x1:  f32x4(0, math.Float32frombits(0b1<<31), 0, 0),
  3988  			x2:  f32x4(math.Float32frombits(0b1<<31), math.Float32frombits(0b1<<31), math.Float32frombits(0b1<<31), 0),
  3989  			exp: f32x4(math.Float32frombits(0b1<<31), math.Float32frombits(0b1<<31), math.Float32frombits(0b1<<31), 0),
  3990  		},
  3991  		{
  3992  			name:  "f32x4",
  3993  			shape: wazeroir.ShapeF32x4,
  3994  			// If the sign of zeros are different, negative zeros must be returned according to the spec.
  3995  			x1:  f32x4(math.Float32frombits(0b1<<31), math.Float32frombits(0b1<<31), math.Float32frombits(0b1<<31), 0),
  3996  			x2:  f32x4(0, math.Float32frombits(0b1<<31), 0, 0),
  3997  			exp: f32x4(math.Float32frombits(0b1<<31), math.Float32frombits(0b1<<31), math.Float32frombits(0b1<<31), 0),
  3998  		},
  3999  		{
  4000  			name:  "f32x4",
  4001  			shape: wazeroir.ShapeF32x4,
  4002  			x1:    f32x4(float32(math.NaN()), -123.12, 2.3, float32(math.Inf(1))),
  4003  			x2:    f32x4(5.5, 123.12, 5.0, float32(math.Inf(-1))),
  4004  			exp:   f32x4(float32(math.NaN()), -123.12, 2.3, float32(math.Inf(-1))),
  4005  		},
  4006  		{
  4007  			name:  "f32x4",
  4008  			shape: wazeroir.ShapeF32x4,
  4009  			x1:    f32x4(5.5, 123.12, -5.0, float32(math.Inf(-1))),
  4010  			x2:    f32x4(-123.12, float32(math.NaN()), 2.3, float32(math.Inf(-1))),
  4011  			exp:   f32x4(-123.12, float32(math.NaN()), -5.0, float32(math.Inf(-1))),
  4012  		},
  4013  		{
  4014  			name:  "f32x4",
  4015  			shape: wazeroir.ShapeF32x4,
  4016  			x1:    f32x4(float32(math.Inf(1)), float32(math.Inf(-1)), float32(math.Inf(-1)), float32(math.Inf(1))),
  4017  			x2:    f32x4(float32(math.NaN()), float32(math.NaN()), float32(math.NaN()), float32(math.NaN())),
  4018  			exp:   f32x4(float32(math.NaN()), float32(math.NaN()), float32(math.NaN()), float32(math.NaN())),
  4019  		},
  4020  		{
  4021  			name:  "f32x4",
  4022  			shape: wazeroir.ShapeF32x4,
  4023  			x1:    f32x4(float32(math.NaN()), float32(math.NaN()), float32(math.NaN()), float32(math.NaN())),
  4024  			x2:    f32x4(float32(math.Inf(1)), float32(math.Inf(-1)), float32(math.Inf(-1)), float32(math.Inf(1))),
  4025  			exp:   f32x4(float32(math.NaN()), float32(math.NaN()), float32(math.NaN()), float32(math.NaN())),
  4026  		},
  4027  		{
  4028  			name:  "f64x2",
  4029  			shape: wazeroir.ShapeF64x2,
  4030  			// If the sign of zeros are different, negative zeros must be returned according to the spec.
  4031  			x1:  f64x2(math.Copysign(0, -1), math.Copysign(0, 1)),
  4032  			x2:  f64x2(math.Copysign(0, -1), math.Copysign(0, -1)),
  4033  			exp: f64x2(math.Copysign(0, -1), math.Copysign(0, -1)),
  4034  		},
  4035  		{
  4036  			name:  "f64x2",
  4037  			shape: wazeroir.ShapeF64x2,
  4038  			// If the sign of zeros are different, negative zeros must be returned according to the spec.
  4039  			x1:  f64x2(math.Copysign(0, -1), 0),
  4040  			x2:  f64x2(0, math.Copysign(0, -1)),
  4041  			exp: f64x2(math.Copysign(0, -1), math.Copysign(0, -1)),
  4042  		},
  4043  		{
  4044  			name:  "f64x2",
  4045  			shape: wazeroir.ShapeF64x2,
  4046  			x1:    f64x2(math.MinInt64, 0),
  4047  			x2:    f64x2(math.MaxInt64, -12.3),
  4048  			exp:   f64x2(math.MinInt64, -12.3),
  4049  		},
  4050  		{
  4051  			name:  "f64x2",
  4052  			shape: wazeroir.ShapeF64x2,
  4053  			x1:    f64x2(math.MaxInt64, -12.3),
  4054  			x2:    f64x2(math.MinInt64, 0),
  4055  			exp:   f64x2(math.MinInt64, -12.3),
  4056  		},
  4057  		{
  4058  			name:  "f64x2",
  4059  			shape: wazeroir.ShapeF64x2,
  4060  			x1:    f64x2(math.NaN(), math.NaN()),
  4061  			x2:    f64x2(math.Inf(1), math.Inf(-1)),
  4062  			exp:   f64x2(math.NaN(), math.NaN()),
  4063  		},
  4064  		{
  4065  			name:  "f64x2",
  4066  			shape: wazeroir.ShapeF64x2,
  4067  			x1:    f64x2(math.Inf(1), math.Inf(-1)),
  4068  			x2:    f64x2(math.NaN(), math.NaN()),
  4069  			exp:   f64x2(math.NaN(), math.NaN()),
  4070  		},
  4071  	}
  4072  
  4073  	for _, tc := range tests {
  4074  		tc := tc
  4075  		t.Run(tc.name, func(t *testing.T) {
  4076  			env := newCompilerEnvironment()
  4077  			compiler := env.requireNewCompiler(t, newCompiler,
  4078  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  4079  
  4080  			err := compiler.compilePreamble()
  4081  			require.NoError(t, err)
  4082  
  4083  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  4084  				Lo: binary.LittleEndian.Uint64(tc.x1[:8]),
  4085  				Hi: binary.LittleEndian.Uint64(tc.x1[8:]),
  4086  			})
  4087  			require.NoError(t, err)
  4088  
  4089  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  4090  				Lo: binary.LittleEndian.Uint64(tc.x2[:8]),
  4091  				Hi: binary.LittleEndian.Uint64(tc.x2[8:]),
  4092  			})
  4093  			require.NoError(t, err)
  4094  
  4095  			err = compiler.compileV128Min(&wazeroir.OperationV128Min{Shape: tc.shape, Signed: tc.signed})
  4096  			require.NoError(t, err)
  4097  
  4098  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  4099  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  4100  
  4101  			err = compiler.compileReturnFunction()
  4102  			require.NoError(t, err)
  4103  
  4104  			// Generate and run the code under test.
  4105  			code, _, err := compiler.compile()
  4106  			require.NoError(t, err)
  4107  			env.exec(code)
  4108  
  4109  			require.Equal(t, nativeCallStatusCodeReturned, env.callEngine().statusCode)
  4110  
  4111  			lo, hi := env.stackTopAsV128()
  4112  			switch tc.shape {
  4113  			case wazeroir.ShapeF64x2:
  4114  				for _, vs := range [][2]float64{
  4115  					{math.Float64frombits(lo), math.Float64frombits(binary.LittleEndian.Uint64(tc.exp[:8]))},
  4116  					{math.Float64frombits(hi), math.Float64frombits(binary.LittleEndian.Uint64(tc.exp[8:]))},
  4117  				} {
  4118  					actual, exp := vs[0], vs[1]
  4119  					if math.IsNaN(exp) {
  4120  						require.True(t, math.IsNaN(actual))
  4121  					} else {
  4122  						require.Equal(t, math.Float64bits(exp), math.Float64bits(actual))
  4123  					}
  4124  				}
  4125  			case wazeroir.ShapeF32x4:
  4126  				for _, vs := range [][2]float32{
  4127  					{math.Float32frombits(uint32(lo)), math.Float32frombits(binary.LittleEndian.Uint32(tc.exp[:4]))},
  4128  					{math.Float32frombits(uint32(lo >> 32)), math.Float32frombits(binary.LittleEndian.Uint32(tc.exp[4:8]))},
  4129  					{math.Float32frombits(uint32(hi)), math.Float32frombits(binary.LittleEndian.Uint32(tc.exp[8:12]))},
  4130  					{math.Float32frombits(uint32(hi >> 32)), math.Float32frombits(binary.LittleEndian.Uint32(tc.exp[12:]))},
  4131  				} {
  4132  					actual, exp := vs[0], vs[1]
  4133  					if math.IsNaN(float64(exp)) {
  4134  						require.True(t, math.IsNaN(float64(actual)))
  4135  					} else {
  4136  						require.Equal(t, math.Float32bits(exp), math.Float32bits(actual))
  4137  					}
  4138  				}
  4139  			default:
  4140  				var actual [16]byte
  4141  				binary.LittleEndian.PutUint64(actual[:8], lo)
  4142  				binary.LittleEndian.PutUint64(actual[8:], hi)
  4143  				require.Equal(t, tc.exp, actual)
  4144  			}
  4145  		})
  4146  	}
  4147  }
  4148  
  4149  func TestCompiler_compileV128Max(t *testing.T) {
  4150  	tests := []struct {
  4151  		name        string
  4152  		shape       wazeroir.Shape
  4153  		signed      bool
  4154  		x1, x2, exp [16]byte
  4155  	}{
  4156  		{
  4157  			name:   "i8x16s",
  4158  			shape:  wazeroir.ShapeI8x16,
  4159  			signed: true,
  4160  			x1:     [16]byte{0: 123, 5: i8ToU8(-1), 15: 2},
  4161  			x2:     [16]byte{0: 1, 5: 0, 15: i8ToU8(-1)},
  4162  			exp:    [16]byte{0: 123, 5: 0, 15: 2},
  4163  		},
  4164  		{
  4165  			name:   "i8x16u",
  4166  			shape:  wazeroir.ShapeI8x16,
  4167  			signed: false,
  4168  			x1:     [16]byte{0: 123, 5: i8ToU8(-1), 15: 2},
  4169  			x2:     [16]byte{0: 1, 5: 0, 15: i8ToU8(-1)},
  4170  			exp:    [16]byte{0: 123, 5: i8ToU8(-1), 15: i8ToU8(-1)},
  4171  		},
  4172  		{
  4173  			name:   "i16x8s",
  4174  			shape:  wazeroir.ShapeI16x8,
  4175  			signed: true,
  4176  			x1:     i16x8(1123, 0, 123, 1, 1, 6, i16ToU16(-123), 1),
  4177  			x2:     i16x8(0, 123, i16ToU16(-123), 3, 1, 4, 5, 1),
  4178  			exp:    i16x8(1123, 123, 123, 3, 1, 6, 5, 1),
  4179  		},
  4180  		{
  4181  			name:   "i16x8u",
  4182  			shape:  wazeroir.ShapeI16x8,
  4183  			signed: false,
  4184  			x1:     i16x8(1123, 0, 123, 1, 1, 6, i16ToU16(-123), 1),
  4185  			x2:     i16x8(0, 123, i16ToU16(-123), 3, 1, 4, 5, 1),
  4186  			exp:    i16x8(1123, 123, i16ToU16(-123), 3, 1, 6, i16ToU16(-123), 1),
  4187  		},
  4188  		{
  4189  			name:   "i32x4s",
  4190  			shape:  wazeroir.ShapeI32x4,
  4191  			signed: true,
  4192  			x1:     i32x4(i32ToU32(-123), 0, 1, i32ToU32(math.MinInt32)),
  4193  			x2:     i32x4(123, 5, 1, 0),
  4194  			exp:    i32x4(123, 5, 1, 0),
  4195  		},
  4196  		{
  4197  			name:   "i32x4u",
  4198  			shape:  wazeroir.ShapeI32x4,
  4199  			signed: false,
  4200  			x1:     i32x4(i32ToU32(-123), 0, 1, i32ToU32(math.MinInt32)),
  4201  			x2:     i32x4(123, 5, 1, 0),
  4202  			exp:    i32x4(i32ToU32(-123), 5, 1, i32ToU32(math.MinInt32)),
  4203  		},
  4204  		{
  4205  			name:  "f32x4",
  4206  			shape: wazeroir.ShapeF32x4,
  4207  			x1:    f32x4(float32(math.NaN()), -123.12, 2.3, float32(math.Inf(1))),
  4208  			x2:    f32x4(5.5, 123.12, 5.0, float32(math.Inf(-1))),
  4209  			exp:   f32x4(float32(math.NaN()), 123.12, 5.0, float32(math.Inf(1))),
  4210  		},
  4211  		{
  4212  			name:  "f32x4",
  4213  			shape: wazeroir.ShapeF32x4,
  4214  			x1:    f32x4(5.5, 123.12, -5.0, float32(math.Inf(-1))),
  4215  			x2:    f32x4(-123.12, float32(math.NaN()), 2.3, float32(math.Inf(-1))),
  4216  			exp:   f32x4(5.5, float32(math.NaN()), 2.3, float32(math.Inf(-1))),
  4217  		},
  4218  		{
  4219  			name:  "f32x4",
  4220  			shape: wazeroir.ShapeF32x4,
  4221  			x1:    f32x4(float32(math.Inf(1)), float32(math.Inf(-1)), float32(math.Inf(-1)), float32(math.Inf(1))),
  4222  			x2:    f32x4(float32(math.NaN()), float32(math.NaN()), float32(math.NaN()), float32(math.NaN())),
  4223  			exp:   f32x4(float32(math.NaN()), float32(math.NaN()), float32(math.NaN()), float32(math.NaN())),
  4224  		},
  4225  		{
  4226  			name:  "f32x4",
  4227  			shape: wazeroir.ShapeF32x4,
  4228  			x1:    f32x4(float32(math.NaN()), float32(math.NaN()), float32(math.NaN()), float32(math.NaN())),
  4229  			x2:    f32x4(float32(math.Inf(1)), float32(math.Inf(-1)), float32(math.Inf(-1)), float32(math.Inf(1))),
  4230  			exp:   f32x4(float32(math.NaN()), float32(math.NaN()), float32(math.NaN()), float32(math.NaN())),
  4231  		},
  4232  		{
  4233  			name:  "f32x4",
  4234  			shape: wazeroir.ShapeF32x4,
  4235  			// If the sign of zeros are different, positive zeros must be returned according to the spec.
  4236  			x1:  f32x4(0, 0, math.Float32frombits(1<<31), 0),
  4237  			x2:  f32x4(math.Float32frombits(1<<31), math.Float32frombits(1<<31), math.Float32frombits(1<<31), math.Float32frombits(1<<31)),
  4238  			exp: f32x4(0, 0, math.Float32frombits(1<<31), 0),
  4239  		},
  4240  		{
  4241  			name:  "f64x2",
  4242  			shape: wazeroir.ShapeF64x2,
  4243  			x1:    f64x2(math.MinInt64, 0),
  4244  			x2:    f64x2(math.MaxInt64, -12.3),
  4245  			exp:   f64x2(math.MaxInt64, 0),
  4246  		},
  4247  		{
  4248  			name:  "f64x2",
  4249  			shape: wazeroir.ShapeF64x2,
  4250  			x1:    f64x2(math.MaxInt64, -12.3),
  4251  			x2:    f64x2(math.MinInt64, 0),
  4252  			exp:   f64x2(math.MaxInt64, 0),
  4253  		},
  4254  		{
  4255  			name:  "f64x2",
  4256  			shape: wazeroir.ShapeF64x2,
  4257  			x1:    f64x2(math.NaN(), -12.3),
  4258  			x2:    f64x2(math.MinInt64, math.NaN()),
  4259  			exp:   f64x2(math.NaN(), math.NaN()),
  4260  		},
  4261  		{
  4262  			name:  "f64x2",
  4263  			shape: wazeroir.ShapeF64x2,
  4264  			x1:    f64x2(math.MinInt64, math.NaN()),
  4265  			x2:    f64x2(math.NaN(), -12.3),
  4266  			exp:   f64x2(math.NaN(), math.NaN()),
  4267  		},
  4268  		{
  4269  			name:  "f64x2",
  4270  			shape: wazeroir.ShapeF64x2,
  4271  			x1:    f64x2(math.NaN(), math.NaN()),
  4272  			x2:    f64x2(math.Inf(1), math.Inf(-1)),
  4273  			exp:   f64x2(math.NaN(), math.NaN()),
  4274  		},
  4275  		{
  4276  			name:  "f64x2",
  4277  			shape: wazeroir.ShapeF64x2,
  4278  			x1:    f64x2(math.Inf(1), math.Inf(-1)),
  4279  			x2:    f64x2(math.NaN(), math.NaN()),
  4280  			exp:   f64x2(math.NaN(), math.NaN()),
  4281  		},
  4282  		{
  4283  			name:  "f64x2",
  4284  			shape: wazeroir.ShapeF64x2,
  4285  			// If the sign of zeros are different, positive zeros must be returned according to the spec.
  4286  			x1:  f64x2(0, 0),
  4287  			x2:  f64x2(math.Copysign(0, -1), math.Copysign(0, -1)),
  4288  			exp: f64x2(0, 0),
  4289  		},
  4290  		{
  4291  			name:  "f64x2",
  4292  			shape: wazeroir.ShapeF64x2,
  4293  			// If the sign of zeros are different, positive zeros must be returned according to the spec.
  4294  			x1:  f64x2(math.Copysign(0, -1), math.Copysign(0, 1)),
  4295  			x2:  f64x2(math.Copysign(0, -1), math.Copysign(0, -1)),
  4296  			exp: f64x2(math.Copysign(0, -1), 0),
  4297  		},
  4298  	}
  4299  
  4300  	for _, tc := range tests {
  4301  		tc := tc
  4302  		t.Run(tc.name, func(t *testing.T) {
  4303  			env := newCompilerEnvironment()
  4304  			compiler := env.requireNewCompiler(t, newCompiler,
  4305  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  4306  
  4307  			err := compiler.compilePreamble()
  4308  			require.NoError(t, err)
  4309  
  4310  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  4311  				Lo: binary.LittleEndian.Uint64(tc.x1[:8]),
  4312  				Hi: binary.LittleEndian.Uint64(tc.x1[8:]),
  4313  			})
  4314  			require.NoError(t, err)
  4315  
  4316  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  4317  				Lo: binary.LittleEndian.Uint64(tc.x2[:8]),
  4318  				Hi: binary.LittleEndian.Uint64(tc.x2[8:]),
  4319  			})
  4320  			require.NoError(t, err)
  4321  
  4322  			err = compiler.compileV128Max(&wazeroir.OperationV128Max{Shape: tc.shape, Signed: tc.signed})
  4323  			require.NoError(t, err)
  4324  
  4325  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  4326  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  4327  
  4328  			err = compiler.compileReturnFunction()
  4329  			require.NoError(t, err)
  4330  
  4331  			// Generate and run the code under test.
  4332  			code, _, err := compiler.compile()
  4333  			require.NoError(t, err)
  4334  			env.exec(code)
  4335  
  4336  			require.Equal(t, nativeCallStatusCodeReturned, env.callEngine().statusCode)
  4337  
  4338  			lo, hi := env.stackTopAsV128()
  4339  			switch tc.shape {
  4340  			case wazeroir.ShapeF64x2:
  4341  				for _, vs := range [][2]float64{
  4342  					{math.Float64frombits(lo), math.Float64frombits(binary.LittleEndian.Uint64(tc.exp[:8]))},
  4343  					{math.Float64frombits(hi), math.Float64frombits(binary.LittleEndian.Uint64(tc.exp[8:]))},
  4344  				} {
  4345  					actual, exp := vs[0], vs[1]
  4346  					if math.IsNaN(exp) {
  4347  						require.True(t, math.IsNaN(actual))
  4348  					} else {
  4349  						require.Equal(t, math.Float64bits(exp), math.Float64bits(actual))
  4350  					}
  4351  				}
  4352  			case wazeroir.ShapeF32x4:
  4353  				for _, vs := range [][2]float32{
  4354  					{math.Float32frombits(uint32(lo)), math.Float32frombits(binary.LittleEndian.Uint32(tc.exp[:4]))},
  4355  					{math.Float32frombits(uint32(lo >> 32)), math.Float32frombits(binary.LittleEndian.Uint32(tc.exp[4:8]))},
  4356  					{math.Float32frombits(uint32(hi)), math.Float32frombits(binary.LittleEndian.Uint32(tc.exp[8:12]))},
  4357  					{math.Float32frombits(uint32(hi >> 32)), math.Float32frombits(binary.LittleEndian.Uint32(tc.exp[12:]))},
  4358  				} {
  4359  					actual, exp := vs[0], vs[1]
  4360  					if math.IsNaN(float64(exp)) {
  4361  						require.True(t, math.IsNaN(float64(actual)))
  4362  					} else {
  4363  						require.Equal(t, math.Float32bits(exp), math.Float32bits(actual))
  4364  					}
  4365  				}
  4366  			default:
  4367  				var actual [16]byte
  4368  				binary.LittleEndian.PutUint64(actual[:8], lo)
  4369  				binary.LittleEndian.PutUint64(actual[8:], hi)
  4370  				require.Equal(t, tc.exp, actual)
  4371  			}
  4372  		})
  4373  	}
  4374  }
  4375  
  4376  func TestCompiler_compileV128AddSat(t *testing.T) {
  4377  	tests := []struct {
  4378  		name        string
  4379  		shape       wazeroir.Shape
  4380  		signed      bool
  4381  		x1, x2, exp [16]byte
  4382  	}{
  4383  		{
  4384  			name:   "i8x16s",
  4385  			shape:  wazeroir.ShapeI8x16,
  4386  			signed: true,
  4387  			x1: [16]byte{
  4388  				0:  i8ToU8(math.MaxInt8),
  4389  				5:  i8ToU8(-1),
  4390  				15: i8ToU8(math.MinInt8),
  4391  			},
  4392  			x2: [16]byte{
  4393  				0:  1,
  4394  				5:  0,
  4395  				15: i8ToU8(-1),
  4396  			},
  4397  			exp: [16]byte{
  4398  				0:  i8ToU8(math.MaxInt8),
  4399  				5:  i8ToU8(-1),
  4400  				15: i8ToU8(math.MinInt8),
  4401  			},
  4402  		},
  4403  		{
  4404  			name:   "i8x16u",
  4405  			shape:  wazeroir.ShapeI8x16,
  4406  			signed: false,
  4407  			x1: [16]byte{
  4408  				0:  i8ToU8(math.MaxInt8),
  4409  				5:  0,
  4410  				15: math.MaxUint8,
  4411  			},
  4412  			x2: [16]byte{
  4413  				0:  1,
  4414  				5:  i8ToU8(-1),
  4415  				15: 1,
  4416  			},
  4417  			exp: [16]byte{
  4418  				0:  i8ToU8(math.MaxInt8) + 1,
  4419  				5:  i8ToU8(-1),
  4420  				15: math.MaxUint8,
  4421  			},
  4422  		},
  4423  		{
  4424  			name:   "i16x8s",
  4425  			shape:  wazeroir.ShapeI16x8,
  4426  			signed: true,
  4427  			x1:     i16x8(i16ToU16(math.MinInt16), 0, 123, 1, 1, 6, i16ToU16(-123), i16ToU16(math.MaxInt16)),
  4428  			x2:     i16x8(i16ToU16(-1), 123, i16ToU16(-123), 3, 1, 4, 5, 1),
  4429  			exp:    i16x8(i16ToU16(math.MinInt16), 123, 0, 4, 2, 10, i16ToU16(-118), i16ToU16(math.MaxInt16)),
  4430  		},
  4431  		{
  4432  			name:   "i16x8u",
  4433  			shape:  wazeroir.ShapeI16x8,
  4434  			signed: false,
  4435  			x1:     i16x8(1123, 0, 123, 1, 1, 6, i16ToU16(-123), math.MaxUint16),
  4436  			x2:     i16x8(0, 123, math.MaxUint16, 3, 1, 4, 0, 1),
  4437  			exp:    i16x8(1123, 123, math.MaxUint16, 4, 2, 10, i16ToU16(-123), math.MaxUint16),
  4438  		},
  4439  	}
  4440  
  4441  	for _, tc := range tests {
  4442  		tc := tc
  4443  		t.Run(tc.name, func(t *testing.T) {
  4444  			env := newCompilerEnvironment()
  4445  			compiler := env.requireNewCompiler(t, newCompiler,
  4446  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  4447  
  4448  			err := compiler.compilePreamble()
  4449  			require.NoError(t, err)
  4450  
  4451  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  4452  				Lo: binary.LittleEndian.Uint64(tc.x1[:8]),
  4453  				Hi: binary.LittleEndian.Uint64(tc.x1[8:]),
  4454  			})
  4455  			require.NoError(t, err)
  4456  
  4457  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  4458  				Lo: binary.LittleEndian.Uint64(tc.x2[:8]),
  4459  				Hi: binary.LittleEndian.Uint64(tc.x2[8:]),
  4460  			})
  4461  			require.NoError(t, err)
  4462  
  4463  			err = compiler.compileV128AddSat(&wazeroir.OperationV128AddSat{Shape: tc.shape, Signed: tc.signed})
  4464  			require.NoError(t, err)
  4465  
  4466  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  4467  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  4468  
  4469  			err = compiler.compileReturnFunction()
  4470  			require.NoError(t, err)
  4471  
  4472  			// Generate and run the code under test.
  4473  			code, _, err := compiler.compile()
  4474  			require.NoError(t, err)
  4475  			env.exec(code)
  4476  
  4477  			require.Equal(t, nativeCallStatusCodeReturned, env.callEngine().statusCode)
  4478  
  4479  			lo, hi := env.stackTopAsV128()
  4480  			var actual [16]byte
  4481  			binary.LittleEndian.PutUint64(actual[:8], lo)
  4482  			binary.LittleEndian.PutUint64(actual[8:], hi)
  4483  			require.Equal(t, tc.exp, actual)
  4484  		})
  4485  	}
  4486  }
  4487  
  4488  func TestCompiler_compileV128SubSat(t *testing.T) {
  4489  	tests := []struct {
  4490  		name        string
  4491  		shape       wazeroir.Shape
  4492  		signed      bool
  4493  		x1, x2, exp [16]byte
  4494  	}{
  4495  		{
  4496  			name:   "i8x16s",
  4497  			shape:  wazeroir.ShapeI8x16,
  4498  			signed: true,
  4499  			x1: [16]byte{
  4500  				0:  i8ToU8(math.MinInt8),
  4501  				5:  i8ToU8(-1),
  4502  				15: i8ToU8(math.MaxInt8),
  4503  			},
  4504  			x2: [16]byte{
  4505  				0:  1,
  4506  				5:  0,
  4507  				15: i8ToU8(-1),
  4508  			},
  4509  			exp: [16]byte{
  4510  				0:  i8ToU8(math.MinInt8),
  4511  				5:  i8ToU8(-1),
  4512  				15: i8ToU8(math.MaxInt8),
  4513  			},
  4514  		},
  4515  		{
  4516  			name:   "i8x16u",
  4517  			shape:  wazeroir.ShapeI8x16,
  4518  			signed: false,
  4519  			x1: [16]byte{
  4520  				0:  i8ToU8(math.MinInt8),
  4521  				5:  i8ToU8(-1),
  4522  				15: 0,
  4523  			},
  4524  			x2: [16]byte{
  4525  				0:  1,
  4526  				5:  0,
  4527  				15: 1,
  4528  			},
  4529  			exp: [16]byte{
  4530  				0:  i8ToU8(math.MinInt8) - 1,
  4531  				5:  i8ToU8(-1),
  4532  				15: 0,
  4533  			},
  4534  		},
  4535  		{
  4536  			name:   "i16x8s",
  4537  			shape:  wazeroir.ShapeI16x8,
  4538  			signed: true,
  4539  			x1:     i16x8(i16ToU16(math.MinInt16), 0, 123, 1, 1, 6, i16ToU16(-123), i16ToU16(math.MaxInt16)),
  4540  			x2:     i16x8(1, 123, i16ToU16(-123), 3, 1, 4, 5, i16ToU16(-123)),
  4541  			exp:    i16x8(i16ToU16(math.MinInt16), i16ToU16(-123), 246, i16ToU16(-2), 0, 2, i16ToU16(-128), i16ToU16(math.MaxInt16)),
  4542  		},
  4543  		{
  4544  			name:   "i16x8u",
  4545  			shape:  wazeroir.ShapeI16x8,
  4546  			signed: false,
  4547  			x1:     i16x8(1123, 0, 123, 1, 1, 6, 200, math.MaxUint16),
  4548  			x2:     i16x8(0, 123, math.MaxUint16, 3, 1, 4, i16ToU16(-1), 12),
  4549  			exp:    i16x8(1123, 0, 0, 0, 0, 2, 0, math.MaxUint16-12),
  4550  		},
  4551  	}
  4552  
  4553  	for _, tc := range tests {
  4554  		tc := tc
  4555  		t.Run(tc.name, func(t *testing.T) {
  4556  			env := newCompilerEnvironment()
  4557  			compiler := env.requireNewCompiler(t, newCompiler,
  4558  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  4559  
  4560  			err := compiler.compilePreamble()
  4561  			require.NoError(t, err)
  4562  
  4563  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  4564  				Lo: binary.LittleEndian.Uint64(tc.x1[:8]),
  4565  				Hi: binary.LittleEndian.Uint64(tc.x1[8:]),
  4566  			})
  4567  			require.NoError(t, err)
  4568  
  4569  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  4570  				Lo: binary.LittleEndian.Uint64(tc.x2[:8]),
  4571  				Hi: binary.LittleEndian.Uint64(tc.x2[8:]),
  4572  			})
  4573  			require.NoError(t, err)
  4574  
  4575  			err = compiler.compileV128SubSat(&wazeroir.OperationV128SubSat{Shape: tc.shape, Signed: tc.signed})
  4576  			require.NoError(t, err)
  4577  
  4578  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  4579  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  4580  
  4581  			err = compiler.compileReturnFunction()
  4582  			require.NoError(t, err)
  4583  
  4584  			// Generate and run the code under test.
  4585  			code, _, err := compiler.compile()
  4586  			require.NoError(t, err)
  4587  			env.exec(code)
  4588  
  4589  			require.Equal(t, nativeCallStatusCodeReturned, env.callEngine().statusCode)
  4590  
  4591  			lo, hi := env.stackTopAsV128()
  4592  			var actual [16]byte
  4593  			binary.LittleEndian.PutUint64(actual[:8], lo)
  4594  			binary.LittleEndian.PutUint64(actual[8:], hi)
  4595  			require.Equal(t, tc.exp, actual)
  4596  		})
  4597  	}
  4598  }
  4599  
  4600  func TestCompiler_compileV128Popcnt(t *testing.T) {
  4601  	tests := []struct {
  4602  		name   string
  4603  		v, exp [16]byte
  4604  	}{
  4605  		{
  4606  			name: "ones",
  4607  			v: [16]byte{
  4608  				1, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7,
  4609  				0, 1 << 2, 0, 1 << 4, 0, 1 << 6, 0, 0,
  4610  			},
  4611  			exp: [16]byte{
  4612  				1, 1, 1, 1, 1, 1, 1, 1,
  4613  				0, 1, 0, 1, 0, 1, 0, 0,
  4614  			},
  4615  		},
  4616  		{
  4617  			name: "mix",
  4618  			v: [16]byte{
  4619  				0b1, 0b11, 0b111, 0b1111, 0b11111, 0b111111, 0b1111111, 0b11111111,
  4620  				0b10000001, 0b10000010, 0b10000100, 0b10001000, 0b10010000, 0b10100000, 0b11000000, 0,
  4621  			},
  4622  			exp: [16]byte{
  4623  				1, 2, 3, 4, 5, 6, 7, 8,
  4624  				2, 2, 2, 2, 2, 2, 2, 0,
  4625  			},
  4626  		},
  4627  	}
  4628  
  4629  	for _, tc := range tests {
  4630  		tc := tc
  4631  		t.Run(tc.name, func(t *testing.T) {
  4632  			env := newCompilerEnvironment()
  4633  			compiler := env.requireNewCompiler(t, newCompiler,
  4634  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  4635  
  4636  			err := compiler.compilePreamble()
  4637  			require.NoError(t, err)
  4638  
  4639  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  4640  				Lo: binary.LittleEndian.Uint64(tc.v[:8]),
  4641  				Hi: binary.LittleEndian.Uint64(tc.v[8:]),
  4642  			})
  4643  			require.NoError(t, err)
  4644  
  4645  			err = compiler.compileV128Popcnt(&wazeroir.OperationV128Popcnt{})
  4646  			require.NoError(t, err)
  4647  
  4648  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  4649  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  4650  
  4651  			err = compiler.compileReturnFunction()
  4652  			require.NoError(t, err)
  4653  
  4654  			// Generate and run the code under test.
  4655  			code, _, err := compiler.compile()
  4656  			require.NoError(t, err)
  4657  			env.exec(code)
  4658  
  4659  			require.Equal(t, nativeCallStatusCodeReturned, env.callEngine().statusCode)
  4660  
  4661  			lo, hi := env.stackTopAsV128()
  4662  			var actual [16]byte
  4663  			binary.LittleEndian.PutUint64(actual[:8], lo)
  4664  			binary.LittleEndian.PutUint64(actual[8:], hi)
  4665  			require.Equal(t, tc.exp, actual)
  4666  		})
  4667  	}
  4668  }
  4669  
  4670  func TestCompiler_compileV128Round(t *testing.T) {
  4671  	tests := []struct {
  4672  		name  string
  4673  		shape wazeroir.Shape
  4674  		kind  wazeroir.OperationKind
  4675  		v     [16]byte
  4676  	}{
  4677  		{
  4678  			name:  "f32 ceil",
  4679  			shape: wazeroir.ShapeF32x4,
  4680  			kind:  wazeroir.OperationKindV128Ceil,
  4681  			v:     f32x4(1.4, -1.5, 1.5, float32(math.Inf(1))),
  4682  		},
  4683  		{
  4684  			name:  "f32 ceil",
  4685  			shape: wazeroir.ShapeF32x4,
  4686  			kind:  wazeroir.OperationKindV128Ceil,
  4687  			v:     f32x4(math.Pi, -1231231.123, float32(math.NaN()), float32(math.Inf(-1))),
  4688  		},
  4689  		{
  4690  			name:  "f64 ceil",
  4691  			shape: wazeroir.ShapeF64x2,
  4692  			kind:  wazeroir.OperationKindV128Ceil,
  4693  			v:     f64x2(1.231, -123.12313),
  4694  		},
  4695  		{
  4696  			name:  "f64 ceil",
  4697  			shape: wazeroir.ShapeF64x2,
  4698  			kind:  wazeroir.OperationKindV128Ceil,
  4699  			v:     f64x2(math.Inf(1), math.NaN()),
  4700  		},
  4701  		{
  4702  			name:  "f64 ceil",
  4703  			shape: wazeroir.ShapeF64x2,
  4704  			kind:  wazeroir.OperationKindV128Ceil,
  4705  			v:     f64x2(math.Inf(-1), math.Pi),
  4706  		},
  4707  		{
  4708  			name:  "f32 floor",
  4709  			shape: wazeroir.ShapeF32x4,
  4710  			kind:  wazeroir.OperationKindV128Floor,
  4711  			v:     f32x4(1.4, -1.5, 1.5, float32(math.Inf(1))),
  4712  		},
  4713  		{
  4714  			name:  "f32 floor",
  4715  			shape: wazeroir.ShapeF32x4,
  4716  			kind:  wazeroir.OperationKindV128Floor,
  4717  			v:     f32x4(math.Pi, -1231231.123, float32(math.NaN()), float32(math.Inf(-1))),
  4718  		},
  4719  		{
  4720  			name:  "f64 floor",
  4721  			shape: wazeroir.ShapeF64x2,
  4722  			kind:  wazeroir.OperationKindV128Floor,
  4723  			v:     f64x2(1.231, -123.12313),
  4724  		},
  4725  		{
  4726  			name:  "f64 floor",
  4727  			shape: wazeroir.ShapeF64x2,
  4728  			kind:  wazeroir.OperationKindV128Floor,
  4729  			v:     f64x2(math.Inf(1), math.NaN()),
  4730  		},
  4731  		{
  4732  			name:  "f64 floor",
  4733  			shape: wazeroir.ShapeF64x2,
  4734  			kind:  wazeroir.OperationKindV128Floor,
  4735  			v:     f64x2(math.Inf(-1), math.Pi),
  4736  		},
  4737  		{
  4738  			name:  "f32 trunc",
  4739  			shape: wazeroir.ShapeF32x4,
  4740  			kind:  wazeroir.OperationKindV128Trunc,
  4741  			v:     f32x4(1.4, -1.5, 1.5, float32(math.Inf(1))),
  4742  		},
  4743  		{
  4744  			name:  "f32 trunc",
  4745  			shape: wazeroir.ShapeF32x4,
  4746  			kind:  wazeroir.OperationKindV128Trunc,
  4747  			v:     f32x4(math.Pi, -1231231.123, float32(math.NaN()), float32(math.Inf(-1))),
  4748  		},
  4749  		{
  4750  			name:  "f64 trunc",
  4751  			shape: wazeroir.ShapeF64x2,
  4752  			kind:  wazeroir.OperationKindV128Trunc,
  4753  			v:     f64x2(1.231, -123.12313),
  4754  		},
  4755  		{
  4756  			name:  "f64 trunc",
  4757  			shape: wazeroir.ShapeF64x2,
  4758  			kind:  wazeroir.OperationKindV128Trunc,
  4759  			v:     f64x2(math.Inf(1), math.NaN()),
  4760  		},
  4761  		{
  4762  			name:  "f64 trunc",
  4763  			shape: wazeroir.ShapeF64x2,
  4764  			kind:  wazeroir.OperationKindV128Trunc,
  4765  			v:     f64x2(math.Inf(-1), math.Pi),
  4766  		},
  4767  		{
  4768  			name:  "f32 nearest",
  4769  			shape: wazeroir.ShapeF32x4,
  4770  			kind:  wazeroir.OperationKindV128Nearest,
  4771  			v:     f32x4(1.4, -1.5, 1.5, float32(math.Inf(1))),
  4772  		},
  4773  		{
  4774  			name:  "f32 nearest",
  4775  			shape: wazeroir.ShapeF32x4,
  4776  			kind:  wazeroir.OperationKindV128Nearest,
  4777  			v:     f32x4(math.Pi, -1231231.123, float32(math.NaN()), float32(math.Inf(-1))),
  4778  		},
  4779  		{
  4780  			name:  "f64 nearest",
  4781  			shape: wazeroir.ShapeF64x2,
  4782  			kind:  wazeroir.OperationKindV128Nearest,
  4783  			v:     f64x2(1.231, -123.12313),
  4784  		},
  4785  		{
  4786  			name:  "f64 nearest",
  4787  			shape: wazeroir.ShapeF64x2,
  4788  			kind:  wazeroir.OperationKindV128Nearest,
  4789  			v:     f64x2(math.Inf(1), math.NaN()),
  4790  		},
  4791  		{
  4792  			name:  "f64 nearest",
  4793  			shape: wazeroir.ShapeF64x2,
  4794  			kind:  wazeroir.OperationKindV128Nearest,
  4795  			v:     f64x2(math.Inf(-1), math.Pi),
  4796  		},
  4797  	}
  4798  
  4799  	for _, tc := range tests {
  4800  		tc := tc
  4801  		t.Run(tc.name, func(t *testing.T) {
  4802  			env := newCompilerEnvironment()
  4803  			compiler := env.requireNewCompiler(t, newCompiler,
  4804  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  4805  
  4806  			err := compiler.compilePreamble()
  4807  			require.NoError(t, err)
  4808  
  4809  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  4810  				Lo: binary.LittleEndian.Uint64(tc.v[:8]),
  4811  				Hi: binary.LittleEndian.Uint64(tc.v[8:]),
  4812  			})
  4813  			require.NoError(t, err)
  4814  
  4815  			is32bit := tc.shape == wazeroir.ShapeF32x4
  4816  			switch tc.kind {
  4817  			case wazeroir.OperationKindV128Ceil:
  4818  				err = compiler.compileV128Ceil(&wazeroir.OperationV128Ceil{Shape: tc.shape})
  4819  			case wazeroir.OperationKindV128Floor:
  4820  				err = compiler.compileV128Floor(&wazeroir.OperationV128Floor{Shape: tc.shape})
  4821  			case wazeroir.OperationKindV128Trunc:
  4822  				err = compiler.compileV128Trunc(&wazeroir.OperationV128Trunc{Shape: tc.shape})
  4823  			case wazeroir.OperationKindV128Nearest:
  4824  				err = compiler.compileV128Nearest(&wazeroir.OperationV128Nearest{Shape: tc.shape})
  4825  			}
  4826  			require.NoError(t, err)
  4827  
  4828  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  4829  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  4830  
  4831  			err = compiler.compileReturnFunction()
  4832  			require.NoError(t, err)
  4833  
  4834  			// Generate and run the code under test.
  4835  			code, _, err := compiler.compile()
  4836  			require.NoError(t, err)
  4837  			env.exec(code)
  4838  
  4839  			require.Equal(t, nativeCallStatusCodeReturned, env.callEngine().statusCode)
  4840  
  4841  			lo, hi := env.stackTopAsV128()
  4842  
  4843  			if is32bit {
  4844  				actualFs := [4]float32{
  4845  					math.Float32frombits(uint32(lo)),
  4846  					math.Float32frombits(uint32(lo >> 32)),
  4847  					math.Float32frombits(uint32(hi)),
  4848  					math.Float32frombits(uint32(hi >> 32)),
  4849  				}
  4850  				f1Original, f2Original, f3Original, f4Original := math.Float32frombits(binary.LittleEndian.Uint32(tc.v[:4])),
  4851  					math.Float32frombits(binary.LittleEndian.Uint32(tc.v[4:8])),
  4852  					math.Float32frombits(binary.LittleEndian.Uint32(tc.v[8:12])),
  4853  					math.Float32frombits(binary.LittleEndian.Uint32(tc.v[12:]))
  4854  
  4855  				var expFs [4]float32
  4856  				switch tc.kind {
  4857  				case wazeroir.OperationKindV128Ceil:
  4858  					expFs[0] = float32(math.Ceil(float64(f1Original)))
  4859  					expFs[1] = float32(math.Ceil(float64(f2Original)))
  4860  					expFs[2] = float32(math.Ceil(float64(f3Original)))
  4861  					expFs[3] = float32(math.Ceil(float64(f4Original)))
  4862  				case wazeroir.OperationKindV128Floor:
  4863  					expFs[0] = float32(math.Floor(float64(f1Original)))
  4864  					expFs[1] = float32(math.Floor(float64(f2Original)))
  4865  					expFs[2] = float32(math.Floor(float64(f3Original)))
  4866  					expFs[3] = float32(math.Floor(float64(f4Original)))
  4867  				case wazeroir.OperationKindV128Trunc:
  4868  					expFs[0] = float32(math.Trunc(float64(f1Original)))
  4869  					expFs[1] = float32(math.Trunc(float64(f2Original)))
  4870  					expFs[2] = float32(math.Trunc(float64(f3Original)))
  4871  					expFs[3] = float32(math.Trunc(float64(f4Original)))
  4872  				case wazeroir.OperationKindV128Nearest:
  4873  					expFs[0] = moremath.WasmCompatNearestF32(f1Original)
  4874  					expFs[1] = moremath.WasmCompatNearestF32(f2Original)
  4875  					expFs[2] = moremath.WasmCompatNearestF32(f3Original)
  4876  					expFs[3] = moremath.WasmCompatNearestF32(f4Original)
  4877  				}
  4878  
  4879  				for i := range expFs {
  4880  					exp, actual := expFs[i], actualFs[i]
  4881  					if math.IsNaN(float64(exp)) {
  4882  						require.True(t, math.IsNaN(float64(actual)))
  4883  					} else {
  4884  						require.Equal(t, exp, actual)
  4885  					}
  4886  				}
  4887  			} else {
  4888  				actualFs := [2]float64{math.Float64frombits(lo), math.Float64frombits(hi)}
  4889  				f1Original, f2Original := math.Float64frombits(binary.LittleEndian.Uint64(tc.v[:8])), math.Float64frombits(binary.LittleEndian.Uint64(tc.v[8:]))
  4890  
  4891  				var expFs [2]float64
  4892  				switch tc.kind {
  4893  				case wazeroir.OperationKindV128Ceil:
  4894  					expFs[0] = math.Ceil(f1Original)
  4895  					expFs[1] = math.Ceil(f2Original)
  4896  				case wazeroir.OperationKindV128Floor:
  4897  					expFs[0] = math.Floor(f1Original)
  4898  					expFs[1] = math.Floor(f2Original)
  4899  				case wazeroir.OperationKindV128Trunc:
  4900  					expFs[0] = math.Trunc(f1Original)
  4901  					expFs[1] = math.Trunc(f2Original)
  4902  				case wazeroir.OperationKindV128Nearest:
  4903  					expFs[0] = moremath.WasmCompatNearestF64(f1Original)
  4904  					expFs[1] = moremath.WasmCompatNearestF64(f2Original)
  4905  				}
  4906  
  4907  				for i := range expFs {
  4908  					exp, actual := expFs[i], actualFs[i]
  4909  					if math.IsNaN(exp) {
  4910  						require.True(t, math.IsNaN(actual))
  4911  					} else {
  4912  						require.Equal(t, exp, actual)
  4913  					}
  4914  				}
  4915  			}
  4916  		})
  4917  	}
  4918  }
  4919  
  4920  func TestCompiler_compileV128_Pmax_Pmin(t *testing.T) {
  4921  	tests := []struct {
  4922  		name        string
  4923  		shape       wazeroir.Shape
  4924  		kind        wazeroir.OperationKind
  4925  		x1, x2, exp [16]byte
  4926  	}{
  4927  		{
  4928  			name:  "f32 pmin",
  4929  			shape: wazeroir.ShapeF32x4,
  4930  			kind:  wazeroir.OperationKindV128Pmin,
  4931  			x1:    f32x4(float32(math.Inf(1)), -1.5, 1123.5, float32(math.Inf(1))),
  4932  			x2:    f32x4(1.4, float32(math.Inf(-1)), -1231.5, float32(math.Inf(1))),
  4933  			exp:   f32x4(1.4, float32(math.Inf(-1)), -1231.5, float32(math.Inf(1))),
  4934  		},
  4935  		{
  4936  			name:  "f32 pmin",
  4937  			shape: wazeroir.ShapeF32x4,
  4938  			kind:  wazeroir.OperationKindV128Pmin,
  4939  			x1:    f32x4(float32(math.NaN()), float32(math.NaN()), float32(math.NaN()), float32(math.NaN())),
  4940  			x2:    f32x4(1.4, -1.5, 1.5, float32(math.Inf(1))),
  4941  			exp:   f32x4(float32(math.NaN()), float32(math.NaN()), float32(math.NaN()), float32(math.NaN())),
  4942  		},
  4943  		{
  4944  			name:  "f32 pmin",
  4945  			shape: wazeroir.ShapeF32x4,
  4946  			kind:  wazeroir.OperationKindV128Pmin,
  4947  			x1:    f32x4(1.4, -1.5, 1.5, float32(math.Inf(1))),
  4948  			x2:    f32x4(float32(math.NaN()), float32(math.NaN()), float32(math.NaN()), float32(math.NaN())),
  4949  			exp:   f32x4(1.4, -1.5, 1.5, float32(math.Inf(1))),
  4950  		},
  4951  		{
  4952  			name:  "f32 pmin",
  4953  			shape: wazeroir.ShapeF32x4,
  4954  			kind:  wazeroir.OperationKindV128Pmin,
  4955  			x1:    f32x4(float32(math.Inf(1)), float32(math.Inf(-1)), float32(math.Inf(-1)), float32(math.Inf(1))),
  4956  			x2:    f32x4(float32(math.NaN()), float32(math.NaN()), float32(math.NaN()), float32(math.NaN())),
  4957  			exp:   f32x4(float32(math.Inf(1)), float32(math.Inf(-1)), float32(math.Inf(-1)), float32(math.Inf(1))),
  4958  		},
  4959  		{
  4960  			name:  "f32 pmin",
  4961  			shape: wazeroir.ShapeF32x4,
  4962  			kind:  wazeroir.OperationKindV128Pmin,
  4963  			x1:    f32x4(float32(math.NaN()), float32(math.NaN()), float32(math.NaN()), float32(math.NaN())),
  4964  			x2:    f32x4(float32(math.Inf(1)), float32(math.Inf(-1)), float32(math.Inf(-1)), float32(math.Inf(1))),
  4965  			exp:   f32x4(float32(math.NaN()), float32(math.NaN()), float32(math.NaN()), float32(math.NaN())),
  4966  		},
  4967  		{
  4968  			name:  "f64 pmin",
  4969  			shape: wazeroir.ShapeF64x2,
  4970  			kind:  wazeroir.OperationKindV128Pmin,
  4971  			x1:    f64x2(math.Inf(1), -123123.1231),
  4972  			x2:    f64x2(-123123.1, math.Inf(-1)),
  4973  			exp:   f64x2(-123123.1, math.Inf(-1)),
  4974  		},
  4975  		{
  4976  			name:  "f64 pmin",
  4977  			shape: wazeroir.ShapeF64x2,
  4978  			kind:  wazeroir.OperationKindV128Pmin,
  4979  			x1:    f64x2(math.NaN(), math.NaN()),
  4980  			x2:    f64x2(-123123.1, 1.0),
  4981  			exp:   f64x2(math.NaN(), math.NaN()),
  4982  		},
  4983  		{
  4984  			name:  "f64 pmin",
  4985  			shape: wazeroir.ShapeF64x2,
  4986  			kind:  wazeroir.OperationKindV128Pmin,
  4987  			x1:    f64x2(-123123.1, 1.0),
  4988  			x2:    f64x2(math.NaN(), math.NaN()),
  4989  			exp:   f64x2(-123123.1, 1.0),
  4990  		},
  4991  		{
  4992  			name:  "f64 pmin",
  4993  			shape: wazeroir.ShapeF64x2,
  4994  			kind:  wazeroir.OperationKindV128Pmin,
  4995  			x1:    f64x2(math.NaN(), math.NaN()),
  4996  			x2:    f64x2(math.Inf(1), math.Inf(-1)),
  4997  			exp:   f64x2(math.NaN(), math.NaN()),
  4998  		},
  4999  		{
  5000  			name:  "f64 pmin",
  5001  			shape: wazeroir.ShapeF64x2,
  5002  			kind:  wazeroir.OperationKindV128Pmin,
  5003  			x1:    f64x2(math.Inf(1), math.Inf(-1)),
  5004  			x2:    f64x2(math.NaN(), math.NaN()),
  5005  			exp:   f64x2(math.Inf(1), math.Inf(-1)),
  5006  		},
  5007  		{
  5008  			name:  "f32 pmax",
  5009  			shape: wazeroir.ShapeF32x4,
  5010  			kind:  wazeroir.OperationKindV128Pmax,
  5011  			x1:    f32x4(float32(math.Inf(1)), -1.5, 1123.5, float32(math.Inf(1))),
  5012  			x2:    f32x4(1.4, float32(math.Inf(-1)), -1231.5, float32(math.Inf(1))),
  5013  			exp:   f32x4(float32(math.Inf(1)), -1.5, 1123.5, float32(math.Inf(1))),
  5014  		},
  5015  		{
  5016  			name:  "f32 pmax",
  5017  			shape: wazeroir.ShapeF32x4,
  5018  			kind:  wazeroir.OperationKindV128Pmax,
  5019  			x1:    f32x4(float32(math.NaN()), float32(math.NaN()), float32(math.NaN()), float32(math.NaN())),
  5020  			x2:    f32x4(1.4, -1.5, 1.5, float32(math.Inf(1))),
  5021  			exp:   f32x4(float32(math.NaN()), float32(math.NaN()), float32(math.NaN()), float32(math.NaN())),
  5022  		},
  5023  		{
  5024  			name:  "f32 pmax",
  5025  			shape: wazeroir.ShapeF32x4,
  5026  			kind:  wazeroir.OperationKindV128Pmax,
  5027  			x1:    f32x4(1.4, -1.5, 1.5, float32(math.Inf(1))),
  5028  			x2:    f32x4(float32(math.NaN()), float32(math.NaN()), float32(math.NaN()), float32(math.NaN())),
  5029  			exp:   f32x4(1.4, -1.5, 1.5, float32(math.Inf(1))),
  5030  		},
  5031  		{
  5032  			name:  "f32 pmax",
  5033  			shape: wazeroir.ShapeF32x4,
  5034  			kind:  wazeroir.OperationKindV128Pmax,
  5035  			x1:    f32x4(float32(math.Inf(1)), float32(math.Inf(-1)), float32(math.Inf(-1)), float32(math.Inf(1))),
  5036  			x2:    f32x4(float32(math.NaN()), float32(math.NaN()), float32(math.NaN()), float32(math.NaN())),
  5037  			exp:   f32x4(float32(math.Inf(1)), float32(math.Inf(-1)), float32(math.Inf(-1)), float32(math.Inf(1))),
  5038  		},
  5039  		{
  5040  			name:  "f32 pmax",
  5041  			shape: wazeroir.ShapeF32x4,
  5042  			kind:  wazeroir.OperationKindV128Pmax,
  5043  			x1:    f32x4(float32(math.NaN()), float32(math.NaN()), float32(math.NaN()), float32(math.NaN())),
  5044  			x2:    f32x4(float32(math.Inf(1)), float32(math.Inf(-1)), float32(math.Inf(-1)), float32(math.Inf(1))),
  5045  			exp:   f32x4(float32(math.NaN()), float32(math.NaN()), float32(math.NaN()), float32(math.NaN())),
  5046  		},
  5047  		{
  5048  			name:  "f64 pmax",
  5049  			shape: wazeroir.ShapeF64x2,
  5050  			kind:  wazeroir.OperationKindV128Pmax,
  5051  			x1:    f64x2(math.Inf(1), -123123.1231),
  5052  			x2:    f64x2(-123123.1, math.Inf(-1)),
  5053  			exp:   f64x2(math.Inf(1), -123123.1231),
  5054  		},
  5055  		{
  5056  			name:  "f64 pmax",
  5057  			shape: wazeroir.ShapeF64x2,
  5058  			kind:  wazeroir.OperationKindV128Pmax,
  5059  			x1:    f64x2(math.NaN(), math.NaN()),
  5060  			x2:    f64x2(-123123.1, 1.0),
  5061  			exp:   f64x2(math.NaN(), math.NaN()),
  5062  		},
  5063  		{
  5064  			name:  "f64 pmax",
  5065  			shape: wazeroir.ShapeF64x2,
  5066  			kind:  wazeroir.OperationKindV128Pmax,
  5067  			x1:    f64x2(-123123.1, 1.0),
  5068  			x2:    f64x2(math.NaN(), math.NaN()),
  5069  			exp:   f64x2(-123123.1, 1.0),
  5070  		},
  5071  		{
  5072  			name:  "f64 pmax",
  5073  			shape: wazeroir.ShapeF64x2,
  5074  			kind:  wazeroir.OperationKindV128Pmax,
  5075  			x1:    f64x2(math.NaN(), math.NaN()),
  5076  			x2:    f64x2(math.Inf(1), math.Inf(-1)),
  5077  			exp:   f64x2(math.NaN(), math.NaN()),
  5078  		},
  5079  		{
  5080  			name:  "f64 pmax",
  5081  			shape: wazeroir.ShapeF64x2,
  5082  			kind:  wazeroir.OperationKindV128Pmax,
  5083  			x1:    f64x2(math.Inf(1), math.Inf(-1)),
  5084  			x2:    f64x2(math.NaN(), math.NaN()),
  5085  			exp:   f64x2(math.Inf(1), math.Inf(-1)),
  5086  		},
  5087  	}
  5088  
  5089  	for _, tc := range tests {
  5090  		tc := tc
  5091  		t.Run(tc.name, func(t *testing.T) {
  5092  			env := newCompilerEnvironment()
  5093  			compiler := env.requireNewCompiler(t, newCompiler,
  5094  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  5095  
  5096  			err := compiler.compilePreamble()
  5097  			require.NoError(t, err)
  5098  
  5099  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  5100  				Lo: binary.LittleEndian.Uint64(tc.x1[:8]),
  5101  				Hi: binary.LittleEndian.Uint64(tc.x1[8:]),
  5102  			})
  5103  			require.NoError(t, err)
  5104  
  5105  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  5106  				Lo: binary.LittleEndian.Uint64(tc.x2[:8]),
  5107  				Hi: binary.LittleEndian.Uint64(tc.x2[8:]),
  5108  			})
  5109  			require.NoError(t, err)
  5110  
  5111  			is32bit := tc.shape == wazeroir.ShapeF32x4
  5112  			switch tc.kind {
  5113  			case wazeroir.OperationKindV128Pmin:
  5114  				err = compiler.compileV128Pmin(&wazeroir.OperationV128Pmin{Shape: tc.shape})
  5115  			case wazeroir.OperationKindV128Pmax:
  5116  				err = compiler.compileV128Pmax(&wazeroir.OperationV128Pmax{Shape: tc.shape})
  5117  			}
  5118  			require.NoError(t, err)
  5119  
  5120  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  5121  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  5122  
  5123  			err = compiler.compileReturnFunction()
  5124  			require.NoError(t, err)
  5125  
  5126  			// Generate and run the code under test.
  5127  			code, _, err := compiler.compile()
  5128  			require.NoError(t, err)
  5129  			env.exec(code)
  5130  
  5131  			require.Equal(t, nativeCallStatusCodeReturned, env.callEngine().statusCode)
  5132  
  5133  			lo, hi := env.stackTopAsV128()
  5134  
  5135  			if is32bit {
  5136  				actualFs := [4]float32{
  5137  					math.Float32frombits(uint32(lo)),
  5138  					math.Float32frombits(uint32(lo >> 32)),
  5139  					math.Float32frombits(uint32(hi)),
  5140  					math.Float32frombits(uint32(hi >> 32)),
  5141  				}
  5142  				expFs := [4]float32{
  5143  					math.Float32frombits(binary.LittleEndian.Uint32(tc.exp[:4])),
  5144  					math.Float32frombits(binary.LittleEndian.Uint32(tc.exp[4:8])),
  5145  					math.Float32frombits(binary.LittleEndian.Uint32(tc.exp[8:12])),
  5146  					math.Float32frombits(binary.LittleEndian.Uint32(tc.exp[12:])),
  5147  				}
  5148  				for i := range expFs {
  5149  					exp, actual := expFs[i], actualFs[i]
  5150  					if math.IsNaN(float64(exp)) {
  5151  						require.True(t, math.IsNaN(float64(actual)))
  5152  					} else {
  5153  						require.Equal(t, exp, actual)
  5154  					}
  5155  				}
  5156  			} else {
  5157  				actualFs := [2]float64{
  5158  					math.Float64frombits(lo), math.Float64frombits(hi),
  5159  				}
  5160  				expFs := [2]float64{
  5161  					math.Float64frombits(binary.LittleEndian.Uint64(tc.exp[:8])),
  5162  					math.Float64frombits(binary.LittleEndian.Uint64(tc.exp[8:])),
  5163  				}
  5164  				for i := range expFs {
  5165  					exp, actual := expFs[i], actualFs[i]
  5166  					if math.IsNaN(exp) {
  5167  						require.True(t, math.IsNaN(actual))
  5168  					} else {
  5169  						require.Equal(t, exp, actual)
  5170  					}
  5171  				}
  5172  			}
  5173  		})
  5174  	}
  5175  }
  5176  
  5177  func TestCompiler_compileV128ExtMul(t *testing.T) {
  5178  	tests := []struct {
  5179  		name           string
  5180  		shape          wazeroir.Shape
  5181  		signed, useLow bool
  5182  		x1, x2, exp    [16]byte
  5183  	}{
  5184  		{
  5185  			name:   "i8x16s low",
  5186  			shape:  wazeroir.ShapeI8x16,
  5187  			signed: true,
  5188  			useLow: true,
  5189  			x1:     [16]byte{}, x2: [16]byte{},
  5190  			exp: i16x8(0, 0, 0, 0, 0, 0, 0, 0),
  5191  		},
  5192  		{
  5193  			name:   "i8x16s low",
  5194  			shape:  wazeroir.ShapeI8x16,
  5195  			signed: true,
  5196  			useLow: true,
  5197  			x1: [16]byte{
  5198  				255, 255, 255, 255, 255, 255, 255, 255,
  5199  				0, 0, 0, 0, 0, 0, 0, 0,
  5200  			},
  5201  			x2: [16]byte{
  5202  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  5203  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  5204  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  5205  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  5206  			},
  5207  			exp: i16x8(128, 128, 128, 128, 128, 128, 128, 128),
  5208  		},
  5209  		{
  5210  			name:   "i8x16s low",
  5211  			shape:  wazeroir.ShapeI8x16,
  5212  			signed: true,
  5213  			useLow: true,
  5214  			x1: [16]byte{
  5215  				255, 255, 255, 255, 255, 255, 255, 255,
  5216  				0, 0, 0, 0, 0, 0, 0, 0,
  5217  			},
  5218  			x2: [16]byte{
  5219  				255, 255, 255, 255, 255, 255, 255, 255,
  5220  				0, 0, 0, 0, 0, 0, 0, 0,
  5221  			},
  5222  			exp: i16x8(1, 1, 1, 1, 1, 1, 1, 1),
  5223  		},
  5224  		{
  5225  			name:   "i8x16s low",
  5226  			shape:  wazeroir.ShapeI8x16,
  5227  			signed: true,
  5228  			useLow: true,
  5229  			x1: [16]byte{
  5230  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  5231  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  5232  				0, 0, 0, 0, 0, 0, 0, 0,
  5233  			},
  5234  			x2: [16]byte{
  5235  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  5236  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  5237  				0, 0, 0, 0, 0, 0, 0, 0,
  5238  			},
  5239  			exp: i16x8(16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384),
  5240  		},
  5241  		{
  5242  			name:   "i8x16s hi",
  5243  			shape:  wazeroir.ShapeI8x16,
  5244  			signed: true,
  5245  			useLow: false,
  5246  			x1:     [16]byte{}, x2: [16]byte{},
  5247  			exp: i16x8(0, 0, 0, 0, 0, 0, 0, 0),
  5248  		},
  5249  		{
  5250  			name:   "i8x16s hi",
  5251  			shape:  wazeroir.ShapeI8x16,
  5252  			signed: true,
  5253  			useLow: false,
  5254  			x1: [16]byte{
  5255  				0, 0, 0, 0, 0, 0, 0, 0,
  5256  				255, 255, 255, 255, 255, 255, 255, 255,
  5257  			},
  5258  			x2: [16]byte{
  5259  				0, 0, 0, 0, 0, 0, 0, 0,
  5260  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  5261  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  5262  			},
  5263  			exp: i16x8(128, 128, 128, 128, 128, 128, 128, 128),
  5264  		},
  5265  		{
  5266  			name:   "i8x16s hi",
  5267  			shape:  wazeroir.ShapeI8x16,
  5268  			signed: true,
  5269  			useLow: false,
  5270  			x1: [16]byte{
  5271  				0, 0, 0, 0, 0, 0, 0, 0,
  5272  				255, 255, 255, 255, 255, 255, 255, 255,
  5273  			},
  5274  			x2: [16]byte{
  5275  				0, 0, 0, 0, 0, 0, 0, 0,
  5276  				255, 255, 255, 255, 255, 255, 255, 255,
  5277  			},
  5278  			exp: i16x8(1, 1, 1, 1, 1, 1, 1, 1),
  5279  		},
  5280  		{
  5281  			name:   "i8x16s hi",
  5282  			shape:  wazeroir.ShapeI8x16,
  5283  			signed: true,
  5284  			useLow: false,
  5285  			x1: [16]byte{
  5286  				0, 0, 0, 0, 0, 0, 0, 0,
  5287  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  5288  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  5289  			},
  5290  			x2: [16]byte{
  5291  				0, 0, 0, 0, 0, 0, 0, 0,
  5292  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  5293  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  5294  			},
  5295  			exp: i16x8(16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384),
  5296  		},
  5297  		{
  5298  			name:   "i8x16u low",
  5299  			shape:  wazeroir.ShapeI8x16,
  5300  			signed: false,
  5301  			useLow: true,
  5302  			x1:     [16]byte{}, x2: [16]byte{},
  5303  			exp: i16x8(0, 0, 0, 0, 0, 0, 0, 0),
  5304  		},
  5305  		{
  5306  			name:   "i8x16u low",
  5307  			shape:  wazeroir.ShapeI8x16,
  5308  			signed: false,
  5309  			useLow: true,
  5310  			x1: [16]byte{
  5311  				255, 255, 255, 255, 255, 255, 255, 255,
  5312  				0, 0, 0, 0, 0, 0, 0, 0,
  5313  			},
  5314  			x2: [16]byte{
  5315  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  5316  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  5317  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  5318  				0, 0, 0, 0,
  5319  			},
  5320  			exp: i16x8(32640, 32640, 32640, 32640, 32640, 32640, 32640, 32640),
  5321  		},
  5322  		{
  5323  			name:   "i8x16u low",
  5324  			shape:  wazeroir.ShapeI8x16,
  5325  			signed: false,
  5326  			useLow: true,
  5327  			x1: [16]byte{
  5328  				255, 255, 255, 255, 255, 255, 255, 255,
  5329  				0, 0, 0, 0, 0, 0, 0, 0,
  5330  			},
  5331  			x2: [16]byte{
  5332  				255, 255, 255, 255, 255, 255, 255, 255,
  5333  				0, 0, 0, 0, 0, 0, 0, 0,
  5334  			},
  5335  			exp: i16x8(i16ToU16(-511), i16ToU16(-511), i16ToU16(-511), i16ToU16(-511),
  5336  				i16ToU16(-511), i16ToU16(-511), i16ToU16(-511), i16ToU16(-511)),
  5337  		},
  5338  		{
  5339  			name:   "i8x16u low",
  5340  			shape:  wazeroir.ShapeI8x16,
  5341  			signed: false,
  5342  			useLow: true,
  5343  			x1: [16]byte{
  5344  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  5345  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  5346  				0, 0, 0, 0, 0, 0, 0, 0,
  5347  			},
  5348  			x2: [16]byte{
  5349  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  5350  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  5351  				0, 0, 0, 0, 0, 0, 0, 0,
  5352  			},
  5353  			exp: i16x8(16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384),
  5354  		},
  5355  		{
  5356  			name:   "i8x16u hi",
  5357  			shape:  wazeroir.ShapeI8x16,
  5358  			signed: false,
  5359  			useLow: false,
  5360  			x1:     [16]byte{}, x2: [16]byte{},
  5361  			exp: i16x8(0, 0, 0, 0, 0, 0, 0, 0),
  5362  		},
  5363  		{
  5364  			name:   "i8x16u hi",
  5365  			shape:  wazeroir.ShapeI8x16,
  5366  			signed: false,
  5367  			useLow: false,
  5368  			x1: [16]byte{
  5369  				0, 0, 0, 0, 0, 0, 0, 0,
  5370  				255, 255, 255, 255, 255, 255, 255, 255,
  5371  			},
  5372  			x2: [16]byte{
  5373  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  5374  				0, 0, 0, 0,
  5375  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  5376  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  5377  			},
  5378  			exp: i16x8(32640, 32640, 32640, 32640, 32640, 32640, 32640, 32640),
  5379  		},
  5380  		{
  5381  			name:   "i8x16u hi",
  5382  			shape:  wazeroir.ShapeI8x16,
  5383  			signed: false,
  5384  			useLow: false,
  5385  			x1: [16]byte{
  5386  				0, 0, 0, 0, 0, 0, 0, 0,
  5387  				255, 255, 255, 255, 255, 255, 255, 255,
  5388  			},
  5389  			x2: [16]byte{
  5390  				0, 0, 0, 0, 0, 0, 0, 0,
  5391  				255, 255, 255, 255, 255, 255, 255, 255,
  5392  			},
  5393  			exp: i16x8(i16ToU16(-511), i16ToU16(-511), i16ToU16(-511), i16ToU16(-511),
  5394  				i16ToU16(-511), i16ToU16(-511), i16ToU16(-511), i16ToU16(-511)),
  5395  		},
  5396  		{
  5397  			name:   "i8x16u hi",
  5398  			shape:  wazeroir.ShapeI8x16,
  5399  			signed: false,
  5400  			useLow: false,
  5401  			x1: [16]byte{
  5402  				0, 0, 0, 0, 0, 0, 0, 0,
  5403  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  5404  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  5405  			},
  5406  			x2: [16]byte{
  5407  				0, 0, 0, 0, 0, 0, 0, 0,
  5408  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  5409  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  5410  			},
  5411  			exp: i16x8(16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384),
  5412  		},
  5413  		{
  5414  			name:   "i16x8s lo",
  5415  			shape:  wazeroir.ShapeI16x8,
  5416  			signed: true,
  5417  			useLow: true,
  5418  			x1:     [16]byte{},
  5419  			x2:     [16]byte{},
  5420  			exp:    [16]byte{},
  5421  		},
  5422  		{
  5423  			name:   "i16x8s lo",
  5424  			shape:  wazeroir.ShapeI16x8,
  5425  			signed: true,
  5426  			useLow: true,
  5427  			x1: i16x8(
  5428  				16383, 16383, 16383, 16383,
  5429  				0, 0, 1, 0,
  5430  			),
  5431  			x2: i16x8(
  5432  				16384, 16384, 16384, 16384,
  5433  				0, 0, 1, 0,
  5434  			),
  5435  			exp: i32x4(268419072, 268419072, 268419072, 268419072),
  5436  		},
  5437  		{
  5438  			name:   "i16x8s lo",
  5439  			shape:  wazeroir.ShapeI16x8,
  5440  			signed: true,
  5441  			useLow: true,
  5442  			x1: i16x8(
  5443  				i16ToU16(-32768), i16ToU16(-32768), i16ToU16(-32768), i16ToU16(-32768),
  5444  				0, 0, 1, 0,
  5445  			),
  5446  			x2: i16x8(
  5447  				i16ToU16(-32767), 0, i16ToU16(-32767), 0,
  5448  				0, 0, 1, 0,
  5449  			),
  5450  			exp: i32x4(1073709056, 0, 1073709056, 0),
  5451  		},
  5452  		{
  5453  			name:   "i16x8s lo",
  5454  			shape:  wazeroir.ShapeI16x8,
  5455  			signed: true,
  5456  			useLow: true,
  5457  			x1: i16x8(
  5458  				65535, 65535, 65535, 65535,
  5459  				0, 0, 1, 0,
  5460  			),
  5461  			x2: i16x8(
  5462  				65535, 0, 65535, 0,
  5463  				0, 0, 1, 0,
  5464  			),
  5465  			exp: i32x4(1, 0, 1, 0),
  5466  		},
  5467  		{
  5468  			name:   "i16x8s hi",
  5469  			shape:  wazeroir.ShapeI16x8,
  5470  			signed: true,
  5471  			useLow: false,
  5472  			x1:     [16]byte{},
  5473  			x2:     [16]byte{},
  5474  			exp:    [16]byte{},
  5475  		},
  5476  		{
  5477  			name:   "i16x8s hi",
  5478  			shape:  wazeroir.ShapeI16x8,
  5479  			signed: true,
  5480  			useLow: false,
  5481  			x1: i16x8(
  5482  				0, 0, 1, 0,
  5483  				16383, 16383, 16383, 16383,
  5484  			),
  5485  			x2: i16x8(
  5486  				0, 0, 1, 0,
  5487  				16384, 16384, 16384, 16384,
  5488  			),
  5489  			exp: i32x4(268419072, 268419072, 268419072, 268419072),
  5490  		},
  5491  		{
  5492  			name:   "i16x8s hi",
  5493  			shape:  wazeroir.ShapeI16x8,
  5494  			signed: true,
  5495  			useLow: false,
  5496  			x1: i16x8(
  5497  				0, 0, 1, 0,
  5498  				i16ToU16(-32768), i16ToU16(-32768), i16ToU16(-32768), i16ToU16(-32768),
  5499  			),
  5500  			x2: i16x8(
  5501  				0, 0, 1, 0,
  5502  				i16ToU16(-32767), 0, i16ToU16(-32767), 0,
  5503  			),
  5504  			exp: i32x4(1073709056, 0, 1073709056, 0),
  5505  		},
  5506  		{
  5507  			name:   "i16x8s hi",
  5508  			shape:  wazeroir.ShapeI16x8,
  5509  			signed: true,
  5510  			useLow: false,
  5511  			x1: i16x8(
  5512  				0, 0, 1, 0,
  5513  				65535, 65535, 65535, 65535,
  5514  			),
  5515  			x2: i16x8(
  5516  				0, 0, 1, 0,
  5517  
  5518  				65535, 0, 65535, 0,
  5519  			),
  5520  			exp: i32x4(1, 0, 1, 0),
  5521  		},
  5522  		{
  5523  			name:   "i16x8u lo",
  5524  			shape:  wazeroir.ShapeI16x8,
  5525  			signed: false,
  5526  			useLow: true,
  5527  			x1:     [16]byte{},
  5528  			x2:     [16]byte{},
  5529  			exp:    [16]byte{},
  5530  		},
  5531  		{
  5532  			name:   "i16x8u lo",
  5533  			shape:  wazeroir.ShapeI16x8,
  5534  			signed: false,
  5535  			useLow: true,
  5536  			x1: i16x8(
  5537  				16383, 16383, 16383, 16383,
  5538  				0, 0, 1, 0,
  5539  			),
  5540  			x2: i16x8(
  5541  				16384, 16384, 16384, 16384,
  5542  				0, 0, 1, 0,
  5543  			),
  5544  			exp: i32x4(268419072, 268419072, 268419072, 268419072),
  5545  		},
  5546  		{
  5547  			name:   "i16x8u lo",
  5548  			shape:  wazeroir.ShapeI16x8,
  5549  			signed: false,
  5550  			useLow: true,
  5551  			x1: i16x8(
  5552  				i16ToU16(-32768), i16ToU16(-32768), i16ToU16(-32768), i16ToU16(-32768),
  5553  				0, 0, 1, 0,
  5554  			),
  5555  			x2: i16x8(
  5556  				i16ToU16(-32767), 0, i16ToU16(-32767), 0,
  5557  				0, 0, 1, 0,
  5558  			),
  5559  			exp: i32x4(1073774592, 0, 1073774592, 0),
  5560  		},
  5561  		{
  5562  			name:   "i16x8u lo",
  5563  			shape:  wazeroir.ShapeI16x8,
  5564  			signed: false,
  5565  			useLow: true,
  5566  			x1: i16x8(
  5567  				65535, 65535, 65535, 65535,
  5568  				0, 0, 1, 0,
  5569  			),
  5570  			x2: i16x8(
  5571  				65535, 0, 65535, 0,
  5572  				0, 0, 1, 0,
  5573  			),
  5574  			exp: i32x4(i32ToU32(-131071), 0, i32ToU32(-131071), 0),
  5575  		},
  5576  		{
  5577  			name:   "i16x8u hi",
  5578  			shape:  wazeroir.ShapeI16x8,
  5579  			signed: false,
  5580  			useLow: false,
  5581  			x1:     [16]byte{},
  5582  			x2:     [16]byte{},
  5583  			exp:    [16]byte{},
  5584  		},
  5585  		{
  5586  			name:   "i16x8u hi",
  5587  			shape:  wazeroir.ShapeI16x8,
  5588  			signed: false,
  5589  			useLow: false,
  5590  			x1: i16x8(
  5591  				0, 0, 1, 0,
  5592  				16383, 16383, 16383, 16383,
  5593  			),
  5594  			x2: i16x8(
  5595  				0, 0, 1, 0,
  5596  				16384, 16384, 16384, 16384,
  5597  			),
  5598  			exp: i32x4(268419072, 268419072, 268419072, 268419072),
  5599  		},
  5600  		{
  5601  			name:   "i16x8u hi",
  5602  			shape:  wazeroir.ShapeI16x8,
  5603  			signed: false,
  5604  			useLow: false,
  5605  			x1: i16x8(
  5606  				0, 0, 1, 0,
  5607  				i16ToU16(-32768), i16ToU16(-32768), i16ToU16(-32768), i16ToU16(-32768),
  5608  			),
  5609  			x2: i16x8(
  5610  				0, 0, 1, 0,
  5611  				i16ToU16(-32767), 0, i16ToU16(-32767), 0,
  5612  			),
  5613  			exp: i32x4(1073774592, 0, 1073774592, 0),
  5614  		},
  5615  		{
  5616  			name:   "i16x8u hi",
  5617  			shape:  wazeroir.ShapeI16x8,
  5618  			signed: false,
  5619  			useLow: false,
  5620  			x1: i16x8(
  5621  				0, 0, 1, 0,
  5622  				65535, 65535, 65535, 65535,
  5623  			),
  5624  			x2: i16x8(
  5625  				0, 0, 1, 0,
  5626  				65535, 0, 65535, 0,
  5627  			),
  5628  			exp: i32x4(i32ToU32(-131071), 0, i32ToU32(-131071), 0),
  5629  		},
  5630  		{
  5631  			name:   "i32x4s lo",
  5632  			shape:  wazeroir.ShapeI32x4,
  5633  			signed: true,
  5634  			useLow: true,
  5635  			x1:     [16]byte{},
  5636  			x2:     [16]byte{},
  5637  			exp:    [16]byte{},
  5638  		},
  5639  		{
  5640  			name:   "i32x4s lo",
  5641  			shape:  wazeroir.ShapeI32x4,
  5642  			signed: true,
  5643  			useLow: true,
  5644  			x1: i32x4(
  5645  				1, i32ToU32(-1),
  5646  				0, 0,
  5647  			),
  5648  			x2: i32x4(
  5649  				i32ToU32(-1), 1,
  5650  				0, 0,
  5651  			),
  5652  			exp: i64x2(i64ToU64(-1), i64ToU64(-1)),
  5653  		},
  5654  		{
  5655  			name:   "i32x4s lo",
  5656  			shape:  wazeroir.ShapeI32x4,
  5657  			signed: true,
  5658  			useLow: true,
  5659  			x1: i32x4(
  5660  				1073741824, 4294967295,
  5661  				0, 0,
  5662  			),
  5663  			x2: i32x4(
  5664  				1073741824, 4294967295,
  5665  				0, 0,
  5666  			),
  5667  			exp: i64x2(1152921504606846976, 1),
  5668  		},
  5669  		{
  5670  			name:   "i32x4s hi",
  5671  			shape:  wazeroir.ShapeI32x4,
  5672  			signed: true,
  5673  			useLow: false,
  5674  			x1:     [16]byte{},
  5675  			x2:     [16]byte{},
  5676  			exp:    [16]byte{},
  5677  		},
  5678  		{
  5679  			name:   "i32x4s hi",
  5680  			shape:  wazeroir.ShapeI32x4,
  5681  			signed: true,
  5682  			useLow: false,
  5683  			x1: i32x4(
  5684  				0, 0,
  5685  				1, i32ToU32(-1),
  5686  			),
  5687  			x2: i32x4(
  5688  				0, 0,
  5689  				i32ToU32(-1), 1,
  5690  			),
  5691  			exp: i64x2(i64ToU64(-1), i64ToU64(-1)),
  5692  		},
  5693  		{
  5694  			name:   "i32x4s hi",
  5695  			shape:  wazeroir.ShapeI32x4,
  5696  			signed: true,
  5697  			useLow: false,
  5698  			x1: i32x4(
  5699  				0, 0,
  5700  				1073741824, 4294967295,
  5701  			),
  5702  			x2: i32x4(
  5703  				0, 0,
  5704  				1073741824, 4294967295,
  5705  			),
  5706  			exp: i64x2(1152921504606846976, 1),
  5707  		},
  5708  		{
  5709  			name:   "i32x4u lo",
  5710  			shape:  wazeroir.ShapeI32x4,
  5711  			signed: false,
  5712  			useLow: true,
  5713  			x1:     [16]byte{},
  5714  			x2:     [16]byte{},
  5715  			exp:    [16]byte{},
  5716  		},
  5717  		{
  5718  			name:   "i32x4u lo",
  5719  			shape:  wazeroir.ShapeI32x4,
  5720  			signed: false,
  5721  			useLow: true,
  5722  			x1: i32x4(
  5723  				1, i32ToU32(-1),
  5724  				0, 0,
  5725  			),
  5726  			x2: i32x4(
  5727  				i32ToU32(-1), 1,
  5728  				0, 0,
  5729  			),
  5730  			exp: i64x2(4294967295, 4294967295),
  5731  		},
  5732  		{
  5733  			name:   "i32x4u lo",
  5734  			shape:  wazeroir.ShapeI32x4,
  5735  			signed: false,
  5736  			useLow: true,
  5737  			x1: i32x4(
  5738  				1073741824, 4294967295,
  5739  				0, 0,
  5740  			),
  5741  			x2: i32x4(
  5742  				1073741824, 4294967295,
  5743  				0, 0,
  5744  			),
  5745  			exp: i64x2(1152921504606846976, i64ToU64(-8589934591)),
  5746  		},
  5747  		{
  5748  			name:   "i32x4u hi",
  5749  			shape:  wazeroir.ShapeI32x4,
  5750  			signed: false,
  5751  			useLow: false,
  5752  			x1:     [16]byte{},
  5753  			x2:     [16]byte{},
  5754  			exp:    [16]byte{},
  5755  		},
  5756  		{
  5757  			name:   "i32x4u hi",
  5758  			shape:  wazeroir.ShapeI32x4,
  5759  			signed: false,
  5760  			useLow: false,
  5761  			x1: i32x4(
  5762  				0, 0,
  5763  				1, i32ToU32(-1),
  5764  			),
  5765  			x2: i32x4(
  5766  				0, 0,
  5767  				i32ToU32(-1), 1,
  5768  			),
  5769  			exp: i64x2(4294967295, 4294967295),
  5770  		},
  5771  		{
  5772  			name:   "i32x4u hi",
  5773  			shape:  wazeroir.ShapeI32x4,
  5774  			signed: false,
  5775  			useLow: false,
  5776  			x1: i32x4(
  5777  				0, 0,
  5778  				1073741824, 4294967295,
  5779  			),
  5780  			x2: i32x4(
  5781  				0, 0,
  5782  				1073741824, 4294967295,
  5783  			),
  5784  			exp: i64x2(1152921504606846976, i64ToU64(-8589934591)),
  5785  		},
  5786  	}
  5787  
  5788  	for _, tc := range tests {
  5789  		tc := tc
  5790  		t.Run(tc.name, func(t *testing.T) {
  5791  			env := newCompilerEnvironment()
  5792  			compiler := env.requireNewCompiler(t, newCompiler,
  5793  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  5794  
  5795  			err := compiler.compilePreamble()
  5796  			require.NoError(t, err)
  5797  
  5798  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  5799  				Lo: binary.LittleEndian.Uint64(tc.x1[:8]),
  5800  				Hi: binary.LittleEndian.Uint64(tc.x1[8:]),
  5801  			})
  5802  			require.NoError(t, err)
  5803  
  5804  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  5805  				Lo: binary.LittleEndian.Uint64(tc.x2[:8]),
  5806  				Hi: binary.LittleEndian.Uint64(tc.x2[8:]),
  5807  			})
  5808  			require.NoError(t, err)
  5809  
  5810  			err = compiler.compileV128ExtMul(&wazeroir.OperationV128ExtMul{
  5811  				OriginShape: tc.shape, Signed: tc.signed, UseLow: tc.useLow,
  5812  			})
  5813  			require.NoError(t, err)
  5814  
  5815  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  5816  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  5817  
  5818  			err = compiler.compileReturnFunction()
  5819  			require.NoError(t, err)
  5820  
  5821  			// Generate and run the code under test.
  5822  			code, _, err := compiler.compile()
  5823  			require.NoError(t, err)
  5824  			env.exec(code)
  5825  
  5826  			require.Equal(t, nativeCallStatusCodeReturned, env.callEngine().statusCode)
  5827  
  5828  			lo, hi := env.stackTopAsV128()
  5829  			var actual [16]byte
  5830  			binary.LittleEndian.PutUint64(actual[:8], lo)
  5831  			binary.LittleEndian.PutUint64(actual[8:], hi)
  5832  			require.Equal(t, tc.exp, actual)
  5833  		})
  5834  	}
  5835  }
  5836  
  5837  func TestCompiler_compileV128Extend(t *testing.T) {
  5838  	tests := []struct {
  5839  		name           string
  5840  		shape          wazeroir.Shape
  5841  		signed, useLow bool
  5842  		v, exp         [16]byte
  5843  	}{
  5844  		{
  5845  			name:   "i8x16s hi",
  5846  			shape:  wazeroir.ShapeI8x16,
  5847  			signed: true,
  5848  			useLow: false,
  5849  			v:      [16]byte{},
  5850  			exp:    [16]byte{},
  5851  		},
  5852  		{
  5853  			name:   "i8x16s hi",
  5854  			shape:  wazeroir.ShapeI8x16,
  5855  			signed: true,
  5856  			useLow: false,
  5857  			v: [16]byte{
  5858  				0, 0, 0, 0, 0, 0, 0, 0,
  5859  				i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1),
  5860  			},
  5861  			exp: i16x8(i16ToU16(-1), i16ToU16(-1), i16ToU16(-1), i16ToU16(-1), i16ToU16(-1), i16ToU16(-1), i16ToU16(-1), i16ToU16(-1)),
  5862  		},
  5863  		{
  5864  			name:   "i8x16s hi",
  5865  			shape:  wazeroir.ShapeI8x16,
  5866  			signed: true,
  5867  			useLow: false,
  5868  			v: [16]byte{
  5869  				0, 0, 0, 0, 0, 0, 0, 0,
  5870  				1, 1, 1, 1, 1, 1, 1, 1,
  5871  			},
  5872  			exp: i16x8(1, 1, 1, 1, 1, 1, 1, 1),
  5873  		},
  5874  		{
  5875  			name:   "i8x16s hi",
  5876  			shape:  wazeroir.ShapeI8x16,
  5877  			signed: true,
  5878  			useLow: false,
  5879  			v: [16]byte{
  5880  				i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1),
  5881  				0, 0, 0, 0, 0, 0, 0, 0,
  5882  			},
  5883  			exp: i16x8(0, 0, 0, 0, 0, 0, 0, 0),
  5884  		},
  5885  		{
  5886  			name:   "i8x16s lo",
  5887  			shape:  wazeroir.ShapeI8x16,
  5888  			signed: true,
  5889  			useLow: true,
  5890  			v:      [16]byte{},
  5891  			exp:    [16]byte{},
  5892  		},
  5893  		{
  5894  			name:   "i8x16s lo",
  5895  			shape:  wazeroir.ShapeI8x16,
  5896  			signed: true,
  5897  			useLow: true,
  5898  			v: [16]byte{
  5899  				i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1),
  5900  				0, 0, 0, 0, 0, 0, 0, 0,
  5901  			},
  5902  			exp: i16x8(i16ToU16(-1), i16ToU16(-1), i16ToU16(-1), i16ToU16(-1), i16ToU16(-1), i16ToU16(-1), i16ToU16(-1), i16ToU16(-1)),
  5903  		},
  5904  		{
  5905  			name:   "i8x16s lo",
  5906  			shape:  wazeroir.ShapeI8x16,
  5907  			signed: true,
  5908  			useLow: true,
  5909  			v: [16]byte{
  5910  				1, 1, 1, 1, 1, 1, 1, 1,
  5911  				0, 0, 0, 0, 0, 0, 0, 0,
  5912  			},
  5913  			exp: i16x8(1, 1, 1, 1, 1, 1, 1, 1),
  5914  		},
  5915  		{
  5916  			name:   "i8x16s lo",
  5917  			shape:  wazeroir.ShapeI8x16,
  5918  			signed: true,
  5919  			useLow: true,
  5920  			v: [16]byte{
  5921  				0, 0, 0, 0, 0, 0, 0, 0,
  5922  				i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1),
  5923  			},
  5924  			exp: i16x8(0, 0, 0, 0, 0, 0, 0, 0),
  5925  		},
  5926  		// unsigned
  5927  		{
  5928  			name:   "i8x16u hi",
  5929  			shape:  wazeroir.ShapeI8x16,
  5930  			signed: false,
  5931  			useLow: false,
  5932  			v:      [16]byte{},
  5933  			exp:    [16]byte{},
  5934  		},
  5935  		{
  5936  			name:   "i8x16u hi",
  5937  			shape:  wazeroir.ShapeI8x16,
  5938  			signed: false,
  5939  			useLow: false,
  5940  			v: [16]byte{
  5941  				0, 0, 0, 0, 0, 0, 0, 0,
  5942  				i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1),
  5943  			},
  5944  			exp: i16x8(255, 255, 255, 255, 255, 255, 255, 255),
  5945  		},
  5946  		{
  5947  			name:   "i8x16u hi",
  5948  			shape:  wazeroir.ShapeI8x16,
  5949  			signed: false,
  5950  			useLow: false,
  5951  			v: [16]byte{
  5952  				0, 0, 0, 0, 0, 0, 0, 0,
  5953  				1, 1, 1, 1, 1, 1, 1, 1,
  5954  			},
  5955  			exp: i16x8(1, 1, 1, 1, 1, 1, 1, 1),
  5956  		},
  5957  		{
  5958  			name:   "i8x16u hi",
  5959  			shape:  wazeroir.ShapeI8x16,
  5960  			signed: false,
  5961  			useLow: false,
  5962  			v: [16]byte{
  5963  				i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1),
  5964  				0, 0, 0, 0, 0, 0, 0, 0,
  5965  			},
  5966  			exp: i16x8(0, 0, 0, 0, 0, 0, 0, 0),
  5967  		},
  5968  		{
  5969  			name:   "i8x16u lo",
  5970  			shape:  wazeroir.ShapeI8x16,
  5971  			signed: false,
  5972  			useLow: true,
  5973  			v:      [16]byte{},
  5974  			exp:    [16]byte{},
  5975  		},
  5976  		{
  5977  			name:   "i8x16u lo",
  5978  			shape:  wazeroir.ShapeI8x16,
  5979  			signed: false,
  5980  			useLow: true,
  5981  			v: [16]byte{
  5982  				i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1),
  5983  				0, 0, 0, 0, 0, 0, 0, 0,
  5984  			},
  5985  			exp: i16x8(255, 255, 255, 255, 255, 255, 255, 255),
  5986  		},
  5987  		{
  5988  			name:   "i8x16u lo",
  5989  			shape:  wazeroir.ShapeI8x16,
  5990  			signed: false,
  5991  			useLow: true,
  5992  			v: [16]byte{
  5993  				1, 1, 1, 1, 1, 1, 1, 1,
  5994  				0, 0, 0, 0, 0, 0, 0, 0,
  5995  			},
  5996  			exp: i16x8(1, 1, 1, 1, 1, 1, 1, 1),
  5997  		},
  5998  		{
  5999  			name:   "i8x16u lo",
  6000  			shape:  wazeroir.ShapeI8x16,
  6001  			signed: false,
  6002  			useLow: true,
  6003  			v: [16]byte{
  6004  				0, 0, 0, 0, 0, 0, 0, 0,
  6005  				i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1),
  6006  			},
  6007  			exp: i16x8(0, 0, 0, 0, 0, 0, 0, 0),
  6008  		},
  6009  		{
  6010  			name:   "i16x8s hi",
  6011  			shape:  wazeroir.ShapeI16x8,
  6012  			signed: true,
  6013  			useLow: false,
  6014  			v:      [16]byte{},
  6015  			exp:    [16]byte{},
  6016  		},
  6017  		{
  6018  			name:   "i16x8s hi",
  6019  			shape:  wazeroir.ShapeI16x8,
  6020  			signed: true,
  6021  			useLow: false,
  6022  			v:      i16x8(1, 1, 1, 1, 0, 0, 0, 0),
  6023  			exp:    i32x4(0, 0, 0, 0),
  6024  		},
  6025  		{
  6026  			name:   "i16x8s hi",
  6027  			shape:  wazeroir.ShapeI16x8,
  6028  			signed: true,
  6029  			useLow: false,
  6030  			v:      i16x8(0, 0, 0, 0, i16ToU16(-1), i16ToU16(-1), i16ToU16(-1), i16ToU16(-1)),
  6031  			exp:    i32x4(i32ToU32(-1), i32ToU32(-1), i32ToU32(-1), i32ToU32(-1)),
  6032  		},
  6033  		{
  6034  			name:   "i16x8s hi",
  6035  			shape:  wazeroir.ShapeI16x8,
  6036  			signed: true,
  6037  			useLow: false,
  6038  			v:      i16x8(0, 0, 0, 0, 123, 0, 123, 0),
  6039  			exp:    i32x4(123, 0, 123, 0),
  6040  		},
  6041  		{
  6042  			name:   "i16x8s lo",
  6043  			shape:  wazeroir.ShapeI16x8,
  6044  			signed: true,
  6045  			useLow: true,
  6046  			v:      [16]byte{},
  6047  			exp:    [16]byte{},
  6048  		},
  6049  		{
  6050  			name:   "i16x8s lo",
  6051  			shape:  wazeroir.ShapeI16x8,
  6052  			signed: true,
  6053  			useLow: true,
  6054  			v:      i16x8(0, 0, 0, 0, 1, 1, 1, 1),
  6055  			exp:    i32x4(0, 0, 0, 0),
  6056  		},
  6057  		{
  6058  			name:   "i16x8s lo",
  6059  			shape:  wazeroir.ShapeI16x8,
  6060  			signed: true,
  6061  			useLow: true,
  6062  			v:      i16x8(i16ToU16(-1), i16ToU16(-1), i16ToU16(-1), i16ToU16(-1), 0, 0, 0, 0),
  6063  			exp:    i32x4(i32ToU32(-1), i32ToU32(-1), i32ToU32(-1), i32ToU32(-1)),
  6064  		},
  6065  		{
  6066  			name:   "i16x8s lo",
  6067  			shape:  wazeroir.ShapeI16x8,
  6068  			signed: true,
  6069  			useLow: true,
  6070  			v:      i16x8(123, 0, 123, 0, 0, 0, 0, 0),
  6071  			exp:    i32x4(123, 0, 123, 0),
  6072  		},
  6073  		{
  6074  			name:   "i16x8u hi",
  6075  			shape:  wazeroir.ShapeI16x8,
  6076  			signed: false,
  6077  			useLow: false,
  6078  			v:      [16]byte{},
  6079  			exp:    [16]byte{},
  6080  		},
  6081  		{
  6082  			name:   "i16x8u hi",
  6083  			shape:  wazeroir.ShapeI16x8,
  6084  			signed: false,
  6085  			useLow: false,
  6086  			v:      i16x8(1, 1, 1, 1, 0, 0, 0, 0),
  6087  			exp:    i32x4(0, 0, 0, 0),
  6088  		},
  6089  		{
  6090  			name:   "i16x8u hi",
  6091  			shape:  wazeroir.ShapeI16x8,
  6092  			signed: false,
  6093  			useLow: false,
  6094  			v:      i16x8(0, 0, 0, 0, i16ToU16(-1), i16ToU16(-1), i16ToU16(-1), i16ToU16(-1)),
  6095  			exp:    i32x4(65535, 65535, 65535, 65535),
  6096  		},
  6097  		{
  6098  			name:   "i16x8u hi",
  6099  			shape:  wazeroir.ShapeI16x8,
  6100  			signed: false,
  6101  			useLow: false,
  6102  			v:      i16x8(0, 0, 0, 0, 123, 0, 123, 0),
  6103  			exp:    i32x4(123, 0, 123, 0),
  6104  		},
  6105  		{
  6106  			name:   "i16x8u lo",
  6107  			shape:  wazeroir.ShapeI16x8,
  6108  			signed: false,
  6109  			useLow: true,
  6110  			v:      [16]byte{},
  6111  			exp:    [16]byte{},
  6112  		},
  6113  		{
  6114  			name:   "i16x8u lo",
  6115  			shape:  wazeroir.ShapeI16x8,
  6116  			signed: false,
  6117  			useLow: true,
  6118  			v:      i16x8(0, 0, 0, 0, 1, 1, 1, 1),
  6119  			exp:    i32x4(0, 0, 0, 0),
  6120  		},
  6121  		{
  6122  			name:   "i16x8u lo",
  6123  			shape:  wazeroir.ShapeI16x8,
  6124  			signed: false,
  6125  			useLow: true,
  6126  			v:      i16x8(i16ToU16(-1), i16ToU16(-1), i16ToU16(-1), i16ToU16(-1), 0, 0, 0, 0),
  6127  			exp:    i32x4(65535, 65535, 65535, 65535),
  6128  		},
  6129  		{
  6130  			name:   "i16x8u lo",
  6131  			shape:  wazeroir.ShapeI16x8,
  6132  			signed: false,
  6133  			useLow: true,
  6134  			v:      i16x8(123, 0, 123, 0, 0, 0, 0, 0),
  6135  			exp:    i32x4(123, 0, 123, 0),
  6136  		},
  6137  		{
  6138  			name:   "i32x4s hi",
  6139  			shape:  wazeroir.ShapeI32x4,
  6140  			signed: true,
  6141  			useLow: false,
  6142  			v:      [16]byte{},
  6143  			exp:    [16]byte{},
  6144  		},
  6145  		{
  6146  			name:   "i32x4s hi",
  6147  			shape:  wazeroir.ShapeI32x4,
  6148  			signed: true,
  6149  			useLow: false,
  6150  			v:      i32x4(0, 0, 1, i32ToU32(-1)),
  6151  			exp:    i64x2(1, i64ToU64(-1)),
  6152  		},
  6153  		{
  6154  			name:   "i32x4s hi",
  6155  			shape:  wazeroir.ShapeI32x4,
  6156  			signed: true,
  6157  			useLow: false,
  6158  			v:      i32x4(1, i32ToU32(-1), 0, 0),
  6159  			exp:    i64x2(0, 0),
  6160  		},
  6161  		{
  6162  			name:   "i32x4s hi",
  6163  			shape:  wazeroir.ShapeI32x4,
  6164  			signed: true,
  6165  			useLow: false,
  6166  			v:      i32x4(1, i32ToU32(-1), 123, 123),
  6167  			exp:    i64x2(123, 123),
  6168  		},
  6169  		{
  6170  			name:   "i32x4s lo",
  6171  			shape:  wazeroir.ShapeI32x4,
  6172  			signed: true,
  6173  			useLow: true,
  6174  			v:      [16]byte{},
  6175  			exp:    [16]byte{},
  6176  		},
  6177  		{
  6178  			name:   "i32x4s lo",
  6179  			shape:  wazeroir.ShapeI32x4,
  6180  			signed: true,
  6181  			useLow: true,
  6182  			v:      i32x4(1, i32ToU32(-1), 0, 0),
  6183  			exp:    i64x2(1, i64ToU64(-1)),
  6184  		},
  6185  		{
  6186  			name:   "i32x4s lo",
  6187  			shape:  wazeroir.ShapeI32x4,
  6188  			signed: true,
  6189  			useLow: true,
  6190  			v:      i32x4(0, 0, 1, i32ToU32(-1)),
  6191  			exp:    i64x2(0, 0),
  6192  		},
  6193  		{
  6194  			name:   "i32x4s lo",
  6195  			shape:  wazeroir.ShapeI32x4,
  6196  			signed: true,
  6197  			useLow: true,
  6198  			v:      i32x4(123, 123, 1, i32ToU32(-1)),
  6199  			exp:    i64x2(123, 123),
  6200  		},
  6201  		{
  6202  			name:   "i32x4u hi",
  6203  			shape:  wazeroir.ShapeI32x4,
  6204  			signed: false,
  6205  			useLow: false,
  6206  			v:      [16]byte{},
  6207  			exp:    [16]byte{},
  6208  		},
  6209  		{
  6210  			name:   "i32x4u hi",
  6211  			shape:  wazeroir.ShapeI32x4,
  6212  			signed: false,
  6213  			useLow: false,
  6214  			v:      i32x4(0, 0, 1, i32ToU32(-1)),
  6215  			exp:    i64x2(1, 4294967295),
  6216  		},
  6217  		{
  6218  			name:   "i32x4u hi",
  6219  			shape:  wazeroir.ShapeI32x4,
  6220  			signed: false,
  6221  			useLow: false,
  6222  			v:      i32x4(1, i32ToU32(-1), 0, 0),
  6223  			exp:    i64x2(0, 0),
  6224  		},
  6225  		{
  6226  			name:   "i32x4u hi",
  6227  			shape:  wazeroir.ShapeI32x4,
  6228  			signed: false,
  6229  			useLow: false,
  6230  			v:      i32x4(1, i32ToU32(-1), 123, 123),
  6231  			exp:    i64x2(123, 123),
  6232  		},
  6233  		{
  6234  			name:   "i32x4u lo",
  6235  			shape:  wazeroir.ShapeI32x4,
  6236  			signed: false,
  6237  			useLow: true,
  6238  			v:      [16]byte{},
  6239  			exp:    [16]byte{},
  6240  		},
  6241  		{
  6242  			name:   "i32x4u lo",
  6243  			shape:  wazeroir.ShapeI32x4,
  6244  			signed: false,
  6245  			useLow: true,
  6246  			v:      i32x4(1, i32ToU32(-1), 0, 0),
  6247  			exp:    i64x2(1, 4294967295),
  6248  		},
  6249  		{
  6250  			name:   "i32x4u lo",
  6251  			shape:  wazeroir.ShapeI32x4,
  6252  			signed: false,
  6253  			useLow: true,
  6254  			v:      i32x4(0, 0, 1, i32ToU32(-1)),
  6255  			exp:    i64x2(0, 0),
  6256  		},
  6257  		{
  6258  			name:   "i32x4u lo",
  6259  			shape:  wazeroir.ShapeI32x4,
  6260  			signed: false,
  6261  			useLow: true,
  6262  			v:      i32x4(123, 123, 1, i32ToU32(-1)),
  6263  			exp:    i64x2(123, 123),
  6264  		},
  6265  	}
  6266  
  6267  	for _, tc := range tests {
  6268  		tc := tc
  6269  		t.Run(tc.name, func(t *testing.T) {
  6270  			env := newCompilerEnvironment()
  6271  			compiler := env.requireNewCompiler(t, newCompiler,
  6272  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  6273  
  6274  			err := compiler.compilePreamble()
  6275  			require.NoError(t, err)
  6276  
  6277  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  6278  				Lo: binary.LittleEndian.Uint64(tc.v[:8]),
  6279  				Hi: binary.LittleEndian.Uint64(tc.v[8:]),
  6280  			})
  6281  			require.NoError(t, err)
  6282  
  6283  			err = compiler.compileV128Extend(&wazeroir.OperationV128Extend{
  6284  				OriginShape: tc.shape, Signed: tc.signed, UseLow: tc.useLow,
  6285  			})
  6286  			require.NoError(t, err)
  6287  
  6288  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  6289  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  6290  
  6291  			err = compiler.compileReturnFunction()
  6292  			require.NoError(t, err)
  6293  
  6294  			// Generate and run the code under test.
  6295  			code, _, err := compiler.compile()
  6296  			require.NoError(t, err)
  6297  			env.exec(code)
  6298  
  6299  			require.Equal(t, nativeCallStatusCodeReturned, env.callEngine().statusCode)
  6300  
  6301  			lo, hi := env.stackTopAsV128()
  6302  			var actual [16]byte
  6303  			binary.LittleEndian.PutUint64(actual[:8], lo)
  6304  			binary.LittleEndian.PutUint64(actual[8:], hi)
  6305  			require.Equal(t, tc.exp, actual)
  6306  		})
  6307  	}
  6308  }
  6309  
  6310  func TestCompiler_compileV128Q15mulrSatS(t *testing.T) {
  6311  	tests := []struct {
  6312  		name        string
  6313  		x1, x2, exp [16]byte
  6314  	}{
  6315  		{
  6316  			name: "1",
  6317  			x1:   i16x8(0, 0, 0, 0, 0, 0, 0, 0),
  6318  			x2:   i16x8(0, 0, 0, 0, 0, 0, 0, 0),
  6319  			exp:  i16x8(0, 0, 0, 0, 0, 0, 0, 0),
  6320  		},
  6321  		{
  6322  			name: "2",
  6323  			x1:   i16x8(0, 0, 0, 0, 0, 0, 0, 0),
  6324  			x2:   i16x8(1, 1, 1, 1, 1, 1, 1, 1),
  6325  			exp:  i16x8(0, 0, 0, 0, 0, 0, 0, 0),
  6326  		},
  6327  		{
  6328  			name: "3",
  6329  			x1:   i16x8(1, 1, 1, 1, 1, 1, 1, 1),
  6330  			x2:   i16x8(1, 1, 1, 1, 1, 1, 1, 1),
  6331  			exp:  i16x8(0, 0, 0, 0, 0, 0, 0, 0),
  6332  		},
  6333  		{
  6334  			name: "4",
  6335  			x1:   i16x8(65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535),
  6336  			x2:   i16x8(1, 1, 1, 1, 1, 1, 1, 1),
  6337  			exp:  i16x8(0, 0, 0, 0, 0, 0, 0, 0),
  6338  		},
  6339  		{
  6340  			name: "5",
  6341  			x1:   i16x8(32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767),
  6342  			x2:   i16x8(32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767),
  6343  			exp:  i16x8(32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766),
  6344  		},
  6345  	}
  6346  
  6347  	for _, tc := range tests {
  6348  		tc := tc
  6349  		t.Run(tc.name, func(t *testing.T) {
  6350  			env := newCompilerEnvironment()
  6351  			compiler := env.requireNewCompiler(t, newCompiler,
  6352  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  6353  
  6354  			err := compiler.compilePreamble()
  6355  			require.NoError(t, err)
  6356  
  6357  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  6358  				Lo: binary.LittleEndian.Uint64(tc.x1[:8]),
  6359  				Hi: binary.LittleEndian.Uint64(tc.x1[8:]),
  6360  			})
  6361  			require.NoError(t, err)
  6362  
  6363  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  6364  				Lo: binary.LittleEndian.Uint64(tc.x2[:8]),
  6365  				Hi: binary.LittleEndian.Uint64(tc.x2[8:]),
  6366  			})
  6367  			require.NoError(t, err)
  6368  
  6369  			err = compiler.compileV128Q15mulrSatS(&wazeroir.OperationV128Q15mulrSatS{})
  6370  			require.NoError(t, err)
  6371  
  6372  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  6373  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  6374  
  6375  			err = compiler.compileReturnFunction()
  6376  			require.NoError(t, err)
  6377  
  6378  			// Generate and run the code under test.
  6379  			code, _, err := compiler.compile()
  6380  			require.NoError(t, err)
  6381  			env.exec(code)
  6382  
  6383  			require.Equal(t, nativeCallStatusCodeReturned, env.callEngine().statusCode)
  6384  
  6385  			lo, hi := env.stackTopAsV128()
  6386  			var actual [16]byte
  6387  			binary.LittleEndian.PutUint64(actual[:8], lo)
  6388  			binary.LittleEndian.PutUint64(actual[8:], hi)
  6389  			require.Equal(t, tc.exp, actual)
  6390  		})
  6391  	}
  6392  }
  6393  
  6394  func TestCompiler_compileFloatPromote(t *testing.T) {
  6395  	tests := []struct {
  6396  		name   string
  6397  		v, exp [16]byte
  6398  	}{
  6399  		{
  6400  			name: "1",
  6401  			v:    f32x4(float32(0x1.8f867ep+125), float32(0x1.8f867ep+125), float32(0x1.8f867ep+125), float32(0x1.8f867ep+125)),
  6402  			exp:  f64x2(6.6382536710104395e+37, 6.6382536710104395e+37),
  6403  		},
  6404  		{
  6405  			name: "2",
  6406  			v:    f32x4(float32(0x1.8f867ep+125), float32(0x1.8f867ep+125), 0, 0),
  6407  			exp:  f64x2(6.6382536710104395e+37, 6.6382536710104395e+37),
  6408  		},
  6409  		{
  6410  			name: "3",
  6411  			v:    f32x4(0, 0, float32(0x1.8f867ep+125), float32(0x1.8f867ep+125)),
  6412  			exp:  f64x2(0, 0),
  6413  		},
  6414  		{
  6415  			name: "4",
  6416  			v:    f32x4(float32(math.NaN()), float32(math.NaN()), float32(0x1.8f867ep+125), float32(0x1.8f867ep+125)),
  6417  			exp:  f64x2(math.NaN(), math.NaN()),
  6418  		},
  6419  		{
  6420  			name: "5",
  6421  			v:    f32x4(float32(math.Inf(1)), float32(math.Inf(-1)), float32(0x1.8f867ep+125), float32(0x1.8f867ep+125)),
  6422  			exp:  f64x2(math.Inf(1), math.Inf(-1)),
  6423  		},
  6424  	}
  6425  
  6426  	for _, tc := range tests {
  6427  		tc := tc
  6428  		t.Run(tc.name, func(t *testing.T) {
  6429  			env := newCompilerEnvironment()
  6430  			compiler := env.requireNewCompiler(t, newCompiler,
  6431  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  6432  
  6433  			err := compiler.compilePreamble()
  6434  			require.NoError(t, err)
  6435  
  6436  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  6437  				Lo: binary.LittleEndian.Uint64(tc.v[:8]),
  6438  				Hi: binary.LittleEndian.Uint64(tc.v[8:]),
  6439  			})
  6440  			require.NoError(t, err)
  6441  
  6442  			err = compiler.compileV128FloatPromote(&wazeroir.OperationV128FloatPromote{})
  6443  			require.NoError(t, err)
  6444  
  6445  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  6446  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  6447  
  6448  			err = compiler.compileReturnFunction()
  6449  			require.NoError(t, err)
  6450  
  6451  			// Generate and run the code under test.
  6452  			code, _, err := compiler.compile()
  6453  			require.NoError(t, err)
  6454  			env.exec(code)
  6455  
  6456  			require.Equal(t, nativeCallStatusCodeReturned, env.callEngine().statusCode)
  6457  
  6458  			lo, hi := env.stackTopAsV128()
  6459  			actualFs := [2]float64{
  6460  				math.Float64frombits(lo), math.Float64frombits(hi),
  6461  			}
  6462  			expFs := [2]float64{
  6463  				math.Float64frombits(binary.LittleEndian.Uint64(tc.exp[:8])),
  6464  				math.Float64frombits(binary.LittleEndian.Uint64(tc.exp[8:])),
  6465  			}
  6466  			for i := range expFs {
  6467  				exp, actual := expFs[i], actualFs[i]
  6468  				if math.IsNaN(exp) {
  6469  					require.True(t, math.IsNaN(actual))
  6470  				} else {
  6471  					require.Equal(t, exp, actual)
  6472  				}
  6473  			}
  6474  		})
  6475  	}
  6476  }
  6477  
  6478  func TestCompiler_compileV128FloatDemote(t *testing.T) {
  6479  	tests := []struct {
  6480  		name   string
  6481  		v, exp [16]byte
  6482  	}{
  6483  		{
  6484  			name: "1",
  6485  			v:    f64x2(0, 0),
  6486  			exp:  f32x4(0, 0, 0, 0),
  6487  		},
  6488  		{
  6489  			name: "2",
  6490  			v:    f64x2(0x1.fffffe0000000p-127, 0x1.fffffe0000000p-127),
  6491  			exp:  f32x4(0x1p-126, 0x1p-126, 0, 0),
  6492  		},
  6493  		{
  6494  			name: "3",
  6495  			v:    f64x2(0x1.fffffep+127, 0x1.fffffep+127),
  6496  			exp:  f32x4(0x1.fffffep+127, 0x1.fffffep+127, 0, 0),
  6497  		},
  6498  		{
  6499  			name: "4",
  6500  			v:    f64x2(math.NaN(), math.NaN()),
  6501  			exp:  f32x4(float32(math.NaN()), float32(math.NaN()), 0, 0),
  6502  		},
  6503  		{
  6504  			name: "5",
  6505  			v:    f64x2(math.Inf(1), math.Inf(-1)),
  6506  			exp:  f32x4(float32(math.Inf(1)), float32(math.Inf(-1)), 0, 0),
  6507  		},
  6508  	}
  6509  
  6510  	for _, tc := range tests {
  6511  		tc := tc
  6512  		t.Run(tc.name, func(t *testing.T) {
  6513  			env := newCompilerEnvironment()
  6514  			compiler := env.requireNewCompiler(t, newCompiler,
  6515  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  6516  
  6517  			err := compiler.compilePreamble()
  6518  			require.NoError(t, err)
  6519  
  6520  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  6521  				Lo: binary.LittleEndian.Uint64(tc.v[:8]),
  6522  				Hi: binary.LittleEndian.Uint64(tc.v[8:]),
  6523  			})
  6524  			require.NoError(t, err)
  6525  
  6526  			err = compiler.compileV128FloatDemote(&wazeroir.OperationV128FloatDemote{})
  6527  			require.NoError(t, err)
  6528  
  6529  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  6530  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  6531  
  6532  			err = compiler.compileReturnFunction()
  6533  			require.NoError(t, err)
  6534  
  6535  			// Generate and run the code under test.
  6536  			code, _, err := compiler.compile()
  6537  			require.NoError(t, err)
  6538  			env.exec(code)
  6539  
  6540  			require.Equal(t, nativeCallStatusCodeReturned, env.callEngine().statusCode)
  6541  
  6542  			lo, hi := env.stackTopAsV128()
  6543  			actualFs := [4]float32{
  6544  				math.Float32frombits(uint32(lo)),
  6545  				math.Float32frombits(uint32(lo >> 32)),
  6546  				math.Float32frombits(uint32(hi)),
  6547  				math.Float32frombits(uint32(hi >> 32)),
  6548  			}
  6549  			expFs := [4]float32{
  6550  				math.Float32frombits(binary.LittleEndian.Uint32(tc.exp[:4])),
  6551  				math.Float32frombits(binary.LittleEndian.Uint32(tc.exp[4:8])),
  6552  				math.Float32frombits(binary.LittleEndian.Uint32(tc.exp[8:12])),
  6553  				math.Float32frombits(binary.LittleEndian.Uint32(tc.exp[12:])),
  6554  			}
  6555  			for i := range expFs {
  6556  				exp, actual := expFs[i], actualFs[i]
  6557  				if math.IsNaN(float64(exp)) {
  6558  					require.True(t, math.IsNaN(float64(actual)))
  6559  				} else {
  6560  					require.Equal(t, exp, actual)
  6561  				}
  6562  			}
  6563  		})
  6564  	}
  6565  }
  6566  
  6567  func TestCompiler_compileV128ExtAddPairwise(t *testing.T) {
  6568  	tests := []struct {
  6569  		name   string
  6570  		shape  wazeroir.Shape
  6571  		signed bool
  6572  		v, exp [16]byte
  6573  	}{
  6574  		{
  6575  			name:   "i8x16 s",
  6576  			shape:  wazeroir.ShapeI8x16,
  6577  			signed: true,
  6578  			v:      [16]byte{},
  6579  			exp:    [16]byte{},
  6580  		},
  6581  		{
  6582  			name:   "i8x16 s",
  6583  			shape:  wazeroir.ShapeI8x16,
  6584  			signed: true,
  6585  			v:      [16]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
  6586  			exp:    i16x8(2, 2, 2, 2, 2, 2, 2, 2),
  6587  		},
  6588  		{
  6589  			name:   "i8x16 s",
  6590  			shape:  wazeroir.ShapeI8x16,
  6591  			signed: true,
  6592  			v: [16]byte{
  6593  				i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1),
  6594  				i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1),
  6595  			},
  6596  			exp: i16x8(
  6597  				i16ToU16(-2), i16ToU16(-2), i16ToU16(-2), i16ToU16(-2),
  6598  				i16ToU16(-2), i16ToU16(-2), i16ToU16(-2), i16ToU16(-2),
  6599  			),
  6600  		},
  6601  		{
  6602  			name:   "i8x16 s",
  6603  			shape:  wazeroir.ShapeI8x16,
  6604  			signed: true,
  6605  			v: [16]byte{
  6606  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  6607  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  6608  			},
  6609  			exp: i16x8(
  6610  				i16ToU16(-256), i16ToU16(-256), i16ToU16(-256), i16ToU16(-256),
  6611  				i16ToU16(-256), i16ToU16(-256), i16ToU16(-256), i16ToU16(-256),
  6612  			),
  6613  		},
  6614  		{
  6615  			name:   "i8x16 u",
  6616  			shape:  wazeroir.ShapeI8x16,
  6617  			signed: false,
  6618  			v:      [16]byte{},
  6619  			exp:    [16]byte{},
  6620  		},
  6621  		{
  6622  			name:   "i8x16 u",
  6623  			shape:  wazeroir.ShapeI8x16,
  6624  			signed: false,
  6625  			v:      [16]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
  6626  			exp:    i16x8(2, 2, 2, 2, 2, 2, 2, 2),
  6627  		},
  6628  		{
  6629  			name:   "i8x16 u",
  6630  			shape:  wazeroir.ShapeI8x16,
  6631  			signed: false,
  6632  			v: [16]byte{
  6633  				i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1),
  6634  				i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1), i8ToU8(-1),
  6635  			},
  6636  			exp: i16x8(510, 510, 510, 510, 510, 510, 510, 510),
  6637  		},
  6638  		{
  6639  			name:   "i8x16 u",
  6640  			shape:  wazeroir.ShapeI8x16,
  6641  			signed: false,
  6642  			v: [16]byte{
  6643  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  6644  				i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128), i8ToU8(-128),
  6645  			},
  6646  			exp: i16x8(256, 256, 256, 256, 256, 256, 256, 256),
  6647  		},
  6648  		{
  6649  			name:   "i16x8 s",
  6650  			shape:  wazeroir.ShapeI16x8,
  6651  			signed: true,
  6652  			v:      [16]byte{},
  6653  			exp:    [16]byte{},
  6654  		},
  6655  		{
  6656  			name:   "i16x8 s",
  6657  			shape:  wazeroir.ShapeI16x8,
  6658  			signed: true,
  6659  			v:      i16x8(1, 1, 1, 1, 1, 1, 1, 1),
  6660  			exp:    i32x4(2, 2, 2, 2),
  6661  		},
  6662  		{
  6663  			name:   "i16x8 s",
  6664  			shape:  wazeroir.ShapeI16x8,
  6665  			signed: true,
  6666  			v: i16x8(
  6667  				i16ToU16(-1), i16ToU16(-1), i16ToU16(-1), i16ToU16(-1),
  6668  				i16ToU16(-1), i16ToU16(-1), i16ToU16(-1), i16ToU16(-1),
  6669  			),
  6670  			exp: i32x4(i32ToU32(-2), i32ToU32(-2), i32ToU32(-2), i32ToU32(-2)),
  6671  		},
  6672  		{
  6673  			name:   "i16x8 s",
  6674  			shape:  wazeroir.ShapeI16x8,
  6675  			signed: true,
  6676  			v: i16x8(
  6677  				i16ToU16(-32768), i16ToU16(-32768), i16ToU16(-32768), i16ToU16(-32768),
  6678  				i16ToU16(-32768), i16ToU16(-32768), i16ToU16(-32768), i16ToU16(-32768),
  6679  			),
  6680  			exp: i32x4(i32ToU32(-65536), i32ToU32(-65536), i32ToU32(-65536), i32ToU32(-65536)),
  6681  		},
  6682  		{
  6683  			name:   "i16x8 u",
  6684  			shape:  wazeroir.ShapeI16x8,
  6685  			signed: false,
  6686  			v:      [16]byte{},
  6687  			exp:    [16]byte{},
  6688  		},
  6689  		{
  6690  			name:   "i16x8 u",
  6691  			shape:  wazeroir.ShapeI16x8,
  6692  			signed: false,
  6693  			v:      i16x8(1, 1, 1, 1, 1, 1, 1, 1),
  6694  			exp:    i32x4(2, 2, 2, 2),
  6695  		},
  6696  		{
  6697  			name:   "i16x8 u",
  6698  			shape:  wazeroir.ShapeI16x8,
  6699  			signed: false,
  6700  			v: i16x8(
  6701  				i16ToU16(-1), i16ToU16(-1), i16ToU16(-1), i16ToU16(-1),
  6702  				i16ToU16(-1), i16ToU16(-1), i16ToU16(-1), i16ToU16(-1),
  6703  			),
  6704  			exp: i32x4(131070, 131070, 131070, 131070),
  6705  		},
  6706  		{
  6707  			name:   "i16x8 u",
  6708  			shape:  wazeroir.ShapeI16x8,
  6709  			signed: false,
  6710  			v: i16x8(
  6711  				i16ToU16(-32768), i16ToU16(-32768), i16ToU16(-32768), i16ToU16(-32768),
  6712  				i16ToU16(-32768), i16ToU16(-32768), i16ToU16(-32768), i16ToU16(-32768),
  6713  			),
  6714  			exp: i32x4(65536, 65536, 65536, 65536),
  6715  		},
  6716  	}
  6717  
  6718  	for _, tc := range tests {
  6719  		tc := tc
  6720  		t.Run(tc.name, func(t *testing.T) {
  6721  			env := newCompilerEnvironment()
  6722  			compiler := env.requireNewCompiler(t, newCompiler,
  6723  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  6724  
  6725  			err := compiler.compilePreamble()
  6726  			require.NoError(t, err)
  6727  
  6728  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  6729  				Lo: binary.LittleEndian.Uint64(tc.v[:8]),
  6730  				Hi: binary.LittleEndian.Uint64(tc.v[8:]),
  6731  			})
  6732  			require.NoError(t, err)
  6733  
  6734  			err = compiler.compileV128ExtAddPairwise(&wazeroir.OperationV128ExtAddPairwise{
  6735  				OriginShape: tc.shape, Signed: tc.signed,
  6736  			})
  6737  			require.NoError(t, err)
  6738  
  6739  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  6740  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  6741  
  6742  			err = compiler.compileReturnFunction()
  6743  			require.NoError(t, err)
  6744  
  6745  			// Generate and run the code under test.
  6746  			code, _, err := compiler.compile()
  6747  			require.NoError(t, err)
  6748  			env.exec(code)
  6749  
  6750  			require.Equal(t, nativeCallStatusCodeReturned, env.callEngine().statusCode)
  6751  
  6752  			lo, hi := env.stackTopAsV128()
  6753  			var actual [16]byte
  6754  			binary.LittleEndian.PutUint64(actual[:8], lo)
  6755  			binary.LittleEndian.PutUint64(actual[8:], hi)
  6756  			require.Equal(t, tc.exp, actual)
  6757  		})
  6758  	}
  6759  }
  6760  
  6761  func TestCompiler_compileV128Narrow(t *testing.T) {
  6762  	tests := []struct {
  6763  		name        string
  6764  		shape       wazeroir.Shape
  6765  		signed      bool
  6766  		x1, x2, exp [16]byte
  6767  	}{
  6768  		{
  6769  			name:   "i16x8 s",
  6770  			shape:  wazeroir.ShapeI16x8,
  6771  			signed: true,
  6772  			x1:     i16x8(0, 0, 0, 0, 0, 0, 0, 0),
  6773  			x2:     i16x8(0, 0, 0, 0, 0, 0, 0, 0),
  6774  			exp:    [16]byte{},
  6775  		},
  6776  		{
  6777  			name:   "i16x8 s",
  6778  			shape:  wazeroir.ShapeI16x8,
  6779  			signed: true,
  6780  			x1:     i16x8(0, 0, 0, 0, 0, 0, 0, 0),
  6781  			x2:     i16x8(1, 1, 1, 1, 1, 1, 1, 1),
  6782  			exp: [16]byte{
  6783  				0, 0, 0, 0, 0, 0, 0, 0,
  6784  				1, 1, 1, 1, 1, 1, 1, 1,
  6785  			},
  6786  		},
  6787  		{
  6788  			name:   "i16x8 s",
  6789  			shape:  wazeroir.ShapeI16x8,
  6790  			signed: true,
  6791  			x1:     i16x8(1, 1, 1, 1, 1, 1, 1, 1),
  6792  			x2:     i16x8(0, 0, 0, 0, 0, 0, 0, 0),
  6793  			exp: [16]byte{
  6794  				1, 1, 1, 1, 1, 1, 1, 1,
  6795  				0, 0, 0, 0, 0, 0, 0, 0,
  6796  			},
  6797  		},
  6798  		{
  6799  			name:   "i16x8 s",
  6800  			shape:  wazeroir.ShapeI16x8,
  6801  			signed: true,
  6802  			x1:     i16x8(i16ToU16(-0x8000), 0, i16ToU16(-0x8000), 0, i16ToU16(-0x8000), 0, i16ToU16(-0x8000), 0),
  6803  			x2:     i16x8(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff),
  6804  			exp: [16]byte{
  6805  				0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
  6806  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  6807  			},
  6808  		},
  6809  		{
  6810  			name:   "i16x8 s",
  6811  			shape:  wazeroir.ShapeI16x8,
  6812  			signed: true,
  6813  			x1:     i16x8(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff),
  6814  			x2:     i16x8(i16ToU16(-0x8000), 0, i16ToU16(-0x8000), 0, i16ToU16(-0x8000), 0, i16ToU16(-0x8000), 0),
  6815  			exp: [16]byte{
  6816  				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  6817  				0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
  6818  			},
  6819  		},
  6820  		{
  6821  			name:   "i16x8 u",
  6822  			shape:  wazeroir.ShapeI16x8,
  6823  			signed: false,
  6824  			x1:     i16x8(0, 0, 0, 0, 0, 0, 0, 0),
  6825  			x2:     i16x8(0, 0, 0, 0, 0, 0, 0, 0),
  6826  			exp:    [16]byte{},
  6827  		},
  6828  		{
  6829  			name:   "i16x8 u",
  6830  			shape:  wazeroir.ShapeI16x8,
  6831  			signed: false,
  6832  			x1:     i16x8(0, 0, 0, 0, 0, 0, 0, 0),
  6833  			x2:     i16x8(1, 1, 1, 1, 1, 1, 1, 1),
  6834  			exp: [16]byte{
  6835  				0, 0, 0, 0, 0, 0, 0, 0,
  6836  				1, 1, 1, 1, 1, 1, 1, 1,
  6837  			},
  6838  		},
  6839  		{
  6840  			name:   "i16x8 u",
  6841  			shape:  wazeroir.ShapeI16x8,
  6842  			signed: false,
  6843  			x1:     i16x8(1, 1, 1, 1, 1, 1, 1, 1),
  6844  			x2:     i16x8(0, 0, 0, 0, 0, 0, 0, 0),
  6845  			exp: [16]byte{
  6846  				1, 1, 1, 1, 1, 1, 1, 1,
  6847  				0, 0, 0, 0, 0, 0, 0, 0,
  6848  			},
  6849  		},
  6850  		{
  6851  			name:   "i16x8 u",
  6852  			shape:  wazeroir.ShapeI16x8,
  6853  			signed: false,
  6854  			x1:     i16x8(i16ToU16(-0x8000), 0, i16ToU16(-0x8000), 0, i16ToU16(-0x8000), 0, i16ToU16(-0x8000), 0),
  6855  			x2:     i16x8(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff),
  6856  			exp: [16]byte{
  6857  				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  6858  				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  6859  			},
  6860  		},
  6861  		{
  6862  			name:   "i16x8 u",
  6863  			shape:  wazeroir.ShapeI16x8,
  6864  			signed: false,
  6865  			x1:     i16x8(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff),
  6866  			x2:     i16x8(i16ToU16(-0x8000), 0, i16ToU16(-0x8000), 0, i16ToU16(-0x8000), 0, i16ToU16(-0x8000), 0),
  6867  			exp: [16]byte{
  6868  				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  6869  				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  6870  			},
  6871  		},
  6872  		{
  6873  			name:   "i16x8 u",
  6874  			shape:  wazeroir.ShapeI16x8,
  6875  			signed: false,
  6876  			x1:     i16x8(i16ToU16(-1), 0, i16ToU16(-1), 0, i16ToU16(-1), 0, i16ToU16(-1), 0),
  6877  			x2:     i16x8(0, 0x100, 0, 0x100, 0, 0x100, 0, 0x100),
  6878  			exp: [16]byte{
  6879  				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  6880  				0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
  6881  			},
  6882  		},
  6883  		{
  6884  			name:   "i16x8 u",
  6885  			shape:  wazeroir.ShapeI16x8,
  6886  			signed: false,
  6887  			x1:     i16x8(0, 0x100, 0, 0x100, 0, 0x100, 0, 0x100),
  6888  			x2:     i16x8(i16ToU16(-1), 0, i16ToU16(-1), 0, i16ToU16(-1), 0, i16ToU16(-1), 0),
  6889  			exp: [16]byte{
  6890  				0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
  6891  				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  6892  			},
  6893  		},
  6894  		{
  6895  			name:   "i32x4 s",
  6896  			shape:  wazeroir.ShapeI32x4,
  6897  			signed: true,
  6898  			x1:     i32x4(0, 0, 0, 0),
  6899  			x2:     i32x4(0, 0, 0, 0),
  6900  			exp:    i16x8(0, 0, 0, 0, 0, 0, 0, 0),
  6901  		},
  6902  		{
  6903  			name:   "i32x4 s",
  6904  			shape:  wazeroir.ShapeI32x4,
  6905  			signed: true,
  6906  			x1:     i32x4(0, 0, 0, 0),
  6907  			x2:     i32x4(1, 1, 1, 1),
  6908  			exp:    i16x8(0, 0, 0, 0, 1, 1, 1, 1),
  6909  		},
  6910  		{
  6911  			name:   "i32x4 s",
  6912  			shape:  wazeroir.ShapeI32x4,
  6913  			signed: true,
  6914  			x1:     i32x4(1, 1, 1, 1),
  6915  			x2:     i32x4(0, 0, 0, 0),
  6916  			exp:    i16x8(1, 1, 1, 1, 0, 0, 0, 0),
  6917  		},
  6918  		{
  6919  			name:   "i32x4 s",
  6920  			shape:  wazeroir.ShapeI32x4,
  6921  			signed: true,
  6922  			x1:     i32x4(0x8000, 0x8000, 0x7fff, 0x7fff),
  6923  			x2:     i32x4(0x7fff, 0x7fff, 0x8000, 0x8000),
  6924  			exp:    i16x8(0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff),
  6925  		},
  6926  		{
  6927  			name:   "i32x4 u",
  6928  			shape:  wazeroir.ShapeI32x4,
  6929  			signed: false,
  6930  			x1:     i32x4(0, 0, 0, 0),
  6931  			x2:     i32x4(0, 0, 0, 0),
  6932  			exp:    i16x8(0, 0, 0, 0, 0, 0, 0, 0),
  6933  		},
  6934  		{
  6935  			name:   "i32x4 u",
  6936  			shape:  wazeroir.ShapeI32x4,
  6937  			signed: false,
  6938  			x1:     i32x4(0, 0, 0, 0),
  6939  			x2:     i32x4(1, 1, 1, 1),
  6940  			exp:    i16x8(0, 0, 0, 0, 1, 1, 1, 1),
  6941  		},
  6942  		{
  6943  			name:   "i32x4 u",
  6944  			shape:  wazeroir.ShapeI32x4,
  6945  			signed: false,
  6946  			x1:     i32x4(1, 1, 1, 1),
  6947  			x2:     i32x4(0, 0, 0, 0),
  6948  			exp:    i16x8(1, 1, 1, 1, 0, 0, 0, 0),
  6949  		},
  6950  		{
  6951  			name:   "i32x4 u",
  6952  			shape:  wazeroir.ShapeI32x4,
  6953  			signed: false,
  6954  			x1:     i32x4(0x8000, 0x8000, 0x7fff, 0x7fff),
  6955  			x2:     i32x4(0x7fff, 0x7fff, 0x8000, 0x8000),
  6956  			exp:    i16x8(0x8000, 0x8000, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x8000, 0x8000),
  6957  		},
  6958  	}
  6959  
  6960  	for _, tc := range tests {
  6961  		tc := tc
  6962  		t.Run(tc.name, func(t *testing.T) {
  6963  			env := newCompilerEnvironment()
  6964  			compiler := env.requireNewCompiler(t, newCompiler,
  6965  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  6966  
  6967  			err := compiler.compilePreamble()
  6968  			require.NoError(t, err)
  6969  
  6970  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  6971  				Lo: binary.LittleEndian.Uint64(tc.x1[:8]),
  6972  				Hi: binary.LittleEndian.Uint64(tc.x1[8:]),
  6973  			})
  6974  			require.NoError(t, err)
  6975  
  6976  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  6977  				Lo: binary.LittleEndian.Uint64(tc.x2[:8]),
  6978  				Hi: binary.LittleEndian.Uint64(tc.x2[8:]),
  6979  			})
  6980  			require.NoError(t, err)
  6981  
  6982  			err = compiler.compileV128Narrow(&wazeroir.OperationV128Narrow{
  6983  				OriginShape: tc.shape, Signed: tc.signed,
  6984  			})
  6985  			require.NoError(t, err)
  6986  
  6987  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  6988  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  6989  
  6990  			err = compiler.compileReturnFunction()
  6991  			require.NoError(t, err)
  6992  
  6993  			// Generate and run the code under test.
  6994  			code, _, err := compiler.compile()
  6995  			require.NoError(t, err)
  6996  			env.exec(code)
  6997  
  6998  			require.Equal(t, nativeCallStatusCodeReturned, env.callEngine().statusCode)
  6999  
  7000  			lo, hi := env.stackTopAsV128()
  7001  			var actual [16]byte
  7002  			binary.LittleEndian.PutUint64(actual[:8], lo)
  7003  			binary.LittleEndian.PutUint64(actual[8:], hi)
  7004  			require.Equal(t, tc.exp, actual)
  7005  		})
  7006  	}
  7007  }
  7008  
  7009  func TestCompiler_compileV128FConvertFromI(t *testing.T) {
  7010  	tests := []struct {
  7011  		name      string
  7012  		destShape wazeroir.Shape
  7013  		signed    bool
  7014  		v, exp    [16]byte
  7015  	}{
  7016  		{
  7017  			name:      "f32x4 s",
  7018  			destShape: wazeroir.ShapeF32x4,
  7019  			signed:    true,
  7020  			v:         i32x4(0, 0, 0, 0),
  7021  			exp:       f32x4(0, 0, 0, 0),
  7022  		},
  7023  		{
  7024  			name:      "f32x4 s",
  7025  			destShape: wazeroir.ShapeF32x4,
  7026  			signed:    true,
  7027  			v:         i32x4(1, 0, 2, 3),
  7028  			exp:       f32x4(1, 0, 2.0, 3),
  7029  		},
  7030  		{
  7031  			name:      "f32x4 s",
  7032  			destShape: wazeroir.ShapeF32x4,
  7033  			signed:    true,
  7034  			v:         i32x4(1234567890, i32ToU32(-2147483648.0), 2147483647, 1234567890),
  7035  			exp:       f32x4(0x1.26580cp+30, -2147483648.0, 2147483647, 0x1.26580cp+30),
  7036  		},
  7037  		{
  7038  			name:      "f32x4 s",
  7039  			destShape: wazeroir.ShapeF32x4,
  7040  			signed:    false,
  7041  			v:         i32x4(0, 0, 0, 0),
  7042  			exp:       f32x4(0, 0, 0, 0),
  7043  		},
  7044  		{
  7045  			name:      "f32x4 s",
  7046  			destShape: wazeroir.ShapeF32x4,
  7047  			signed:    false,
  7048  			v:         i32x4(1, 0, 2, 3),
  7049  			exp:       f32x4(1, 0, 2.0, 3),
  7050  		},
  7051  		{
  7052  			name:      "f32x4 s",
  7053  			destShape: wazeroir.ShapeF32x4,
  7054  			signed:    false,
  7055  			v:         i32x4(2147483647, i32ToU32(-2147483648.0), 2147483647, i32ToU32(-1)),
  7056  			exp:       f32x4(2147483648.0, 2147483648.0, 2147483648.0, 4294967295.0),
  7057  		},
  7058  		{
  7059  			name:      "f64x2 s",
  7060  			destShape: wazeroir.ShapeF64x2,
  7061  			signed:    true,
  7062  			v:         i32x4(0, 0, 0, 0),
  7063  			exp:       f64x2(0, 0),
  7064  		},
  7065  		{
  7066  			name:      "f64x2 s",
  7067  			destShape: wazeroir.ShapeF64x2,
  7068  			signed:    true,
  7069  			v:         i32x4(0, 0, i32ToU32(-1), i32ToU32(-32)),
  7070  			exp:       f64x2(0, 0),
  7071  		},
  7072  		{
  7073  			name:      "f64x2 s",
  7074  			destShape: wazeroir.ShapeF64x2,
  7075  			signed:    true,
  7076  			v:         i32x4(2147483647, i32ToU32(-2147483648), 0, 0),
  7077  			exp:       f64x2(2147483647, -2147483648),
  7078  		},
  7079  		{
  7080  			name:      "f64x2 s",
  7081  			destShape: wazeroir.ShapeF64x2,
  7082  			signed:    false,
  7083  			v:         i32x4(0, 0, 0, 0),
  7084  			exp:       f64x2(0, 0),
  7085  		},
  7086  		{
  7087  			name:      "f64x2 s",
  7088  			destShape: wazeroir.ShapeF64x2,
  7089  			signed:    false,
  7090  			v:         i32x4(0, 0, i32ToU32(-1), i32ToU32(-32)),
  7091  			exp:       f64x2(0, 0),
  7092  		},
  7093  		{
  7094  			name:      "f64x2 s",
  7095  			destShape: wazeroir.ShapeF64x2,
  7096  			signed:    false,
  7097  			v:         i32x4(2147483647, i32ToU32(-2147483648), 0, 0),
  7098  			exp:       f64x2(2147483647, 2147483648),
  7099  		},
  7100  	}
  7101  
  7102  	for _, tc := range tests {
  7103  		tc := tc
  7104  		t.Run(tc.name, func(t *testing.T) {
  7105  			env := newCompilerEnvironment()
  7106  			compiler := env.requireNewCompiler(t, newCompiler,
  7107  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  7108  
  7109  			err := compiler.compilePreamble()
  7110  			require.NoError(t, err)
  7111  
  7112  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  7113  				Lo: binary.LittleEndian.Uint64(tc.v[:8]),
  7114  				Hi: binary.LittleEndian.Uint64(tc.v[8:]),
  7115  			})
  7116  			require.NoError(t, err)
  7117  
  7118  			err = compiler.compileV128FConvertFromI(&wazeroir.OperationV128FConvertFromI{
  7119  				DestinationShape: tc.destShape,
  7120  				Signed:           tc.signed,
  7121  			})
  7122  			require.NoError(t, err)
  7123  
  7124  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  7125  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  7126  
  7127  			err = compiler.compileReturnFunction()
  7128  			require.NoError(t, err)
  7129  
  7130  			// Generate and run the code under test.
  7131  			code, _, err := compiler.compile()
  7132  			require.NoError(t, err)
  7133  			env.exec(code)
  7134  
  7135  			require.Equal(t, nativeCallStatusCodeReturned, env.callEngine().statusCode)
  7136  
  7137  			lo, hi := env.stackTopAsV128()
  7138  			var actual [16]byte
  7139  			binary.LittleEndian.PutUint64(actual[:8], lo)
  7140  			binary.LittleEndian.PutUint64(actual[8:], hi)
  7141  			require.Equal(t, tc.exp, actual)
  7142  		})
  7143  	}
  7144  }
  7145  
  7146  func TestCompiler_compileV128Dot(t *testing.T) {
  7147  	tests := []struct {
  7148  		name        string
  7149  		x1, x2, exp [16]byte
  7150  	}{
  7151  		{
  7152  			name: "1",
  7153  			x1:   i16x8(0, 0, 0, 0, 0, 0, 0, 0),
  7154  			x2:   i16x8(0, 0, 0, 0, 0, 0, 0, 0),
  7155  			exp:  i32x4(0, 0, 0, 0),
  7156  		},
  7157  		{
  7158  			name: "2",
  7159  			x1:   i16x8(1, 1, 1, 1, i16ToU16(-1), i16ToU16(-1), i16ToU16(-1), i16ToU16(-1)),
  7160  			x2:   i16x8(i16ToU16(-1), i16ToU16(-1), i16ToU16(-1), i16ToU16(-1), 2, 2, 2, 2),
  7161  			exp:  i32x4(i32ToU32(-2), i32ToU32(-2), i32ToU32(-4), i32ToU32(-4)),
  7162  		},
  7163  		{
  7164  			name: "3",
  7165  			x1:   i16x8(65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535),
  7166  			x2:   i16x8(65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535),
  7167  			exp:  i32x4(2, 2, 2, 2),
  7168  		},
  7169  	}
  7170  
  7171  	for _, tc := range tests {
  7172  		tc := tc
  7173  		t.Run(tc.name, func(t *testing.T) {
  7174  			env := newCompilerEnvironment()
  7175  			compiler := env.requireNewCompiler(t, newCompiler,
  7176  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  7177  
  7178  			err := compiler.compilePreamble()
  7179  			require.NoError(t, err)
  7180  
  7181  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  7182  				Lo: binary.LittleEndian.Uint64(tc.x2[:8]),
  7183  				Hi: binary.LittleEndian.Uint64(tc.x2[8:]),
  7184  			})
  7185  			require.NoError(t, err)
  7186  
  7187  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  7188  				Lo: binary.LittleEndian.Uint64(tc.x1[:8]),
  7189  				Hi: binary.LittleEndian.Uint64(tc.x1[8:]),
  7190  			})
  7191  			require.NoError(t, err)
  7192  
  7193  			err = compiler.compileV128Dot(&wazeroir.OperationV128Dot{})
  7194  			require.NoError(t, err)
  7195  
  7196  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  7197  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  7198  
  7199  			err = compiler.compileReturnFunction()
  7200  			require.NoError(t, err)
  7201  
  7202  			// Generate and run the code under test.
  7203  			code, _, err := compiler.compile()
  7204  			require.NoError(t, err)
  7205  			env.exec(code)
  7206  
  7207  			require.Equal(t, nativeCallStatusCodeReturned, env.callEngine().statusCode)
  7208  
  7209  			lo, hi := env.stackTopAsV128()
  7210  			var actual [16]byte
  7211  			binary.LittleEndian.PutUint64(actual[:8], lo)
  7212  			binary.LittleEndian.PutUint64(actual[8:], hi)
  7213  			require.Equal(t, tc.exp, actual)
  7214  		})
  7215  	}
  7216  }
  7217  
  7218  func TestCompiler_compileV128ITruncSatFromF(t *testing.T) {
  7219  	tests := []struct {
  7220  		name        string
  7221  		originShape wazeroir.Shape
  7222  		signed      bool
  7223  		v, exp      [16]byte
  7224  	}{
  7225  		{
  7226  			name:        "f32x4 s",
  7227  			originShape: wazeroir.ShapeF32x4,
  7228  			signed:      true,
  7229  			v:           i32x4(0, 0, 0, 0),
  7230  			exp:         f32x4(0, 0, 0, 0),
  7231  		},
  7232  		{
  7233  			name:        "f32x4 s",
  7234  			originShape: wazeroir.ShapeF32x4,
  7235  			signed:      true,
  7236  			v:           f32x4(1.5, -1.9, -1.9, 1.5),
  7237  			exp:         i32x4(1, i32ToU32(-1), i32ToU32(-1), 1),
  7238  		},
  7239  		{
  7240  			name:        "f32x4 s",
  7241  			originShape: wazeroir.ShapeF32x4,
  7242  			signed:      true,
  7243  			v:           f32x4(float32(math.NaN()), -4294967294.0, float32(math.Inf(-1)), float32(math.Inf(1))),
  7244  			exp:         i32x4(0, i32ToU32(-2147483648), i32ToU32(-2147483648), 2147483647),
  7245  		},
  7246  		{
  7247  			name:        "f32x4 u",
  7248  			originShape: wazeroir.ShapeF32x4,
  7249  			signed:      false,
  7250  			v:           i32x4(0, 0, 0, 0),
  7251  			exp:         f32x4(0, 0, 0, 0),
  7252  		},
  7253  		{
  7254  			name:        "f32x4 u",
  7255  			originShape: wazeroir.ShapeF32x4,
  7256  			signed:      false,
  7257  			v:           f32x4(1.5, -1.9, -1.9, 1.5),
  7258  			exp:         i32x4(1, 0, 0, 1),
  7259  		},
  7260  		{
  7261  			name:        "f32x4 u",
  7262  			originShape: wazeroir.ShapeF32x4,
  7263  			signed:      false,
  7264  			v:           f32x4(float32(math.NaN()), -4294967294.0, 4294967294.0, float32(math.Inf(1))),
  7265  			exp:         i32x4(0, 0, 4294967295, 4294967295),
  7266  		},
  7267  		{
  7268  			name:        "f64x2 s",
  7269  			originShape: wazeroir.ShapeF64x2,
  7270  			signed:      true,
  7271  			v:           f64x2(0, 0),
  7272  			exp:         i32x4(0, 0, 0, 0),
  7273  		},
  7274  		{
  7275  			name:        "f64x2 s",
  7276  			originShape: wazeroir.ShapeF64x2,
  7277  			signed:      true,
  7278  			v:           f64x2(5.123, -2.0),
  7279  			exp:         i32x4(5, i32ToU32(-2), 0, 0),
  7280  		},
  7281  		{
  7282  			name:        "f64x2 s",
  7283  			originShape: wazeroir.ShapeF64x2,
  7284  			signed:      true,
  7285  			v:           f64x2(math.NaN(), math.Inf(1)),
  7286  			exp:         i32x4(0, 2147483647, 0, 0),
  7287  		},
  7288  		{
  7289  			name:        "f64x2 s",
  7290  			originShape: wazeroir.ShapeF64x2,
  7291  			signed:      true,
  7292  			v:           f64x2(math.Inf(-1), 4294967294.0),
  7293  			exp:         i32x4(i32ToU32(-2147483648), 2147483647, 0, 0),
  7294  		},
  7295  		{
  7296  			name:        "f64x2 u",
  7297  			originShape: wazeroir.ShapeF64x2,
  7298  			signed:      false,
  7299  			v:           f64x2(0, 0),
  7300  			exp:         i32x4(0, 0, 0, 0),
  7301  		},
  7302  		{
  7303  			name:        "f64x2 u",
  7304  			originShape: wazeroir.ShapeF64x2,
  7305  			signed:      false,
  7306  			v:           f64x2(5.123, -2.0),
  7307  			exp:         i32x4(5, 0, 0, 0),
  7308  		},
  7309  		{
  7310  			name:        "f64x2 u",
  7311  			originShape: wazeroir.ShapeF64x2,
  7312  			signed:      false,
  7313  			v:           f64x2(math.NaN(), math.Inf(1)),
  7314  			exp:         i32x4(0, 4294967295, 0, 0),
  7315  		},
  7316  		{
  7317  			name:        "f64x2 u",
  7318  			originShape: wazeroir.ShapeF64x2,
  7319  			signed:      false,
  7320  			v:           f64x2(math.Inf(-1), 4294967296.0),
  7321  			exp:         i32x4(0, 4294967295, 0, 0),
  7322  		},
  7323  	}
  7324  
  7325  	for _, tc := range tests {
  7326  		tc := tc
  7327  		t.Run(tc.name, func(t *testing.T) {
  7328  			env := newCompilerEnvironment()
  7329  			compiler := env.requireNewCompiler(t, newCompiler,
  7330  				&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  7331  
  7332  			err := compiler.compilePreamble()
  7333  			require.NoError(t, err)
  7334  
  7335  			err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  7336  				Lo: binary.LittleEndian.Uint64(tc.v[:8]),
  7337  				Hi: binary.LittleEndian.Uint64(tc.v[8:]),
  7338  			})
  7339  			require.NoError(t, err)
  7340  
  7341  			err = compiler.compileV128ITruncSatFromF(&wazeroir.OperationV128ITruncSatFromF{
  7342  				OriginShape: tc.originShape,
  7343  				Signed:      tc.signed,
  7344  			})
  7345  			require.NoError(t, err)
  7346  
  7347  			requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  7348  			require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  7349  
  7350  			err = compiler.compileReturnFunction()
  7351  			require.NoError(t, err)
  7352  
  7353  			// Generate and run the code under test.
  7354  			code, _, err := compiler.compile()
  7355  			require.NoError(t, err)
  7356  			env.exec(code)
  7357  
  7358  			require.Equal(t, nativeCallStatusCodeReturned, env.callEngine().statusCode)
  7359  
  7360  			lo, hi := env.stackTopAsV128()
  7361  			var actual [16]byte
  7362  			binary.LittleEndian.PutUint64(actual[:8], lo)
  7363  			binary.LittleEndian.PutUint64(actual[8:], hi)
  7364  			require.Equal(t, tc.exp, actual)
  7365  		})
  7366  	}
  7367  }
  7368  
  7369  // TestCompiler_compileSelect_v128 is for select instructions on vector values.
  7370  func TestCompiler_compileSelect_v128(t *testing.T) {
  7371  	const x1Lo, x1Hi = uint64(0x1), uint64(0x2)
  7372  	const x2Lo, x2Hi = uint64(0x3), uint64(0x4)
  7373  
  7374  	for _, selector := range []uint32{0, 1} {
  7375  		env := newCompilerEnvironment()
  7376  		compiler := env.requireNewCompiler(t, newCompiler,
  7377  			&wazeroir.CompilationResult{HasMemory: true, Signature: &wasm.FunctionType{}})
  7378  
  7379  		err := compiler.compilePreamble()
  7380  		require.NoError(t, err)
  7381  
  7382  		err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  7383  			Lo: x1Lo,
  7384  			Hi: x1Hi,
  7385  		})
  7386  		require.NoError(t, err)
  7387  
  7388  		err = compiler.compileV128Const(&wazeroir.OperationV128Const{
  7389  			Lo: x2Lo,
  7390  			Hi: x2Hi,
  7391  		})
  7392  		require.NoError(t, err)
  7393  
  7394  		err = compiler.compileConstI32(&wazeroir.OperationConstI32{Value: selector})
  7395  		require.NoError(t, err)
  7396  
  7397  		err = compiler.compileSelect(&wazeroir.OperationSelect{IsTargetVector: true})
  7398  		require.NoError(t, err)
  7399  
  7400  		requireRuntimeLocationStackPointerEqual(t, uint64(2), compiler)
  7401  		require.Equal(t, 1, len(compiler.runtimeValueLocationStack().usedRegisters))
  7402  
  7403  		err = compiler.compileReturnFunction()
  7404  		require.NoError(t, err)
  7405  
  7406  		// Generate and run the code under test.
  7407  		code, _, err := compiler.compile()
  7408  		require.NoError(t, err)
  7409  		env.exec(code)
  7410  
  7411  		require.Equal(t, nativeCallStatusCodeReturned, env.callEngine().statusCode)
  7412  
  7413  		lo, hi := env.stackTopAsV128()
  7414  		if selector == 0 {
  7415  			require.Equal(t, x2Lo, lo)
  7416  			require.Equal(t, x2Hi, hi)
  7417  		} else {
  7418  			require.Equal(t, x1Lo, lo)
  7419  			require.Equal(t, x1Hi, hi)
  7420  		}
  7421  	}
  7422  }