Skip to content

Commit

Permalink
cmd/compile: manage Slot array better
Browse files Browse the repository at this point in the history
steals idea from CL 312093

further investigation revealed additional duplicate
slots (equivalent, but not equal), so delete those too.

Rearranged Func.Names to be addresses of slots,
create canonical addresses so that split slots
(which use those addresses to refer to their parent,
and split slots can be further split)
will preserve "equivalent slots are equal".

Removes duplicates, improves metrics for "args at entry".

Change-Id: I5bbdcb50bd33655abcab3d27ad8cdce25499faaf
Reviewed-on: https://go-review.googlesource.com/c/go/+/312292
Trust: David Chase <[email protected]>
Run-TryBot: David Chase <[email protected]>
TryBot-Result: Go Bot <[email protected]>
Reviewed-by: Cherry Mui <[email protected]>
  • Loading branch information
dr2chase committed May 8, 2021
1 parent 68327e1 commit b38b1b2
Show file tree
Hide file tree
Showing 12 changed files with 238 additions and 220 deletions.
7 changes: 0 additions & 7 deletions src/cmd/compile/internal/ssa/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,13 +147,6 @@ type Frontend interface {

// Given the name for a compound type, returns the name we should use
// for the parts of that compound type.
SplitString(LocalSlot) (LocalSlot, LocalSlot)
SplitInterface(LocalSlot) (LocalSlot, LocalSlot)
SplitSlice(LocalSlot) (LocalSlot, LocalSlot, LocalSlot)
SplitComplex(LocalSlot) (LocalSlot, LocalSlot)
SplitStruct(LocalSlot, int) LocalSlot
SplitArray(LocalSlot) LocalSlot // array must be length 1
SplitInt64(LocalSlot) (LocalSlot, LocalSlot) // returns (hi, lo)
SplitSlot(parent *LocalSlot, suffix string, offset int64, t *types.Type) LocalSlot

// DerefItab dereferences an itab function
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/compile/internal/ssa/copyelim.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func copyelim(f *Func) {

// Update named values.
for _, name := range f.Names {
values := f.NamedValues[name]
values := f.NamedValues[*name]
for i, v := range values {
if v.Op == OpCopy {
values[i] = v.Args[0]
Expand Down
8 changes: 4 additions & 4 deletions src/cmd/compile/internal/ssa/deadcode.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ func deadcode(f *Func) {
for _, name := range f.Names {
j := 0
s.clear()
values := f.NamedValues[name]
values := f.NamedValues[*name]
for _, v := range values {
if live[v.ID] && !s.contains(v.ID) {
values[j] = v
Expand All @@ -232,19 +232,19 @@ func deadcode(f *Func) {
}
}
if j == 0 {
delete(f.NamedValues, name)
delete(f.NamedValues, *name)
} else {
f.Names[i] = name
i++
for k := len(values) - 1; k >= j; k-- {
values[k] = nil
}
f.NamedValues[name] = values[:j]
f.NamedValues[*name] = values[:j]
}
}
clearNames := f.Names[i:]
for j := range clearNames {
clearNames[j] = LocalSlot{}
clearNames[j] = nil
}
f.Names = f.Names[:i]

Expand Down
6 changes: 3 additions & 3 deletions src/cmd/compile/internal/ssa/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -367,12 +367,12 @@ func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingEnabled bool, stackOffset fu
state.slots = state.slots[:0]
state.vars = state.vars[:0]
for i, slot := range f.Names {
state.slots = append(state.slots, slot)
state.slots = append(state.slots, *slot)
if ir.IsSynthetic(slot.N) {
continue
}

topSlot := &slot
topSlot := slot
for topSlot.SplitOf != nil {
topSlot = topSlot.SplitOf
}
Expand Down Expand Up @@ -436,7 +436,7 @@ func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingEnabled bool, stackOffset fu
if ir.IsSynthetic(slot.N) {
continue
}
for _, value := range f.NamedValues[slot] {
for _, value := range f.NamedValues[*slot] {
state.valueNames[value.ID] = append(state.valueNames[value.ID], SlotID(i))
}
}
Expand Down
140 changes: 87 additions & 53 deletions src/cmd/compile/internal/ssa/decompose.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,64 +36,65 @@ func decomposeBuiltIn(f *Func) {
// accumulate new LocalSlots in newNames for addition after the iteration. This decomposition is for
// builtin types with leaf components, and thus there is no need to reprocess the newly create LocalSlots.
var toDelete []namedVal
var newNames []LocalSlot
var newNames []*LocalSlot
for i, name := range f.Names {
t := name.Type
switch {
case t.IsInteger() && t.Size() > f.Config.RegSize:
hiName, loName := f.fe.SplitInt64(name)
newNames = append(newNames, hiName, loName)
for j, v := range f.NamedValues[name] {
hiName, loName := f.SplitInt64(name)
newNames = maybeAppend2(f, newNames, hiName, loName)
for j, v := range f.NamedValues[*name] {
if v.Op != OpInt64Make {
continue
}
f.NamedValues[hiName] = append(f.NamedValues[hiName], v.Args[0])
f.NamedValues[loName] = append(f.NamedValues[loName], v.Args[1])
f.NamedValues[*hiName] = append(f.NamedValues[*hiName], v.Args[0])
f.NamedValues[*loName] = append(f.NamedValues[*loName], v.Args[1])
toDelete = append(toDelete, namedVal{i, j})
}
case t.IsComplex():
rName, iName := f.fe.SplitComplex(name)
newNames = append(newNames, rName, iName)
for j, v := range f.NamedValues[name] {
rName, iName := f.SplitComplex(name)
newNames = maybeAppend2(f, newNames, rName, iName)
for j, v := range f.NamedValues[*name] {
if v.Op != OpComplexMake {
continue
}
f.NamedValues[rName] = append(f.NamedValues[rName], v.Args[0])
f.NamedValues[iName] = append(f.NamedValues[iName], v.Args[1])
f.NamedValues[*rName] = append(f.NamedValues[*rName], v.Args[0])
f.NamedValues[*iName] = append(f.NamedValues[*iName], v.Args[1])
toDelete = append(toDelete, namedVal{i, j})
}
case t.IsString():
ptrName, lenName := f.fe.SplitString(name)
newNames = append(newNames, ptrName, lenName)
for j, v := range f.NamedValues[name] {
ptrName, lenName := f.SplitString(name)
newNames = maybeAppend2(f, newNames, ptrName, lenName)
for j, v := range f.NamedValues[*name] {
if v.Op != OpStringMake {
continue
}
f.NamedValues[ptrName] = append(f.NamedValues[ptrName], v.Args[0])
f.NamedValues[lenName] = append(f.NamedValues[lenName], v.Args[1])
f.NamedValues[*ptrName] = append(f.NamedValues[*ptrName], v.Args[0])
f.NamedValues[*lenName] = append(f.NamedValues[*lenName], v.Args[1])
toDelete = append(toDelete, namedVal{i, j})
}
case t.IsSlice():
ptrName, lenName, capName := f.fe.SplitSlice(name)
newNames = append(newNames, ptrName, lenName, capName)
for j, v := range f.NamedValues[name] {
ptrName, lenName, capName := f.SplitSlice(name)
newNames = maybeAppend2(f, newNames, ptrName, lenName)
newNames = maybeAppend(f, newNames, capName)
for j, v := range f.NamedValues[*name] {
if v.Op != OpSliceMake {
continue
}
f.NamedValues[ptrName] = append(f.NamedValues[ptrName], v.Args[0])
f.NamedValues[lenName] = append(f.NamedValues[lenName], v.Args[1])
f.NamedValues[capName] = append(f.NamedValues[capName], v.Args[2])
f.NamedValues[*ptrName] = append(f.NamedValues[*ptrName], v.Args[0])
f.NamedValues[*lenName] = append(f.NamedValues[*lenName], v.Args[1])
f.NamedValues[*capName] = append(f.NamedValues[*capName], v.Args[2])
toDelete = append(toDelete, namedVal{i, j})
}
case t.IsInterface():
typeName, dataName := f.fe.SplitInterface(name)
newNames = append(newNames, typeName, dataName)
for j, v := range f.NamedValues[name] {
typeName, dataName := f.SplitInterface(name)
newNames = maybeAppend2(f, newNames, typeName, dataName)
for j, v := range f.NamedValues[*name] {
if v.Op != OpIMake {
continue
}
f.NamedValues[typeName] = append(f.NamedValues[typeName], v.Args[0])
f.NamedValues[dataName] = append(f.NamedValues[dataName], v.Args[1])
f.NamedValues[*typeName] = append(f.NamedValues[*typeName], v.Args[0])
f.NamedValues[*dataName] = append(f.NamedValues[*dataName], v.Args[1])
toDelete = append(toDelete, namedVal{i, j})
}
case t.IsFloat():
Expand All @@ -107,6 +108,18 @@ func decomposeBuiltIn(f *Func) {
f.Names = append(f.Names, newNames...)
}

func maybeAppend(f *Func, ss []*LocalSlot, s *LocalSlot) []*LocalSlot {
if _, ok := f.NamedValues[*s]; !ok {
f.NamedValues[*s] = nil
return append(ss, s)
}
return ss
}

func maybeAppend2(f *Func, ss []*LocalSlot, s1, s2 *LocalSlot) []*LocalSlot {
return maybeAppend(f, maybeAppend(f, ss, s1), s2)
}

func decomposeBuiltInPhi(v *Value) {
switch {
case v.Type.IsInteger() && v.Type.Size() > v.Block.Func.Config.RegSize:
Expand Down Expand Up @@ -230,7 +243,7 @@ func decomposeUser(f *Func) {
}
// Split up named values into their components.
i := 0
var newNames []LocalSlot
var newNames []*LocalSlot
for _, name := range f.Names {
t := name.Type
switch {
Expand All @@ -250,7 +263,7 @@ func decomposeUser(f *Func) {
// decomposeUserArrayInto creates names for the element(s) of arrays referenced
// by name where possible, and appends those new names to slots, which is then
// returned.
func decomposeUserArrayInto(f *Func, name LocalSlot, slots []LocalSlot) []LocalSlot {
func decomposeUserArrayInto(f *Func, name *LocalSlot, slots []*LocalSlot) []*LocalSlot {
t := name.Type
if t.NumElem() == 0 {
// TODO(khr): Not sure what to do here. Probably nothing.
Expand All @@ -261,20 +274,20 @@ func decomposeUserArrayInto(f *Func, name LocalSlot, slots []LocalSlot) []LocalS
// shouldn't get here due to CanSSA
f.Fatalf("array not of size 1")
}
elemName := f.fe.SplitArray(name)
elemName := f.SplitArray(name)
var keep []*Value
for _, v := range f.NamedValues[name] {
for _, v := range f.NamedValues[*name] {
if v.Op != OpArrayMake1 {
keep = append(keep, v)
continue
}
f.NamedValues[elemName] = append(f.NamedValues[elemName], v.Args[0])
f.NamedValues[*elemName] = append(f.NamedValues[*elemName], v.Args[0])
}
if len(keep) == 0 {
// delete the name for the array as a whole
delete(f.NamedValues, name)
delete(f.NamedValues, *name)
} else {
f.NamedValues[name] = keep
f.NamedValues[*name] = keep
}

if t.Elem().IsArray() {
Expand All @@ -289,49 +302,49 @@ func decomposeUserArrayInto(f *Func, name LocalSlot, slots []LocalSlot) []LocalS
// decomposeUserStructInto creates names for the fields(s) of structs referenced
// by name where possible, and appends those new names to slots, which is then
// returned.
func decomposeUserStructInto(f *Func, name LocalSlot, slots []LocalSlot) []LocalSlot {
fnames := []LocalSlot{} // slots for struct in name
func decomposeUserStructInto(f *Func, name *LocalSlot, slots []*LocalSlot) []*LocalSlot {
fnames := []*LocalSlot{} // slots for struct in name
t := name.Type
n := t.NumFields()

for i := 0; i < n; i++ {
fs := f.fe.SplitStruct(name, i)
fs := f.SplitStruct(name, i)
fnames = append(fnames, fs)
// arrays and structs will be decomposed further, so
// there's no need to record a name
if !fs.Type.IsArray() && !fs.Type.IsStruct() {
slots = append(slots, fs)
slots = maybeAppend(f, slots, fs)
}
}

makeOp := StructMakeOp(n)
var keep []*Value
// create named values for each struct field
for _, v := range f.NamedValues[name] {
for _, v := range f.NamedValues[*name] {
if v.Op != makeOp {
keep = append(keep, v)
continue
}
for i := 0; i < len(fnames); i++ {
f.NamedValues[fnames[i]] = append(f.NamedValues[fnames[i]], v.Args[i])
f.NamedValues[*fnames[i]] = append(f.NamedValues[*fnames[i]], v.Args[i])
}
}
if len(keep) == 0 {
// delete the name for the struct as a whole
delete(f.NamedValues, name)
delete(f.NamedValues, *name)
} else {
f.NamedValues[name] = keep
f.NamedValues[*name] = keep
}

// now that this f.NamedValues contains values for the struct
// fields, recurse into nested structs
for i := 0; i < n; i++ {
if name.Type.FieldType(i).IsStruct() {
slots = decomposeUserStructInto(f, fnames[i], slots)
delete(f.NamedValues, fnames[i])
delete(f.NamedValues, *fnames[i])
} else if name.Type.FieldType(i).IsArray() {
slots = decomposeUserArrayInto(f, fnames[i], slots)
delete(f.NamedValues, fnames[i])
delete(f.NamedValues, *fnames[i])
}
}
return slots
Expand Down Expand Up @@ -416,9 +429,10 @@ type namedVal struct {
locIndex, valIndex int // f.NamedValues[f.Names[locIndex]][valIndex] = key
}

// deleteNamedVals removes particular values with debugger names from f's naming data structures
// deleteNamedVals removes particular values with debugger names from f's naming data structures,
// removes all values with OpInvalid, and re-sorts the list of Names.
func deleteNamedVals(f *Func, toDelete []namedVal) {
// Arrange to delete from larger indices to smaller, to ensure swap-with-end deletion does not invalid pending indices.
// Arrange to delete from larger indices to smaller, to ensure swap-with-end deletion does not invalidate pending indices.
sort.Slice(toDelete, func(i, j int) bool {
if toDelete[i].locIndex != toDelete[j].locIndex {
return toDelete[i].locIndex > toDelete[j].locIndex
Expand All @@ -430,16 +444,36 @@ func deleteNamedVals(f *Func, toDelete []namedVal) {
// Get rid of obsolete names
for _, d := range toDelete {
loc := f.Names[d.locIndex]
vals := f.NamedValues[loc]
vals := f.NamedValues[*loc]
l := len(vals) - 1
if l > 0 {
vals[d.valIndex] = vals[l]
f.NamedValues[loc] = vals[:l]
} else {
delete(f.NamedValues, loc)
l = len(f.Names) - 1
f.Names[d.locIndex] = f.Names[l]
f.Names = f.Names[:l]
}
vals[l] = nil
f.NamedValues[*loc] = vals[:l]
}
// Delete locations with no values attached.
end := len(f.Names)
for i := len(f.Names) - 1; i >= 0; i-- {
loc := f.Names[i]
vals := f.NamedValues[*loc]
last := len(vals)
for j := len(vals) - 1; j >= 0; j-- {
if vals[j].Op == OpInvalid {
last--
vals[j] = vals[last]
vals[last] = nil
}
}
if last < len(vals) {
f.NamedValues[*loc] = vals[:last]
}
if len(vals) == 0 {
delete(f.NamedValues, *loc)
end--
f.Names[i] = f.Names[end]
f.Names[end] = nil
}
}
f.Names = f.Names[:end]
}
Loading

0 comments on commit b38b1b2

Please sign in to comment.