aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Chase <drchase@google.com>2020-10-02 14:53:48 -0400
committerDavid Chase <drchase@google.com>2020-10-06 15:37:42 +0000
commitf8d80977b784fd4879963e61dc9fca1fc9bf2193 (patch)
tree27a7b8f1fef2f0cd1c61cc20ab83a14eb0811003
parentd2a80f3fb5b44450e0b304ac5a718f99c053d82a (diff)
downloadgo-f8d80977b784fd4879963e61dc9fca1fc9bf2193.tar.xz
cmd/compile: correct leaf type when "selecting" singleton register-sized struct
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>
-rw-r--r--src/cmd/compile/internal/ssa/config.go2
-rw-r--r--src/cmd/compile/internal/ssa/expand_calls.go41
-rw-r--r--test/fixedbugs/issue41736.go105
3 files changed, 141 insertions, 7 deletions
diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go
index 649b5ba820..f1a748309c 100644
--- a/src/cmd/compile/internal/ssa/config.go
+++ b/src/cmd/compile/internal/ssa/config.go
@@ -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").
diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go
index 7b1d656b64..992936b2d3 100644
--- a/src/cmd/compile/internal/ssa/expand_calls.go
+++ b/src/cmd/compile/internal/ssa/expand_calls.go
@@ -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
index 0000000000..36f127f4fb
--- /dev/null
+++ b/test/fixedbugs/issue41736.go
@@ -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
+}