Commit b04e1452 authored by Keith Randall's avatar Keith Randall

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/21389Reviewed-by: default avatarDavid Chase <drchase@google.com>
parent 6c6089b3
...@@ -4227,7 +4227,7 @@ func (e *ssaExport) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.Local ...@@ -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) { func (e *ssaExport) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot, ssa.LocalSlot) {
n := name.N.(*Node) n := name.N.(*Node)
ptrType := Ptrto(n.Type.Elem()) ptrType := Ptrto(name.Type.ElemType().(*Type))
lenType := Types[TINT] lenType := Types[TINT]
if n.Class == PAUTO && !n.Addrtaken { if n.Class == PAUTO && !n.Addrtaken {
// Split this slice up into three separate variables. // Split this slice up into three separate variables.
...@@ -4261,6 +4261,20 @@ func (e *ssaExport) SplitComplex(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSl ...@@ -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} 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. // namedAuto returns a new AUTO variable with the given name and type.
func (e *ssaExport) namedAuto(name string, typ ssa.Type) ssa.GCNode { func (e *ssaExport) namedAuto(name string, typ ssa.Type) ssa.GCNode {
t := typ.(*Type) t := typ.(*Type)
......
...@@ -1193,6 +1193,9 @@ func (t *Type) FieldType(i int) ssa.Type { ...@@ -1193,6 +1193,9 @@ func (t *Type) FieldType(i int) ssa.Type {
func (t *Type) FieldOff(i int) int64 { func (t *Type) FieldOff(i int) int64 {
return t.Field(i).Offset return t.Field(i).Offset
} }
func (t *Type) FieldName(i int) string {
return t.Field(i).Sym.Name
}
func (t *Type) NumElem() int64 { func (t *Type) NumElem() int64 {
t.wantEtype(TARRAY) t.wantEtype(TARRAY)
......
...@@ -103,6 +103,7 @@ type Frontend interface { ...@@ -103,6 +103,7 @@ type Frontend interface {
SplitInterface(LocalSlot) (LocalSlot, LocalSlot) SplitInterface(LocalSlot) (LocalSlot, LocalSlot)
SplitSlice(LocalSlot) (LocalSlot, LocalSlot, LocalSlot) SplitSlice(LocalSlot) (LocalSlot, LocalSlot, LocalSlot)
SplitComplex(LocalSlot) (LocalSlot, LocalSlot) SplitComplex(LocalSlot) (LocalSlot, LocalSlot)
SplitStruct(LocalSlot, int) LocalSlot
// Line returns a string describing the given line number. // Line returns a string describing the given line number.
Line(int32) string Line(int32) string
......
...@@ -21,6 +21,7 @@ func decomposeBuiltIn(f *Func) { ...@@ -21,6 +21,7 @@ func decomposeBuiltIn(f *Func) {
// NOTE: the component values we are making are dead at this point. // 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 // We must do the opt pass before any deadcode elimination or we will
// lose the name->value correspondence. // lose the name->value correspondence.
var newNames []LocalSlot
for _, name := range f.Names { for _, name := range f.Names {
t := name.Type t := name.Type
switch { switch {
...@@ -32,29 +33,31 @@ func decomposeBuiltIn(f *Func) { ...@@ -32,29 +33,31 @@ func decomposeBuiltIn(f *Func) {
elemType = f.Config.fe.TypeFloat32() elemType = f.Config.fe.TypeFloat32()
} }
rName, iName := f.Config.fe.SplitComplex(name) 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] { for _, v := range f.NamedValues[name] {
r := v.Block.NewValue1(v.Line, OpComplexReal, elemType, v) r := v.Block.NewValue1(v.Line, OpComplexReal, elemType, v)
i := v.Block.NewValue1(v.Line, OpComplexImag, elemType, v) i := v.Block.NewValue1(v.Line, OpComplexImag, elemType, v)
f.NamedValues[rName] = append(f.NamedValues[rName], r) f.NamedValues[rName] = append(f.NamedValues[rName], r)
f.NamedValues[iName] = append(f.NamedValues[iName], i) f.NamedValues[iName] = append(f.NamedValues[iName], i)
} }
delete(f.NamedValues, name)
case t.IsString(): case t.IsString():
ptrType := f.Config.fe.TypeBytePtr() ptrType := f.Config.fe.TypeBytePtr()
lenType := f.Config.fe.TypeInt() lenType := f.Config.fe.TypeInt()
ptrName, lenName := f.Config.fe.SplitString(name) 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] { for _, v := range f.NamedValues[name] {
ptr := v.Block.NewValue1(v.Line, OpStringPtr, ptrType, v) ptr := v.Block.NewValue1(v.Line, OpStringPtr, ptrType, v)
len := v.Block.NewValue1(v.Line, OpStringLen, lenType, v) len := v.Block.NewValue1(v.Line, OpStringLen, lenType, v)
f.NamedValues[ptrName] = append(f.NamedValues[ptrName], ptr) f.NamedValues[ptrName] = append(f.NamedValues[ptrName], ptr)
f.NamedValues[lenName] = append(f.NamedValues[lenName], len) f.NamedValues[lenName] = append(f.NamedValues[lenName], len)
} }
delete(f.NamedValues, name)
case t.IsSlice(): case t.IsSlice():
ptrType := f.Config.fe.TypeBytePtr() ptrType := f.Config.fe.TypeBytePtr()
lenType := f.Config.fe.TypeInt() lenType := f.Config.fe.TypeInt()
ptrName, lenName, capName := f.Config.fe.SplitSlice(name) 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] { for _, v := range f.NamedValues[name] {
ptr := v.Block.NewValue1(v.Line, OpSlicePtr, ptrType, v) ptr := v.Block.NewValue1(v.Line, OpSlicePtr, ptrType, v)
len := v.Block.NewValue1(v.Line, OpSliceLen, lenType, v) len := v.Block.NewValue1(v.Line, OpSliceLen, lenType, v)
...@@ -63,20 +66,25 @@ func decomposeBuiltIn(f *Func) { ...@@ -63,20 +66,25 @@ func decomposeBuiltIn(f *Func) {
f.NamedValues[lenName] = append(f.NamedValues[lenName], len) f.NamedValues[lenName] = append(f.NamedValues[lenName], len)
f.NamedValues[capName] = append(f.NamedValues[capName], cap) f.NamedValues[capName] = append(f.NamedValues[capName], cap)
} }
delete(f.NamedValues, name)
case t.IsInterface(): case t.IsInterface():
ptrType := f.Config.fe.TypeBytePtr() ptrType := f.Config.fe.TypeBytePtr()
typeName, dataName := f.Config.fe.SplitInterface(name) 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] { for _, v := range f.NamedValues[name] {
typ := v.Block.NewValue1(v.Line, OpITab, ptrType, v) typ := v.Block.NewValue1(v.Line, OpITab, ptrType, v)
data := v.Block.NewValue1(v.Line, OpIData, ptrType, v) data := v.Block.NewValue1(v.Line, OpIData, ptrType, v)
f.NamedValues[typeName] = append(f.NamedValues[typeName], typ) f.NamedValues[typeName] = append(f.NamedValues[typeName], typ)
f.NamedValues[dataName] = append(f.NamedValues[dataName], data) f.NamedValues[dataName] = append(f.NamedValues[dataName], data)
} }
delete(f.NamedValues, name)
case t.Size() > f.Config.IntSize: case t.Size() > f.Config.IntSize:
f.Unimplementedf("undecomposed named type %s", t) f.Unimplementedf("undecomposed named type %s", t)
default:
newNames = append(newNames, name)
} }
} }
f.Names = newNames
} }
func decomposeBuiltInPhi(v *Value) { func decomposeBuiltInPhi(v *Value) {
...@@ -181,25 +189,32 @@ func decomposeUser(f *Func) { ...@@ -181,25 +189,32 @@ func decomposeUser(f *Func) {
// We must do the opt pass before any deadcode elimination or we will // We must do the opt pass before any deadcode elimination or we will
// lose the name->value correspondence. // lose the name->value correspondence.
i := 0 i := 0
var fnames []LocalSlot
var newNames []LocalSlot
for _, name := range f.Names { for _, name := range f.Names {
t := name.Type t := name.Type
switch { switch {
case t.IsStruct(): case t.IsStruct():
n := t.NumFields() 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 _, v := range f.NamedValues[name] {
for i := 0; i < n; i++ { 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) 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) delete(f.NamedValues, name)
newNames = append(newNames, fnames...)
default: default:
f.Names[i] = name f.Names[i] = name
i++ i++
} }
} }
f.Names = f.Names[:i] f.Names = f.Names[:i]
f.Names = append(f.Names, newNames...)
} }
func decomposeUserPhi(v *Value) { func decomposeUserPhi(v *Value) {
......
...@@ -48,6 +48,9 @@ func (d DummyFrontend) SplitComplex(s LocalSlot) (LocalSlot, LocalSlot) { ...@@ -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} 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 { func (DummyFrontend) Line(line int32) string {
return "unknown.go:0" return "unknown.go:0"
} }
......
...@@ -31,9 +31,10 @@ type Type interface { ...@@ -31,9 +31,10 @@ type Type interface {
ElemType() Type // given []T or *T or [n]T, return T ElemType() Type // given []T or *T or [n]T, return T
PtrTo() Type // given T, return *T PtrTo() Type // given T, return *T
NumFields() int // # of fields of a struct NumFields() int // # of fields of a struct
FieldType(i int) Type // type of ith field of the struct FieldType(i int) Type // type of ith field of the struct
FieldOff(i int) int64 // offset 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 NumElem() int64 // # of elements of an array
...@@ -53,30 +54,31 @@ type CompilerType struct { ...@@ -53,30 +54,31 @@ type CompilerType struct {
Int128 bool Int128 bool
} }
func (t *CompilerType) Size() int64 { return t.size } // Size in bytes func (t *CompilerType) Size() int64 { return t.size } // Size in bytes
func (t *CompilerType) Alignment() int64 { return 0 } func (t *CompilerType) Alignment() int64 { return 0 }
func (t *CompilerType) IsBoolean() bool { return false } func (t *CompilerType) IsBoolean() bool { return false }
func (t *CompilerType) IsInteger() bool { return false } func (t *CompilerType) IsInteger() bool { return false }
func (t *CompilerType) IsSigned() bool { return false } func (t *CompilerType) IsSigned() bool { return false }
func (t *CompilerType) IsFloat() bool { return false } func (t *CompilerType) IsFloat() bool { return false }
func (t *CompilerType) IsComplex() bool { return false } func (t *CompilerType) IsComplex() bool { return false }
func (t *CompilerType) IsPtrShaped() bool { return false } func (t *CompilerType) IsPtrShaped() bool { return false }
func (t *CompilerType) IsString() bool { return false } func (t *CompilerType) IsString() bool { return false }
func (t *CompilerType) IsSlice() bool { return false } func (t *CompilerType) IsSlice() bool { return false }
func (t *CompilerType) IsArray() bool { return false } func (t *CompilerType) IsArray() bool { return false }
func (t *CompilerType) IsStruct() bool { return false } func (t *CompilerType) IsStruct() bool { return false }
func (t *CompilerType) IsInterface() bool { return false } func (t *CompilerType) IsInterface() bool { return false }
func (t *CompilerType) IsMemory() bool { return t.Memory } func (t *CompilerType) IsMemory() bool { return t.Memory }
func (t *CompilerType) IsFlags() bool { return t.Flags } func (t *CompilerType) IsFlags() bool { return t.Flags }
func (t *CompilerType) IsVoid() bool { return t.Void } func (t *CompilerType) IsVoid() bool { return t.Void }
func (t *CompilerType) String() string { return t.Name } func (t *CompilerType) String() string { return t.Name }
func (t *CompilerType) SimpleString() string { return t.Name } func (t *CompilerType) SimpleString() string { return t.Name }
func (t *CompilerType) ElemType() Type { panic("not implemented") } func (t *CompilerType) ElemType() Type { panic("not implemented") }
func (t *CompilerType) PtrTo() Type { panic("not implemented") } func (t *CompilerType) PtrTo() Type { panic("not implemented") }
func (t *CompilerType) NumFields() int { panic("not implemented") } func (t *CompilerType) NumFields() int { panic("not implemented") }
func (t *CompilerType) FieldType(i int) Type { 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) FieldOff(i int) int64 { panic("not implemented") }
func (t *CompilerType) NumElem() 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. // Cmp is a comparison between values a and b.
// -1 if a < b // -1 if a < b
......
...@@ -24,30 +24,31 @@ type TypeImpl struct { ...@@ -24,30 +24,31 @@ type TypeImpl struct {
Name string Name string
} }
func (t *TypeImpl) Size() int64 { return t.Size_ } func (t *TypeImpl) Size() int64 { return t.Size_ }
func (t *TypeImpl) Alignment() int64 { return t.Align } func (t *TypeImpl) Alignment() int64 { return t.Align }
func (t *TypeImpl) IsBoolean() bool { return t.Boolean } func (t *TypeImpl) IsBoolean() bool { return t.Boolean }
func (t *TypeImpl) IsInteger() bool { return t.Integer } func (t *TypeImpl) IsInteger() bool { return t.Integer }
func (t *TypeImpl) IsSigned() bool { return t.Signed } func (t *TypeImpl) IsSigned() bool { return t.Signed }
func (t *TypeImpl) IsFloat() bool { return t.Float } func (t *TypeImpl) IsFloat() bool { return t.Float }
func (t *TypeImpl) IsComplex() bool { return t.Complex } func (t *TypeImpl) IsComplex() bool { return t.Complex }
func (t *TypeImpl) IsPtrShaped() bool { return t.Ptr } func (t *TypeImpl) IsPtrShaped() bool { return t.Ptr }
func (t *TypeImpl) IsString() bool { return t.string } func (t *TypeImpl) IsString() bool { return t.string }
func (t *TypeImpl) IsSlice() bool { return t.slice } func (t *TypeImpl) IsSlice() bool { return t.slice }
func (t *TypeImpl) IsArray() bool { return t.array } func (t *TypeImpl) IsArray() bool { return t.array }
func (t *TypeImpl) IsStruct() bool { return t.struct_ } func (t *TypeImpl) IsStruct() bool { return t.struct_ }
func (t *TypeImpl) IsInterface() bool { return t.inter } func (t *TypeImpl) IsInterface() bool { return t.inter }
func (t *TypeImpl) IsMemory() bool { return false } func (t *TypeImpl) IsMemory() bool { return false }
func (t *TypeImpl) IsFlags() bool { return false } func (t *TypeImpl) IsFlags() bool { return false }
func (t *TypeImpl) IsVoid() bool { return false } func (t *TypeImpl) IsVoid() bool { return false }
func (t *TypeImpl) String() string { return t.Name } func (t *TypeImpl) String() string { return t.Name }
func (t *TypeImpl) SimpleString() string { return t.Name } func (t *TypeImpl) SimpleString() string { return t.Name }
func (t *TypeImpl) ElemType() Type { return t.Elem_ } func (t *TypeImpl) ElemType() Type { return t.Elem_ }
func (t *TypeImpl) PtrTo() Type { panic("not implemented") } func (t *TypeImpl) PtrTo() Type { panic("not implemented") }
func (t *TypeImpl) NumFields() int { panic("not implemented") } func (t *TypeImpl) NumFields() int { panic("not implemented") }
func (t *TypeImpl) FieldType(i int) Type { 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) FieldOff(i int) int64 { panic("not implemented") }
func (t *TypeImpl) NumElem() 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 { func (t *TypeImpl) Equal(u Type) bool {
x, ok := u.(*TypeImpl) x, ok := u.(*TypeImpl)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment