From: David Chase Date: Tue, 30 Sep 2025 20:27:32 +0000 (-0400) Subject: cmd/compile: make 386 float-to-int conversions match amd64 X-Git-Tag: go1.26rc1~655 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=78d75b37992be01326b9bd2666195aaba9bf2ae2;p=gostls13.git cmd/compile: make 386 float-to-int conversions match amd64 Change-Id: Iff13b4471f94a6a91d8b159603a9338cb9c89747 Reviewed-on: https://go-review.googlesource.com/c/go/+/708295 Reviewed-by: Keith Randall Reviewed-by: Keith Randall LUCI-TryBot-Result: Go LUCI --- diff --git a/src/cmd/compile/internal/ssa/_gen/386.rules b/src/cmd/compile/internal/ssa/_gen/386.rules index 5f11502419..4e3d3203c7 100644 --- a/src/cmd/compile/internal/ssa/_gen/386.rules +++ b/src/cmd/compile/internal/ssa/_gen/386.rules @@ -88,8 +88,10 @@ (Cvt32to32F ...) => (CVTSL2SS ...) (Cvt32to64F ...) => (CVTSL2SD ...) -(Cvt32Fto32 ...) => (CVTTSS2SL ...) -(Cvt64Fto32 ...) => (CVTTSD2SL ...) +(Cvt32Fto32 x) && base.ConvertHash.MatchPos(v.Pos, nil) => (XORL y (SARLconst [31] (ANDL y:(CVTTSS2SL x) (NOTL (MOVLf2i x))))) +(Cvt64Fto32 x) && base.ConvertHash.MatchPos(v.Pos, nil) => (XORL y (SARLconst [31] (ANDL y:(CVTTSD2SL x) (NOTL (MOVLf2i (CVTSD2SS x)))))) +(Cvt32Fto32 x) && !base.ConvertHash.MatchPos(v.Pos, nil) => (CVTTSS2SL x) +(Cvt64Fto32 x) && !base.ConvertHash.MatchPos(v.Pos, nil) => (CVTTSD2SL x) (Cvt32Fto64F ...) => (CVTSS2SD ...) (Cvt64Fto32F ...) => (CVTSD2SS ...) diff --git a/src/cmd/compile/internal/ssa/_gen/386Ops.go b/src/cmd/compile/internal/ssa/_gen/386Ops.go index 60599a33ab..86c2f9c8f0 100644 --- a/src/cmd/compile/internal/ssa/_gen/386Ops.go +++ b/src/cmd/compile/internal/ssa/_gen/386Ops.go @@ -342,6 +342,8 @@ func init() { {name: "MOVWLSX", argLength: 1, reg: gp11, asm: "MOVWLSX"}, // sign extend arg0 from int16 to int32 {name: "MOVWLZX", argLength: 1, reg: gp11, asm: "MOVWLZX"}, // zero extend arg0 from int16 to int32 + {name: "MOVLf2i", argLength: 1, reg: fpgp, typ: "UInt32"}, // move 32 bits from float to int reg, zero extend + {name: "MOVLconst", reg: gp01, asm: "MOVL", typ: "UInt32", aux: "Int32", rematerializeable: true}, // 32 low bits of auxint {name: "CVTTSD2SL", argLength: 1, reg: fpgp, asm: "CVTTSD2SL"}, // convert float64 to int32 diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index 92adf5341b..2a60398bc6 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -499,6 +499,7 @@ const ( Op386MOVBLZX Op386MOVWLSX Op386MOVWLZX + Op386MOVLf2i Op386MOVLconst Op386CVTTSD2SL Op386CVTTSS2SL @@ -5601,6 +5602,18 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "MOVLf2i", + argLen: 1, + reg: regInfo{ + inputs: []inputInfo{ + {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7 + }, + outputs: []outputInfo{ + {0, 239}, // AX CX DX BX BP SI DI + }, + }, + }, { name: "MOVLconst", auxType: auxInt32, diff --git a/src/cmd/compile/internal/ssa/rewrite386.go b/src/cmd/compile/internal/ssa/rewrite386.go index 0495438710..4845f1e025 100644 --- a/src/cmd/compile/internal/ssa/rewrite386.go +++ b/src/cmd/compile/internal/ssa/rewrite386.go @@ -3,6 +3,7 @@ package ssa import "math" +import "cmd/compile/internal/base" import "cmd/compile/internal/types" func rewriteValue386(v *Value) bool { @@ -340,8 +341,7 @@ func rewriteValue386(v *Value) bool { v.Op = Op386BSFL return true case OpCvt32Fto32: - v.Op = Op386CVTTSS2SL - return true + return rewriteValue386_OpCvt32Fto32(v) case OpCvt32Fto64F: v.Op = Op386CVTSS2SD return true @@ -352,8 +352,7 @@ func rewriteValue386(v *Value) bool { v.Op = Op386CVTSL2SD return true case OpCvt64Fto32: - v.Op = Op386CVTTSD2SL - return true + return rewriteValue386_OpCvt64Fto32(v) case OpCvt64Fto32F: v.Op = Op386CVTSD2SS return true @@ -7964,6 +7963,98 @@ func rewriteValue386_OpCtz8(v *Value) bool { return true } } +func rewriteValue386_OpCvt32Fto32(v *Value) bool { + v_0 := v.Args[0] + b := v.Block + typ := &b.Func.Config.Types + // match: (Cvt32Fto32 x) + // cond: base.ConvertHash.MatchPos(v.Pos, nil) + // result: (XORL y (SARLconst [31] (ANDL y:(CVTTSS2SL x) (NOTL (MOVLf2i x))))) + for { + t := v.Type + x := v_0 + if !(base.ConvertHash.MatchPos(v.Pos, nil)) { + break + } + v.reset(Op386XORL) + v.Type = t + v0 := b.NewValue0(v.Pos, Op386SARLconst, t) + v0.AuxInt = int32ToAuxInt(31) + v1 := b.NewValue0(v.Pos, Op386ANDL, t) + y := b.NewValue0(v.Pos, Op386CVTTSS2SL, t) + y.AddArg(x) + v3 := b.NewValue0(v.Pos, Op386NOTL, typ.Int32) + v4 := b.NewValue0(v.Pos, Op386MOVLf2i, typ.UInt32) + v4.AddArg(x) + v3.AddArg(v4) + v1.AddArg2(y, v3) + v0.AddArg(v1) + v.AddArg2(y, v0) + return true + } + // match: (Cvt32Fto32 x) + // cond: !base.ConvertHash.MatchPos(v.Pos, nil) + // result: (CVTTSS2SL x) + for { + t := v.Type + x := v_0 + if !(!base.ConvertHash.MatchPos(v.Pos, nil)) { + break + } + v.reset(Op386CVTTSS2SL) + v.Type = t + v.AddArg(x) + return true + } + return false +} +func rewriteValue386_OpCvt64Fto32(v *Value) bool { + v_0 := v.Args[0] + b := v.Block + typ := &b.Func.Config.Types + // match: (Cvt64Fto32 x) + // cond: base.ConvertHash.MatchPos(v.Pos, nil) + // result: (XORL y (SARLconst [31] (ANDL y:(CVTTSD2SL x) (NOTL (MOVLf2i (CVTSD2SS x)))))) + for { + t := v.Type + x := v_0 + if !(base.ConvertHash.MatchPos(v.Pos, nil)) { + break + } + v.reset(Op386XORL) + v.Type = t + v0 := b.NewValue0(v.Pos, Op386SARLconst, t) + v0.AuxInt = int32ToAuxInt(31) + v1 := b.NewValue0(v.Pos, Op386ANDL, t) + y := b.NewValue0(v.Pos, Op386CVTTSD2SL, t) + y.AddArg(x) + v3 := b.NewValue0(v.Pos, Op386NOTL, typ.Int32) + v4 := b.NewValue0(v.Pos, Op386MOVLf2i, typ.UInt32) + v5 := b.NewValue0(v.Pos, Op386CVTSD2SS, typ.Float32) + v5.AddArg(x) + v4.AddArg(v5) + v3.AddArg(v4) + v1.AddArg2(y, v3) + v0.AddArg(v1) + v.AddArg2(y, v0) + return true + } + // match: (Cvt64Fto32 x) + // cond: !base.ConvertHash.MatchPos(v.Pos, nil) + // result: (CVTTSD2SL x) + for { + t := v.Type + x := v_0 + if !(!base.ConvertHash.MatchPos(v.Pos, nil)) { + break + } + v.reset(Op386CVTTSD2SL) + v.Type = t + v.AddArg(x) + return true + } + return false +} func rewriteValue386_OpDiv8(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] diff --git a/src/cmd/compile/internal/x86/ssa.go b/src/cmd/compile/internal/x86/ssa.go index d0aad08849..2858a81b4b 100644 --- a/src/cmd/compile/internal/x86/ssa.go +++ b/src/cmd/compile/internal/x86/ssa.go @@ -538,6 +538,13 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.To.Type = obj.TYPE_MEM p.To.Reg = v.Args[0].Reg() ssagen.AddAux(&p.To, v) + case ssa.Op386MOVLf2i: + var p *obj.Prog + p = s.Prog(x86.AMOVL) + p.From.Type = obj.TYPE_REG + p.From.Reg = v.Args[0].Reg() + p.To.Type = obj.TYPE_REG + p.To.Reg = v.Reg() case ssa.Op386ADDLconstmodify: sc := v.AuxValAndOff() val := sc.Val() diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s index df32e90fda..2a6de64f9f 100644 --- a/src/runtime/asm_386.s +++ b/src/runtime/asm_386.s @@ -1407,16 +1407,6 @@ TEXT runtime·uint32tofloat64(SB),NOSPLIT,$8-12 FMOVDP F0, ret+4(FP) RET -TEXT runtime·float64touint32(SB),NOSPLIT,$12-12 - FMOVD a+0(FP), F0 - FSTCW 0(SP) - FLDCW runtime·controlWord64trunc(SB) - FMOVVP F0, 4(SP) - FLDCW 0(SP) - MOVL 4(SP), AX - MOVL AX, ret+8(FP) - RET - // gcWriteBarrier informs the GC about heap pointer writes. // // gcWriteBarrier returns space in a write barrier buffer which diff --git a/src/runtime/stubs_386.go b/src/runtime/stubs_386.go index a1dd023974..4f3dcd4fd9 100644 --- a/src/runtime/stubs_386.go +++ b/src/runtime/stubs_386.go @@ -6,7 +6,6 @@ package runtime import "unsafe" -func float64touint32(a float64) uint32 func uint32tofloat64(a uint32) float64 // stackcheck checks that SP is in range [g->stack.lo, g->stack.hi). diff --git a/src/runtime/vlrt.go b/src/runtime/vlrt.go index 4b12f593c8..511eb0dd4e 100644 --- a/src/runtime/vlrt.go +++ b/src/runtime/vlrt.go @@ -40,10 +40,17 @@ func float64toint64(d float64) (y uint64) { } func float64touint64(d float64) (y uint64) { - _d2v(&y, d) + _d2vu(&y, d) return } +func float64touint32(a float64) uint32 { + if a >= 0xffffffff { + return 0xffffffff + } + return uint32(float64touint64(a)) +} + func int64tofloat64(y int64) float64 { if y < 0 { return -uint64tofloat64(-uint64(y)) @@ -117,12 +124,16 @@ func _d2v(y *uint64, d float64) { } else { /* v = (hi||lo) << -sh */ sh := uint32(-sh) - if sh <= 11 { + if sh <= 10 { ylo = xlo << sh yhi = xhi<>(32-sh) } else { - /* overflow */ - yhi = uint32(d) /* causes something awful */ + if x&sign64 != 0 { + *y = 0x8000000000000000 + } else { + *y = 0x7fffffffffffffff + } + return } } if x&sign64 != 0 { @@ -136,6 +147,50 @@ func _d2v(y *uint64, d float64) { *y = uint64(yhi)<<32 | uint64(ylo) } +func _d2vu(y *uint64, d float64) { + x := *(*uint64)(unsafe.Pointer(&d)) + if x&sign64 != 0 { + *y = 0 + return + } + + xhi := uint32(x>>32)&0xfffff | 0x100000 + xlo := uint32(x) + sh := 1075 - int32(uint32(x>>52)&0x7ff) + + var ylo, yhi uint32 + if sh >= 0 { + sh := uint32(sh) + /* v = (hi||lo) >> sh */ + if sh < 32 { + if sh == 0 { + ylo = xlo + yhi = xhi + } else { + ylo = xlo>>sh | xhi<<(32-sh) + yhi = xhi >> sh + } + } else { + if sh == 32 { + ylo = xhi + } else if sh < 64 { + ylo = xhi >> (sh - 32) + } + } + } else { + /* v = (hi||lo) << -sh */ + sh := uint32(-sh) + if sh <= 11 { + ylo = xlo << sh + yhi = xhi<>(32-sh) + } else { + /* overflow */ + *y = 0xffffffffffffffff + return + } + } + *y = uint64(yhi)<<32 | uint64(ylo) +} func uint64div(n, d uint64) uint64 { // Check for 32 bit operands if uint32(n>>32) == 0 && uint32(d>>32) == 0 { diff --git a/test/convert5.go b/test/convert5.go index 1bd74abdad..57585ef76e 100644 --- a/test/convert5.go +++ b/test/convert5.go @@ -4,9 +4,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !wasm && !386 && !arm && !mips +//go:build !wasm -// TODO fix this to work for wasm and 32-bit architectures. +// TODO fix this to work for wasm // Doing more than this, however, expands the change. package main