]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: fix naming of decomposed structs
authorKeith Randall <khr@golang.org>
Fri, 1 Apr 2016 04:24:10 +0000 (21:24 -0700)
committerKeith Randall <khr@golang.org>
Mon, 11 Apr 2016 17:11:23 +0000 (17:11 +0000)
When a struct is SSAable, we will name its component parts
by their field names.  For example,
type T struct {
     a, b, c int
}
If we ever need to spill a variable x of type T, we will
spill its individual components to variables named x.a, x.b,
and x.c.

Change-Id: I857286ff1f2597f2c4bbd7b4c0b936386fb37131
Reviewed-on: https://go-review.googlesource.com/21389
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/config.go
src/cmd/compile/internal/ssa/decompose.go
src/cmd/compile/internal/ssa/export_test.go
src/cmd/compile/internal/ssa/type.go
src/cmd/compile/internal/ssa/type_test.go

index d69559d945c75ee45596413717a9a4c8fcb97164..5ee370395b505086ee8403c4969803515d04c2d5 100644 (file)
@@ -4227,7 +4227,7 @@ func (e *ssaExport) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.Local
 
 func (e *ssaExport) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot, ssa.LocalSlot) {
        n := name.N.(*Node)
-       ptrType := Ptrto(n.Type.Elem())
+       ptrType := Ptrto(name.Type.ElemType().(*Type))
        lenType := Types[TINT]
        if n.Class == PAUTO && !n.Addrtaken {
                // Split this slice up into three separate variables.
@@ -4261,6 +4261,20 @@ func (e *ssaExport) SplitComplex(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSl
        return ssa.LocalSlot{n, t, name.Off}, ssa.LocalSlot{n, t, name.Off + s}
 }
 
+func (e *ssaExport) SplitStruct(name ssa.LocalSlot, i int) ssa.LocalSlot {
+       n := name.N.(*Node)
+       st := name.Type
+       ft := st.FieldType(i)
+       if n.Class == PAUTO && !n.Addrtaken {
+               // Note: the _ field may appear several times.  But
+               // have no fear, identically-named but distinct Autos are
+               // ok, albeit maybe confusing for a debugger.
+               x := e.namedAuto(n.Sym.Name+"."+st.FieldName(i), ft)
+               return ssa.LocalSlot{x, ft, 0}
+       }
+       return ssa.LocalSlot{n, ft, name.Off + st.FieldOff(i)}
+}
+
 // namedAuto returns a new AUTO variable with the given name and type.
 func (e *ssaExport) namedAuto(name string, typ ssa.Type) ssa.GCNode {
        t := typ.(*Type)
index eee8e0384ad733d27255fcd56f70fb25f2cfbed1..25c1bcc2039d35e4062ae195878d84b0170b4727 100644 (file)
@@ -1193,6 +1193,9 @@ func (t *Type) FieldType(i int) ssa.Type {
 func (t *Type) FieldOff(i int) int64 {
        return t.Field(i).Offset
 }
+func (t *Type) FieldName(i int) string {
+       return t.Field(i).Sym.Name
+}
 
 func (t *Type) NumElem() int64 {
        t.wantEtype(TARRAY)
index 33357124fc5a5ab76ce7cc1ec78b4bef5f1107fe..2a676e39b3a1f7031581c76df91b5cabe5cc25ec 100644 (file)
@@ -103,6 +103,7 @@ type Frontend interface {
        SplitInterface(LocalSlot) (LocalSlot, LocalSlot)
        SplitSlice(LocalSlot) (LocalSlot, LocalSlot, LocalSlot)
        SplitComplex(LocalSlot) (LocalSlot, LocalSlot)
+       SplitStruct(LocalSlot, int) LocalSlot
 
        // Line returns a string describing the given line number.
        Line(int32) string
index eab9974106ce884aa5e02289e894ceb671343698..de02885d76f860c515bcb3a34ce9956fc2ff68a2 100644 (file)
@@ -21,6 +21,7 @@ func decomposeBuiltIn(f *Func) {
        // NOTE: the component values we are making are dead at this point.
        // We must do the opt pass before any deadcode elimination or we will
        // lose the name->value correspondence.
+       var newNames []LocalSlot
        for _, name := range f.Names {
                t := name.Type
                switch {
@@ -32,29 +33,31 @@ func decomposeBuiltIn(f *Func) {
                                elemType = f.Config.fe.TypeFloat32()
                        }
                        rName, iName := f.Config.fe.SplitComplex(name)
-                       f.Names = append(f.Names, rName, iName)
+                       newNames = append(newNames, rName, iName)
                        for _, v := range f.NamedValues[name] {
                                r := v.Block.NewValue1(v.Line, OpComplexReal, elemType, v)
                                i := v.Block.NewValue1(v.Line, OpComplexImag, elemType, v)
                                f.NamedValues[rName] = append(f.NamedValues[rName], r)
                                f.NamedValues[iName] = append(f.NamedValues[iName], i)
                        }
+                       delete(f.NamedValues, name)
                case t.IsString():
                        ptrType := f.Config.fe.TypeBytePtr()
                        lenType := f.Config.fe.TypeInt()
                        ptrName, lenName := f.Config.fe.SplitString(name)
-                       f.Names = append(f.Names, ptrName, lenName)
+                       newNames = append(newNames, ptrName, lenName)
                        for _, v := range f.NamedValues[name] {
                                ptr := v.Block.NewValue1(v.Line, OpStringPtr, ptrType, v)
                                len := v.Block.NewValue1(v.Line, OpStringLen, lenType, v)
                                f.NamedValues[ptrName] = append(f.NamedValues[ptrName], ptr)
                                f.NamedValues[lenName] = append(f.NamedValues[lenName], len)
                        }
+                       delete(f.NamedValues, name)
                case t.IsSlice():
                        ptrType := f.Config.fe.TypeBytePtr()
                        lenType := f.Config.fe.TypeInt()
                        ptrName, lenName, capName := f.Config.fe.SplitSlice(name)
-                       f.Names = append(f.Names, ptrName, lenName, capName)
+                       newNames = append(newNames, ptrName, lenName, capName)
                        for _, v := range f.NamedValues[name] {
                                ptr := v.Block.NewValue1(v.Line, OpSlicePtr, ptrType, v)
                                len := v.Block.NewValue1(v.Line, OpSliceLen, lenType, v)
@@ -63,20 +66,25 @@ func decomposeBuiltIn(f *Func) {
                                f.NamedValues[lenName] = append(f.NamedValues[lenName], len)
                                f.NamedValues[capName] = append(f.NamedValues[capName], cap)
                        }
+                       delete(f.NamedValues, name)
                case t.IsInterface():
                        ptrType := f.Config.fe.TypeBytePtr()
                        typeName, dataName := f.Config.fe.SplitInterface(name)
-                       f.Names = append(f.Names, typeName, dataName)
+                       newNames = append(newNames, typeName, dataName)
                        for _, v := range f.NamedValues[name] {
                                typ := v.Block.NewValue1(v.Line, OpITab, ptrType, v)
                                data := v.Block.NewValue1(v.Line, OpIData, ptrType, v)
                                f.NamedValues[typeName] = append(f.NamedValues[typeName], typ)
                                f.NamedValues[dataName] = append(f.NamedValues[dataName], data)
                        }
+                       delete(f.NamedValues, name)
                case t.Size() > f.Config.IntSize:
                        f.Unimplementedf("undecomposed named type %s", t)
+               default:
+                       newNames = append(newNames, name)
                }
        }
+       f.Names = newNames
 }
 
 func decomposeBuiltInPhi(v *Value) {
@@ -181,25 +189,32 @@ func decomposeUser(f *Func) {
        // We must do the opt pass before any deadcode elimination or we will
        // lose the name->value correspondence.
        i := 0
+       var fnames []LocalSlot
+       var newNames []LocalSlot
        for _, name := range f.Names {
                t := name.Type
                switch {
                case t.IsStruct():
                        n := t.NumFields()
+                       fnames = fnames[:0]
+                       for i := 0; i < n; i++ {
+                               fnames = append(fnames, f.Config.fe.SplitStruct(name, i))
+                       }
                        for _, v := range f.NamedValues[name] {
                                for i := 0; i < n; i++ {
-                                       fname := LocalSlot{name.N, t.FieldType(i), name.Off + t.FieldOff(i)} // TODO: use actual field name?
                                        x := v.Block.NewValue1I(v.Line, OpStructSelect, t.FieldType(i), int64(i), v)
-                                       f.NamedValues[fname] = append(f.NamedValues[fname], x)
+                                       f.NamedValues[fnames[i]] = append(f.NamedValues[fnames[i]], x)
                                }
                        }
                        delete(f.NamedValues, name)
+                       newNames = append(newNames, fnames...)
                default:
                        f.Names[i] = name
                        i++
                }
        }
        f.Names = f.Names[:i]
+       f.Names = append(f.Names, newNames...)
 }
 
 func decomposeUserPhi(v *Value) {
index ce577ef05566e24ebbda08f539e2377a1e1f92c5..0a67de9f0590774e0c321ba19f58e4e45a5f1c5a 100644 (file)
@@ -48,6 +48,9 @@ func (d DummyFrontend) SplitComplex(s LocalSlot) (LocalSlot, LocalSlot) {
        }
        return LocalSlot{s.N, d.TypeFloat32(), s.Off}, LocalSlot{s.N, d.TypeFloat32(), s.Off + 4}
 }
+func (d DummyFrontend) SplitStruct(s LocalSlot, i int) LocalSlot {
+       return LocalSlot{s.N, s.Type.FieldType(i), s.Off + s.Type.FieldOff(i)}
+}
 func (DummyFrontend) Line(line int32) string {
        return "unknown.go:0"
 }
index 9643b07556749bd94b1dd6239f00f7b83815d4ea..2a3de282cb5a093621a83ac68a52728ba0849ead 100644 (file)
@@ -31,9 +31,10 @@ type Type interface {
        ElemType() Type // given []T or *T or [n]T, return T
        PtrTo() Type    // given T, return *T
 
-       NumFields() int       // # of fields of a struct
-       FieldType(i int) Type // type of ith field of the struct
-       FieldOff(i int) int64 // offset of ith field of the struct
+       NumFields() int         // # of fields of a struct
+       FieldType(i int) Type   // type of ith field of the struct
+       FieldOff(i int) int64   // offset of ith field of the struct
+       FieldName(i int) string // name of ith field of the struct
 
        NumElem() int64 // # of elements of an array
 
@@ -53,30 +54,31 @@ type CompilerType struct {
        Int128 bool
 }
 
-func (t *CompilerType) Size() int64          { return t.size } // 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) IsPtrShaped() 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) IsVoid() bool         { return t.Void }
-func (t *CompilerType) String() string       { return t.Name }
-func (t *CompilerType) SimpleString() string { return t.Name }
-func (t *CompilerType) ElemType() Type       { panic("not implemented") }
-func (t *CompilerType) PtrTo() Type          { panic("not implemented") }
-func (t *CompilerType) NumFields() int       { panic("not implemented") }
-func (t *CompilerType) FieldType(i int) Type { panic("not implemented") }
-func (t *CompilerType) FieldOff(i int) int64 { panic("not implemented") }
-func (t *CompilerType) NumElem() int64       { panic("not implemented") }
+func (t *CompilerType) Size() int64            { return t.size } // 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) IsPtrShaped() 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) IsVoid() bool           { return t.Void }
+func (t *CompilerType) String() string         { return t.Name }
+func (t *CompilerType) SimpleString() string   { return t.Name }
+func (t *CompilerType) ElemType() Type         { panic("not implemented") }
+func (t *CompilerType) PtrTo() Type            { panic("not implemented") }
+func (t *CompilerType) NumFields() int         { panic("not implemented") }
+func (t *CompilerType) FieldType(i int) Type   { panic("not implemented") }
+func (t *CompilerType) FieldOff(i int) int64   { panic("not implemented") }
+func (t *CompilerType) FieldName(i int) string { panic("not implemented") }
+func (t *CompilerType) NumElem() int64         { panic("not implemented") }
 
 // Cmp is a comparison between values a and b.
 // -1 if a < b
index cd80abf03f4c4c151dca7b4deafc4e3242ea422d..3b1a892083dccdd548e7462968ae1e5fd9cb61e4 100644 (file)
@@ -24,30 +24,31 @@ type TypeImpl struct {
        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) IsPtrShaped() 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) IsVoid() bool         { return false }
-func (t *TypeImpl) String() string       { return t.Name }
-func (t *TypeImpl) SimpleString() string { return t.Name }
-func (t *TypeImpl) ElemType() Type       { return t.Elem_ }
-func (t *TypeImpl) PtrTo() Type          { panic("not implemented") }
-func (t *TypeImpl) NumFields() int       { panic("not implemented") }
-func (t *TypeImpl) FieldType(i int) Type { panic("not implemented") }
-func (t *TypeImpl) FieldOff(i int) int64 { panic("not implemented") }
-func (t *TypeImpl) NumElem() int64       { 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) IsPtrShaped() 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) IsVoid() bool           { return false }
+func (t *TypeImpl) String() string         { return t.Name }
+func (t *TypeImpl) SimpleString() string   { return t.Name }
+func (t *TypeImpl) ElemType() Type         { return t.Elem_ }
+func (t *TypeImpl) PtrTo() Type            { panic("not implemented") }
+func (t *TypeImpl) NumFields() int         { panic("not implemented") }
+func (t *TypeImpl) FieldType(i int) Type   { panic("not implemented") }
+func (t *TypeImpl) FieldOff(i int) int64   { panic("not implemented") }
+func (t *TypeImpl) FieldName(i int) string { panic("not implemented") }
+func (t *TypeImpl) NumElem() int64         { panic("not implemented") }
 
 func (t *TypeImpl) Equal(u Type) bool {
        x, ok := u.(*TypeImpl)