From: Keith Randall Date: Fri, 1 Apr 2016 04:24:10 +0000 (-0700) Subject: cmd/compile: fix naming of decomposed structs X-Git-Tag: go1.7beta1~773 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=b04e145248d5d3721a41d4bb26704fdb43caaf38;p=gostls13.git cmd/compile: fix naming of decomposed structs 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 --- diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index d69559d945..5ee370395b 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -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) diff --git a/src/cmd/compile/internal/gc/type.go b/src/cmd/compile/internal/gc/type.go index eee8e0384a..25c1bcc203 100644 --- a/src/cmd/compile/internal/gc/type.go +++ b/src/cmd/compile/internal/gc/type.go @@ -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) diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go index 33357124fc..2a676e39b3 100644 --- a/src/cmd/compile/internal/ssa/config.go +++ b/src/cmd/compile/internal/ssa/config.go @@ -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 diff --git a/src/cmd/compile/internal/ssa/decompose.go b/src/cmd/compile/internal/ssa/decompose.go index eab9974106..de02885d76 100644 --- a/src/cmd/compile/internal/ssa/decompose.go +++ b/src/cmd/compile/internal/ssa/decompose.go @@ -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) { diff --git a/src/cmd/compile/internal/ssa/export_test.go b/src/cmd/compile/internal/ssa/export_test.go index ce577ef055..0a67de9f05 100644 --- a/src/cmd/compile/internal/ssa/export_test.go +++ b/src/cmd/compile/internal/ssa/export_test.go @@ -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" } diff --git a/src/cmd/compile/internal/ssa/type.go b/src/cmd/compile/internal/ssa/type.go index 9643b07556..2a3de282cb 100644 --- a/src/cmd/compile/internal/ssa/type.go +++ b/src/cmd/compile/internal/ssa/type.go @@ -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 diff --git a/src/cmd/compile/internal/ssa/type_test.go b/src/cmd/compile/internal/ssa/type_test.go index cd80abf03f..3b1a892083 100644 --- a/src/cmd/compile/internal/ssa/type_test.go +++ b/src/cmd/compile/internal/ssa/type_test.go @@ -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)