]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.typeparams] cmd/compile: make softfloat mode work with register ABI
authorCherry Mui <cherryyz@google.com>
Thu, 10 Jun 2021 00:14:15 +0000 (20:14 -0400)
committerCherry Mui <cherryyz@google.com>
Tue, 3 Aug 2021 16:14:24 +0000 (16:14 +0000)
Previously, softfloat mode does not work with register ABI, mainly
because the compiler doesn't know how to pass floating point
arguments and results. According to the ABI it should be passed in
FP registers, but there isn't any in softfloat mode.

This CL makes it work. When softfloat is used, we define the ABI
as having 0 floating point registers (because there aren't any).
The integer registers are unchanged. So floating point arguments
and results are passed in memory.

Another option is to pass (the bit representation of) floating
point values in integer registers. But this complicates things
because it'd need to reorder integer argument registers.

Change-Id: Ibecbeccb658c10a868fa7f2dcf75138f719cc809
Reviewed-on: https://go-review.googlesource.com/c/go/+/327274
Trust: Cherry Mui <cherryyz@google.com>
Run-TryBot: Cherry Mui <cherryyz@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
src/cmd/compile/internal/gc/main.go
src/cmd/compile/internal/ssa/config.go
src/cmd/compile/internal/ssa/expand_calls.go
src/cmd/compile/internal/ssa/export_test.go
src/cmd/compile/internal/ssa/softfloat.go
src/cmd/compile/internal/ssagen/ssa.go
test/fixedbugs/issue26163.go
test/fixedbugs/issue28688.go

index 68017516dfddaa08d7b5d4483137892ebb2fd98c..6a373ce33d7851cc121ec9e49833d4156e1435a5 100644 (file)
@@ -160,9 +160,6 @@ func Main(archInit func(*ssagen.ArchInfo)) {
                dwarf.EnableLogging(base.Debug.DwarfInl != 0)
        }
        if base.Debug.SoftFloat != 0 {
-               if buildcfg.Experiment.RegabiArgs {
-                       log.Fatalf("softfloat mode with GOEXPERIMENT=regabiargs not implemented ")
-               }
                ssagen.Arch.SoftFloat = true
        }
 
index b08a394368653d20330d22d13fd783215006d73c..32e3a0860e3dadc9417063665566082e824a021c 100644 (file)
@@ -171,7 +171,7 @@ type Frontend interface {
 }
 
 // NewConfig returns a new configuration object for the given architecture.
-func NewConfig(arch string, types Types, ctxt *obj.Link, optimize bool) *Config {
+func NewConfig(arch string, types Types, ctxt *obj.Link, optimize, softfloat bool) *Config {
        c := &Config{arch: arch, Types: types}
        c.useAvg = true
        c.useHmul = true
@@ -320,6 +320,10 @@ func NewConfig(arch string, types Types, ctxt *obj.Link, optimize bool) *Config
        c.optimize = optimize
        c.useSSE = true
        c.UseFMA = true
+       c.SoftFloat = softfloat
+       if softfloat {
+               c.floatParamRegs = nil // no FP registers in softfloat mode
+       }
 
        c.ABI0 = abi.NewABIConfig(0, 0, ctxt.FixedFrameSize())
        c.ABI1 = abi.NewABIConfig(len(c.intParamRegs), len(c.floatParamRegs), ctxt.FixedFrameSize())
index 7e973ab20591fb8ae42eddcc542f6ca6c1c67451..a8c6c26dadc0eea1e0a7c8952727ddacf0d5dbc6 100644 (file)
@@ -215,7 +215,7 @@ func (x *expandState) isAlreadyExpandedAggregateType(t *types.Type) bool {
                return false
        }
        return t.IsStruct() || t.IsArray() || t.IsComplex() || t.IsInterface() || t.IsString() || t.IsSlice() ||
-               t.Size() > x.regSize && t.IsInteger()
+               (t.Size() > x.regSize && (t.IsInteger() || (x.f.Config.SoftFloat && t.IsFloat())))
 }
 
 // offsetFrom creates an offset from a pointer, simplifying chained offsets and offsets from SP
@@ -380,6 +380,12 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64,
                // The OpLoad was created to load the single field of the IData
                // This case removes that StructSelect.
                if leafType != selector.Type {
+                       if x.f.Config.SoftFloat && selector.Type.IsFloat() {
+                               if x.debug {
+                                       x.Printf("---OpLoad, break\n")
+                               }
+                               break // softfloat pass will take care of that
+                       }
                        x.f.Fatalf("Unexpected Load as selector, leaf=%s, selector=%s\n", leaf.LongString(), selector.LongString())
                }
                leaf.copyOf(selector)
@@ -525,11 +531,11 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64,
 
        case OpComplexReal:
                ls := x.rewriteSelect(leaf, selector.Args[0], offset, regOffset)
-               locs = x.splitSlots(ls, ".real", 0, leafType)
+               locs = x.splitSlots(ls, ".real", 0, selector.Type)
 
        case OpComplexImag:
-               ls := x.rewriteSelect(leaf, selector.Args[0], offset+leafType.Width, regOffset+RO_complex_imag) // result is FloatNN, width of result is offset of imaginary part.
-               locs = x.splitSlots(ls, ".imag", leafType.Width, leafType)
+               ls := x.rewriteSelect(leaf, selector.Args[0], offset+selector.Type.Width, regOffset+RO_complex_imag) // result is FloatNN, width of result is offset of imaginary part.
+               locs = x.splitSlots(ls, ".imag", selector.Type.Width, selector.Type)
 
        case OpStringLen, OpSliceLen:
                ls := x.rewriteSelect(leaf, selector.Args[0], offset+x.ptrSize, regOffset+RO_slice_len)
index 8ed8a0c4a6e3b725f5f621b0ea8855a3a6b9bac7..6d3c0f3ccbda17fb89ef7b4152fcf5a1f570c589 100644 (file)
@@ -39,7 +39,7 @@ func testConfigArch(tb testing.TB, arch string) *Conf {
                tb.Fatal("testTypes is 64-bit only")
        }
        c := &Conf{
-               config: NewConfig(arch, testTypes, ctxt, true),
+               config: NewConfig(arch, testTypes, ctxt, true, false),
                tb:     tb,
        }
        return c
index a8a8f836294b9790c4864f9674aa4dad2b94fe7c..351f824a9f579a2f8d4675e0be4d6d2a256631f2 100644 (file)
@@ -63,6 +63,7 @@ func softfloat(f *Func) {
                                        v.Aux = f.Config.Types.UInt32
                                case 8:
                                        v.Aux = f.Config.Types.UInt64
+                                       newInt64 = true
                                default:
                                        v.Fatalf("bad float type with size %d", size)
                                }
index 7e2f6a7471c06fc2a6a8a12564ce662115a15778..1a0a98f6aa1eea549122f01b3ff966ba2b6313e7 100644 (file)
@@ -87,8 +87,7 @@ func InitConfig() {
        _ = types.NewPtr(types.Types[types.TINT64])                             // *int64
        _ = types.NewPtr(types.ErrorType)                                       // *error
        types.NewPtrCacheEnabled = false
-       ssaConfig = ssa.NewConfig(base.Ctxt.Arch.Name, *types_, base.Ctxt, base.Flag.N == 0)
-       ssaConfig.SoftFloat = Arch.SoftFloat
+       ssaConfig = ssa.NewConfig(base.Ctxt.Arch.Name, *types_, base.Ctxt, base.Flag.N == 0, Arch.SoftFloat)
        ssaConfig.Race = base.Flag.Race
        ssaCaches = make([]ssa.Cache, base.Flag.LowerC)
 
@@ -3653,6 +3652,16 @@ func softfloatInit() {
 // TODO: do not emit sfcall if operation can be optimized to constant in later
 // opt phase
 func (s *state) sfcall(op ssa.Op, args ...*ssa.Value) (*ssa.Value, bool) {
+       f2i := func(t *types.Type) *types.Type {
+               switch t.Kind() {
+               case types.TFLOAT32:
+                       return types.Types[types.TUINT32]
+               case types.TFLOAT64:
+                       return types.Types[types.TUINT64]
+               }
+               return t
+       }
+
        if callDef, ok := softFloatOps[op]; ok {
                switch op {
                case ssa.OpLess32F,
@@ -3665,7 +3674,19 @@ func (s *state) sfcall(op ssa.Op, args ...*ssa.Value) (*ssa.Value, bool) {
                        args[1] = s.newValue1(s.ssaOp(ir.ONEG, types.Types[callDef.rtype]), args[1].Type, args[1])
                }
 
-               result := s.rtcall(callDef.rtfn, true, []*types.Type{types.Types[callDef.rtype]}, args...)[0]
+               // runtime functions take uints for floats and returns uints.
+               // Convert to uints so we use the right calling convention.
+               for i, a := range args {
+                       if a.Type.IsFloat() {
+                               args[i] = s.newValue1(ssa.OpCopy, f2i(a.Type), a)
+                       }
+               }
+
+               rt := types.Types[callDef.rtype]
+               result := s.rtcall(callDef.rtfn, true, []*types.Type{f2i(rt)}, args...)[0]
+               if rt.IsFloat() {
+                       result = s.newValue1(ssa.OpCopy, rt, result)
+               }
                if op == ssa.OpNeq32F || op == ssa.OpNeq64F {
                        result = s.newValue1(ssa.OpNot, result.Type, result)
                }
index d141a2797d60f15e5047d756d063fb3102305e75..3f3d77859def812a43f934347592b7013c87836e 100644 (file)
@@ -1,4 +1,4 @@
-// compile -N -d=softfloat -goexperiment noregabiargs
+// compile -N -d=softfloat
 
 // Copyright 2018 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
index 8ef0802812c6824a6b0e74f070115a843921738a..0d2000e149872f2d0d5496e64123bbcd0f491d8f 100644 (file)
@@ -1,4 +1,4 @@
-// run -gcflags=-d=softfloat -goexperiment noregabiargs
+// run -gcflags=-d=softfloat
 
 // Copyright 2018 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style