github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/internal/engine/compiler/compiler_vec_test.go (about)

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