mirror of
https://github.com/golang/go
synced 2024-11-26 17:36:56 -07:00
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 <cherryyz@google.com> Reviewed-by: Ian Lance Taylor <iant@golang.org> Run-TryBot: Cherry Zhang <cherryyz@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
d23bf3daa9
commit
4d23cbc671
@ -645,7 +645,7 @@ for which the compiler will target. The default is <code>power8</code>.
|
|||||||
The default is to use no experimental features.
|
The default is to use no experimental features.
|
||||||
</p>
|
</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>(no features yet)</li>
|
<li><code>GOWASM=signext</code>: generate <a href="https://github.com/WebAssembly/sign-extension-ops/blob/master/proposals/sign-extension-ops/Overview.md">sign-extension operators</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
@ -56,6 +56,9 @@
|
|||||||
(ZeroExt32to64 x:(I64Load32U _ _)) -> x
|
(ZeroExt32to64 x:(I64Load32U _ _)) -> x
|
||||||
(ZeroExt16to(64|32) x:(I64Load16U _ _)) -> x
|
(ZeroExt16to(64|32) x:(I64Load16U _ _)) -> x
|
||||||
(ZeroExt8to(64|32|16) x:(I64Load8U _ _)) -> 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]))
|
(SignExt32to64 x) -> (I64ShrS (I64Shl x (I64Const [32])) (I64Const [32]))
|
||||||
(SignExt16to(64|32) x) -> (I64ShrS (I64Shl x (I64Const [48])) (I64Const [48]))
|
(SignExt16to(64|32) x) -> (I64ShrS (I64Shl x (I64Const [48])) (I64Const [48]))
|
||||||
(SignExt8to(64|32|16) x) -> (I64ShrS (I64Shl x (I64Const [56])) (I64Const [56]))
|
(SignExt8to(64|32|16) x) -> (I64ShrS (I64Shl x (I64Const [56])) (I64Const [56]))
|
||||||
|
@ -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: "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: "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: "F64Sqrt", asm: "F64Sqrt", argLength: 1, reg: fp11, typ: "Float64"}, // sqrt(arg0)
|
||||||
{name: "F64Trunc", asm: "F64Trunc", argLength: 1, reg: fp11, typ: "Float64"}, // trunc(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)
|
{name: "F64Ceil", asm: "F64Ceil", argLength: 1, reg: fp11, typ: "Float64"}, // ceil(arg0)
|
||||||
|
@ -2136,6 +2136,9 @@ const (
|
|||||||
OpWasmI64TruncF64U
|
OpWasmI64TruncF64U
|
||||||
OpWasmF64ConvertI64S
|
OpWasmF64ConvertI64S
|
||||||
OpWasmF64ConvertI64U
|
OpWasmF64ConvertI64U
|
||||||
|
OpWasmI64Extend8S
|
||||||
|
OpWasmI64Extend16S
|
||||||
|
OpWasmI64Extend32S
|
||||||
OpWasmF64Sqrt
|
OpWasmF64Sqrt
|
||||||
OpWasmF64Trunc
|
OpWasmF64Trunc
|
||||||
OpWasmF64Ceil
|
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",
|
name: "F64Sqrt",
|
||||||
argLen: 1,
|
argLen: 1,
|
||||||
|
@ -4426,6 +4426,18 @@ func rewriteValueWasm_OpSignExt16to32_0(v *Value) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// match: (SignExt16to32 x)
|
// 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:
|
// cond:
|
||||||
// result: (I64ShrS (I64Shl x (I64Const [48])) (I64Const [48]))
|
// result: (I64ShrS (I64Shl x (I64Const [48])) (I64Const [48]))
|
||||||
for {
|
for {
|
||||||
@ -4461,6 +4473,18 @@ func rewriteValueWasm_OpSignExt16to64_0(v *Value) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// match: (SignExt16to64 x)
|
// 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:
|
// cond:
|
||||||
// result: (I64ShrS (I64Shl x (I64Const [48])) (I64Const [48]))
|
// result: (I64ShrS (I64Shl x (I64Const [48])) (I64Const [48]))
|
||||||
for {
|
for {
|
||||||
@ -4496,6 +4520,18 @@ func rewriteValueWasm_OpSignExt32to64_0(v *Value) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// match: (SignExt32to64 x)
|
// 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:
|
// cond:
|
||||||
// result: (I64ShrS (I64Shl x (I64Const [32])) (I64Const [32]))
|
// result: (I64ShrS (I64Shl x (I64Const [32])) (I64Const [32]))
|
||||||
for {
|
for {
|
||||||
@ -4531,6 +4567,18 @@ func rewriteValueWasm_OpSignExt8to16_0(v *Value) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// match: (SignExt8to16 x)
|
// 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:
|
// cond:
|
||||||
// result: (I64ShrS (I64Shl x (I64Const [56])) (I64Const [56]))
|
// result: (I64ShrS (I64Shl x (I64Const [56])) (I64Const [56]))
|
||||||
for {
|
for {
|
||||||
@ -4566,6 +4614,18 @@ func rewriteValueWasm_OpSignExt8to32_0(v *Value) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// match: (SignExt8to32 x)
|
// 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:
|
// cond:
|
||||||
// result: (I64ShrS (I64Shl x (I64Const [56])) (I64Const [56]))
|
// result: (I64ShrS (I64Shl x (I64Const [56])) (I64Const [56]))
|
||||||
for {
|
for {
|
||||||
@ -4601,6 +4661,18 @@ func rewriteValueWasm_OpSignExt8to64_0(v *Value) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// match: (SignExt8to64 x)
|
// 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:
|
// cond:
|
||||||
// result: (I64ShrS (I64Shl x (I64Const [56])) (I64Const [56]))
|
// result: (I64ShrS (I64Shl x (I64Const [56])) (I64Const [56]))
|
||||||
for {
|
for {
|
||||||
|
@ -317,7 +317,10 @@ func ssaGenValueOnStack(s *gc.SSAGenState, v *ssa.Value) {
|
|||||||
p := s.Prog(wasm.ACall)
|
p := s.Prog(wasm.ACall)
|
||||||
p.To = obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_EXTERN, Sym: gc.WasmTruncU}
|
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])
|
getValue64(s, v.Args[0])
|
||||||
s.Prog(v.Op.Asm())
|
s.Prog(v.Op.Asm())
|
||||||
|
|
||||||
|
@ -1569,6 +1569,9 @@
|
|||||||
// GOMIPS64
|
// GOMIPS64
|
||||||
// For GOARCH=mips64{,le}, whether to use floating point instructions.
|
// For GOARCH=mips64{,le}, whether to use floating point instructions.
|
||||||
// Valid values are hardfloat (default), softfloat.
|
// 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:
|
// Special-purpose environment variables:
|
||||||
//
|
//
|
||||||
|
@ -563,6 +563,9 @@ Architecture-specific environment variables:
|
|||||||
GOMIPS64
|
GOMIPS64
|
||||||
For GOARCH=mips64{,le}, whether to use floating point instructions.
|
For GOARCH=mips64{,le}, whether to use floating point instructions.
|
||||||
Valid values are hardfloat (default), softfloat.
|
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:
|
Special-purpose environment variables:
|
||||||
|
|
||||||
|
@ -210,8 +210,13 @@ const (
|
|||||||
AI64ReinterpretF64
|
AI64ReinterpretF64
|
||||||
AF32ReinterpretI32
|
AF32ReinterpretI32
|
||||||
AF64ReinterpretI64
|
AF64ReinterpretI64
|
||||||
|
AI32Extend8S
|
||||||
|
AI32Extend16S
|
||||||
|
AI64Extend8S
|
||||||
|
AI64Extend16S
|
||||||
|
AI64Extend32S
|
||||||
|
|
||||||
// End of low-level WebAssembly instructions.
|
ALast // Sentinel: End of low-level WebAssembly instructions.
|
||||||
|
|
||||||
ARESUMEPOINT
|
ARESUMEPOINT
|
||||||
// ACALLNORESUME is a call which is not followed by a resume point.
|
// ACALLNORESUME is a call which is not followed by a resume point.
|
||||||
|
@ -177,6 +177,12 @@ var Anames = []string{
|
|||||||
"I64ReinterpretF64",
|
"I64ReinterpretF64",
|
||||||
"F32ReinterpretI32",
|
"F32ReinterpretI32",
|
||||||
"F64ReinterpretI64",
|
"F64ReinterpretI64",
|
||||||
|
"I32Extend8S",
|
||||||
|
"I32Extend16S",
|
||||||
|
"I64Extend8S",
|
||||||
|
"I64Extend16S",
|
||||||
|
"I64Extend32S",
|
||||||
|
"Last",
|
||||||
"RESUMEPOINT",
|
"RESUMEPOINT",
|
||||||
"CALLNORESUME",
|
"CALLNORESUME",
|
||||||
"RETUNWIND",
|
"RETUNWIND",
|
||||||
|
@ -886,7 +886,7 @@ func assemble(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case p.As < AUnreachable || p.As > AF64ReinterpretI64:
|
case p.As < AUnreachable || p.As >= ALast:
|
||||||
panic(fmt.Sprintf("unexpected assembler op: %s", p.As))
|
panic(fmt.Sprintf("unexpected assembler op: %s", p.As))
|
||||||
case p.As < AEnd:
|
case p.As < AEnd:
|
||||||
w.WriteByte(byte(p.As - AUnreachable + 0x00))
|
w.WriteByte(byte(p.As - AUnreachable + 0x00))
|
||||||
|
@ -78,19 +78,22 @@ func goppc64() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type gowasmFeatures struct {
|
type gowasmFeatures struct {
|
||||||
// no features yet
|
SignExt bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *gowasmFeatures) String() string {
|
func (f *gowasmFeatures) String() string {
|
||||||
var flags []string
|
var flags []string
|
||||||
// no features yet
|
if f.SignExt {
|
||||||
|
flags = append(flags, "signext")
|
||||||
|
}
|
||||||
return strings.Join(flags, ",")
|
return strings.Join(flags, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
func gowasm() (f gowasmFeatures) {
|
func gowasm() (f gowasmFeatures) {
|
||||||
for _, opt := range strings.Split(envOr("GOWASM", ""), ",") {
|
for _, opt := range strings.Split(envOr("GOWASM", ""), ",") {
|
||||||
switch opt {
|
switch opt {
|
||||||
// no features yet
|
case "signext":
|
||||||
|
f.SignExt = true
|
||||||
case "":
|
case "":
|
||||||
// ignore
|
// ignore
|
||||||
default:
|
default:
|
||||||
|
Loading…
Reference in New Issue
Block a user