These features have been standardized since at least Wasm 2.0.
Always enable them.
The corresponding GOWASM settings are now no-op.
Change-Id: I0e59f21696a69a4e289127988aad629a720b002b
Reviewed-on: https://go-review.googlesource.com/c/go/+/707855
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: David Chase <drchase@google.com>
(ZeroExt32to64 x:(I64Load32U _ _)) => x
(ZeroExt16to(64|32) x:(I64Load16U _ _)) => x
(ZeroExt8to(64|32|16) x:(I64Load8U _ _)) => x
-(SignExt32to64 x) && buildcfg.GOWASM.SignExt => (I64Extend32S x)
-(SignExt8to(64|32|16) x) && buildcfg.GOWASM.SignExt => (I64Extend8S x)
-(SignExt16to(64|32) x) && buildcfg.GOWASM.SignExt => (I64Extend16S x)
-(SignExt32to64 x) => (I64ShrS (I64Shl x (I64Const [32])) (I64Const [32]))
-(SignExt16to(64|32) x) => (I64ShrS (I64Shl x (I64Const [48])) (I64Const [48]))
-(SignExt8to(64|32|16) x) => (I64ShrS (I64Shl x (I64Const [56])) (I64Const [56]))
+(SignExt32to64 x) => (I64Extend32S x)
+(SignExt8to(64|32|16) x) => (I64Extend8S x)
+(SignExt16to(64|32) x) => (I64Extend16S x)
(ZeroExt32to64 x) => (I64And x (I64Const [0xffffffff]))
(ZeroExt16to(64|32) x) => (I64And x (I64Const [0xffff]))
(ZeroExt8to(64|32|16) x) => (I64And x (I64Const [0xff]))
package ssa
-import "internal/buildcfg"
import "math"
import "cmd/compile/internal/types"
}
func rewriteValueWasm_OpSignExt16to32(v *Value) bool {
v_0 := v.Args[0]
- b := v.Block
- typ := &b.Func.Config.Types
// match: (SignExt16to32 x:(I64Load16S _ _))
// result: x
for {
return true
}
// match: (SignExt16to32 x)
- // cond: buildcfg.GOWASM.SignExt
// result: (I64Extend16S x)
for {
x := v_0
- if !(buildcfg.GOWASM.SignExt) {
- break
- }
v.reset(OpWasmI64Extend16S)
v.AddArg(x)
return true
}
- // match: (SignExt16to32 x)
- // result: (I64ShrS (I64Shl x (I64Const [48])) (I64Const [48]))
- for {
- x := v_0
- v.reset(OpWasmI64ShrS)
- v0 := b.NewValue0(v.Pos, OpWasmI64Shl, typ.Int64)
- v1 := b.NewValue0(v.Pos, OpWasmI64Const, typ.Int64)
- v1.AuxInt = int64ToAuxInt(48)
- v0.AddArg2(x, v1)
- v.AddArg2(v0, v1)
- return true
- }
}
func rewriteValueWasm_OpSignExt16to64(v *Value) bool {
v_0 := v.Args[0]
- b := v.Block
- typ := &b.Func.Config.Types
// match: (SignExt16to64 x:(I64Load16S _ _))
// result: x
for {
return true
}
// match: (SignExt16to64 x)
- // cond: buildcfg.GOWASM.SignExt
// result: (I64Extend16S x)
for {
x := v_0
- if !(buildcfg.GOWASM.SignExt) {
- break
- }
v.reset(OpWasmI64Extend16S)
v.AddArg(x)
return true
}
- // match: (SignExt16to64 x)
- // result: (I64ShrS (I64Shl x (I64Const [48])) (I64Const [48]))
- for {
- x := v_0
- v.reset(OpWasmI64ShrS)
- v0 := b.NewValue0(v.Pos, OpWasmI64Shl, typ.Int64)
- v1 := b.NewValue0(v.Pos, OpWasmI64Const, typ.Int64)
- v1.AuxInt = int64ToAuxInt(48)
- v0.AddArg2(x, v1)
- v.AddArg2(v0, v1)
- return true
- }
}
func rewriteValueWasm_OpSignExt32to64(v *Value) bool {
v_0 := v.Args[0]
- b := v.Block
- typ := &b.Func.Config.Types
// match: (SignExt32to64 x:(I64Load32S _ _))
// result: x
for {
return true
}
// match: (SignExt32to64 x)
- // cond: buildcfg.GOWASM.SignExt
// result: (I64Extend32S x)
for {
x := v_0
- if !(buildcfg.GOWASM.SignExt) {
- break
- }
v.reset(OpWasmI64Extend32S)
v.AddArg(x)
return true
}
- // match: (SignExt32to64 x)
- // result: (I64ShrS (I64Shl x (I64Const [32])) (I64Const [32]))
- for {
- x := v_0
- v.reset(OpWasmI64ShrS)
- v0 := b.NewValue0(v.Pos, OpWasmI64Shl, typ.Int64)
- v1 := b.NewValue0(v.Pos, OpWasmI64Const, typ.Int64)
- v1.AuxInt = int64ToAuxInt(32)
- v0.AddArg2(x, v1)
- v.AddArg2(v0, v1)
- return true
- }
}
func rewriteValueWasm_OpSignExt8to16(v *Value) bool {
v_0 := v.Args[0]
- b := v.Block
- typ := &b.Func.Config.Types
// match: (SignExt8to16 x:(I64Load8S _ _))
// result: x
for {
return true
}
// match: (SignExt8to16 x)
- // cond: buildcfg.GOWASM.SignExt
// result: (I64Extend8S x)
for {
x := v_0
- if !(buildcfg.GOWASM.SignExt) {
- break
- }
v.reset(OpWasmI64Extend8S)
v.AddArg(x)
return true
}
- // match: (SignExt8to16 x)
- // result: (I64ShrS (I64Shl x (I64Const [56])) (I64Const [56]))
- for {
- x := v_0
- v.reset(OpWasmI64ShrS)
- v0 := b.NewValue0(v.Pos, OpWasmI64Shl, typ.Int64)
- v1 := b.NewValue0(v.Pos, OpWasmI64Const, typ.Int64)
- v1.AuxInt = int64ToAuxInt(56)
- v0.AddArg2(x, v1)
- v.AddArg2(v0, v1)
- return true
- }
}
func rewriteValueWasm_OpSignExt8to32(v *Value) bool {
v_0 := v.Args[0]
- b := v.Block
- typ := &b.Func.Config.Types
// match: (SignExt8to32 x:(I64Load8S _ _))
// result: x
for {
return true
}
// match: (SignExt8to32 x)
- // cond: buildcfg.GOWASM.SignExt
// result: (I64Extend8S x)
for {
x := v_0
- if !(buildcfg.GOWASM.SignExt) {
- break
- }
v.reset(OpWasmI64Extend8S)
v.AddArg(x)
return true
}
- // match: (SignExt8to32 x)
- // result: (I64ShrS (I64Shl x (I64Const [56])) (I64Const [56]))
- for {
- x := v_0
- v.reset(OpWasmI64ShrS)
- v0 := b.NewValue0(v.Pos, OpWasmI64Shl, typ.Int64)
- v1 := b.NewValue0(v.Pos, OpWasmI64Const, typ.Int64)
- v1.AuxInt = int64ToAuxInt(56)
- v0.AddArg2(x, v1)
- v.AddArg2(v0, v1)
- return true
- }
}
func rewriteValueWasm_OpSignExt8to64(v *Value) bool {
v_0 := v.Args[0]
- b := v.Block
- typ := &b.Func.Config.Types
// match: (SignExt8to64 x:(I64Load8S _ _))
// result: x
for {
return true
}
// match: (SignExt8to64 x)
- // cond: buildcfg.GOWASM.SignExt
// result: (I64Extend8S x)
for {
x := v_0
- if !(buildcfg.GOWASM.SignExt) {
- break
- }
v.reset(OpWasmI64Extend8S)
v.AddArg(x)
return true
}
- // match: (SignExt8to64 x)
- // result: (I64ShrS (I64Shl x (I64Const [56])) (I64Const [56]))
- for {
- x := v_0
- v.reset(OpWasmI64ShrS)
- v0 := b.NewValue0(v.Pos, OpWasmI64Shl, typ.Int64)
- v1 := b.NewValue0(v.Pos, OpWasmI64Const, typ.Int64)
- v1.AuxInt = int64ToAuxInt(56)
- v0.AddArg2(x, v1)
- v.AddArg2(v0, v1)
- return true
- }
}
func rewriteValueWasm_OpSlicemask(v *Value) bool {
v_0 := v.Args[0]
"cmd/compile/internal/types"
"cmd/internal/obj"
"cmd/internal/obj/wasm"
- "internal/buildcfg"
)
/*
case ssa.OpWasmI64TruncSatF32S, ssa.OpWasmI64TruncSatF64S:
getValue64(s, v.Args[0])
- if buildcfg.GOWASM.SatConv {
- s.Prog(v.Op.Asm())
- } else {
- if v.Op == ssa.OpWasmI64TruncSatF32S {
- s.Prog(wasm.AF64PromoteF32)
- }
- p := s.Prog(wasm.ACall)
- p.To = obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_EXTERN, Sym: ir.Syms.WasmTruncS}
- }
+ s.Prog(v.Op.Asm())
case ssa.OpWasmI64TruncSatF32U, ssa.OpWasmI64TruncSatF64U:
getValue64(s, v.Args[0])
- if buildcfg.GOWASM.SatConv {
- s.Prog(v.Op.Asm())
- } else {
- if v.Op == ssa.OpWasmI64TruncSatF32U {
- s.Prog(wasm.AF64PromoteF32)
- }
- p := s.Prog(wasm.ACall)
- p.To = obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_EXTERN, Sym: ir.Syms.WasmTruncU}
- }
+ s.Prog(v.Op.Asm())
case ssa.OpWasmF32DemoteF64:
getValue64(s, v.Args[0])
}
type gowasmFeatures struct {
- SatConv bool
- SignExt bool
+ // Legacy features, now always enabled
+ //SatConv bool
+ //SignExt bool
}
func (f gowasmFeatures) String() string {
var flags []string
- if f.SatConv {
- flags = append(flags, "satconv")
- }
- if f.SignExt {
- flags = append(flags, "signext")
- }
return strings.Join(flags, ",")
}
for opt := range strings.SplitSeq(envOr("GOWASM", ""), ",") {
switch opt {
case "satconv":
- f.SatConv = true
+ // ignore, always enabled
case "signext":
- f.SignExt = true
+ // ignore, always enabled
case "":
// ignore
default:
return list
case "wasm":
var list []string
- if GOWASM.SatConv {
- list = append(list, GOARCH+".satconv")
- }
- if GOWASM.SignExt {
- list = append(list, GOARCH+".signext")
- }
+ // SatConv is always enabled
+ list = append(list, GOARCH+".satconv")
+ // SignExt is always enabled
+ list = append(list, GOARCH+".signext")
return list
}
return nil
var res int64
var ures uint64
+// TODO: This test probably should be in a different place.
+
func TestFloatTruncation(t *testing.T) {
testdata := []struct {
input float64
// max +- 1
{
input: 0x7fffffffffffffff,
- convInt64: -0x8000000000000000,
+ convInt64: 0x7fffffffffffffff,
convUInt64: 0x8000000000000000,
},
// For out-of-bounds conversion, the result is implementation-dependent.
- // This test verifies the implementation of wasm architecture.
+ // This test verifies the implementation of wasm architecture, which is,
+ // saturating to the min/max value.
{
input: 0x8000000000000000,
- convInt64: -0x8000000000000000,
+ convInt64: 0x7fffffffffffffff,
convUInt64: 0x8000000000000000,
},
{
input: 0x7ffffffffffffffe,
- convInt64: -0x8000000000000000,
+ convInt64: 0x7fffffffffffffff,
convUInt64: 0x8000000000000000,
},
// neg max +- 1
{
input: -0x8000000000000000,
convInt64: -0x8000000000000000,
- convUInt64: 0x8000000000000000,
+ convUInt64: 0,
},
{
input: -0x8000000000000001,
convInt64: -0x8000000000000000,
- convUInt64: 0x8000000000000000,
+ convUInt64: 0,
},
{
input: -0x7fffffffffffffff,
convInt64: -0x8000000000000000,
- convUInt64: 0x8000000000000000,
+ convUInt64: 0,
},
// trunc point +- 1
{
},
{
input: 0x7ffffffffffffe00,
- convInt64: -0x8000000000000000,
+ convInt64: 0x7fffffffffffffff,
convUInt64: 0x8000000000000000,
},
{
{
input: -0x7ffffffffffffdff,
convInt64: -0x7ffffffffffffc00,
- convUInt64: 0x8000000000000000,
+ convUInt64: 0,
},
{
input: -0x7ffffffffffffe00,
convInt64: -0x8000000000000000,
- convUInt64: 0x8000000000000000,
+ convUInt64: 0,
},
{
input: -0x7ffffffffffffdfe,
convInt64: -0x7ffffffffffffc00,
- convUInt64: 0x8000000000000000,
+ convUInt64: 0,
},
// umax +- 1
{
input: 0xffffffffffffffff,
- convInt64: -0x8000000000000000,
- convUInt64: 0x8000000000000000,
+ convInt64: 0x7fffffffffffffff,
+ convUInt64: 0xffffffffffffffff,
},
{
input: 0x10000000000000000,
- convInt64: -0x8000000000000000,
- convUInt64: 0x8000000000000000,
+ convInt64: 0x7fffffffffffffff,
+ convUInt64: 0xffffffffffffffff,
},
{
input: 0xfffffffffffffffe,
- convInt64: -0x8000000000000000,
- convUInt64: 0x8000000000000000,
+ convInt64: 0x7fffffffffffffff,
+ convUInt64: 0xffffffffffffffff,
},
// umax trunc +- 1
{
input: 0xfffffffffffffbff,
- convInt64: -0x8000000000000000,
+ convInt64: 0x7fffffffffffffff,
convUInt64: 0xfffffffffffff800,
},
{
input: 0xfffffffffffffc00,
- convInt64: -0x8000000000000000,
- convUInt64: 0x8000000000000000,
+ convInt64: 0x7fffffffffffffff,
+ convUInt64: 0xffffffffffffffff,
},
{
input: 0xfffffffffffffbfe,
- convInt64: -0x8000000000000000,
+ convInt64: 0x7fffffffffffffff,
convUInt64: 0xfffffffffffff800,
},
}
I64DivS
Return
-TEXT runtime·wasmTruncS(SB), NOSPLIT, $0-0
- Get R0
- Get R0
- F64Ne // NaN
- If
- I64Const $0x8000000000000000
- Return
- End
-
- Get R0
- F64Const $0x7ffffffffffffc00p0 // Maximum truncated representation of 0x7fffffffffffffff
- F64Gt
- If
- I64Const $0x8000000000000000
- Return
- End
-
- Get R0
- F64Const $-0x7ffffffffffffc00p0 // Minimum truncated representation of -0x8000000000000000
- F64Lt
- If
- I64Const $0x8000000000000000
- Return
- End
-
- Get R0
- I64TruncF64S
- Return
-
-TEXT runtime·wasmTruncU(SB), NOSPLIT, $0-0
- Get R0
- Get R0
- F64Ne // NaN
- If
- I64Const $0x8000000000000000
- Return
- End
-
- Get R0
- F64Const $0xfffffffffffff800p0 // Maximum truncated representation of 0xffffffffffffffff
- F64Gt
- If
- I64Const $0x8000000000000000
- Return
- End
-
- Get R0
- F64Const $0.
- F64Lt
- If
- I64Const $0x8000000000000000
- Return
- End
-
- Get R0
- I64TruncF64U
- Return
-
TEXT runtime·exitThread(SB), NOSPLIT, $0-0
UNDEF