Files
wazero/wasm/vm_num.go
2021-10-11 12:11:40 +09:00

882 lines
23 KiB
Go

package wasm
import (
"math"
"math/bits"
)
// fixme: there seems to be virtually nop instructions
func i32eqz(vm *VirtualMachine) {
vm.OperandStack.PushBool(int32(vm.OperandStack.Pop()) == 0)
vm.ActiveContext.PC++
}
func i32eq(vm *VirtualMachine) {
vm.OperandStack.PushBool(int32(vm.OperandStack.Pop()) == int32(vm.OperandStack.Pop())) //nolint
vm.ActiveContext.PC++
}
func i32ne(vm *VirtualMachine) {
vm.OperandStack.PushBool(int32(vm.OperandStack.Pop()) != int32(vm.OperandStack.Pop())) //nolint
vm.ActiveContext.PC++
}
func i32lts(vm *VirtualMachine) {
v2 := vm.OperandStack.Pop()
v1 := vm.OperandStack.Pop()
vm.OperandStack.PushBool(int32(v1) < int32(v2))
vm.ActiveContext.PC++
}
func i32ltu(vm *VirtualMachine) {
v2 := vm.OperandStack.Pop()
v1 := vm.OperandStack.Pop()
vm.OperandStack.PushBool(v1 < v2)
vm.ActiveContext.PC++
}
func i32gts(vm *VirtualMachine) {
v2 := vm.OperandStack.Pop()
v1 := vm.OperandStack.Pop()
vm.OperandStack.PushBool(int32(v1) > int32(v2))
vm.ActiveContext.PC++
}
func i32gtu(vm *VirtualMachine) {
v2 := vm.OperandStack.Pop()
v1 := vm.OperandStack.Pop()
vm.OperandStack.PushBool(v1 > v2)
vm.ActiveContext.PC++
}
func i32les(vm *VirtualMachine) {
v2 := vm.OperandStack.Pop()
v1 := vm.OperandStack.Pop()
vm.OperandStack.PushBool(int32(v1) <= int32(v2))
vm.ActiveContext.PC++
}
func i32leu(vm *VirtualMachine) {
v2 := vm.OperandStack.Pop()
v1 := vm.OperandStack.Pop()
vm.OperandStack.PushBool(v1 <= v2)
vm.ActiveContext.PC++
}
func i32ges(vm *VirtualMachine) {
v2 := vm.OperandStack.Pop()
v1 := vm.OperandStack.Pop()
vm.OperandStack.PushBool(int32(v1) >= int32(v2))
vm.ActiveContext.PC++
}
func i32geu(vm *VirtualMachine) {
v2 := vm.OperandStack.Pop()
v1 := vm.OperandStack.Pop()
vm.OperandStack.PushBool(v1 >= v2)
vm.ActiveContext.PC++
}
func i64eqz(vm *VirtualMachine) {
vm.OperandStack.PushBool(vm.OperandStack.Pop() == 0)
vm.ActiveContext.PC++
}
func i64eq(vm *VirtualMachine) {
vm.OperandStack.PushBool(vm.OperandStack.Pop() == vm.OperandStack.Pop()) //nolint
vm.ActiveContext.PC++
}
func i64ne(vm *VirtualMachine) {
vm.OperandStack.PushBool(vm.OperandStack.Pop() != vm.OperandStack.Pop()) //nolint
vm.ActiveContext.PC++
}
func i64lts(vm *VirtualMachine) {
v2 := vm.OperandStack.Pop()
v1 := vm.OperandStack.Pop()
vm.OperandStack.PushBool(int64(v1) < int64(v2))
vm.ActiveContext.PC++
}
func i64ltu(vm *VirtualMachine) {
v2 := vm.OperandStack.Pop()
v1 := vm.OperandStack.Pop()
vm.OperandStack.PushBool(v1 < v2)
vm.ActiveContext.PC++
}
func i64gts(vm *VirtualMachine) {
v2 := vm.OperandStack.Pop()
v1 := vm.OperandStack.Pop()
vm.OperandStack.PushBool(int64(v1) > int64(v2))
vm.ActiveContext.PC++
}
func i64gtu(vm *VirtualMachine) {
v2 := vm.OperandStack.Pop()
v1 := vm.OperandStack.Pop()
vm.OperandStack.PushBool(v1 > v2)
vm.ActiveContext.PC++
}
func i64les(vm *VirtualMachine) {
v2 := vm.OperandStack.Pop()
v1 := vm.OperandStack.Pop()
vm.OperandStack.PushBool(int64(v1) <= int64(v2))
vm.ActiveContext.PC++
}
func i64leu(vm *VirtualMachine) {
v2 := vm.OperandStack.Pop()
v1 := vm.OperandStack.Pop()
vm.OperandStack.PushBool(v1 <= v2)
vm.ActiveContext.PC++
}
func i64ges(vm *VirtualMachine) {
v2 := vm.OperandStack.Pop()
v1 := vm.OperandStack.Pop()
vm.OperandStack.PushBool(int64(v1) >= int64(v2))
vm.ActiveContext.PC++
}
func i64geu(vm *VirtualMachine) {
v2 := vm.OperandStack.Pop()
v1 := vm.OperandStack.Pop()
vm.OperandStack.PushBool(v1 >= v2)
vm.ActiveContext.PC++
}
func f32eq(vm *VirtualMachine) {
f2 := math.Float32frombits(uint32(vm.OperandStack.Pop()))
f1 := math.Float32frombits(uint32(vm.OperandStack.Pop()))
vm.OperandStack.PushBool(f1 == f2)
vm.ActiveContext.PC++
}
func f32ne(vm *VirtualMachine) {
f2 := math.Float32frombits(uint32(vm.OperandStack.Pop()))
f1 := math.Float32frombits(uint32(vm.OperandStack.Pop()))
vm.OperandStack.PushBool(f1 != f2)
vm.ActiveContext.PC++
}
func f32lt(vm *VirtualMachine) {
f2 := math.Float32frombits(uint32(vm.OperandStack.Pop()))
f1 := math.Float32frombits(uint32(vm.OperandStack.Pop()))
vm.OperandStack.PushBool(f1 < f2)
vm.ActiveContext.PC++
}
func f32gt(vm *VirtualMachine) {
f2 := math.Float32frombits(uint32(vm.OperandStack.Pop()))
f1 := math.Float32frombits(uint32(vm.OperandStack.Pop()))
vm.OperandStack.PushBool(f1 > f2)
vm.ActiveContext.PC++
}
func f32le(vm *VirtualMachine) {
f2 := math.Float32frombits(uint32(vm.OperandStack.Pop()))
f1 := math.Float32frombits(uint32(vm.OperandStack.Pop()))
vm.OperandStack.PushBool(f1 <= f2)
vm.ActiveContext.PC++
}
func f32ge(vm *VirtualMachine) {
f2 := math.Float32frombits(uint32(vm.OperandStack.Pop()))
f1 := math.Float32frombits(uint32(vm.OperandStack.Pop()))
vm.OperandStack.PushBool(f1 >= f2)
vm.ActiveContext.PC++
}
func f64eq(vm *VirtualMachine) {
f2 := math.Float64frombits(vm.OperandStack.Pop())
f1 := math.Float64frombits(vm.OperandStack.Pop())
vm.OperandStack.PushBool(f1 == f2)
vm.ActiveContext.PC++
}
func f64ne(vm *VirtualMachine) {
f2 := math.Float64frombits(vm.OperandStack.Pop())
f1 := math.Float64frombits(vm.OperandStack.Pop())
vm.OperandStack.PushBool(f1 != f2)
vm.ActiveContext.PC++
}
func f64lt(vm *VirtualMachine) {
f2 := math.Float64frombits(vm.OperandStack.Pop())
f1 := math.Float64frombits(vm.OperandStack.Pop())
vm.OperandStack.PushBool(f1 < f2)
vm.ActiveContext.PC++
}
func f64gt(vm *VirtualMachine) {
f2 := math.Float64frombits(vm.OperandStack.Pop())
f1 := math.Float64frombits(vm.OperandStack.Pop())
vm.OperandStack.PushBool(f1 > f2)
vm.ActiveContext.PC++
}
func f64le(vm *VirtualMachine) {
f2 := math.Float64frombits(vm.OperandStack.Pop())
f1 := math.Float64frombits(vm.OperandStack.Pop())
vm.OperandStack.PushBool(f1 <= f2)
vm.ActiveContext.PC++
}
func f64ge(vm *VirtualMachine) {
f2 := math.Float64frombits(vm.OperandStack.Pop())
f1 := math.Float64frombits(vm.OperandStack.Pop())
vm.OperandStack.PushBool(f1 >= f2)
vm.ActiveContext.PC++
}
func i32clz(vm *VirtualMachine) {
vm.OperandStack.Push(uint64(bits.LeadingZeros32(uint32(vm.OperandStack.Pop()))))
vm.ActiveContext.PC++
}
func i32ctz(vm *VirtualMachine) {
vm.OperandStack.Push(uint64(bits.TrailingZeros32(uint32(vm.OperandStack.Pop()))))
vm.ActiveContext.PC++
}
func i32popcnt(vm *VirtualMachine) {
vm.OperandStack.Push(uint64(bits.OnesCount32(uint32(vm.OperandStack.Pop()))))
vm.ActiveContext.PC++
}
func i32add(vm *VirtualMachine) {
vm.OperandStack.Push(uint64(uint32(vm.OperandStack.Pop()) + uint32(vm.OperandStack.Pop())))
vm.ActiveContext.PC++
}
func i32sub(vm *VirtualMachine) {
v2 := uint32(vm.OperandStack.Pop())
v1 := uint32(vm.OperandStack.Pop())
vm.OperandStack.Push(uint64(v1 - v2))
vm.ActiveContext.PC++
}
func i32mul(vm *VirtualMachine) {
vm.OperandStack.Push(uint64(uint32(vm.OperandStack.Pop()) * uint32(vm.OperandStack.Pop())))
vm.ActiveContext.PC++
}
func i32divs(vm *VirtualMachine) {
v2 := int32(vm.OperandStack.Pop())
v1 := int32(vm.OperandStack.Pop())
if v2 == 0 || (v1 == math.MinInt32 && v2 == -1) {
panic("undefined")
}
vm.OperandStack.Push(uint64(uint32(v1 / v2)))
vm.ActiveContext.PC++
}
func i32divu(vm *VirtualMachine) {
v2 := uint32(vm.OperandStack.Pop())
v1 := uint32(vm.OperandStack.Pop())
vm.OperandStack.Push(uint64(v1 / v2))
vm.ActiveContext.PC++
}
func i32rems(vm *VirtualMachine) {
v2 := int32(vm.OperandStack.Pop())
v1 := int32(vm.OperandStack.Pop())
vm.OperandStack.Push(uint64(uint32(v1 % v2)))
vm.ActiveContext.PC++
}
func i32remu(vm *VirtualMachine) {
v2 := uint32(vm.OperandStack.Pop())
v1 := uint32(vm.OperandStack.Pop())
vm.OperandStack.Push(uint64(v1 % v2))
vm.ActiveContext.PC++
}
func i32and(vm *VirtualMachine) {
vm.OperandStack.Push(uint64(uint32(vm.OperandStack.Pop()) & uint32(vm.OperandStack.Pop()))) //nolint
vm.ActiveContext.PC++
}
func i32or(vm *VirtualMachine) {
vm.OperandStack.Push(uint64(uint32(vm.OperandStack.Pop()) | uint32(vm.OperandStack.Pop()))) //nolint
vm.ActiveContext.PC++
}
func i32xor(vm *VirtualMachine) {
vm.OperandStack.Push(uint64(uint32(vm.OperandStack.Pop()) ^ uint32(vm.OperandStack.Pop()))) //nolint
vm.ActiveContext.PC++
}
func i32shl(vm *VirtualMachine) {
v2 := uint32(vm.OperandStack.Pop())
v1 := uint32(vm.OperandStack.Pop())
vm.OperandStack.Push(uint64(v1 << (v2 % 32)))
vm.ActiveContext.PC++
}
func i32shru(vm *VirtualMachine) {
v2 := uint32(vm.OperandStack.Pop())
v1 := uint32(vm.OperandStack.Pop())
vm.OperandStack.Push(uint64(v1 >> (v2 % 32)))
vm.ActiveContext.PC++
}
func i32shrs(vm *VirtualMachine) {
v2 := uint32(vm.OperandStack.Pop())
v1 := int32(vm.OperandStack.Pop())
vm.OperandStack.Push(uint64(v1 >> (v2 % 32)))
vm.ActiveContext.PC++
}
func i32rotl(vm *VirtualMachine) {
v2 := int(vm.OperandStack.Pop())
v1 := uint32(vm.OperandStack.Pop())
vm.OperandStack.Push(uint64(bits.RotateLeft32(v1, v2)))
vm.ActiveContext.PC++
}
func i32rotr(vm *VirtualMachine) {
v2 := int(vm.OperandStack.Pop())
v1 := uint32(vm.OperandStack.Pop())
vm.OperandStack.Push(uint64(bits.RotateLeft32(v1, -v2)))
vm.ActiveContext.PC++
}
// i64
func i64clz(vm *VirtualMachine) {
vm.OperandStack.Push(uint64(bits.LeadingZeros64(vm.OperandStack.Pop())))
vm.ActiveContext.PC++
}
func i64ctz(vm *VirtualMachine) {
vm.OperandStack.Push(uint64(bits.TrailingZeros64(vm.OperandStack.Pop())))
vm.ActiveContext.PC++
}
func i64popcnt(vm *VirtualMachine) {
vm.OperandStack.Push(uint64(bits.OnesCount64(vm.OperandStack.Pop())))
vm.ActiveContext.PC++
}
func i64add(vm *VirtualMachine) {
vm.OperandStack.Push(vm.OperandStack.Pop() + vm.OperandStack.Pop())
vm.ActiveContext.PC++
}
func i64sub(vm *VirtualMachine) {
v2 := vm.OperandStack.Pop()
v1 := vm.OperandStack.Pop()
vm.OperandStack.Push(v1 - v2)
vm.ActiveContext.PC++
}
func i64mul(vm *VirtualMachine) {
vm.OperandStack.Push(vm.OperandStack.Pop() * vm.OperandStack.Pop())
vm.ActiveContext.PC++
}
func i64divs(vm *VirtualMachine) {
v2 := int64(vm.OperandStack.Pop())
v1 := int64(vm.OperandStack.Pop())
if v2 == 0 || (v1 == math.MinInt64 && v2 == -1) {
panic("undefined")
}
vm.OperandStack.Push(uint64(v1 / v2))
vm.ActiveContext.PC++
}
func i64divu(vm *VirtualMachine) {
v2 := vm.OperandStack.Pop()
v1 := vm.OperandStack.Pop()
vm.OperandStack.Push(v1 / v2)
vm.ActiveContext.PC++
}
func i64rems(vm *VirtualMachine) {
v2 := int64(vm.OperandStack.Pop())
v1 := int64(vm.OperandStack.Pop())
vm.OperandStack.Push(uint64(v1 % v2))
vm.ActiveContext.PC++
}
func i64remu(vm *VirtualMachine) {
v2 := vm.OperandStack.Pop()
v1 := vm.OperandStack.Pop()
vm.OperandStack.Push(v1 % v2)
vm.ActiveContext.PC++
}
func i64and(vm *VirtualMachine) {
vm.OperandStack.Push(vm.OperandStack.Pop() & vm.OperandStack.Pop()) //nolint
vm.ActiveContext.PC++
}
func i64or(vm *VirtualMachine) {
vm.OperandStack.Push(vm.OperandStack.Pop() | vm.OperandStack.Pop()) //nolint
vm.ActiveContext.PC++
}
func i64xor(vm *VirtualMachine) {
vm.OperandStack.Push(vm.OperandStack.Pop() ^ vm.OperandStack.Pop()) //nolint
vm.ActiveContext.PC++
}
func i64shl(vm *VirtualMachine) {
v2 := vm.OperandStack.Pop()
v1 := vm.OperandStack.Pop()
vm.OperandStack.Push(v1 << (v2 % 64))
vm.ActiveContext.PC++
}
func i64shru(vm *VirtualMachine) {
v2 := vm.OperandStack.Pop()
v1 := vm.OperandStack.Pop()
vm.OperandStack.Push(v1 >> (v2 % 64))
vm.ActiveContext.PC++
}
func i64shrs(vm *VirtualMachine) {
v2 := vm.OperandStack.Pop()
v1 := int64(vm.OperandStack.Pop())
vm.OperandStack.Push(uint64(v1 >> (v2 % 64)))
vm.ActiveContext.PC++
}
func i64rotl(vm *VirtualMachine) {
v2 := int(vm.OperandStack.Pop())
v1 := vm.OperandStack.Pop()
vm.OperandStack.Push(bits.RotateLeft64(v1, v2))
vm.ActiveContext.PC++
}
func i64rotr(vm *VirtualMachine) {
v2 := int(vm.OperandStack.Pop())
v1 := vm.OperandStack.Pop()
vm.OperandStack.Push(bits.RotateLeft64(v1, -v2))
vm.ActiveContext.PC++
}
func f32abs(vm *VirtualMachine) {
const mask uint32 = 1 << 31
v := uint32(vm.OperandStack.Pop()) &^ mask
vm.OperandStack.Push(uint64(v))
vm.ActiveContext.PC++
}
func f32neg(vm *VirtualMachine) {
v := -math.Float32frombits(uint32(vm.OperandStack.Pop()))
vm.OperandStack.Push(uint64(math.Float32bits(v)))
vm.ActiveContext.PC++
}
func f32ceil(vm *VirtualMachine) {
v := math.Float32frombits(uint32(vm.OperandStack.Pop()))
vm.OperandStack.Push(uint64(math.Float32bits(float32(math.Ceil(float64(v))))))
vm.ActiveContext.PC++
}
func f32floor(vm *VirtualMachine) {
v := math.Float32frombits(uint32(vm.OperandStack.Pop()))
vm.OperandStack.Push(uint64(math.Float32bits(float32(math.Floor(float64(v))))))
vm.ActiveContext.PC++
}
func f32trunc(vm *VirtualMachine) {
v := math.Float32frombits(uint32(vm.OperandStack.Pop()))
vm.OperandStack.Push(uint64(math.Float32bits(float32(math.Trunc(float64(v))))))
vm.ActiveContext.PC++
}
func f32nearest(vm *VirtualMachine) {
// Borrowed from https://github.com/wasmerio/wasmer/blob/703bb4ee2ffb17b2929a194fc045a7e351b696e2/lib/vm/src/libcalls.rs#L77
f := math.Float32frombits(uint32(vm.OperandStack.Pop()))
f64 := float64(f)
if f != -0 && f != 0 {
u := float32(math.Ceil(f64))
d := float32(math.Floor(f64))
um := math.Abs(float64(f - u))
dm := math.Abs(float64(f - d))
h := u / 2.0
if um < dm || float32(math.Floor(float64(h))) == h {
f = u
} else {
f = d
}
}
vm.OperandStack.Push(uint64(math.Float32bits(f)))
vm.ActiveContext.PC++
}
func f32sqrt(vm *VirtualMachine) {
v := math.Float32frombits(uint32(vm.OperandStack.Pop()))
vm.OperandStack.Push(uint64(math.Float32bits(float32(math.Sqrt(float64(v))))))
vm.ActiveContext.PC++
}
func f32add(vm *VirtualMachine) {
v := math.Float32frombits(uint32(vm.OperandStack.Pop())) + math.Float32frombits(uint32(vm.OperandStack.Pop()))
vm.OperandStack.Push(uint64(math.Float32bits(v)))
vm.ActiveContext.PC++
}
func f32sub(vm *VirtualMachine) {
v2 := math.Float32frombits(uint32(vm.OperandStack.Pop()))
v1 := math.Float32frombits(uint32(vm.OperandStack.Pop()))
vm.OperandStack.Push(uint64(math.Float32bits(v1 - v2)))
vm.ActiveContext.PC++
}
func f32mul(vm *VirtualMachine) {
v := math.Float32frombits(uint32(vm.OperandStack.Pop())) * math.Float32frombits(uint32(vm.OperandStack.Pop()))
vm.OperandStack.Push(uint64(math.Float32bits(v)))
vm.ActiveContext.PC++
}
func f32div(vm *VirtualMachine) {
v2 := math.Float32frombits(uint32(vm.OperandStack.Pop()))
v1 := math.Float32frombits(uint32(vm.OperandStack.Pop()))
vm.OperandStack.Push(uint64(math.Float32bits(v1 / v2)))
vm.ActiveContext.PC++
}
func f32min(vm *VirtualMachine) {
v2 := math.Float32frombits(uint32(vm.OperandStack.Pop()))
v1 := math.Float32frombits(uint32(vm.OperandStack.Pop()))
vm.OperandStack.Push(uint64(math.Float32bits(float32(min(float64(v1), float64(v2))))))
vm.ActiveContext.PC++
}
func f32max(vm *VirtualMachine) {
v2 := math.Float32frombits(uint32(vm.OperandStack.Pop()))
v1 := math.Float32frombits(uint32(vm.OperandStack.Pop()))
vm.OperandStack.Push(uint64(math.Float32bits(float32(max(float64(v1), float64(v2))))))
vm.ActiveContext.PC++
}
func f32copysign(vm *VirtualMachine) {
v2 := math.Float32frombits(uint32(vm.OperandStack.Pop()))
v1 := math.Float32frombits(uint32(vm.OperandStack.Pop()))
vm.OperandStack.Push(uint64(math.Float32bits(float32(math.Copysign(float64(v1), float64(v2))))))
vm.ActiveContext.PC++
}
func f64abs(vm *VirtualMachine) {
const mask = 1 << 63
v := vm.OperandStack.Pop() &^ mask
vm.OperandStack.Push(v)
vm.ActiveContext.PC++
}
func f64neg(vm *VirtualMachine) {
v := -math.Float64frombits(vm.OperandStack.Pop())
vm.OperandStack.Push(math.Float64bits(v))
vm.ActiveContext.PC++
}
func f64ceil(vm *VirtualMachine) {
v := math.Float64frombits(vm.OperandStack.Pop())
vm.OperandStack.Push(math.Float64bits(math.Ceil(v)))
vm.ActiveContext.PC++
}
func f64floor(vm *VirtualMachine) {
v := math.Float64frombits(vm.OperandStack.Pop())
vm.OperandStack.Push(math.Float64bits(math.Floor(v)))
vm.ActiveContext.PC++
}
func f64trunc(vm *VirtualMachine) {
v := math.Float64frombits(vm.OperandStack.Pop())
vm.OperandStack.Push(math.Float64bits(math.Trunc(v)))
vm.ActiveContext.PC++
}
func f64nearest(vm *VirtualMachine) {
// Borrowed from https://github.com/wasmerio/wasmer/blob/703bb4ee2ffb17b2929a194fc045a7e351b696e2/lib/vm/src/libcalls.rs#L77
f := math.Float64frombits(vm.OperandStack.Pop())
f64 := float64(f)
if f != -0 && f != 0 {
u := math.Ceil(f64)
d := math.Floor(f64)
um := math.Abs(f - u)
dm := math.Abs(f - d)
h := u / 2.0
if um < dm || math.Floor(float64(h)) == h {
f = u
} else {
f = d
}
}
vm.OperandStack.Push(math.Float64bits(f))
vm.ActiveContext.PC++
}
func f64sqrt(vm *VirtualMachine) {
v := math.Float64frombits(vm.OperandStack.Pop())
vm.OperandStack.Push(math.Float64bits(math.Sqrt(v)))
vm.ActiveContext.PC++
}
func f64add(vm *VirtualMachine) {
v := math.Float64frombits(vm.OperandStack.Pop()) + math.Float64frombits(vm.OperandStack.Pop())
vm.OperandStack.Push(math.Float64bits(v))
vm.ActiveContext.PC++
}
func f64sub(vm *VirtualMachine) {
v2 := math.Float64frombits(vm.OperandStack.Pop())
v1 := math.Float64frombits(vm.OperandStack.Pop())
vm.OperandStack.Push(math.Float64bits(v1 - v2))
vm.ActiveContext.PC++
}
func f64mul(vm *VirtualMachine) {
v := math.Float64frombits(vm.OperandStack.Pop()) * math.Float64frombits(vm.OperandStack.Pop())
vm.OperandStack.Push(math.Float64bits(v))
vm.ActiveContext.PC++
}
func f64div(vm *VirtualMachine) {
v2 := math.Float64frombits(vm.OperandStack.Pop())
v1 := math.Float64frombits(vm.OperandStack.Pop())
vm.OperandStack.Push(math.Float64bits(v1 / v2))
vm.ActiveContext.PC++
}
// math.Min doen't comply with the Wasm spec, so we borrow from the original
// with a change that either one of NaN results in NaN even if another is -Inf.
// https://github.com/golang/go/blob/1d20a362d0ca4898d77865e314ef6f73582daef0/src/math/dim.go#L74-L91
func min(x, y float64) float64 {
switch {
case math.IsNaN(x) || math.IsNaN(y):
return math.NaN()
case math.IsInf(x, -1) || math.IsInf(y, -1):
return math.Inf(-1)
case x == 0 && x == y:
if math.Signbit(x) {
return x
}
return y
}
if x < y {
return x
}
return y
}
func f64min(vm *VirtualMachine) {
v2 := math.Float64frombits(vm.OperandStack.Pop())
v1 := math.Float64frombits(vm.OperandStack.Pop())
vm.OperandStack.Push(math.Float64bits(min(v1, v2)))
vm.ActiveContext.PC++
}
// math.Max doen't comply with the Wasm spec, so we borrow from the original
// with a change that either one of NaN results in NaN even if another is Inf.
// https://github.com/golang/go/blob/1d20a362d0ca4898d77865e314ef6f73582daef0/src/math/dim.go#L42-L59
func max(x, y float64) float64 {
switch {
case math.IsNaN(x) || math.IsNaN(y):
return math.NaN()
case math.IsInf(x, 1) || math.IsInf(y, 1):
return math.Inf(1)
case x == 0 && x == y:
if math.Signbit(x) {
return y
}
return x
}
if x > y {
return x
}
return y
}
func f64max(vm *VirtualMachine) {
v2 := math.Float64frombits(vm.OperandStack.Pop())
v1 := math.Float64frombits(vm.OperandStack.Pop())
vm.OperandStack.Push(math.Float64bits(max(v1, v2)))
vm.ActiveContext.PC++
}
func f64copysign(vm *VirtualMachine) {
v2 := math.Float64frombits(vm.OperandStack.Pop())
v1 := math.Float64frombits(vm.OperandStack.Pop())
vm.OperandStack.Push(math.Float64bits(math.Copysign(v1, v2)))
vm.ActiveContext.PC++
}
func i32wrapi64(vm *VirtualMachine) {
vm.OperandStack.Push(uint64(uint32(vm.OperandStack.Pop())))
vm.ActiveContext.PC++
}
func i32truncf32s(vm *VirtualMachine) {
v := math.Trunc(float64(math.Float32frombits(uint32(vm.OperandStack.Pop()))))
if math.IsNaN(v) {
panic("invalid conversion")
} else if v < math.MinInt32 || v > math.MaxInt32 {
panic("integer overflow")
}
vm.OperandStack.Push(uint64(int32(v)))
vm.ActiveContext.PC++
}
func i32truncf32u(vm *VirtualMachine) {
v := math.Trunc(float64(math.Float32frombits(uint32(vm.OperandStack.Pop()))))
if math.IsNaN(v) {
panic("invalid conversion")
} else if v < 0 || v > math.MaxUint32 {
panic("integer overflow")
}
vm.OperandStack.Push(uint64(uint32(v)))
vm.ActiveContext.PC++
}
func i32truncf64s(vm *VirtualMachine) {
v := math.Trunc(math.Float64frombits(vm.OperandStack.Pop()))
if math.IsNaN(v) {
panic("invalid conversion")
} else if v < math.MinInt32 || v > math.MaxInt32 {
panic("integer overflow")
}
vm.OperandStack.Push(uint64(int32(v)))
vm.ActiveContext.PC++
}
func i32truncf64u(vm *VirtualMachine) {
v := math.Trunc(math.Float64frombits(vm.OperandStack.Pop()))
if math.IsNaN(v) {
panic("invalid conversion")
} else if v < 0 || v > math.MaxUint32 {
panic("integer overflow")
}
vm.OperandStack.Push(uint64(uint32(v)))
vm.ActiveContext.PC++
}
func i64extendi32s(vm *VirtualMachine) {
v := int64(int32(vm.OperandStack.Pop()))
vm.OperandStack.Push(uint64(v))
vm.ActiveContext.PC++
}
func i64extendi32u(vm *VirtualMachine) {
v := uint64(uint32(vm.OperandStack.Pop()))
vm.OperandStack.Push(v)
vm.ActiveContext.PC++
}
func i64truncf32s(vm *VirtualMachine) {
v := math.Trunc(float64(math.Float32frombits(uint32(vm.OperandStack.Pop()))))
res := int64(v)
if math.IsNaN(v) {
panic("invalid conversion")
} else if v < math.MinInt64 || v > 0 && res < 0 {
panic("integer overflow")
}
vm.OperandStack.Push(uint64(res))
vm.ActiveContext.PC++
}
func i64truncf32u(vm *VirtualMachine) {
v := math.Trunc(float64(math.Float32frombits(uint32(vm.OperandStack.Pop()))))
res := uint64(v)
if math.IsNaN(v) {
panic("invalid conversion")
} else if v < 0 || v > float64(res) {
panic("integer overflow")
}
vm.OperandStack.Push(res)
vm.ActiveContext.PC++
}
func i64truncf64s(vm *VirtualMachine) {
v := math.Trunc(math.Float64frombits(vm.OperandStack.Pop()))
res := int64(v)
if math.IsNaN(v) {
panic("invalid conversion")
} else if v < math.MinInt64 || v > 0 && res < 0 {
panic("integer overflow")
}
vm.OperandStack.Push(uint64(res))
vm.ActiveContext.PC++
}
func i64truncf64u(vm *VirtualMachine) {
v := math.Trunc(math.Float64frombits(vm.OperandStack.Pop()))
res := uint64(v)
if math.IsNaN(v) {
panic("invalid conversion")
} else if v < 0 || v > float64(res) {
panic("integer overflow")
}
vm.OperandStack.Push(res)
vm.ActiveContext.PC++
}
func f32converti32s(vm *VirtualMachine) {
v := float32(int32(vm.OperandStack.Pop()))
vm.OperandStack.Push(uint64(math.Float32bits(v)))
vm.ActiveContext.PC++
}
func f32converti32u(vm *VirtualMachine) {
v := float32(uint32(vm.OperandStack.Pop()))
vm.OperandStack.Push(uint64(math.Float32bits(v)))
vm.ActiveContext.PC++
}
func f32converti64s(vm *VirtualMachine) {
v := float32(int64(vm.OperandStack.Pop()))
vm.OperandStack.Push(uint64(math.Float32bits(v)))
vm.ActiveContext.PC++
}
func f32converti64u(vm *VirtualMachine) {
v := float32(vm.OperandStack.Pop())
vm.OperandStack.Push(uint64(math.Float32bits(v)))
vm.ActiveContext.PC++
}
func f32demotef64(vm *VirtualMachine) {
v := float32(math.Float64frombits(vm.OperandStack.Pop()))
vm.OperandStack.Push(uint64(math.Float32bits(v)))
vm.ActiveContext.PC++
}
func f64converti32s(vm *VirtualMachine) {
v := float64(int32(vm.OperandStack.Pop()))
vm.OperandStack.Push(math.Float64bits(v))
vm.ActiveContext.PC++
}
func f64converti32u(vm *VirtualMachine) {
v := float64(uint32(vm.OperandStack.Pop()))
vm.OperandStack.Push(math.Float64bits(v))
vm.ActiveContext.PC++
}
func f64converti64s(vm *VirtualMachine) {
v := float64(int64(vm.OperandStack.Pop()))
vm.OperandStack.Push(math.Float64bits(v))
vm.ActiveContext.PC++
}
func f64converti64u(vm *VirtualMachine) {
v := float64(vm.OperandStack.Pop())
vm.OperandStack.Push(math.Float64bits(v))
vm.ActiveContext.PC++
}
func f64promotef32(vm *VirtualMachine) {
v := float64(math.Float32frombits(uint32(vm.OperandStack.Pop())))
vm.OperandStack.Push(math.Float64bits(v))
vm.ActiveContext.PC++
}