]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: make 386 float-to-int conversions match amd64
authorDavid Chase <drchase@google.com>
Tue, 30 Sep 2025 20:27:32 +0000 (16:27 -0400)
committerDavid Chase <drchase@google.com>
Thu, 9 Oct 2025 15:23:30 +0000 (08:23 -0700)
Change-Id: Iff13b4471f94a6a91d8b159603a9338cb9c89747
Reviewed-on: https://go-review.googlesource.com/c/go/+/708295
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>

src/cmd/compile/internal/ssa/_gen/386.rules
src/cmd/compile/internal/ssa/_gen/386Ops.go
src/cmd/compile/internal/ssa/opGen.go
src/cmd/compile/internal/ssa/rewrite386.go
src/cmd/compile/internal/x86/ssa.go
src/runtime/asm_386.s
src/runtime/stubs_386.go
src/runtime/vlrt.go
test/convert5.go

index 5f1150241929eb8d3958d8b7d8c8fd841636ab8a..4e3d3203c790413cffbf52f645bcd20be92ae8e1 100644 (file)
 (Cvt32to32F ...) => (CVTSL2SS ...)
 (Cvt32to64F ...) => (CVTSL2SD ...)
 
-(Cvt32Fto32 ...) => (CVTTSS2SL ...)
-(Cvt64Fto32 ...) => (CVTTSD2SL ...)
+(Cvt32Fto32 <t> x) && base.ConvertHash.MatchPos(v.Pos, nil) => (XORL <t> y (SARLconst <t> [31] (ANDL <t> y:(CVTTSS2SL <t> x) (NOTL <typ.Int32> (MOVLf2i x)))))
+(Cvt64Fto32 <t> x) && base.ConvertHash.MatchPos(v.Pos, nil) => (XORL <t> y (SARLconst <t> [31] (ANDL <t> y:(CVTTSD2SL <t> x) (NOTL <typ.Int32> (MOVLf2i (CVTSD2SS <typ.Float32> x))))))
+(Cvt32Fto32 <t> x) && !base.ConvertHash.MatchPos(v.Pos, nil) => (CVTTSS2SL <t> x)
+(Cvt64Fto32 <t> x) && !base.ConvertHash.MatchPos(v.Pos, nil) => (CVTTSD2SL <t> x)
 
 (Cvt32Fto64F ...) => (CVTSS2SD ...)
 (Cvt64Fto32F ...) => (CVTSD2SS ...)
index 60599a33abb587f22597717e4c240baec3e48ecd..86c2f9c8f080f8e4b085068b62756e051a006e9d 100644 (file)
@@ -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
index 92adf5341b25745a7cca71daa1425c147a4a2ebc..2a60398bc6871140462e65b9776a1ef5fb21d59b 100644 (file)
@@ -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,
index 0495438710659e78b8b472f9c2be9ec140a25067..4845f1e0250ea8bdb9b736162ff9db4d96525281 100644 (file)
@@ -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 <t> x)
+       // cond: base.ConvertHash.MatchPos(v.Pos, nil)
+       // result: (XORL <t> y (SARLconst <t> [31] (ANDL <t> y:(CVTTSS2SL <t> x) (NOTL <typ.Int32> (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 <t> x)
+       // cond: !base.ConvertHash.MatchPos(v.Pos, nil)
+       // result: (CVTTSS2SL <t> 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 <t> x)
+       // cond: base.ConvertHash.MatchPos(v.Pos, nil)
+       // result: (XORL <t> y (SARLconst <t> [31] (ANDL <t> y:(CVTTSD2SL <t> x) (NOTL <typ.Int32> (MOVLf2i (CVTSD2SS <typ.Float32> 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 <t> x)
+       // cond: !base.ConvertHash.MatchPos(v.Pos, nil)
+       // result: (CVTTSD2SL <t> 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]
index d0aad08849635137fe22963f0b6afce919396ef6..2858a81b4b977b4a8cb24b606157111be82cd733 100644 (file)
@@ -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()
index df32e90fda841613d29f8c3a218b1d86281ac7b1..2a6de64f9fbdb35fe2171ee96cb7122d1eb32736 100644 (file)
@@ -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
index a1dd023974a0c6fc41159a759ead4b5ed8ab84c6..4f3dcd4fd9b250743e839d1351745832b91ff253 100644 (file)
@@ -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).
index 4b12f593c8a8ec40bd767d2e78195e4cece1598f..511eb0dd4edf40b003d7154a3a3e9a62f8bde426 100644 (file)
@@ -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<<sh | xlo>>(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<<sh | xlo>>(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 {
index 1bd74abdad071543722a6385df6db6830a6f8d5b..57585ef76e16731cfda60723a42eea016a29832a 100644 (file)
@@ -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