]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.ssa] cmd/compile: fix failed lowerings
authorKeith Randall <khr@golang.org>
Wed, 7 Oct 2015 21:35:25 +0000 (14:35 -0700)
committerKeith Randall <khr@golang.org>
Thu, 8 Oct 2015 18:12:09 +0000 (18:12 +0000)
One was OAPPEND of large types.  We need to mem-mem copy them
instead of storing them.

Another was pointer-like struct and array types being put in the
data field of an eface.  We need to use the underlying pointer
type for the load that fills in the eface.data field.

Change-Id: Id8278c0381904e52d59011a66ce46386b41b5521
Reviewed-on: https://go-review.googlesource.com/15552
Run-TryBot: Keith Randall <khr@golang.org>
Reviewed-by: David Chase <drchase@google.com>
src/cmd/compile/internal/gc/ssa.go
src/cmd/compile/internal/gc/type.go
src/cmd/compile/internal/ssa/type.go
src/cmd/compile/internal/ssa/type_test.go

index 7e00fc91620e0704e44f65fbb42476ad91981580..69a9b8639b5d690bfe3e35e6e4c10265c30dcd46 100644 (file)
@@ -1801,6 +1801,31 @@ func (s *state) expr(n *Node) *ssa.Value {
        case OEFACE:
                tab := s.expr(n.Left)
                data := s.expr(n.Right)
+               // The frontend allows putting things like struct{*byte} in
+               // the data portion of an eface.  But we don't want struct{*byte}
+               // as a register type because (among other reasons) the liveness
+               // analysis is confused by the "fat" variables that result from
+               // such types being spilled.
+               // So here we ensure that we are selecting the underlying pointer
+               // when we build an eface.
+               for !data.Type.IsPtr() {
+                       switch {
+                       case data.Type.IsArray():
+                               data = s.newValue2(ssa.OpArrayIndex, data.Type.Elem(), data, s.constInt(Types[TINT], 0))
+                       case data.Type.IsStruct():
+                               for i := data.Type.NumFields() - 1; i >= 0; i-- {
+                                       f := data.Type.FieldType(i)
+                                       if f.Size() == 0 {
+                                               // eface type could also be struct{p *byte; q [0]int}
+                                               continue
+                                       }
+                                       data = s.newValue1I(ssa.OpStructSelect, f, data.Type.FieldOff(i), data)
+                                       break
+                               }
+                       default:
+                               s.Fatalf("type being put into an eface isn't a pointer")
+                       }
+               }
                return s.newValue2(ssa.OpIMake, n.Type, tab, data)
 
        case OSLICE, OSLICEARR:
@@ -1898,8 +1923,15 @@ func (s *state) expr(n *Node) *ssa.Value {
 
                // Evaluate args
                args := make([]*ssa.Value, 0, nargs)
+               store := make([]bool, 0, nargs)
                for l := n.List.Next; l != nil; l = l.Next {
-                       args = append(args, s.expr(l.N))
+                       if canSSAType(l.N.Type) {
+                               args = append(args, s.expr(l.N))
+                               store = append(store, true)
+                       } else {
+                               args = append(args, s.addr(l.N))
+                               store = append(store, false)
+                       }
                }
 
                p = s.variable(&ptrVar, pt)          // generates phi for ptr
@@ -1907,7 +1939,11 @@ func (s *state) expr(n *Node) *ssa.Value {
                p2 := s.newValue2(ssa.OpPtrIndex, pt, p, l)
                for i, arg := range args {
                        addr := s.newValue2(ssa.OpPtrIndex, pt, p2, s.constInt(Types[TUINTPTR], int64(i)))
-                       s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, et.Size(), addr, arg, s.mem())
+                       if store[i] {
+                               s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, et.Size(), addr, arg, s.mem())
+                       } else {
+                               s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, et.Size(), addr, arg, s.mem())
+                       }
                        if haspointers(et) {
                                // TODO: just one write barrier call for all of these writes?
                                // TODO: maybe just one writeBarrierEnabled check?
index 3e07df367d695299f99fa35ba22aeca9ea5192a6..87af2860e8749c1454f211ebfd6a7a7ce9b106b2 100644 (file)
@@ -88,6 +88,10 @@ func (t *Type) IsArray() bool {
        return t.Etype == TARRAY && t.Bound >= 0
 }
 
+func (t *Type) IsStruct() bool {
+       return t.Etype == TSTRUCT
+}
+
 func (t *Type) IsInterface() bool {
        return t.Etype == TINTER
 }
@@ -99,5 +103,42 @@ func (t *Type) PtrTo() ssa.Type {
        return Ptrto(t)
 }
 
+func (t *Type) NumFields() int64 {
+       return int64(countfield(t))
+}
+func (t *Type) FieldType(i int64) ssa.Type {
+       // TODO: store fields in a slice so we can
+       // look them up by index in constant time.
+       for t1 := t.Type; t1 != nil; t1 = t1.Down {
+               if t1.Etype != TFIELD {
+                       panic("non-TFIELD in a TSTRUCT")
+               }
+               if i == 0 {
+                       return t1.Type
+               }
+               i--
+       }
+       panic("not enough fields")
+}
+func (t *Type) FieldOff(i int64) int64 {
+       for t1 := t.Type; t1 != nil; t1 = t1.Down {
+               if t1.Etype != TFIELD {
+                       panic("non-TFIELD in a TSTRUCT")
+               }
+               if i == 0 {
+                       return t1.Width
+               }
+               i--
+       }
+       panic("not enough fields")
+}
+
+func (t *Type) NumElem() int64 {
+       if t.Etype != TARRAY {
+               panic("NumElem on non-TARRAY")
+       }
+       return int64(t.Bound)
+}
+
 func (t *Type) IsMemory() bool { return false }
 func (t *Type) IsFlags() bool  { return false }
index 6800731de6fd2159f3ef6c4d4e1ced569de17f30..d558881b2fe5ec34bcead682e23534f7d155ba29 100644 (file)
@@ -21,14 +21,21 @@ type Type interface {
        IsString() bool
        IsSlice() bool
        IsArray() bool
+       IsStruct() bool
        IsInterface() bool
 
        IsMemory() bool // special ssa-package-only types
        IsFlags() bool
 
-       Elem() Type  // given []T or *T, return T
+       Elem() Type  // given []T or *T or [n]T, return T
        PtrTo() Type // given T, return *T
 
+       NumFields() int64       // # of fields of a struct
+       FieldType(i int64) Type // type of ith field of the struct
+       FieldOff(i int64) int64 // offset of ith field of the struct
+
+       NumElem() int64 // # of elements of an array
+
        String() string
        SimpleString() string // a coarser generic description of T, e.g. T's underlying type
        Equal(Type) bool
@@ -41,24 +48,29 @@ type CompilerType struct {
        Flags  bool
 }
 
-func (t *CompilerType) Size() int64          { return 0 } // Size in bytes
-func (t *CompilerType) Alignment() int64     { return 0 }
-func (t *CompilerType) IsBoolean() bool      { return false }
-func (t *CompilerType) IsInteger() bool      { return false }
-func (t *CompilerType) IsSigned() bool       { return false }
-func (t *CompilerType) IsFloat() bool        { return false }
-func (t *CompilerType) IsComplex() bool      { return false }
-func (t *CompilerType) IsPtr() bool          { return false }
-func (t *CompilerType) IsString() bool       { return false }
-func (t *CompilerType) IsSlice() bool        { return false }
-func (t *CompilerType) IsArray() bool        { return false }
-func (t *CompilerType) IsInterface() bool    { return false }
-func (t *CompilerType) IsMemory() bool       { return t.Memory }
-func (t *CompilerType) IsFlags() bool        { return t.Flags }
-func (t *CompilerType) String() string       { return t.Name }
-func (t *CompilerType) SimpleString() string { return t.Name }
-func (t *CompilerType) Elem() Type           { panic("not implemented") }
-func (t *CompilerType) PtrTo() Type          { panic("not implemented") }
+func (t *CompilerType) Size() int64            { return 0 } // Size in bytes
+func (t *CompilerType) Alignment() int64       { return 0 }
+func (t *CompilerType) IsBoolean() bool        { return false }
+func (t *CompilerType) IsInteger() bool        { return false }
+func (t *CompilerType) IsSigned() bool         { return false }
+func (t *CompilerType) IsFloat() bool          { return false }
+func (t *CompilerType) IsComplex() bool        { return false }
+func (t *CompilerType) IsPtr() bool            { return false }
+func (t *CompilerType) IsString() bool         { return false }
+func (t *CompilerType) IsSlice() bool          { return false }
+func (t *CompilerType) IsArray() bool          { return false }
+func (t *CompilerType) IsStruct() bool         { return false }
+func (t *CompilerType) IsInterface() bool      { return false }
+func (t *CompilerType) IsMemory() bool         { return t.Memory }
+func (t *CompilerType) IsFlags() bool          { return t.Flags }
+func (t *CompilerType) String() string         { return t.Name }
+func (t *CompilerType) SimpleString() string   { return t.Name }
+func (t *CompilerType) Elem() Type             { panic("not implemented") }
+func (t *CompilerType) PtrTo() Type            { panic("not implemented") }
+func (t *CompilerType) NumFields() int64       { panic("not implemented") }
+func (t *CompilerType) FieldType(i int64) Type { panic("not implemented") }
+func (t *CompilerType) FieldOff(i int64) int64 { panic("not implemented") }
+func (t *CompilerType) NumElem() int64         { panic("not implemented") }
 
 func (t *CompilerType) Equal(u Type) bool {
        x, ok := u.(*CompilerType)
index f3ac0aec2cf3e1f6534d13c4445dd95dea959c05..c8889608dbdf57e17099d879e82f32ec92c5dd66 100644 (file)
@@ -17,30 +17,36 @@ type TypeImpl struct {
        string  bool
        slice   bool
        array   bool
+       struct_ bool
        inter   bool
        Elem_   Type
 
        Name string
 }
 
-func (t *TypeImpl) Size() int64          { return t.Size_ }
-func (t *TypeImpl) Alignment() int64     { return t.Align }
-func (t *TypeImpl) IsBoolean() bool      { return t.Boolean }
-func (t *TypeImpl) IsInteger() bool      { return t.Integer }
-func (t *TypeImpl) IsSigned() bool       { return t.Signed }
-func (t *TypeImpl) IsFloat() bool        { return t.Float }
-func (t *TypeImpl) IsComplex() bool      { return t.Complex }
-func (t *TypeImpl) IsPtr() bool          { return t.Ptr }
-func (t *TypeImpl) IsString() bool       { return t.string }
-func (t *TypeImpl) IsSlice() bool        { return t.slice }
-func (t *TypeImpl) IsArray() bool        { return t.array }
-func (t *TypeImpl) IsInterface() bool    { return t.inter }
-func (t *TypeImpl) IsMemory() bool       { return false }
-func (t *TypeImpl) IsFlags() bool        { return false }
-func (t *TypeImpl) String() string       { return t.Name }
-func (t *TypeImpl) SimpleString() string { return t.Name }
-func (t *TypeImpl) Elem() Type           { return t.Elem_ }
-func (t *TypeImpl) PtrTo() Type          { panic("not implemented") }
+func (t *TypeImpl) Size() int64            { return t.Size_ }
+func (t *TypeImpl) Alignment() int64       { return t.Align }
+func (t *TypeImpl) IsBoolean() bool        { return t.Boolean }
+func (t *TypeImpl) IsInteger() bool        { return t.Integer }
+func (t *TypeImpl) IsSigned() bool         { return t.Signed }
+func (t *TypeImpl) IsFloat() bool          { return t.Float }
+func (t *TypeImpl) IsComplex() bool        { return t.Complex }
+func (t *TypeImpl) IsPtr() bool            { return t.Ptr }
+func (t *TypeImpl) IsString() bool         { return t.string }
+func (t *TypeImpl) IsSlice() bool          { return t.slice }
+func (t *TypeImpl) IsArray() bool          { return t.array }
+func (t *TypeImpl) IsStruct() bool         { return t.struct_ }
+func (t *TypeImpl) IsInterface() bool      { return t.inter }
+func (t *TypeImpl) IsMemory() bool         { return false }
+func (t *TypeImpl) IsFlags() bool          { return false }
+func (t *TypeImpl) String() string         { return t.Name }
+func (t *TypeImpl) SimpleString() string   { return t.Name }
+func (t *TypeImpl) Elem() Type             { return t.Elem_ }
+func (t *TypeImpl) PtrTo() Type            { panic("not implemented") }
+func (t *TypeImpl) NumFields() int64       { panic("not implemented") }
+func (t *TypeImpl) FieldType(i int64) Type { panic("not implemented") }
+func (t *TypeImpl) FieldOff(i int64) int64 { panic("not implemented") }
+func (t *TypeImpl) NumElem() int64         { panic("not implemented") }
 
 func (t *TypeImpl) Equal(u Type) bool {
        x, ok := u.(*TypeImpl)