interpreter,compiler(amd64): complete SIMD instructions (#624)
This completes the implementation of SIMD proposal for both the interpreter and compiler(amd64). This also fixes #210 by adding the complete documentation over all the wazeroir operations. Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io> Co-authored-by: Crypt Keeper <64215+codefromthecrypt@users.noreply.github.com>
This commit is contained in:
@@ -66,25 +66,51 @@ type (
|
||||
}
|
||||
|
||||
commandActionVal struct {
|
||||
ValType string `json:"type"`
|
||||
LaneType string `json:"lane_type"`
|
||||
ValType string `json:"type"`
|
||||
// LaneType is not empty if ValueType == "v128"
|
||||
LaneType laneType `json:"lane_type"`
|
||||
Value interface{} `json:"value"`
|
||||
}
|
||||
)
|
||||
|
||||
// laneType is a type of each lane of vector value.
|
||||
//
|
||||
// See https://github.com/WebAssembly/wabt/blob/main/docs/wast2json.md#const
|
||||
type laneType = string
|
||||
|
||||
const (
|
||||
laneTypeI8 laneType = "i8"
|
||||
laneTypeI16 laneType = "i16"
|
||||
laneTypeI32 laneType = "i32"
|
||||
laneTypeI64 laneType = "i64"
|
||||
laneTypeF32 laneType = "f32"
|
||||
laneTypeF64 laneType = "f64"
|
||||
)
|
||||
|
||||
func (c commandActionVal) String() string {
|
||||
var v string
|
||||
valTypeStr := c.ValType
|
||||
switch c.ValType {
|
||||
case "i32":
|
||||
v = c.Value.(string)
|
||||
case "f32":
|
||||
ret, _ := strconv.ParseUint(c.Value.(string), 10, 32)
|
||||
v = fmt.Sprintf("%f", math.Float32frombits(uint32(ret)))
|
||||
str := c.Value.(string)
|
||||
if strings.Contains(str, "nan") {
|
||||
v = "nan"
|
||||
} else {
|
||||
ret, _ := strconv.ParseUint(str, 10, 32)
|
||||
v = fmt.Sprintf("%f", math.Float32frombits(uint32(ret)))
|
||||
}
|
||||
case "i64":
|
||||
v = c.Value.(string)
|
||||
case "f64":
|
||||
ret, _ := strconv.ParseUint(c.Value.(string), 10, 64)
|
||||
v = fmt.Sprintf("%f", math.Float64frombits(ret))
|
||||
str := c.Value.(string)
|
||||
if strings.Contains(str, "nan") {
|
||||
v = "nan"
|
||||
} else {
|
||||
ret, _ := strconv.ParseUint(str, 10, 64)
|
||||
v = fmt.Sprintf("%f", math.Float64frombits(ret))
|
||||
}
|
||||
case "externref":
|
||||
if c.Value == "null" {
|
||||
v = "null"
|
||||
@@ -107,8 +133,9 @@ func (c commandActionVal) String() string {
|
||||
strs = append(strs, v.(string))
|
||||
}
|
||||
v = strings.Join(strs, ",")
|
||||
valTypeStr = fmt.Sprintf("v128[lane=%s]", c.LaneType)
|
||||
}
|
||||
return fmt.Sprintf("{type: %s, value: %v}", c.ValType, v)
|
||||
return fmt.Sprintf("{type: %s, value: %v}", valTypeStr, v)
|
||||
}
|
||||
|
||||
func (c command) String() string {
|
||||
@@ -153,15 +180,14 @@ func (c command) getAssertReturnArgs() []uint64 {
|
||||
return args
|
||||
}
|
||||
|
||||
func (c command) getAssertReturnArgsExps() ([]uint64, []uint64) {
|
||||
var args, exps []uint64
|
||||
func (c command) getAssertReturnArgsExps() (args []uint64, exps []uint64) {
|
||||
for _, arg := range c.Action.Args {
|
||||
args = append(args, arg.toUint64s()...)
|
||||
}
|
||||
for _, exp := range c.Exps {
|
||||
exps = append(exps, exp.toUint64s()...)
|
||||
}
|
||||
return args, exps
|
||||
return
|
||||
}
|
||||
|
||||
func (c commandActionVal) toUint64s() (ret []uint64) {
|
||||
@@ -170,7 +196,6 @@ func (c commandActionVal) toUint64s() (ret []uint64) {
|
||||
if !ok {
|
||||
panic("BUG")
|
||||
}
|
||||
var low, high uint64
|
||||
var width, valNum int
|
||||
switch c.LaneType {
|
||||
case "i8":
|
||||
@@ -188,26 +213,41 @@ func (c commandActionVal) toUint64s() (ret []uint64) {
|
||||
default:
|
||||
panic("BUG")
|
||||
}
|
||||
for i := 0; i < valNum/2; i++ {
|
||||
v, err := strconv.ParseUint(strValues[i].(string), 10, width)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
low |= (v << (i * width))
|
||||
}
|
||||
for i := valNum / 2; i < valNum; i++ {
|
||||
v, err := strconv.ParseUint(strValues[i].(string), 10, width)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
high |= (v << ((i - valNum/2) * width))
|
||||
}
|
||||
return []uint64{low, high}
|
||||
lo, hi := buildLaneUint64(strValues, width, valNum)
|
||||
return []uint64{lo, hi}
|
||||
} else {
|
||||
return []uint64{c.toUint64()}
|
||||
}
|
||||
}
|
||||
|
||||
func buildLaneUint64(raw []interface{}, width, valNum int) (lo, hi uint64) {
|
||||
for i := 0; i < valNum; i++ {
|
||||
str := raw[i].(string)
|
||||
|
||||
var v uint64
|
||||
var err error
|
||||
if strings.Contains(str, "nan") {
|
||||
if width == 64 {
|
||||
v = math.Float64bits(math.NaN())
|
||||
} else {
|
||||
v = uint64(math.Float32bits(float32(math.NaN())))
|
||||
}
|
||||
} else {
|
||||
v, err = strconv.ParseUint(str, 10, width)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
if half := valNum / 2; i < half {
|
||||
lo |= v << (i * width)
|
||||
} else {
|
||||
hi |= v << ((i - half) * width)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c commandActionVal) toUint64() (ret uint64) {
|
||||
strValue := c.Value.(string)
|
||||
if strings.Contains(strValue, "nan") {
|
||||
@@ -441,7 +481,14 @@ func Run(t *testing.T, testDataFS embed.FS, newEngine func(wasm.Features) wasm.E
|
||||
vals, types, err := callFunction(ns, moduleName, c.Action.Field, args...)
|
||||
require.NoError(t, err, msg)
|
||||
require.Equal(t, len(exps), len(vals), msg)
|
||||
requireValuesEq(t, vals, exps, types, msg)
|
||||
laneTypes := map[int]string{}
|
||||
for i, expV := range c.Exps {
|
||||
if expV.ValType == "v128" {
|
||||
laneTypes[i] = expV.LaneType
|
||||
}
|
||||
}
|
||||
matched, valuesMsg := valuesEq(vals, exps, types, laneTypes)
|
||||
require.True(t, matched, msg+"\n"+valuesMsg)
|
||||
case "get":
|
||||
_, exps := c.getAssertReturnArgsExps()
|
||||
require.Equal(t, 1, len(exps))
|
||||
@@ -597,52 +644,157 @@ func testdataPath(filename string) string {
|
||||
return fmt.Sprintf("testdata/%s", filename)
|
||||
}
|
||||
|
||||
func requireValuesEq(t *testing.T, actual, exps []uint64, valTypes []wasm.ValueType, msg string) {
|
||||
var expectedTypesVectorFlattend []wasm.ValueType
|
||||
for _, tp := range valTypes {
|
||||
if tp != wasm.ValueTypeV128 {
|
||||
expectedTypesVectorFlattend = append(expectedTypesVectorFlattend, tp)
|
||||
} else {
|
||||
expectedTypesVectorFlattend = append(expectedTypesVectorFlattend, wasm.ValueTypeI64)
|
||||
expectedTypesVectorFlattend = append(expectedTypesVectorFlattend, wasm.ValueTypeI64)
|
||||
// valuesEq returns true if all the actual result matches exps which are all expressed as uint64.
|
||||
// * actual,exps: comparison target values which are all represented as uint64, meaning that if valTypes = [V128,I32], then
|
||||
// we have actual/exp = [(lower-64bit of the first V128), (higher-64bit of the first V128), I32].
|
||||
// * valTypes holds the wasm.ValueType(s) of the original values in Wasm.
|
||||
// * laneTypes maps the index of valueTypes to laneType if valueTypes[i] == wasm.ValueTypeV128.
|
||||
//
|
||||
// Also, if matched == false this returns non-empty valuesMsg which can be used to augment the test failure message.
|
||||
func valuesEq(actual, exps []uint64, valTypes []wasm.ValueType, laneTypes map[int]laneType) (matched bool, valuesMsg string) {
|
||||
matched = true
|
||||
|
||||
var msgExpValuesStrs, msgActualValuesStrs []string
|
||||
var uint64RepPos int // the index to actual and exps slice.
|
||||
for i, tp := range valTypes {
|
||||
switch tp {
|
||||
case wasm.ValueTypeI32:
|
||||
msgExpValuesStrs = append(msgExpValuesStrs, fmt.Sprintf("%d", uint32(exps[uint64RepPos])))
|
||||
msgActualValuesStrs = append(msgActualValuesStrs, fmt.Sprintf("%d", uint32(actual[uint64RepPos])))
|
||||
matched = matched && uint32(exps[uint64RepPos]) == uint32(actual[uint64RepPos])
|
||||
uint64RepPos++
|
||||
case wasm.ValueTypeI64, wasm.ValueTypeExternref, wasm.ValueTypeFuncref:
|
||||
msgExpValuesStrs = append(msgExpValuesStrs, fmt.Sprintf("%d", exps[uint64RepPos]))
|
||||
msgActualValuesStrs = append(msgActualValuesStrs, fmt.Sprintf("%d", actual[uint64RepPos]))
|
||||
matched = matched && exps[uint64RepPos] == actual[uint64RepPos]
|
||||
uint64RepPos++
|
||||
case wasm.ValueTypeF32:
|
||||
a := math.Float32frombits(uint32(actual[uint64RepPos]))
|
||||
e := math.Float32frombits(uint32(exps[uint64RepPos]))
|
||||
msgExpValuesStrs = append(msgExpValuesStrs, fmt.Sprintf("%f", e))
|
||||
msgActualValuesStrs = append(msgActualValuesStrs, fmt.Sprintf("%f", a))
|
||||
matched = matched && f32Equal(e, a)
|
||||
uint64RepPos++
|
||||
case wasm.ValueTypeF64:
|
||||
e := math.Float64frombits(exps[uint64RepPos])
|
||||
a := math.Float64frombits(actual[uint64RepPos])
|
||||
msgExpValuesStrs = append(msgExpValuesStrs, fmt.Sprintf("%f", e))
|
||||
msgActualValuesStrs = append(msgActualValuesStrs, fmt.Sprintf("%f", a))
|
||||
matched = matched && f64Equal(e, a)
|
||||
uint64RepPos++
|
||||
case wasm.ValueTypeV128:
|
||||
actualLo, actualHi := actual[uint64RepPos], actual[uint64RepPos+1]
|
||||
expLo, expHi := exps[uint64RepPos], exps[uint64RepPos+1]
|
||||
switch laneTypes[i] {
|
||||
case laneTypeI8:
|
||||
msgExpValuesStrs = append(msgExpValuesStrs,
|
||||
fmt.Sprintf("i8x16(%#x, %#x, %#x, %#x, %#x, %#x, %#x, %#x, %#x, %#x, %#x, %#x, %#x, %#x, %#x, %#x)",
|
||||
byte(expLo), byte(expLo>>8), byte(expLo>>16), byte(expLo>>24),
|
||||
byte(expLo>>32), byte(expLo>>40), byte(expLo>>48), byte(expLo>>56),
|
||||
byte(expHi), byte(expHi>>8), byte(expHi>>16), byte(expHi>>24),
|
||||
byte(expHi>>32), byte(expHi>>40), byte(expHi>>48), byte(expHi>>56),
|
||||
),
|
||||
)
|
||||
msgActualValuesStrs = append(msgActualValuesStrs,
|
||||
fmt.Sprintf("i8x16(%#x, %#x, %#x, %#x, %#x, %#x, %#x, %#x, %#x, %#x, %#x, %#x, %#x, %#x, %#x, %#x)",
|
||||
byte(actualLo), byte(actualLo>>8), byte(actualLo>>16), byte(actualLo>>24),
|
||||
byte(actualLo>>32), byte(actualLo>>40), byte(actualLo>>48), byte(actualLo>>56),
|
||||
byte(actualHi), byte(actualHi>>8), byte(actualHi>>16), byte(actualHi>>24),
|
||||
byte(actualHi>>32), byte(actualHi>>40), byte(actualHi>>48), byte(actualHi>>56),
|
||||
),
|
||||
)
|
||||
matched = matched && (expLo == actualLo) && (expHi == actualHi)
|
||||
case laneTypeI16:
|
||||
msgExpValuesStrs = append(msgExpValuesStrs,
|
||||
fmt.Sprintf("i16x8(%#x, %#x, %#x, %#x, %#x, %#x, %#x, %#x)",
|
||||
uint16(expLo), uint16(expLo>>16), uint16(expLo>>32), uint16(expLo>>48),
|
||||
uint16(expHi), uint16(expHi>>16), uint16(expHi>>32), uint16(expHi>>48),
|
||||
),
|
||||
)
|
||||
msgActualValuesStrs = append(msgActualValuesStrs,
|
||||
fmt.Sprintf("i16x8(%#x, %#x, %#x, %#x, %#x, %#x, %#x, %#x)",
|
||||
uint16(actualLo), uint16(actualLo>>16), uint16(actualLo>>32), uint16(actualLo>>48),
|
||||
uint16(actualHi), uint16(actualHi>>16), uint16(actualHi>>32), uint16(actualHi>>48),
|
||||
),
|
||||
)
|
||||
matched = matched && (expLo == actualLo) && (expHi == actualHi)
|
||||
case laneTypeI32:
|
||||
msgExpValuesStrs = append(msgExpValuesStrs,
|
||||
fmt.Sprintf("i32x4(%#x, %#x, %#x, %#x)", uint32(expLo), uint32(expLo>>32), uint32(expHi), uint32(expHi>>32)),
|
||||
)
|
||||
msgActualValuesStrs = append(msgActualValuesStrs,
|
||||
fmt.Sprintf("i32x4(%#x, %#x, %#x, %#x)", uint32(actualLo), uint32(actualLo>>32), uint32(actualHi), uint32(actualHi>>32)),
|
||||
)
|
||||
matched = matched && (expLo == actualLo) && (expHi == actualHi)
|
||||
case laneTypeI64:
|
||||
msgExpValuesStrs = append(msgExpValuesStrs,
|
||||
fmt.Sprintf("i64x2(%#x, %#x)", expLo, expHi),
|
||||
)
|
||||
msgActualValuesStrs = append(msgActualValuesStrs,
|
||||
fmt.Sprintf("i64x2(%#x, %#x)", actualLo, actualHi),
|
||||
)
|
||||
matched = matched && (expLo == actualLo) && (expHi == actualHi)
|
||||
case laneTypeF32:
|
||||
msgExpValuesStrs = append(msgExpValuesStrs,
|
||||
fmt.Sprintf("f32x4(%f, %f, %f, %f)",
|
||||
math.Float32frombits(uint32(expLo)), math.Float32frombits(uint32(expLo>>32)),
|
||||
math.Float32frombits(uint32(expHi)), math.Float32frombits(uint32(expHi>>32)),
|
||||
),
|
||||
)
|
||||
msgActualValuesStrs = append(msgActualValuesStrs,
|
||||
fmt.Sprintf("f32x4(%f, %f, %f, %f)",
|
||||
math.Float32frombits(uint32(actualLo)), math.Float32frombits(uint32(actualLo>>32)),
|
||||
math.Float32frombits(uint32(actualHi)), math.Float32frombits(uint32(actualHi>>32)),
|
||||
),
|
||||
)
|
||||
matched = matched &&
|
||||
f32Equal(math.Float32frombits(uint32(expLo)), math.Float32frombits(uint32(actualLo))) &&
|
||||
f32Equal(math.Float32frombits(uint32(expLo>>32)), math.Float32frombits(uint32(actualLo>>32))) &&
|
||||
f32Equal(math.Float32frombits(uint32(expHi)), math.Float32frombits(uint32(actualHi))) &&
|
||||
f32Equal(math.Float32frombits(uint32(expHi>>32)), math.Float32frombits(uint32(actualHi>>32)))
|
||||
case laneTypeF64:
|
||||
msgExpValuesStrs = append(msgExpValuesStrs,
|
||||
fmt.Sprintf("f64x2(%f, %f)", math.Float64frombits(expLo), math.Float64frombits(expHi)),
|
||||
)
|
||||
msgActualValuesStrs = append(msgActualValuesStrs,
|
||||
fmt.Sprintf("f64x2(%f, %f)", math.Float64frombits(actualLo), math.Float64frombits(actualHi)),
|
||||
)
|
||||
matched = matched &&
|
||||
f64Equal(math.Float64frombits(expLo), math.Float64frombits(actualLo)) &&
|
||||
f64Equal(math.Float64frombits(expHi), math.Float64frombits(actualHi))
|
||||
default:
|
||||
panic("BUG")
|
||||
}
|
||||
uint64RepPos += 2
|
||||
default:
|
||||
panic("BUG")
|
||||
}
|
||||
}
|
||||
|
||||
result := fmt.Sprintf("\thave (%v)\n\twant (%v)", actual, exps)
|
||||
for i := range exps {
|
||||
requireValueEq(t, actual[i], exps[i], expectedTypesVectorFlattend[i], msg+"\n"+result)
|
||||
if !matched {
|
||||
valuesMsg = fmt.Sprintf("\thave [%s]\n\twant [%s]",
|
||||
strings.Join(msgActualValuesStrs, ", "),
|
||||
strings.Join(msgExpValuesStrs, ", "))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func requireValueEq(t *testing.T, actual, expected uint64, valType wasm.ValueType, msg string) {
|
||||
switch valType {
|
||||
case wasm.ValueTypeI32:
|
||||
require.Equal(t, uint32(expected), uint32(actual), msg)
|
||||
case wasm.ValueTypeI64:
|
||||
require.Equal(t, expected, actual, msg)
|
||||
case wasm.ValueTypeF32:
|
||||
expF := math.Float32frombits(uint32(expected))
|
||||
actualF := math.Float32frombits(uint32(actual))
|
||||
if math.IsNaN(float64(expF)) { // NaN cannot be compared with themselves, so we have to use IsNaN
|
||||
require.True(t, math.IsNaN(float64(actualF)), msg)
|
||||
} else {
|
||||
require.Equal(t, expF, actualF, msg)
|
||||
}
|
||||
case wasm.ValueTypeF64:
|
||||
expF := math.Float64frombits(expected)
|
||||
actualF := math.Float64frombits(actual)
|
||||
if math.IsNaN(expF) { // NaN cannot be compared with themselves, so we have to use IsNaN
|
||||
require.True(t, math.IsNaN(actualF), msg)
|
||||
} else {
|
||||
require.Equal(t, expF, actualF, msg)
|
||||
}
|
||||
case wasm.ValueTypeExternref:
|
||||
require.Equal(t, expected, actual, msg)
|
||||
case wasm.ValueTypeFuncref:
|
||||
require.Equal(t, expected, actual, msg)
|
||||
default:
|
||||
t.Fatal(msg)
|
||||
func f32Equal(expected, actual float32) (matched bool) {
|
||||
if math.IsNaN(float64(expected)) { // NaN cannot be compared with themselves, so we have to use IsNaN
|
||||
matched = math.IsNaN(float64(actual))
|
||||
} else {
|
||||
matched = expected == actual
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func f64Equal(actual, expected float64) (matched bool) {
|
||||
if math.IsNaN(expected) { // NaN cannot be compared with themselves, so we have to use IsNaN
|
||||
matched = math.IsNaN(actual)
|
||||
} else {
|
||||
matched = expected == actual
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// callFunction is inlined here as the spectest needs to validate the signature was correct
|
||||
|
||||
581
internal/integration_test/spectest/spectest_test.go
Normal file
581
internal/integration_test/spectest/spectest_test.go
Normal file
@@ -0,0 +1,581 @@
|
||||
package spectest
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||
"github.com/tetratelabs/wazero/internal/wasm"
|
||||
)
|
||||
|
||||
func Test_f32Equal(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
f1, f2 float32
|
||||
exp bool
|
||||
}{
|
||||
{name: "1", f1: 1.1, f2: 1.1, exp: true},
|
||||
{name: "2", f1: float32(math.NaN()), f2: float32(math.NaN()), exp: true},
|
||||
{name: "3", f1: float32(math.Inf(1)), f2: float32(math.Inf(1)), exp: true},
|
||||
{name: "4", f1: float32(math.Inf(-1)), f2: float32(math.Inf(-1)), exp: true},
|
||||
{name: "5", f1: 1.1, f2: -1.1, exp: false},
|
||||
{name: "6", f1: float32(math.NaN()), f2: -1.1, exp: false},
|
||||
{name: "7", f1: -1.1, f2: float32(math.NaN()), exp: false},
|
||||
{name: "8", f1: float32(math.NaN()), f2: float32(math.Inf(1)), exp: false},
|
||||
{name: "9", f1: float32(math.Inf(1)), f2: float32(math.NaN()), exp: false},
|
||||
{name: "10", f1: float32(math.NaN()), f2: float32(math.Inf(-1)), exp: false},
|
||||
{name: "11", f1: float32(math.Inf(-1)), f2: float32(math.NaN()), exp: false},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
require.Equal(t, tc.exp, f32Equal(tc.f1, tc.f2))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_f64Equal(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
f1, f2 float64
|
||||
exp bool
|
||||
}{
|
||||
{name: "1", f1: 1.1, f2: 1.1, exp: true},
|
||||
{name: "2", f1: math.NaN(), f2: math.NaN(), exp: true},
|
||||
{name: "3", f1: math.Inf(1), f2: math.Inf(1), exp: true},
|
||||
{name: "4", f1: math.Inf(-1), f2: math.Inf(-1), exp: true},
|
||||
{name: "5", f1: 1.1, f2: -1.1, exp: false},
|
||||
{name: "6", f1: math.NaN(), f2: -1.1, exp: false},
|
||||
{name: "7", f1: -1.1, f2: math.NaN(), exp: false},
|
||||
{name: "8", f1: math.NaN(), f2: math.Inf(1), exp: false},
|
||||
{name: "9", f1: math.Inf(1), f2: math.NaN(), exp: false},
|
||||
{name: "10", f1: math.NaN(), f2: math.Inf(-1), exp: false},
|
||||
{name: "11", f1: math.Inf(-1), f2: math.NaN(), exp: false},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
require.Equal(t, tc.exp, f64Equal(tc.f1, tc.f2))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_valuesEq(t *testing.T) {
|
||||
i32, i64, f32, f64, v128 := wasm.ValueTypeI32, wasm.ValueTypeI64, wasm.ValueTypeF32, wasm.ValueTypeF64, wasm.ValueTypeV128
|
||||
tests := []struct {
|
||||
name string
|
||||
exps, actual []uint64
|
||||
valueTypes []wasm.ValueType
|
||||
laneTypes map[int]laneType
|
||||
expMatched bool
|
||||
expValuesMsg string
|
||||
}{
|
||||
{
|
||||
name: "matched/i32",
|
||||
exps: []uint64{0},
|
||||
actual: []uint64{0},
|
||||
valueTypes: []wasm.ValueType{i32},
|
||||
expMatched: true,
|
||||
},
|
||||
{
|
||||
name: "unmatched/i32",
|
||||
exps: []uint64{1},
|
||||
actual: []uint64{0},
|
||||
valueTypes: []wasm.ValueType{i32},
|
||||
expMatched: false,
|
||||
expValuesMsg: ` have [0]
|
||||
want [1]`,
|
||||
},
|
||||
{
|
||||
name: "unmatched/i32",
|
||||
exps: []uint64{math.MaxUint32},
|
||||
actual: []uint64{1123},
|
||||
valueTypes: []wasm.ValueType{i32},
|
||||
expMatched: false,
|
||||
expValuesMsg: ` have [1123]
|
||||
want [4294967295]`,
|
||||
},
|
||||
{
|
||||
name: "matched/i64",
|
||||
exps: []uint64{0},
|
||||
actual: []uint64{0},
|
||||
valueTypes: []wasm.ValueType{i64},
|
||||
expMatched: true,
|
||||
},
|
||||
{
|
||||
name: "unmatched/i64",
|
||||
exps: []uint64{1},
|
||||
actual: []uint64{0},
|
||||
valueTypes: []wasm.ValueType{i64},
|
||||
expMatched: false,
|
||||
expValuesMsg: ` have [0]
|
||||
want [1]`,
|
||||
},
|
||||
{
|
||||
name: "unmatched/i64",
|
||||
exps: []uint64{math.MaxUint64},
|
||||
actual: []uint64{1123},
|
||||
valueTypes: []wasm.ValueType{i64},
|
||||
expMatched: false,
|
||||
expValuesMsg: ` have [1123]
|
||||
want [18446744073709551615]`,
|
||||
},
|
||||
{
|
||||
name: "matched/f32",
|
||||
exps: []uint64{0},
|
||||
actual: []uint64{0},
|
||||
valueTypes: []wasm.ValueType{f32},
|
||||
expMatched: true,
|
||||
},
|
||||
{
|
||||
name: "unmatched/f32",
|
||||
exps: []uint64{uint64(math.Float32bits(-13123.1))},
|
||||
actual: []uint64{0},
|
||||
valueTypes: []wasm.ValueType{f32},
|
||||
expMatched: false,
|
||||
expValuesMsg: ` have [0.000000]
|
||||
want [-13123.099609]`,
|
||||
},
|
||||
{
|
||||
name: "matched/f64",
|
||||
exps: []uint64{0},
|
||||
actual: []uint64{0},
|
||||
valueTypes: []wasm.ValueType{f64},
|
||||
expMatched: true,
|
||||
},
|
||||
{
|
||||
name: "unmatched/f64",
|
||||
exps: []uint64{math.Float64bits(1.0)},
|
||||
actual: []uint64{0},
|
||||
valueTypes: []wasm.ValueType{f64},
|
||||
expMatched: false,
|
||||
expValuesMsg: ` have [0.000000]
|
||||
want [1.000000]`,
|
||||
},
|
||||
{
|
||||
name: "unmatched/f64",
|
||||
actual: []uint64{math.Float64bits(-1231231.0)},
|
||||
exps: []uint64{0},
|
||||
valueTypes: []wasm.ValueType{f64},
|
||||
expMatched: false,
|
||||
expValuesMsg: ` have [-1231231.000000]
|
||||
want [0.000000]`,
|
||||
},
|
||||
{
|
||||
name: "matched/i8x16",
|
||||
exps: []uint64{math.MaxUint64, 123},
|
||||
actual: []uint64{math.MaxUint64, 123},
|
||||
laneTypes: map[int]laneType{0: laneTypeI8},
|
||||
valueTypes: []wasm.ValueType{v128},
|
||||
expMatched: true,
|
||||
},
|
||||
{
|
||||
name: "unmatched/i8x16",
|
||||
exps: []uint64{0, 0xff<<56 | 0xaa},
|
||||
actual: []uint64{math.MaxUint64, 0xff<<48 | 0xcc},
|
||||
laneTypes: map[int]laneType{0: laneTypeI8},
|
||||
valueTypes: []wasm.ValueType{v128},
|
||||
expMatched: false,
|
||||
expValuesMsg: ` have [i8x16(0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcc, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0)]
|
||||
want [i8x16(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xaa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff)]`,
|
||||
},
|
||||
{
|
||||
name: "matched/i16x8",
|
||||
exps: []uint64{math.MaxUint64, 123},
|
||||
actual: []uint64{math.MaxUint64, 123},
|
||||
laneTypes: map[int]laneType{0: laneTypeI16},
|
||||
valueTypes: []wasm.ValueType{v128},
|
||||
expMatched: true,
|
||||
},
|
||||
{
|
||||
name: "unmatched/i16x8",
|
||||
exps: []uint64{0xffff << 32, 0},
|
||||
actual: []uint64{0xaabb << 16, ^uint64(0)},
|
||||
laneTypes: map[int]laneType{0: laneTypeI16},
|
||||
valueTypes: []wasm.ValueType{v128},
|
||||
expMatched: false,
|
||||
expValuesMsg: ` have [i16x8(0x0, 0xaabb, 0x0, 0x0, 0xffff, 0xffff, 0xffff, 0xffff)]
|
||||
want [i16x8(0x0, 0x0, 0xffff, 0x0, 0x0, 0x0, 0x0, 0x0)]`,
|
||||
},
|
||||
{
|
||||
name: "matched/i32x4",
|
||||
exps: []uint64{math.MaxUint64, 123},
|
||||
actual: []uint64{math.MaxUint64, 123},
|
||||
laneTypes: map[int]laneType{0: laneTypeI32},
|
||||
valueTypes: []wasm.ValueType{v128},
|
||||
expMatched: true,
|
||||
},
|
||||
{
|
||||
name: "matched/i32x4",
|
||||
exps: []uint64{0xffff_ffff<<32 | 0xa, 123},
|
||||
actual: []uint64{0x1a1a_1a1a<<32 | 0xa, 123},
|
||||
laneTypes: map[int]laneType{0: laneTypeI32},
|
||||
valueTypes: []wasm.ValueType{v128},
|
||||
expMatched: false,
|
||||
expValuesMsg: ` have [i32x4(0xa, 0x1a1a1a1a, 0x7b, 0x0)]
|
||||
want [i32x4(0xa, 0xffffffff, 0x7b, 0x0)]`,
|
||||
},
|
||||
{
|
||||
name: "matched/i64x2",
|
||||
exps: []uint64{math.MaxUint64, 123},
|
||||
actual: []uint64{math.MaxUint64, 123},
|
||||
laneTypes: map[int]laneType{0: laneTypeI64},
|
||||
valueTypes: []wasm.ValueType{v128},
|
||||
expMatched: true,
|
||||
},
|
||||
{
|
||||
name: "unmatched/i64x2",
|
||||
exps: []uint64{math.MaxUint64, 123},
|
||||
actual: []uint64{math.MaxUint64, 0},
|
||||
laneTypes: map[int]laneType{0: laneTypeI64},
|
||||
valueTypes: []wasm.ValueType{v128},
|
||||
expMatched: false,
|
||||
expValuesMsg: ` have [i64x2(0xffffffffffffffff, 0x0)]
|
||||
want [i64x2(0xffffffffffffffff, 0x7b)]`,
|
||||
},
|
||||
{
|
||||
name: "matched/f32x4",
|
||||
exps: []uint64{
|
||||
(uint64(math.Float32bits(float32(math.NaN()))) << 32) | uint64(math.Float32bits(float32(math.NaN()))),
|
||||
(uint64(math.Float32bits(float32(math.NaN()))) << 32) | uint64(math.Float32bits(float32(math.NaN()))),
|
||||
},
|
||||
actual: []uint64{
|
||||
(uint64(math.Float32bits(float32(math.NaN()))) << 32) | uint64(math.Float32bits(float32(math.NaN()))),
|
||||
(uint64(math.Float32bits(float32(math.NaN()))) << 32) | uint64(math.Float32bits(float32(math.NaN()))),
|
||||
},
|
||||
valueTypes: []wasm.ValueType{v128},
|
||||
laneTypes: map[int]laneType{0: laneTypeF32},
|
||||
expMatched: true,
|
||||
},
|
||||
{
|
||||
name: "unmatched/f32x4",
|
||||
exps: []uint64{
|
||||
(uint64(math.Float32bits(float32(1.213))) << 32) | uint64(math.Float32bits(float32(math.NaN()))),
|
||||
(uint64(math.Float32bits(float32(math.NaN()))) << 32) | uint64(math.Float32bits(float32(math.NaN()))),
|
||||
},
|
||||
actual: []uint64{
|
||||
(uint64(math.Float32bits(float32(math.NaN()))) << 32) | uint64(math.Float32bits(float32(math.Inf(1)))),
|
||||
(uint64(math.Float32bits(float32(math.Inf(-1)))) << 32) | uint64(math.Float32bits(float32(math.NaN()))),
|
||||
},
|
||||
valueTypes: []wasm.ValueType{v128},
|
||||
laneTypes: map[int]laneType{0: laneTypeF32},
|
||||
expMatched: false,
|
||||
expValuesMsg: ` have [f32x4(+Inf, NaN, NaN, -Inf)]
|
||||
want [f32x4(NaN, 1.213000, NaN, NaN)]`,
|
||||
},
|
||||
{
|
||||
name: "matched/f64x2",
|
||||
exps: []uint64{math.Float64bits(1.0), math.Float64bits(math.NaN())},
|
||||
actual: []uint64{math.Float64bits(1.0), math.Float64bits(math.NaN())},
|
||||
valueTypes: []wasm.ValueType{v128},
|
||||
laneTypes: map[int]laneType{0: laneTypeF64},
|
||||
expMatched: true,
|
||||
},
|
||||
{
|
||||
name: "unmatched/f64x2",
|
||||
exps: []uint64{math.Float64bits(1.0), math.Float64bits(math.NaN())},
|
||||
actual: []uint64{math.Float64bits(-1.0), math.Float64bits(math.Inf(1))},
|
||||
valueTypes: []wasm.ValueType{v128},
|
||||
laneTypes: map[int]laneType{0: laneTypeF64},
|
||||
expMatched: false,
|
||||
expValuesMsg: ` have [f64x2(-1.000000, +Inf)]
|
||||
want [f64x2(1.000000, NaN)]`,
|
||||
},
|
||||
{
|
||||
name: "unmatched/f64x2",
|
||||
exps: []uint64{math.Float64bits(math.Inf(1)), math.Float64bits(math.NaN())},
|
||||
actual: []uint64{math.Float64bits(math.Inf(-1)), math.Float64bits(math.NaN())},
|
||||
valueTypes: []wasm.ValueType{v128},
|
||||
laneTypes: map[int]laneType{0: laneTypeF64},
|
||||
expMatched: false,
|
||||
expValuesMsg: ` have [f64x2(-Inf, NaN)]
|
||||
want [f64x2(+Inf, NaN)]`,
|
||||
},
|
||||
{
|
||||
name: "matched/[i32,f64x2]",
|
||||
exps: []uint64{1, math.Float64bits(1.0), math.Float64bits(math.NaN())},
|
||||
actual: []uint64{1, math.Float64bits(1.0), math.Float64bits(math.NaN())},
|
||||
valueTypes: []wasm.ValueType{i32, v128},
|
||||
laneTypes: map[int]laneType{1: laneTypeF64},
|
||||
expMatched: true,
|
||||
},
|
||||
{
|
||||
name: "unmatched/[i32,f64x2]",
|
||||
exps: []uint64{123, math.Float64bits(math.Inf(1)), math.Float64bits(math.NaN())},
|
||||
actual: []uint64{123, math.Float64bits(math.Inf(-1)), math.Float64bits(math.NaN())},
|
||||
valueTypes: []wasm.ValueType{i32, v128},
|
||||
laneTypes: map[int]laneType{1: laneTypeF64},
|
||||
expMatched: false,
|
||||
expValuesMsg: ` have [123, f64x2(-Inf, NaN)]
|
||||
want [123, f64x2(+Inf, NaN)]`,
|
||||
},
|
||||
{
|
||||
name: "matched/[i32,f64x2]",
|
||||
exps: []uint64{math.Float64bits(1.0), math.Float64bits(math.NaN()), 1},
|
||||
actual: []uint64{math.Float64bits(1.0), math.Float64bits(math.NaN()), 1},
|
||||
valueTypes: []wasm.ValueType{v128, i32},
|
||||
laneTypes: map[int]laneType{0: laneTypeF64},
|
||||
expMatched: true,
|
||||
},
|
||||
{
|
||||
name: "unmatched/[f64x2,i32]",
|
||||
exps: []uint64{math.Float64bits(math.Inf(1)), math.Float64bits(math.NaN()), 123},
|
||||
actual: []uint64{math.Float64bits(math.Inf(-1)), math.Float64bits(math.NaN()), 123},
|
||||
valueTypes: []wasm.ValueType{v128, i32},
|
||||
laneTypes: map[int]laneType{0: laneTypeF64},
|
||||
expMatched: false,
|
||||
expValuesMsg: ` have [f64x2(-Inf, NaN), 123]
|
||||
want [f64x2(+Inf, NaN), 123]`,
|
||||
},
|
||||
{
|
||||
name: "matched/[f32,i32,f64x2]",
|
||||
exps: []uint64{uint64(math.Float32bits(float32(math.NaN()))), math.Float64bits(1.0), math.Float64bits(math.NaN()), 1},
|
||||
actual: []uint64{uint64(math.Float32bits(float32(math.NaN()))), math.Float64bits(1.0), math.Float64bits(math.NaN()), 1},
|
||||
valueTypes: []wasm.ValueType{f32, v128, i32},
|
||||
laneTypes: map[int]laneType{1: laneTypeF64},
|
||||
expMatched: true,
|
||||
},
|
||||
{
|
||||
name: "unmatched/[f32,f64x2,i32]",
|
||||
exps: []uint64{uint64(math.Float32bits(1.0)), math.Float64bits(math.Inf(1)), math.Float64bits(math.NaN()), 123},
|
||||
actual: []uint64{uint64(math.Float32bits(1.0)), math.Float64bits(math.Inf(-1)), math.Float64bits(math.NaN()), 123},
|
||||
valueTypes: []wasm.ValueType{f32, v128, i32},
|
||||
laneTypes: map[int]laneType{1: laneTypeF64},
|
||||
expMatched: false,
|
||||
expValuesMsg: ` have [1.000000, f64x2(-Inf, NaN), 123]
|
||||
want [1.000000, f64x2(+Inf, NaN), 123]`,
|
||||
},
|
||||
{
|
||||
name: "matched/[i8x16,f64x2]",
|
||||
exps: []uint64{0, 0, math.Float64bits(1.0), math.Float64bits(math.NaN())},
|
||||
actual: []uint64{0, 0, math.Float64bits(1.0), math.Float64bits(math.NaN())},
|
||||
valueTypes: []wasm.ValueType{v128, v128},
|
||||
laneTypes: map[int]laneType{0: laneTypeI8, 1: laneTypeF64},
|
||||
expMatched: true,
|
||||
},
|
||||
{
|
||||
name: "unmatched/[i8x16,f64x2]",
|
||||
exps: []uint64{0, 0xff << 56, math.Float64bits(1.0), math.Float64bits(math.NaN())},
|
||||
actual: []uint64{0, 0xaa << 56, math.Float64bits(1.0), math.Float64bits(math.NaN())},
|
||||
valueTypes: []wasm.ValueType{v128, v128},
|
||||
laneTypes: map[int]laneType{0: laneTypeI8, 1: laneTypeF64},
|
||||
expMatched: false,
|
||||
expValuesMsg: ` have [i8x16(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xaa), f64x2(1.000000, NaN)]
|
||||
want [i8x16(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff), f64x2(1.000000, NaN)]`,
|
||||
},
|
||||
{
|
||||
name: "unmatched/[i8x16,f64x2]",
|
||||
exps: []uint64{0, 0xff << 56, math.Float64bits(1.0), math.Float64bits(math.NaN())},
|
||||
actual: []uint64{0, 0xff << 56, math.Float64bits(1.0), math.Float64bits(math.Inf(1))},
|
||||
valueTypes: []wasm.ValueType{v128, v128},
|
||||
laneTypes: map[int]laneType{0: laneTypeI8, 1: laneTypeF64},
|
||||
expMatched: false,
|
||||
expValuesMsg: ` have [i8x16(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff), f64x2(1.000000, +Inf)]
|
||||
want [i8x16(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff), f64x2(1.000000, NaN)]`,
|
||||
},
|
||||
{
|
||||
name: "matched/[i8x16,i32,f64x2]",
|
||||
exps: []uint64{0, 0, math.MaxUint32, math.Float64bits(1.0), math.Float64bits(math.NaN())},
|
||||
actual: []uint64{0, 0, math.MaxUint32, math.Float64bits(1.0), math.Float64bits(math.NaN())},
|
||||
valueTypes: []wasm.ValueType{v128, i32, v128},
|
||||
laneTypes: map[int]laneType{0: laneTypeI8, 2: laneTypeF64},
|
||||
expMatched: true,
|
||||
},
|
||||
{
|
||||
name: "matched/[i8x16,i32,f64x2]",
|
||||
exps: []uint64{0, 0, math.MaxUint32, math.Float64bits(1.0), math.Float64bits(math.NaN())},
|
||||
actual: []uint64{0, 0, math.MaxUint32 - 1, math.Float64bits(1.0), math.Float64bits(math.NaN())},
|
||||
valueTypes: []wasm.ValueType{v128, i32, v128},
|
||||
laneTypes: map[int]laneType{0: laneTypeI8, 2: laneTypeF64},
|
||||
expMatched: false,
|
||||
expValuesMsg: ` have [i8x16(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0), 4294967294, f64x2(1.000000, NaN)]
|
||||
want [i8x16(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0), 4294967295, f64x2(1.000000, NaN)]`,
|
||||
},
|
||||
{
|
||||
name: "matched/[i8x16,i32,f64x2]",
|
||||
exps: []uint64{0, 0, math.MaxUint32, math.Float64bits(1.0), math.Float64bits(math.NaN())},
|
||||
actual: []uint64{0, 0xff << 16, math.MaxUint32, math.Float64bits(1.0), math.Float64bits(math.NaN())},
|
||||
valueTypes: []wasm.ValueType{v128, i32, v128},
|
||||
laneTypes: map[int]laneType{0: laneTypeI8, 2: laneTypeF64},
|
||||
expMatched: false,
|
||||
expValuesMsg: ` have [i8x16(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0), 4294967295, f64x2(1.000000, NaN)]
|
||||
want [i8x16(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0), 4294967295, f64x2(1.000000, NaN)]`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
actualMatched, actualValuesMsg := valuesEq(tc.actual, tc.exps, tc.valueTypes, tc.laneTypes)
|
||||
require.Equal(t, tc.expMatched, actualMatched)
|
||||
require.Equal(t, tc.expValuesMsg, actualValuesMsg)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommandActionVal_toUint64s(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
rawCommandActionVal string
|
||||
exp []uint64
|
||||
}{
|
||||
{
|
||||
name: "i32",
|
||||
rawCommandActionVal: `{"type": "i32", "value": "0"}`,
|
||||
exp: []uint64{0},
|
||||
},
|
||||
{
|
||||
name: "i32",
|
||||
rawCommandActionVal: `{"type": "i32", "value": "4294967295"}`,
|
||||
exp: []uint64{4294967295},
|
||||
},
|
||||
{
|
||||
name: "i64",
|
||||
rawCommandActionVal: `{"type": "i64", "value": "0"}`,
|
||||
exp: []uint64{0},
|
||||
},
|
||||
{
|
||||
name: "i64",
|
||||
rawCommandActionVal: `{"type": "i64", "value": "7034535277573963776"}`,
|
||||
exp: []uint64{7034535277573963776},
|
||||
},
|
||||
{
|
||||
name: "f32",
|
||||
rawCommandActionVal: `{"type": "f32", "value": "0"}`,
|
||||
exp: []uint64{0},
|
||||
},
|
||||
{
|
||||
name: "f32",
|
||||
rawCommandActionVal: `{"type": "f32", "value": "2147483648"}`,
|
||||
exp: []uint64{2147483648},
|
||||
},
|
||||
{
|
||||
name: "f64",
|
||||
rawCommandActionVal: `{"type": "f64", "value": "0"}`,
|
||||
exp: []uint64{0},
|
||||
},
|
||||
{
|
||||
name: "f64",
|
||||
rawCommandActionVal: `{"type": "f64", "value": "4616189618054758400"}`,
|
||||
exp: []uint64{4616189618054758400},
|
||||
},
|
||||
{
|
||||
name: "f32x4",
|
||||
rawCommandActionVal: `{"type": "v128", "lane_type": "f32", "value": ["645922816", "645922816", "645922816", "645922816"]}`,
|
||||
exp: []uint64{645922816<<32 | 645922816, 645922816<<32 | 645922816},
|
||||
},
|
||||
{
|
||||
name: "f32x4",
|
||||
rawCommandActionVal: `{"type": "v128", "lane_type": "f32", "value": ["nan:canonical", "nan:arithmetic", "nan:canonical", "nan:arithmetic"]}`,
|
||||
exp: []uint64{
|
||||
uint64(math.Float32bits(float32(math.NaN()))) | (uint64(math.Float32bits(float32(math.NaN()))) << 32),
|
||||
uint64(math.Float32bits(float32(math.NaN()))) | (uint64(math.Float32bits(float32(math.NaN()))) << 32),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "f64x2",
|
||||
rawCommandActionVal: `{"type": "v128", "lane_type": "f64", "value": ["9223372036854775808", "9223372036854775808"]}`,
|
||||
exp: []uint64{9223372036854775808, 9223372036854775808},
|
||||
},
|
||||
{
|
||||
name: "f64x2",
|
||||
rawCommandActionVal: `{"type": "v128", "lane_type": "f64", "value": ["nan:canonical", "nan:arithmetic"]}`,
|
||||
exp: []uint64{math.Float64bits(math.NaN()), math.Float64bits(math.NaN())},
|
||||
},
|
||||
{
|
||||
name: "i8x16",
|
||||
rawCommandActionVal: `{"type": "v128", "lane_type": "i8", "value": ["128", "129", "130", "131", "253", "254", "255", "0", "0", "1", "2", "127", "128", "253", "254", "255"]}`,
|
||||
exp: []uint64{
|
||||
128 | (129 << 8) | (130 << 16) | (131 << 24) | (253 << 32) | (254 << 40) | (255 << 48),
|
||||
1<<8 | 2<<16 | 127<<24 | 128<<32 | 253<<40 | 254<<48 | 255<<56,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "i16x8",
|
||||
rawCommandActionVal: `{"type": "v128", "lane_type": "i16", "value": ["256", "770", "1284", "1798", "2312", "2826", "3340", "3854"]}`,
|
||||
exp: []uint64{
|
||||
256 | 770<<16 | 1284<<32 | 1798<<48,
|
||||
2312 | 2826<<16 | 3340<<32 | 3854<<48,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "i32x4",
|
||||
rawCommandActionVal: `{"type": "v128", "lane_type": "i32", "value": ["123", "32766", "32766", "40000"]}`,
|
||||
exp: []uint64{
|
||||
123 | 32766<<32,
|
||||
32766 | 40000<<32,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "i64x2",
|
||||
rawCommandActionVal: `{"type": "v128", "lane_type": "i64", "value": ["18446744073709551615", "123124"]}`,
|
||||
exp: []uint64{
|
||||
18446744073709551615,
|
||||
123124,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
var c commandActionVal
|
||||
err := json.Unmarshal([]byte(tc.rawCommandActionVal), &c)
|
||||
require.NoError(t, err)
|
||||
actual := c.toUint64s()
|
||||
require.Equal(t, tc.exp, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommand_getAssertReturnArgsExps(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
rawCommand string
|
||||
args, exps []uint64
|
||||
}{
|
||||
{
|
||||
name: "1",
|
||||
rawCommand: `
|
||||
{
|
||||
"type": "assert_return",
|
||||
"line": 148,
|
||||
"action": {
|
||||
"type": "invoke", "field": "f32x4.min",
|
||||
"args": [
|
||||
{"type": "v128", "lane_type": "f32", "value": ["2147483648", "123", "2147483648", "1"]},
|
||||
{"type": "v128", "lane_type": "i8", "value": ["128", "129", "130", "131", "253", "254", "255", "0", "0", "1", "2", "127", "128", "253", "254", "255"]}
|
||||
]
|
||||
},
|
||||
"expected": [
|
||||
{"type": "v128", "lane_type": "f32", "value": ["2147483648", "0", "0", "2147483648"]}
|
||||
]
|
||||
}`,
|
||||
args: []uint64{
|
||||
123<<32 | 2147483648,
|
||||
1<<32 | 2147483648,
|
||||
128 | (129 << 8) | (130 << 16) | (131 << 24) | (253 << 32) | (254 << 40) | (255 << 48),
|
||||
1<<8 | 2<<16 | 127<<24 | 128<<32 | 253<<40 | 254<<48 | 255<<56,
|
||||
},
|
||||
exps: []uint64{
|
||||
2147483648,
|
||||
2147483648 << 32,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
var c command
|
||||
err := json.Unmarshal([]byte(tc.rawCommand), &c)
|
||||
require.NoError(t, err)
|
||||
actualArgs, actualExps := c.getAssertReturnArgsExps()
|
||||
require.Equal(t, tc.args, actualArgs)
|
||||
require.Equal(t, tc.exps, actualExps)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"embed"
|
||||
"path"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/engine/compiler"
|
||||
@@ -26,43 +25,28 @@ func TestCompiler(t *testing.T) {
|
||||
}
|
||||
|
||||
spectest.Run(t, testcases, compiler.NewEngine, enabledFeatures, func(jsonname string) bool {
|
||||
// TODO: remove after SIMD proposal
|
||||
if strings.Contains(jsonname, "simd") {
|
||||
switch path.Base(jsonname) {
|
||||
case "simd_address.json", "simd_const.json", "simd_align.json", "simd_load16_lane.json", "simd_load32_lane.json",
|
||||
"simd_load64_lane.json", "simd_load8_lane.json", "simd_lane.json", "simd_load_extend.json",
|
||||
"simd_load_splat.json", "simd_load_zero.json", "simd_store.json", "simd_store16_lane.json",
|
||||
"simd_store32_lane.json", "simd_store64_lane.json", "simd_store8_lane.json":
|
||||
return true
|
||||
case "simd_bitwise.json", "simd_boolean.json", "simd_bit_shift.json",
|
||||
"simd_i8x16_cmp.json", "simd_i16x8_cmp.json", "simd_i32x4_cmp.json", "simd_i64x2_cmp.json",
|
||||
"simd_f32x4_cmp.json", "simd_f64x2_cmp.json":
|
||||
// TODO: implement on arm64.
|
||||
return runtime.GOARCH == "amd64"
|
||||
default:
|
||||
return false // others not supported, yet!
|
||||
}
|
||||
switch path.Base(jsonname) {
|
||||
case "simd_bitwise.json", "simd_boolean.json", "simd_bit_shift.json",
|
||||
"simd_i8x16_cmp.json", "simd_i16x8_cmp.json", "simd_i32x4_cmp.json", "simd_i64x2_cmp.json",
|
||||
"simd_f32x4_cmp.json", "simd_f64x2_cmp.json", "simd_f32x4_arith.json", "simd_f64x2_arith.json",
|
||||
"simd_i16x8_arith.json", "simd_i64x2_arith.json", "simd_i32x4_arith.json", "simd_i8x16_arith.json",
|
||||
"simd_i16x8_sat_arith.json", "simd_i8x16_sat_arith.json",
|
||||
"simd_i16x8_arith2.json", "simd_i8x16_arith2.json", "simd_i32x4_arith2.json", "simd_i64x2_arith2.json",
|
||||
"simd_f64x2.json", "simd_f32x4.json", "simd_f32x4_rounding.json", "simd_f64x2_rounding.json",
|
||||
"simd_f64x2_pmin_pmax.json", "simd_f32x4_pmin_pmax.json", "simd_int_to_int_extend.json",
|
||||
"simd_i64x2_extmul_i32x4.json", "simd_i32x4_extmul_i16x8.json", "simd_i16x8_extmul_i8x16.json",
|
||||
"simd_i16x8_q15mulr_sat_s.json", "simd_i16x8_extadd_pairwise_i8x16.json", "simd_i32x4_extadd_pairwise_i16x8.json",
|
||||
"simd_i32x4_dot_i16x8.json", "simd_i32x4_trunc_sat_f32x4.json",
|
||||
"simd_splat.json", "simd_load.json", "simd_i32x4_trunc_sat_f64x2.json",
|
||||
"simd_conversions.json":
|
||||
// TODO: implement on arm64.
|
||||
return runtime.GOARCH == "amd64"
|
||||
default:
|
||||
return true
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
func TestInterpreter(t *testing.T) {
|
||||
spectest.Run(t, testcases, interpreter.NewEngine, enabledFeatures, func(jsonname string) bool {
|
||||
// TODO: remove after SIMD proposal
|
||||
if strings.Contains(jsonname, "simd") {
|
||||
switch path.Base(jsonname) {
|
||||
case "simd_address.json", "simd_const.json", "simd_align.json", "simd_load16_lane.json",
|
||||
"simd_load32_lane.json", "simd_load64_lane.json", "simd_load8_lane.json", "simd_lane.json",
|
||||
"simd_load_extend.json", "simd_load_splat.json", "simd_load_zero.json", "simd_store.json",
|
||||
"simd_store16_lane.json", "simd_store32_lane.json", "simd_store64_lane.json", "simd_store8_lane.json",
|
||||
"simd_bitwise.json", "simd_boolean.json", "simd_bit_shift.json", "simd_i8x16_cmp.json", "simd_i16x8_cmp.json",
|
||||
"simd_i32x4_cmp.json", "simd_i64x2_cmp.json", "simd_f32x4_cmp.json", "simd_f64x2_cmp.json":
|
||||
return true
|
||||
default:
|
||||
return false // others not supported, yet!
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
spectest.Run(t, testcases, interpreter.NewEngine, enabledFeatures, func(string) bool { return true })
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user