The default is to use no experimental features.
</p>
<ul>
+ <li><code>GOWASM=satconv</code>: generate <a href="https://github.com/WebAssembly/nontrapping-float-to-int-conversions/blob/master/proposals/nontrapping-float-to-int-conversion/Overview.md">saturating (non-trapping) float-to-int conversions</a></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>
</li>
(Cvt64Uto32F x) -> (LoweredRound32F (F64ConvertI64U x))
(Cvt64Uto64F x) -> (F64ConvertI64U x)
-(Cvt32Fto32 x) -> (I64TruncF64S x)
-(Cvt32Fto64 x) -> (I64TruncF64S x)
-(Cvt64Fto32 x) -> (I64TruncF64S x)
-(Cvt64Fto64 x) -> (I64TruncF64S x)
-(Cvt32Fto32U x) -> (I64TruncF64U x)
-(Cvt32Fto64U x) -> (I64TruncF64U x)
-(Cvt64Fto32U x) -> (I64TruncF64U x)
-(Cvt64Fto64U x) -> (I64TruncF64U x)
+(Cvt32Fto32 x) -> (I64TruncSatF64S x)
+(Cvt32Fto64 x) -> (I64TruncSatF64S x)
+(Cvt64Fto32 x) -> (I64TruncSatF64S x)
+(Cvt64Fto64 x) -> (I64TruncSatF64S x)
+(Cvt32Fto32U x) -> (I64TruncSatF64U x)
+(Cvt32Fto64U x) -> (I64TruncSatF64U x)
+(Cvt64Fto32U x) -> (I64TruncSatF64U x)
+(Cvt64Fto64U x) -> (I64TruncSatF64U x)
(Cvt32Fto64F x) -> x
(Cvt64Fto32F x) -> (LoweredRound32F x)
{name: "F64Mul", asm: "F64Mul", argLength: 2, reg: fp21, typ: "Float64"}, // arg0 * arg1
{name: "F64Div", asm: "F64Div", argLength: 2, reg: fp21, typ: "Float64"}, // arg0 / arg1
- {name: "I64TruncF64S", asm: "I64TruncF64S", argLength: 1, reg: regInfo{inputs: []regMask{fp}, outputs: []regMask{gp}}, typ: "Int64"}, // truncates the float arg0 to a signed integer
- {name: "I64TruncF64U", asm: "I64TruncF64U", argLength: 1, reg: regInfo{inputs: []regMask{fp}, outputs: []regMask{gp}}, typ: "Int64"}, // truncates the float arg0 to an unsigned integer
+ {name: "I64TruncSatF64S", asm: "I64TruncSatF64S", argLength: 1, reg: regInfo{inputs: []regMask{fp}, outputs: []regMask{gp}}, typ: "Int64"}, // truncates the float arg0 to a signed integer (saturating)
+ {name: "I64TruncSatF64U", asm: "I64TruncSatF64U", argLength: 1, reg: regInfo{inputs: []regMask{fp}, outputs: []regMask{gp}}, typ: "Int64"}, // truncates the float arg0 to an unsigned integer (saturating)
{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
OpWasmF64Sub
OpWasmF64Mul
OpWasmF64Div
- OpWasmI64TruncF64S
- OpWasmI64TruncF64U
+ OpWasmI64TruncSatF64S
+ OpWasmI64TruncSatF64U
OpWasmF64ConvertI64S
OpWasmF64ConvertI64U
OpWasmI64Extend8S
},
},
{
- name: "I64TruncF64S",
+ name: "I64TruncSatF64S",
argLen: 1,
- asm: wasm.AI64TruncF64S,
+ asm: wasm.AI64TruncSatF64S,
reg: regInfo{
inputs: []inputInfo{
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
},
{
- name: "I64TruncF64U",
+ name: "I64TruncSatF64U",
argLen: 1,
- asm: wasm.AI64TruncF64U,
+ asm: wasm.AI64TruncSatF64U,
reg: regInfo{
inputs: []inputInfo{
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
func rewriteValueWasm_OpCvt32Fto32_0(v *Value) bool {
// match: (Cvt32Fto32 x)
// cond:
- // result: (I64TruncF64S x)
+ // result: (I64TruncSatF64S x)
for {
x := v.Args[0]
- v.reset(OpWasmI64TruncF64S)
+ v.reset(OpWasmI64TruncSatF64S)
v.AddArg(x)
return true
}
func rewriteValueWasm_OpCvt32Fto32U_0(v *Value) bool {
// match: (Cvt32Fto32U x)
// cond:
- // result: (I64TruncF64U x)
+ // result: (I64TruncSatF64U x)
for {
x := v.Args[0]
- v.reset(OpWasmI64TruncF64U)
+ v.reset(OpWasmI64TruncSatF64U)
v.AddArg(x)
return true
}
func rewriteValueWasm_OpCvt32Fto64_0(v *Value) bool {
// match: (Cvt32Fto64 x)
// cond:
- // result: (I64TruncF64S x)
+ // result: (I64TruncSatF64S x)
for {
x := v.Args[0]
- v.reset(OpWasmI64TruncF64S)
+ v.reset(OpWasmI64TruncSatF64S)
v.AddArg(x)
return true
}
func rewriteValueWasm_OpCvt32Fto64U_0(v *Value) bool {
// match: (Cvt32Fto64U x)
// cond:
- // result: (I64TruncF64U x)
+ // result: (I64TruncSatF64U x)
for {
x := v.Args[0]
- v.reset(OpWasmI64TruncF64U)
+ v.reset(OpWasmI64TruncSatF64U)
v.AddArg(x)
return true
}
func rewriteValueWasm_OpCvt64Fto32_0(v *Value) bool {
// match: (Cvt64Fto32 x)
// cond:
- // result: (I64TruncF64S x)
+ // result: (I64TruncSatF64S x)
for {
x := v.Args[0]
- v.reset(OpWasmI64TruncF64S)
+ v.reset(OpWasmI64TruncSatF64S)
v.AddArg(x)
return true
}
func rewriteValueWasm_OpCvt64Fto32U_0(v *Value) bool {
// match: (Cvt64Fto32U x)
// cond:
- // result: (I64TruncF64U x)
+ // result: (I64TruncSatF64U x)
for {
x := v.Args[0]
- v.reset(OpWasmI64TruncF64U)
+ v.reset(OpWasmI64TruncSatF64U)
v.AddArg(x)
return true
}
func rewriteValueWasm_OpCvt64Fto64_0(v *Value) bool {
// match: (Cvt64Fto64 x)
// cond:
- // result: (I64TruncF64S x)
+ // result: (I64TruncSatF64S x)
for {
x := v.Args[0]
- v.reset(OpWasmI64TruncF64S)
+ v.reset(OpWasmI64TruncSatF64S)
v.AddArg(x)
return true
}
func rewriteValueWasm_OpCvt64Fto64U_0(v *Value) bool {
// match: (Cvt64Fto64U x)
// cond:
- // result: (I64TruncF64U x)
+ // result: (I64TruncSatF64U x)
for {
x := v.Args[0]
- v.reset(OpWasmI64TruncF64U)
+ v.reset(OpWasmI64TruncSatF64U)
v.AddArg(x)
return true
}
"cmd/compile/internal/types"
"cmd/internal/obj"
"cmd/internal/obj/wasm"
+ "cmd/internal/objabi"
)
func Init(arch *gc.Arch) {
}
s.Prog(wasm.AI64DivS)
- case ssa.OpWasmI64TruncF64S:
+ case ssa.OpWasmI64TruncSatF64S:
getValue64(s, v.Args[0])
- p := s.Prog(wasm.ACall)
- p.To = obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_EXTERN, Sym: gc.WasmTruncS}
+ if objabi.GOWASM.SatConv {
+ s.Prog(v.Op.Asm())
+ } else {
+ p := s.Prog(wasm.ACall)
+ p.To = obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_EXTERN, Sym: gc.WasmTruncS}
+ }
- case ssa.OpWasmI64TruncF64U:
+ case ssa.OpWasmI64TruncSatF64U:
getValue64(s, v.Args[0])
- p := s.Prog(wasm.ACall)
- p.To = obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_EXTERN, Sym: gc.WasmTruncU}
+ if objabi.GOWASM.SatConv {
+ s.Prog(v.Op.Asm())
+ } else {
+ 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,
// Valid values are hardfloat (default), softfloat.
// GOWASM
// For GOARCH=wasm, comma-separated list of experimental WebAssembly features to use.
-// Valid values are: signext.
+// Valid values are satconv, signext.
//
// Special-purpose environment variables:
//
Valid values are hardfloat (default), softfloat.
GOWASM
For GOARCH=wasm, comma-separated list of experimental WebAssembly features to use.
- Valid values are: signext.
+ Valid values are satconv, signext.
Special-purpose environment variables:
AI64Extend16S
AI64Extend32S
+ AI32TruncSatF32S // opcode 0xFC 0x00
+ AI32TruncSatF32U
+ AI32TruncSatF64S
+ AI32TruncSatF64U
+ AI64TruncSatF32S
+ AI64TruncSatF32U
+ AI64TruncSatF64S
+ AI64TruncSatF64U
+
ALast // Sentinel: End of low-level WebAssembly instructions.
ARESUMEPOINT
"I64Extend8S",
"I64Extend16S",
"I64Extend32S",
+ "I32TruncSatF32S",
+ "I32TruncSatF32U",
+ "I32TruncSatF64S",
+ "I32TruncSatF64U",
+ "I64TruncSatF32S",
+ "I64TruncSatF32U",
+ "I64TruncSatF64S",
+ "I64TruncSatF64U",
"Last",
"RESUMEPOINT",
"CALLNORESUME",
}
switch {
- case p.As < AUnreachable || p.As >= ALast:
+ case p.As < AUnreachable:
panic(fmt.Sprintf("unexpected assembler op: %s", p.As))
case p.As < AEnd:
w.WriteByte(byte(p.As - AUnreachable + 0x00))
w.WriteByte(byte(p.As - AEnd + 0x0B))
case p.As < AI32Load:
w.WriteByte(byte(p.As - ADrop + 0x1A))
- default:
+ case p.As < AI32TruncSatF32S:
w.WriteByte(byte(p.As - AI32Load + 0x28))
+ case p.As < ALast:
+ w.WriteByte(0xFC)
+ w.WriteByte(byte(p.As - AI32TruncSatF32S + 0x00))
+ default:
+ panic(fmt.Sprintf("unexpected assembler op: %s", p.As))
}
switch p.As {
type gowasmFeatures struct {
SignExt bool
+ SatConv bool
}
func (f *gowasmFeatures) String() string {
var flags []string
+ if f.SatConv {
+ flags = append(flags, "satconv")
+ }
if f.SignExt {
flags = append(flags, "signext")
}
func gowasm() (f gowasmFeatures) {
for _, opt := range strings.Split(envOr("GOWASM", ""), ",") {
switch opt {
+ case "satconv":
+ f.SatConv = true
case "signext":
f.SignExt = true
case "":