From 4d23cbc67100c1ce50b7d4fcc67e50091f92eb5b Mon Sep 17 00:00:00 2001 From: Richard Musiol Date: Sat, 23 Mar 2019 15:25:42 +0100 Subject: [PATCH] cmd/compile: add sign-extension operators on wasm This change adds the GOWASM option "signext" to enable the generation of experimental sign-extension operators. The feature is in phase 4 of the WebAssembly proposal process: https://github.com/WebAssembly/meetings/blob/master/process/phases.md More information on the feature can be found at: https://github.com/WebAssembly/sign-extension-ops/blob/master/proposals/sign-extension-ops/Overview.md Change-Id: I6b30069390a8699fbecd9fb4d1d61e13c59b0333 Reviewed-on: https://go-review.googlesource.com/c/go/+/168882 Reviewed-by: Cherry Zhang Reviewed-by: Ian Lance Taylor Run-TryBot: Cherry Zhang TryBot-Result: Gobot Gobot --- doc/install-source.html | 2 +- src/cmd/compile/internal/ssa/gen/Wasm.rules | 3 + src/cmd/compile/internal/ssa/gen/WasmOps.go | 4 ++ src/cmd/compile/internal/ssa/opGen.go | 42 ++++++++++++ src/cmd/compile/internal/ssa/rewriteWasm.go | 72 +++++++++++++++++++++ src/cmd/compile/internal/wasm/ssa.go | 5 +- src/cmd/go/alldocs.go | 3 + src/cmd/go/internal/help/helpdoc.go | 3 + src/cmd/internal/obj/wasm/a.out.go | 7 +- src/cmd/internal/obj/wasm/anames.go | 6 ++ src/cmd/internal/obj/wasm/wasmobj.go | 2 +- src/cmd/internal/objabi/util.go | 9 ++- 12 files changed, 151 insertions(+), 7 deletions(-) diff --git a/doc/install-source.html b/doc/install-source.html index 46dc618a9c..9c73b925b1 100644 --- a/doc/install-source.html +++ b/doc/install-source.html @@ -645,7 +645,7 @@ for which the compiler will target. The default is power8. The default is to use no experimental features.

diff --git a/src/cmd/compile/internal/ssa/gen/Wasm.rules b/src/cmd/compile/internal/ssa/gen/Wasm.rules index 83e1be798e..72f4805edf 100644 --- a/src/cmd/compile/internal/ssa/gen/Wasm.rules +++ b/src/cmd/compile/internal/ssa/gen/Wasm.rules @@ -56,6 +56,9 @@ (ZeroExt32to64 x:(I64Load32U _ _)) -> x (ZeroExt16to(64|32) x:(I64Load16U _ _)) -> x (ZeroExt8to(64|32|16) x:(I64Load8U _ _)) -> x +(SignExt32to64 x) && objabi.GOWASM.SignExt -> (I64Extend32S x) +(SignExt8to(64|32|16) x) && objabi.GOWASM.SignExt -> (I64Extend8S x) +(SignExt16to(64|32) x) && objabi.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])) diff --git a/src/cmd/compile/internal/ssa/gen/WasmOps.go b/src/cmd/compile/internal/ssa/gen/WasmOps.go index 4a01bf6c28..4e5f076575 100644 --- a/src/cmd/compile/internal/ssa/gen/WasmOps.go +++ b/src/cmd/compile/internal/ssa/gen/WasmOps.go @@ -192,6 +192,10 @@ func init() { {name: "F64ConvertI64S", asm: "F64ConvertI64S", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{fp}}, typ: "Float64"}, // converts the signed integer arg0 to a float {name: "F64ConvertI64U", asm: "F64ConvertI64U", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{fp}}, typ: "Float64"}, // converts the unsigned integer arg0 to a float + {name: "I64Extend8S", asm: "I64Extend8S", argLength: 1, reg: gp11, typ: "Int64"}, // sign-extend arg0 from 8 to 64 bit + {name: "I64Extend16S", asm: "I64Extend16S", argLength: 1, reg: gp11, typ: "Int64"}, // sign-extend arg0 from 16 to 64 bit + {name: "I64Extend32S", asm: "I64Extend32S", argLength: 1, reg: gp11, typ: "Int64"}, // sign-extend arg0 from 32 to 64 bit + {name: "F64Sqrt", asm: "F64Sqrt", argLength: 1, reg: fp11, typ: "Float64"}, // sqrt(arg0) {name: "F64Trunc", asm: "F64Trunc", argLength: 1, reg: fp11, typ: "Float64"}, // trunc(arg0) {name: "F64Ceil", asm: "F64Ceil", argLength: 1, reg: fp11, typ: "Float64"}, // ceil(arg0) diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index d71d6146d1..214d68757c 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -2136,6 +2136,9 @@ const ( OpWasmI64TruncF64U OpWasmF64ConvertI64S OpWasmF64ConvertI64U + OpWasmI64Extend8S + OpWasmI64Extend16S + OpWasmI64Extend32S OpWasmF64Sqrt OpWasmF64Trunc OpWasmF64Ceil @@ -28724,6 +28727,45 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "I64Extend8S", + argLen: 1, + asm: wasm.AI64Extend8S, + reg: regInfo{ + inputs: []inputInfo{ + {0, 4295032831}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 SP + }, + outputs: []outputInfo{ + {0, 65535}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 + }, + }, + }, + { + name: "I64Extend16S", + argLen: 1, + asm: wasm.AI64Extend16S, + reg: regInfo{ + inputs: []inputInfo{ + {0, 4295032831}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 SP + }, + outputs: []outputInfo{ + {0, 65535}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 + }, + }, + }, + { + name: "I64Extend32S", + argLen: 1, + asm: wasm.AI64Extend32S, + reg: regInfo{ + inputs: []inputInfo{ + {0, 4295032831}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 SP + }, + outputs: []outputInfo{ + {0, 65535}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 + }, + }, + }, { name: "F64Sqrt", argLen: 1, diff --git a/src/cmd/compile/internal/ssa/rewriteWasm.go b/src/cmd/compile/internal/ssa/rewriteWasm.go index 7796548ee4..fe85922e31 100644 --- a/src/cmd/compile/internal/ssa/rewriteWasm.go +++ b/src/cmd/compile/internal/ssa/rewriteWasm.go @@ -4426,6 +4426,18 @@ func rewriteValueWasm_OpSignExt16to32_0(v *Value) bool { return true } // match: (SignExt16to32 x) + // cond: objabi.GOWASM.SignExt + // result: (I64Extend16S x) + for { + x := v.Args[0] + if !(objabi.GOWASM.SignExt) { + break + } + v.reset(OpWasmI64Extend16S) + v.AddArg(x) + return true + } + // match: (SignExt16to32 x) // cond: // result: (I64ShrS (I64Shl x (I64Const [48])) (I64Const [48])) for { @@ -4461,6 +4473,18 @@ func rewriteValueWasm_OpSignExt16to64_0(v *Value) bool { return true } // match: (SignExt16to64 x) + // cond: objabi.GOWASM.SignExt + // result: (I64Extend16S x) + for { + x := v.Args[0] + if !(objabi.GOWASM.SignExt) { + break + } + v.reset(OpWasmI64Extend16S) + v.AddArg(x) + return true + } + // match: (SignExt16to64 x) // cond: // result: (I64ShrS (I64Shl x (I64Const [48])) (I64Const [48])) for { @@ -4496,6 +4520,18 @@ func rewriteValueWasm_OpSignExt32to64_0(v *Value) bool { return true } // match: (SignExt32to64 x) + // cond: objabi.GOWASM.SignExt + // result: (I64Extend32S x) + for { + x := v.Args[0] + if !(objabi.GOWASM.SignExt) { + break + } + v.reset(OpWasmI64Extend32S) + v.AddArg(x) + return true + } + // match: (SignExt32to64 x) // cond: // result: (I64ShrS (I64Shl x (I64Const [32])) (I64Const [32])) for { @@ -4531,6 +4567,18 @@ func rewriteValueWasm_OpSignExt8to16_0(v *Value) bool { return true } // match: (SignExt8to16 x) + // cond: objabi.GOWASM.SignExt + // result: (I64Extend8S x) + for { + x := v.Args[0] + if !(objabi.GOWASM.SignExt) { + break + } + v.reset(OpWasmI64Extend8S) + v.AddArg(x) + return true + } + // match: (SignExt8to16 x) // cond: // result: (I64ShrS (I64Shl x (I64Const [56])) (I64Const [56])) for { @@ -4566,6 +4614,18 @@ func rewriteValueWasm_OpSignExt8to32_0(v *Value) bool { return true } // match: (SignExt8to32 x) + // cond: objabi.GOWASM.SignExt + // result: (I64Extend8S x) + for { + x := v.Args[0] + if !(objabi.GOWASM.SignExt) { + break + } + v.reset(OpWasmI64Extend8S) + v.AddArg(x) + return true + } + // match: (SignExt8to32 x) // cond: // result: (I64ShrS (I64Shl x (I64Const [56])) (I64Const [56])) for { @@ -4601,6 +4661,18 @@ func rewriteValueWasm_OpSignExt8to64_0(v *Value) bool { return true } // match: (SignExt8to64 x) + // cond: objabi.GOWASM.SignExt + // result: (I64Extend8S x) + for { + x := v.Args[0] + if !(objabi.GOWASM.SignExt) { + break + } + v.reset(OpWasmI64Extend8S) + v.AddArg(x) + return true + } + // match: (SignExt8to64 x) // cond: // result: (I64ShrS (I64Shl x (I64Const [56])) (I64Const [56])) for { diff --git a/src/cmd/compile/internal/wasm/ssa.go b/src/cmd/compile/internal/wasm/ssa.go index d2ac2df613..7575df548a 100644 --- a/src/cmd/compile/internal/wasm/ssa.go +++ b/src/cmd/compile/internal/wasm/ssa.go @@ -317,7 +317,10 @@ func ssaGenValueOnStack(s *gc.SSAGenState, v *ssa.Value) { p := s.Prog(wasm.ACall) p.To = obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_EXTERN, Sym: gc.WasmTruncU} - case ssa.OpWasmF64Neg, ssa.OpWasmF64ConvertI64S, ssa.OpWasmF64ConvertI64U, ssa.OpWasmF64Sqrt, ssa.OpWasmF64Trunc, ssa.OpWasmF64Ceil, ssa.OpWasmF64Floor, ssa.OpWasmF64Nearest, ssa.OpWasmF64Abs, ssa.OpWasmI64Ctz, ssa.OpWasmI64Clz, ssa.OpWasmI64Popcnt: + case + ssa.OpWasmF64Neg, ssa.OpWasmF64ConvertI64S, ssa.OpWasmF64ConvertI64U, + ssa.OpWasmI64Extend8S, ssa.OpWasmI64Extend16S, ssa.OpWasmI64Extend32S, + ssa.OpWasmF64Sqrt, ssa.OpWasmF64Trunc, ssa.OpWasmF64Ceil, ssa.OpWasmF64Floor, ssa.OpWasmF64Nearest, ssa.OpWasmF64Abs, ssa.OpWasmI64Ctz, ssa.OpWasmI64Clz, ssa.OpWasmI64Popcnt: getValue64(s, v.Args[0]) s.Prog(v.Op.Asm()) diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index 8dd3f8eb18..f42635f6a8 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -1569,6 +1569,9 @@ // GOMIPS64 // For GOARCH=mips64{,le}, whether to use floating point instructions. // Valid values are hardfloat (default), softfloat. +// GOWASM +// For GOARCH=wasm, comma-separated list of experimental WebAssembly features to use. +// Valid values are: signext. // // Special-purpose environment variables: // diff --git a/src/cmd/go/internal/help/helpdoc.go b/src/cmd/go/internal/help/helpdoc.go index d931c9225b..777bd511b1 100644 --- a/src/cmd/go/internal/help/helpdoc.go +++ b/src/cmd/go/internal/help/helpdoc.go @@ -563,6 +563,9 @@ Architecture-specific environment variables: GOMIPS64 For GOARCH=mips64{,le}, whether to use floating point instructions. Valid values are hardfloat (default), softfloat. + GOWASM + For GOARCH=wasm, comma-separated list of experimental WebAssembly features to use. + Valid values are: signext. Special-purpose environment variables: diff --git a/src/cmd/internal/obj/wasm/a.out.go b/src/cmd/internal/obj/wasm/a.out.go index f1830ba036..29ea87f3b0 100644 --- a/src/cmd/internal/obj/wasm/a.out.go +++ b/src/cmd/internal/obj/wasm/a.out.go @@ -210,8 +210,13 @@ const ( AI64ReinterpretF64 AF32ReinterpretI32 AF64ReinterpretI64 + AI32Extend8S + AI32Extend16S + AI64Extend8S + AI64Extend16S + AI64Extend32S - // End of low-level WebAssembly instructions. + ALast // Sentinel: End of low-level WebAssembly instructions. ARESUMEPOINT // ACALLNORESUME is a call which is not followed by a resume point. diff --git a/src/cmd/internal/obj/wasm/anames.go b/src/cmd/internal/obj/wasm/anames.go index 7ef09d665e..fb4b72c398 100644 --- a/src/cmd/internal/obj/wasm/anames.go +++ b/src/cmd/internal/obj/wasm/anames.go @@ -177,6 +177,12 @@ var Anames = []string{ "I64ReinterpretF64", "F32ReinterpretI32", "F64ReinterpretI64", + "I32Extend8S", + "I32Extend16S", + "I64Extend8S", + "I64Extend16S", + "I64Extend32S", + "Last", "RESUMEPOINT", "CALLNORESUME", "RETUNWIND", diff --git a/src/cmd/internal/obj/wasm/wasmobj.go b/src/cmd/internal/obj/wasm/wasmobj.go index ad98cfe90a..dded62a4be 100644 --- a/src/cmd/internal/obj/wasm/wasmobj.go +++ b/src/cmd/internal/obj/wasm/wasmobj.go @@ -886,7 +886,7 @@ func assemble(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) { } switch { - case p.As < AUnreachable || p.As > AF64ReinterpretI64: + case p.As < AUnreachable || p.As >= ALast: panic(fmt.Sprintf("unexpected assembler op: %s", p.As)) case p.As < AEnd: w.WriteByte(byte(p.As - AUnreachable + 0x00)) diff --git a/src/cmd/internal/objabi/util.go b/src/cmd/internal/objabi/util.go index c007f6c475..02f9d9273a 100644 --- a/src/cmd/internal/objabi/util.go +++ b/src/cmd/internal/objabi/util.go @@ -78,19 +78,22 @@ func goppc64() int { } type gowasmFeatures struct { - // no features yet + SignExt bool } func (f *gowasmFeatures) String() string { var flags []string - // no features yet + if f.SignExt { + flags = append(flags, "signext") + } return strings.Join(flags, ",") } func gowasm() (f gowasmFeatures) { for _, opt := range strings.Split(envOr("GOWASM", ""), ",") { switch opt { - // no features yet + case "signext": + f.SignExt = true case "": // ignore default: -- 2.48.1