]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: correct leaf type when "selecting" singleton register-sized struct
authorDavid Chase <drchase@google.com>
Fri, 2 Oct 2020 18:53:48 +0000 (14:53 -0400)
committerDavid Chase <drchase@google.com>
Tue, 6 Oct 2020 15:37:42 +0000 (15:37 +0000)
Two part fix:
1) bring the type "correction" forward from a later CL in the expand calls series
2) when a leaf-selwect is rewritten in place, update the type (it might have been
   changed by the type correction in 1).

Fixes #41736.

Change-Id: Id097efd10481bf0ad92aaead81a7207221c144b5
Reviewed-on: https://go-review.googlesource.com/c/go/+/259203
Trust: David Chase <drchase@google.com>
Run-TryBot: David Chase <drchase@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
src/cmd/compile/internal/ssa/config.go
src/cmd/compile/internal/ssa/expand_calls.go
test/fixedbugs/issue41736.go [new file with mode: 0644]

index 649b5ba820948642616f85d093457e391bdf75b2..f1a748309c66e51603fe1aeb0e127c6c2a15c32b 100644 (file)
@@ -195,7 +195,7 @@ const (
        ClassParamOut                     // return value
 )
 
-const go116lateCallExpansion = false
+const go116lateCallExpansion = true
 
 // LateCallExpansionEnabledWithin returns true if late call expansion should be tested
 // within compilation of a function/method triggered by GOSSAHASH (defaults to "yes").
index 7b1d656b643415208aa31309750d08ed30649b65..992936b2d3d33d2eb1017d049934ec2606389c97 100644 (file)
@@ -58,6 +58,29 @@ func expandCalls(f *Func) {
                return t.IsStruct() || t.IsArray() || regSize == 4 && t.Size() > 4 && t.IsInteger()
        }
 
+       // removeTrivialWrapperTypes unwraps layers of
+       // struct { singleField SomeType } and [1]SomeType
+       // until a non-wrapper type is reached.  This is useful
+       // for working with assignments to/from interface data
+       // fields (either second operand to OpIMake or OpIData)
+       // where the wrapping or type conversion can be elided
+       // because of type conversions/assertions in source code
+       // that do not appear in SSA.
+       removeTrivialWrapperTypes := func(t *types.Type) *types.Type {
+               for {
+                       if t.IsStruct() && t.NumFields() == 1 {
+                               t = t.Field(0).Type
+                               continue
+                       }
+                       if t.IsArray() && t.NumElem() == 1 {
+                               t = t.Elem()
+                               continue
+                       }
+                       break
+               }
+               return t
+       }
+
        // Calls that need lowering have some number of inputs, including a memory input,
        // and produce a tuple of (value1, value2, ..., mem) where valueK may or may not be SSA-able.
 
@@ -84,7 +107,7 @@ func expandCalls(f *Func) {
                                // rewrite v as a Copy of call -- the replacement call will produce a mem.
                                leaf.copyOf(call)
                        } else {
-                               leafType := leaf.Type
+                               leafType := removeTrivialWrapperTypes(leaf.Type)
                                pt := types.NewPtr(leafType)
                                if canSSAType(leafType) {
                                        off := f.ConstOffPtrSP(pt, offset+aux.OffsetOfResult(which), sp)
@@ -92,6 +115,7 @@ func expandCalls(f *Func) {
                                        if leaf.Block == call.Block {
                                                leaf.reset(OpLoad)
                                                leaf.SetArgs2(off, call)
+                                               leaf.Type = leafType
                                        } else {
                                                w := call.Block.NewValue2(leaf.Pos, OpLoad, leafType, off, call)
                                                leaf.copyOf(w)
@@ -192,6 +216,13 @@ func expandCalls(f *Func) {
 
                case types.TARRAY:
                        elt := t.Elem()
+                       if src.Op == OpIData && t.NumElem() == 1 && t.Width == regSize && elt.Width == regSize {
+                               t = removeTrivialWrapperTypes(t)
+                               if t.Etype == types.TSTRUCT || t.Etype == types.TARRAY {
+                                       f.Fatalf("Did not expect to find IDATA-immediate with non-trivial struct/array in it")
+                               }
+                               break // handle the leaf type.
+                       }
                        for i := int64(0); i < t.NumElem(); i++ {
                                sel := src.Block.NewValue1I(pos, OpArraySelect, elt, i, src)
                                mem = splitStore(dst, sel, mem, v, elt, offset+i*elt.Width, firstStorePos)
@@ -199,7 +230,7 @@ func expandCalls(f *Func) {
                        }
                        return mem
                case types.TSTRUCT:
-                       if src.Op == OpIData && t.NumFields() == 1 && t.Field(0).Type.Width == t.Width && t.Width == regSize   {
+                       if src.Op == OpIData && t.NumFields() == 1 && t.Field(0).Type.Width == t.Width && t.Width == regSize {
                                // This peculiar test deals with accesses to immediate interface data.
                                // It works okay because everything is the same size.
                                // Example code that triggers this can be found in go/constant/value.go, function ToComplex
@@ -207,11 +238,9 @@ func expandCalls(f *Func) {
                                // v121 (+882) = StaticLECall <floatVal,mem> {AuxCall{"".itof([intVal,0])[floatVal,8]}} [16] v119 v1
                                // This corresponds to the generic rewrite rule "(StructSelect [0] (IData x)) => (IData x)"
                                // Guard against "struct{struct{*foo}}"
-                               for t.Etype == types.TSTRUCT && t.NumFields() == 1 {
-                                       t = t.Field(0).Type
-                               }
+                               t = removeTrivialWrapperTypes(t)
                                if t.Etype == types.TSTRUCT || t.Etype == types.TARRAY {
-                                       f.Fatalf("Did not expect to find IDATA-immediate with non-trivial struct in it")
+                                       f.Fatalf("Did not expect to find IDATA-immediate with non-trivial struct/array in it")
                                }
                                break // handle the leaf type.
                        }
diff --git a/test/fixedbugs/issue41736.go b/test/fixedbugs/issue41736.go
new file mode 100644 (file)
index 0000000..36f127f
--- /dev/null
@@ -0,0 +1,105 @@
+// compile
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type I struct {
+       x int64
+}
+
+type F struct {
+       x float64
+}
+
+type C struct {
+       x *complex128
+}
+
+type D struct {
+       x complex64
+}
+
+type A [1]*complex128
+
+//go:noinline
+func (i I) X() C {
+       cx := complex(0, float64(i.x))
+       return C{&cx}
+}
+
+//go:noinline
+func (f F) X() C {
+       cx := complex(f.x, 0)
+       return C{&cx}
+}
+
+//go:noinline
+func (c C) X() C {
+       cx := complex(imag(*c.x), real(*c.x))
+       return C{&cx}
+}
+
+//go:noinline
+func (d D) X() C {
+       cx := complex(float64(imag(d.x)), -float64(real(d.x)))
+       return C{&cx}
+}
+
+//go:noinline
+func (a A) X() C {
+       cx := complex(-float64(imag(*a[0])), float64(real(*a[0])))
+       return C{&cx}
+}
+
+//go:noinline
+func (i I) id() I {
+       return i
+}
+
+//go:noinline
+func (f F) id() F {
+       return f
+}
+
+//go:noinline
+func (c C) id() C {
+       return c
+}
+
+//go:noinline
+func (d D) id() D {
+       return d
+}
+
+//go:noinline
+func (a A) id() A {
+       return a
+}
+
+type T interface {
+       X() C
+}
+
+func G(x []T) []T {
+       var y []T
+       for _, a := range x {
+               var v T
+               switch u := a.(type) {
+               case I:
+                       v = u.id()
+               case F:
+                       v = u.id()
+               case C:
+                       v = u.id()
+               case D:
+                       v = u.id()
+               case A:
+                       v = u.id()
+               }
+               y = append(y, v)
+       }
+       return y
+}