mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: manage Slot array better
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 <drchase@google.com> Run-TryBot: David Chase <drchase@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cherry Mui <cherryyz@google.com>
This commit is contained in:
parent
68327e1aa1
commit
b38b1b2f9a
12 changed files with 238 additions and 220 deletions
|
|
@ -147,13 +147,6 @@ type Frontend interface {
|
||||||
|
|
||||||
// Given the name for a compound type, returns the name we should use
|
// Given the name for a compound type, returns the name we should use
|
||||||
// for the parts of that compound type.
|
// 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
|
SplitSlot(parent *LocalSlot, suffix string, offset int64, t *types.Type) LocalSlot
|
||||||
|
|
||||||
// DerefItab dereferences an itab function
|
// DerefItab dereferences an itab function
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ func copyelim(f *Func) {
|
||||||
|
|
||||||
// Update named values.
|
// Update named values.
|
||||||
for _, name := range f.Names {
|
for _, name := range f.Names {
|
||||||
values := f.NamedValues[name]
|
values := f.NamedValues[*name]
|
||||||
for i, v := range values {
|
for i, v := range values {
|
||||||
if v.Op == OpCopy {
|
if v.Op == OpCopy {
|
||||||
values[i] = v.Args[0]
|
values[i] = v.Args[0]
|
||||||
|
|
|
||||||
|
|
@ -223,7 +223,7 @@ func deadcode(f *Func) {
|
||||||
for _, name := range f.Names {
|
for _, name := range f.Names {
|
||||||
j := 0
|
j := 0
|
||||||
s.clear()
|
s.clear()
|
||||||
values := f.NamedValues[name]
|
values := f.NamedValues[*name]
|
||||||
for _, v := range values {
|
for _, v := range values {
|
||||||
if live[v.ID] && !s.contains(v.ID) {
|
if live[v.ID] && !s.contains(v.ID) {
|
||||||
values[j] = v
|
values[j] = v
|
||||||
|
|
@ -232,19 +232,19 @@ func deadcode(f *Func) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if j == 0 {
|
if j == 0 {
|
||||||
delete(f.NamedValues, name)
|
delete(f.NamedValues, *name)
|
||||||
} else {
|
} else {
|
||||||
f.Names[i] = name
|
f.Names[i] = name
|
||||||
i++
|
i++
|
||||||
for k := len(values) - 1; k >= j; k-- {
|
for k := len(values) - 1; k >= j; k-- {
|
||||||
values[k] = nil
|
values[k] = nil
|
||||||
}
|
}
|
||||||
f.NamedValues[name] = values[:j]
|
f.NamedValues[*name] = values[:j]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
clearNames := f.Names[i:]
|
clearNames := f.Names[i:]
|
||||||
for j := range clearNames {
|
for j := range clearNames {
|
||||||
clearNames[j] = LocalSlot{}
|
clearNames[j] = nil
|
||||||
}
|
}
|
||||||
f.Names = f.Names[:i]
|
f.Names = f.Names[:i]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -367,12 +367,12 @@ func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingEnabled bool, stackOffset fu
|
||||||
state.slots = state.slots[:0]
|
state.slots = state.slots[:0]
|
||||||
state.vars = state.vars[:0]
|
state.vars = state.vars[:0]
|
||||||
for i, slot := range f.Names {
|
for i, slot := range f.Names {
|
||||||
state.slots = append(state.slots, slot)
|
state.slots = append(state.slots, *slot)
|
||||||
if ir.IsSynthetic(slot.N) {
|
if ir.IsSynthetic(slot.N) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
topSlot := &slot
|
topSlot := slot
|
||||||
for topSlot.SplitOf != nil {
|
for topSlot.SplitOf != nil {
|
||||||
topSlot = topSlot.SplitOf
|
topSlot = topSlot.SplitOf
|
||||||
}
|
}
|
||||||
|
|
@ -436,7 +436,7 @@ func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingEnabled bool, stackOffset fu
|
||||||
if ir.IsSynthetic(slot.N) {
|
if ir.IsSynthetic(slot.N) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for _, value := range f.NamedValues[slot] {
|
for _, value := range f.NamedValues[*slot] {
|
||||||
state.valueNames[value.ID] = append(state.valueNames[value.ID], SlotID(i))
|
state.valueNames[value.ID] = append(state.valueNames[value.ID], SlotID(i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,64 +36,65 @@ func decomposeBuiltIn(f *Func) {
|
||||||
// accumulate new LocalSlots in newNames for addition after the iteration. This decomposition is for
|
// 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.
|
// builtin types with leaf components, and thus there is no need to reprocess the newly create LocalSlots.
|
||||||
var toDelete []namedVal
|
var toDelete []namedVal
|
||||||
var newNames []LocalSlot
|
var newNames []*LocalSlot
|
||||||
for i, name := range f.Names {
|
for i, name := range f.Names {
|
||||||
t := name.Type
|
t := name.Type
|
||||||
switch {
|
switch {
|
||||||
case t.IsInteger() && t.Size() > f.Config.RegSize:
|
case t.IsInteger() && t.Size() > f.Config.RegSize:
|
||||||
hiName, loName := f.fe.SplitInt64(name)
|
hiName, loName := f.SplitInt64(name)
|
||||||
newNames = append(newNames, hiName, loName)
|
newNames = maybeAppend2(f, newNames, hiName, loName)
|
||||||
for j, v := range f.NamedValues[name] {
|
for j, v := range f.NamedValues[*name] {
|
||||||
if v.Op != OpInt64Make {
|
if v.Op != OpInt64Make {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
f.NamedValues[hiName] = append(f.NamedValues[hiName], v.Args[0])
|
f.NamedValues[*hiName] = append(f.NamedValues[*hiName], v.Args[0])
|
||||||
f.NamedValues[loName] = append(f.NamedValues[loName], v.Args[1])
|
f.NamedValues[*loName] = append(f.NamedValues[*loName], v.Args[1])
|
||||||
toDelete = append(toDelete, namedVal{i, j})
|
toDelete = append(toDelete, namedVal{i, j})
|
||||||
}
|
}
|
||||||
case t.IsComplex():
|
case t.IsComplex():
|
||||||
rName, iName := f.fe.SplitComplex(name)
|
rName, iName := f.SplitComplex(name)
|
||||||
newNames = append(newNames, rName, iName)
|
newNames = maybeAppend2(f, newNames, rName, iName)
|
||||||
for j, v := range f.NamedValues[name] {
|
for j, v := range f.NamedValues[*name] {
|
||||||
if v.Op != OpComplexMake {
|
if v.Op != OpComplexMake {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
f.NamedValues[rName] = append(f.NamedValues[rName], v.Args[0])
|
f.NamedValues[*rName] = append(f.NamedValues[*rName], v.Args[0])
|
||||||
f.NamedValues[iName] = append(f.NamedValues[iName], v.Args[1])
|
f.NamedValues[*iName] = append(f.NamedValues[*iName], v.Args[1])
|
||||||
toDelete = append(toDelete, namedVal{i, j})
|
toDelete = append(toDelete, namedVal{i, j})
|
||||||
}
|
}
|
||||||
case t.IsString():
|
case t.IsString():
|
||||||
ptrName, lenName := f.fe.SplitString(name)
|
ptrName, lenName := f.SplitString(name)
|
||||||
newNames = append(newNames, ptrName, lenName)
|
newNames = maybeAppend2(f, newNames, ptrName, lenName)
|
||||||
for j, v := range f.NamedValues[name] {
|
for j, v := range f.NamedValues[*name] {
|
||||||
if v.Op != OpStringMake {
|
if v.Op != OpStringMake {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
f.NamedValues[ptrName] = append(f.NamedValues[ptrName], v.Args[0])
|
f.NamedValues[*ptrName] = append(f.NamedValues[*ptrName], v.Args[0])
|
||||||
f.NamedValues[lenName] = append(f.NamedValues[lenName], v.Args[1])
|
f.NamedValues[*lenName] = append(f.NamedValues[*lenName], v.Args[1])
|
||||||
toDelete = append(toDelete, namedVal{i, j})
|
toDelete = append(toDelete, namedVal{i, j})
|
||||||
}
|
}
|
||||||
case t.IsSlice():
|
case t.IsSlice():
|
||||||
ptrName, lenName, capName := f.fe.SplitSlice(name)
|
ptrName, lenName, capName := f.SplitSlice(name)
|
||||||
newNames = append(newNames, ptrName, lenName, capName)
|
newNames = maybeAppend2(f, newNames, ptrName, lenName)
|
||||||
for j, v := range f.NamedValues[name] {
|
newNames = maybeAppend(f, newNames, capName)
|
||||||
|
for j, v := range f.NamedValues[*name] {
|
||||||
if v.Op != OpSliceMake {
|
if v.Op != OpSliceMake {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
f.NamedValues[ptrName] = append(f.NamedValues[ptrName], v.Args[0])
|
f.NamedValues[*ptrName] = append(f.NamedValues[*ptrName], v.Args[0])
|
||||||
f.NamedValues[lenName] = append(f.NamedValues[lenName], v.Args[1])
|
f.NamedValues[*lenName] = append(f.NamedValues[*lenName], v.Args[1])
|
||||||
f.NamedValues[capName] = append(f.NamedValues[capName], v.Args[2])
|
f.NamedValues[*capName] = append(f.NamedValues[*capName], v.Args[2])
|
||||||
toDelete = append(toDelete, namedVal{i, j})
|
toDelete = append(toDelete, namedVal{i, j})
|
||||||
}
|
}
|
||||||
case t.IsInterface():
|
case t.IsInterface():
|
||||||
typeName, dataName := f.fe.SplitInterface(name)
|
typeName, dataName := f.SplitInterface(name)
|
||||||
newNames = append(newNames, typeName, dataName)
|
newNames = maybeAppend2(f, newNames, typeName, dataName)
|
||||||
for j, v := range f.NamedValues[name] {
|
for j, v := range f.NamedValues[*name] {
|
||||||
if v.Op != OpIMake {
|
if v.Op != OpIMake {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
f.NamedValues[typeName] = append(f.NamedValues[typeName], v.Args[0])
|
f.NamedValues[*typeName] = append(f.NamedValues[*typeName], v.Args[0])
|
||||||
f.NamedValues[dataName] = append(f.NamedValues[dataName], v.Args[1])
|
f.NamedValues[*dataName] = append(f.NamedValues[*dataName], v.Args[1])
|
||||||
toDelete = append(toDelete, namedVal{i, j})
|
toDelete = append(toDelete, namedVal{i, j})
|
||||||
}
|
}
|
||||||
case t.IsFloat():
|
case t.IsFloat():
|
||||||
|
|
@ -107,6 +108,18 @@ func decomposeBuiltIn(f *Func) {
|
||||||
f.Names = append(f.Names, newNames...)
|
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) {
|
func decomposeBuiltInPhi(v *Value) {
|
||||||
switch {
|
switch {
|
||||||
case v.Type.IsInteger() && v.Type.Size() > v.Block.Func.Config.RegSize:
|
case v.Type.IsInteger() && v.Type.Size() > v.Block.Func.Config.RegSize:
|
||||||
|
|
@ -230,7 +243,7 @@ func decomposeUser(f *Func) {
|
||||||
}
|
}
|
||||||
// Split up named values into their components.
|
// Split up named values into their components.
|
||||||
i := 0
|
i := 0
|
||||||
var newNames []LocalSlot
|
var newNames []*LocalSlot
|
||||||
for _, name := range f.Names {
|
for _, name := range f.Names {
|
||||||
t := name.Type
|
t := name.Type
|
||||||
switch {
|
switch {
|
||||||
|
|
@ -250,7 +263,7 @@ func decomposeUser(f *Func) {
|
||||||
// decomposeUserArrayInto creates names for the element(s) of arrays referenced
|
// decomposeUserArrayInto creates names for the element(s) of arrays referenced
|
||||||
// by name where possible, and appends those new names to slots, which is then
|
// by name where possible, and appends those new names to slots, which is then
|
||||||
// returned.
|
// returned.
|
||||||
func decomposeUserArrayInto(f *Func, name LocalSlot, slots []LocalSlot) []LocalSlot {
|
func decomposeUserArrayInto(f *Func, name *LocalSlot, slots []*LocalSlot) []*LocalSlot {
|
||||||
t := name.Type
|
t := name.Type
|
||||||
if t.NumElem() == 0 {
|
if t.NumElem() == 0 {
|
||||||
// TODO(khr): Not sure what to do here. Probably nothing.
|
// TODO(khr): Not sure what to do here. Probably nothing.
|
||||||
|
|
@ -261,20 +274,20 @@ func decomposeUserArrayInto(f *Func, name LocalSlot, slots []LocalSlot) []LocalS
|
||||||
// shouldn't get here due to CanSSA
|
// shouldn't get here due to CanSSA
|
||||||
f.Fatalf("array not of size 1")
|
f.Fatalf("array not of size 1")
|
||||||
}
|
}
|
||||||
elemName := f.fe.SplitArray(name)
|
elemName := f.SplitArray(name)
|
||||||
var keep []*Value
|
var keep []*Value
|
||||||
for _, v := range f.NamedValues[name] {
|
for _, v := range f.NamedValues[*name] {
|
||||||
if v.Op != OpArrayMake1 {
|
if v.Op != OpArrayMake1 {
|
||||||
keep = append(keep, v)
|
keep = append(keep, v)
|
||||||
continue
|
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 {
|
if len(keep) == 0 {
|
||||||
// delete the name for the array as a whole
|
// delete the name for the array as a whole
|
||||||
delete(f.NamedValues, name)
|
delete(f.NamedValues, *name)
|
||||||
} else {
|
} else {
|
||||||
f.NamedValues[name] = keep
|
f.NamedValues[*name] = keep
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.Elem().IsArray() {
|
if t.Elem().IsArray() {
|
||||||
|
|
@ -289,38 +302,38 @@ func decomposeUserArrayInto(f *Func, name LocalSlot, slots []LocalSlot) []LocalS
|
||||||
// decomposeUserStructInto creates names for the fields(s) of structs referenced
|
// decomposeUserStructInto creates names for the fields(s) of structs referenced
|
||||||
// by name where possible, and appends those new names to slots, which is then
|
// by name where possible, and appends those new names to slots, which is then
|
||||||
// returned.
|
// returned.
|
||||||
func decomposeUserStructInto(f *Func, name LocalSlot, slots []LocalSlot) []LocalSlot {
|
func decomposeUserStructInto(f *Func, name *LocalSlot, slots []*LocalSlot) []*LocalSlot {
|
||||||
fnames := []LocalSlot{} // slots for struct in name
|
fnames := []*LocalSlot{} // slots for struct in name
|
||||||
t := name.Type
|
t := name.Type
|
||||||
n := t.NumFields()
|
n := t.NumFields()
|
||||||
|
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
fs := f.fe.SplitStruct(name, i)
|
fs := f.SplitStruct(name, i)
|
||||||
fnames = append(fnames, fs)
|
fnames = append(fnames, fs)
|
||||||
// arrays and structs will be decomposed further, so
|
// arrays and structs will be decomposed further, so
|
||||||
// there's no need to record a name
|
// there's no need to record a name
|
||||||
if !fs.Type.IsArray() && !fs.Type.IsStruct() {
|
if !fs.Type.IsArray() && !fs.Type.IsStruct() {
|
||||||
slots = append(slots, fs)
|
slots = maybeAppend(f, slots, fs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
makeOp := StructMakeOp(n)
|
makeOp := StructMakeOp(n)
|
||||||
var keep []*Value
|
var keep []*Value
|
||||||
// create named values for each struct field
|
// create named values for each struct field
|
||||||
for _, v := range f.NamedValues[name] {
|
for _, v := range f.NamedValues[*name] {
|
||||||
if v.Op != makeOp {
|
if v.Op != makeOp {
|
||||||
keep = append(keep, v)
|
keep = append(keep, v)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for i := 0; i < len(fnames); i++ {
|
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 {
|
if len(keep) == 0 {
|
||||||
// delete the name for the struct as a whole
|
// delete the name for the struct as a whole
|
||||||
delete(f.NamedValues, name)
|
delete(f.NamedValues, *name)
|
||||||
} else {
|
} else {
|
||||||
f.NamedValues[name] = keep
|
f.NamedValues[*name] = keep
|
||||||
}
|
}
|
||||||
|
|
||||||
// now that this f.NamedValues contains values for the struct
|
// now that this f.NamedValues contains values for the struct
|
||||||
|
|
@ -328,10 +341,10 @@ func decomposeUserStructInto(f *Func, name LocalSlot, slots []LocalSlot) []Local
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
if name.Type.FieldType(i).IsStruct() {
|
if name.Type.FieldType(i).IsStruct() {
|
||||||
slots = decomposeUserStructInto(f, fnames[i], slots)
|
slots = decomposeUserStructInto(f, fnames[i], slots)
|
||||||
delete(f.NamedValues, fnames[i])
|
delete(f.NamedValues, *fnames[i])
|
||||||
} else if name.Type.FieldType(i).IsArray() {
|
} else if name.Type.FieldType(i).IsArray() {
|
||||||
slots = decomposeUserArrayInto(f, fnames[i], slots)
|
slots = decomposeUserArrayInto(f, fnames[i], slots)
|
||||||
delete(f.NamedValues, fnames[i])
|
delete(f.NamedValues, *fnames[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return slots
|
return slots
|
||||||
|
|
@ -416,9 +429,10 @@ type namedVal struct {
|
||||||
locIndex, valIndex int // f.NamedValues[f.Names[locIndex]][valIndex] = key
|
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) {
|
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 {
|
sort.Slice(toDelete, func(i, j int) bool {
|
||||||
if toDelete[i].locIndex != toDelete[j].locIndex {
|
if toDelete[i].locIndex != toDelete[j].locIndex {
|
||||||
return toDelete[i].locIndex > toDelete[j].locIndex
|
return toDelete[i].locIndex > toDelete[j].locIndex
|
||||||
|
|
@ -430,16 +444,36 @@ func deleteNamedVals(f *Func, toDelete []namedVal) {
|
||||||
// Get rid of obsolete names
|
// Get rid of obsolete names
|
||||||
for _, d := range toDelete {
|
for _, d := range toDelete {
|
||||||
loc := f.Names[d.locIndex]
|
loc := f.Names[d.locIndex]
|
||||||
vals := f.NamedValues[loc]
|
vals := f.NamedValues[*loc]
|
||||||
l := len(vals) - 1
|
l := len(vals) - 1
|
||||||
if l > 0 {
|
if l > 0 {
|
||||||
vals[d.valIndex] = vals[l]
|
vals[d.valIndex] = vals[l]
|
||||||
f.NamedValues[loc] = vals[:l]
|
}
|
||||||
} else {
|
vals[l] = nil
|
||||||
delete(f.NamedValues, loc)
|
f.NamedValues[*loc] = vals[:l]
|
||||||
l = len(f.Names) - 1
|
}
|
||||||
f.Names[d.locIndex] = f.Names[l]
|
// Delete locations with no values attached.
|
||||||
f.Names = f.Names[:l]
|
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]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -243,10 +243,10 @@ func (x *expandState) offsetFrom(b *Block, from *Value, offset int64, pt *types.
|
||||||
}
|
}
|
||||||
|
|
||||||
// splitSlots splits one "field" (specified by sfx, offset, and ty) out of the LocalSlots in ls and returns the new LocalSlots this generates.
|
// splitSlots splits one "field" (specified by sfx, offset, and ty) out of the LocalSlots in ls and returns the new LocalSlots this generates.
|
||||||
func (x *expandState) splitSlots(ls []LocalSlot, sfx string, offset int64, ty *types.Type) []LocalSlot {
|
func (x *expandState) splitSlots(ls []*LocalSlot, sfx string, offset int64, ty *types.Type) []*LocalSlot {
|
||||||
var locs []LocalSlot
|
var locs []*LocalSlot
|
||||||
for i := range ls {
|
for i := range ls {
|
||||||
locs = append(locs, x.f.fe.SplitSlot(&ls[i], sfx, offset, ty))
|
locs = append(locs, x.f.SplitSlot(ls[i], sfx, offset, ty))
|
||||||
}
|
}
|
||||||
return locs
|
return locs
|
||||||
}
|
}
|
||||||
|
|
@ -301,13 +301,13 @@ func (x *expandState) Printf(format string, a ...interface{}) (n int, err error)
|
||||||
// It emits the code necessary to implement the leaf select operation that leads to the root.
|
// It emits the code necessary to implement the leaf select operation that leads to the root.
|
||||||
//
|
//
|
||||||
// TODO when registers really arrive, must also decompose anything split across two registers or registers and memory.
|
// TODO when registers really arrive, must also decompose anything split across two registers or registers and memory.
|
||||||
func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64, regOffset Abi1RO) []LocalSlot {
|
func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64, regOffset Abi1RO) []*LocalSlot {
|
||||||
if x.debug {
|
if x.debug {
|
||||||
x.indent(3)
|
x.indent(3)
|
||||||
defer x.indent(-3)
|
defer x.indent(-3)
|
||||||
x.Printf("rewriteSelect(%s; %s; memOff=%d; regOff=%d)\n", leaf.LongString(), selector.LongString(), offset, regOffset)
|
x.Printf("rewriteSelect(%s; %s; memOff=%d; regOff=%d)\n", leaf.LongString(), selector.LongString(), offset, regOffset)
|
||||||
}
|
}
|
||||||
var locs []LocalSlot
|
var locs []*LocalSlot
|
||||||
leafType := leaf.Type
|
leafType := leaf.Type
|
||||||
if len(selector.Args) > 0 {
|
if len(selector.Args) > 0 {
|
||||||
w := selector.Args[0]
|
w := selector.Args[0]
|
||||||
|
|
@ -477,7 +477,7 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64,
|
||||||
|
|
||||||
case OpStructSelect:
|
case OpStructSelect:
|
||||||
w := selector.Args[0]
|
w := selector.Args[0]
|
||||||
var ls []LocalSlot
|
var ls []*LocalSlot
|
||||||
if w.Type.Kind() != types.TSTRUCT { // IData artifact
|
if w.Type.Kind() != types.TSTRUCT { // IData artifact
|
||||||
ls = x.rewriteSelect(leaf, w, offset, regOffset)
|
ls = x.rewriteSelect(leaf, w, offset, regOffset)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -485,7 +485,7 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64,
|
||||||
ls = x.rewriteSelect(leaf, w, offset+w.Type.FieldOff(fldi), regOffset+x.regOffset(w.Type, fldi))
|
ls = x.rewriteSelect(leaf, w, offset+w.Type.FieldOff(fldi), regOffset+x.regOffset(w.Type, fldi))
|
||||||
if w.Op != OpIData {
|
if w.Op != OpIData {
|
||||||
for _, l := range ls {
|
for _, l := range ls {
|
||||||
locs = append(locs, x.f.fe.SplitStruct(l, int(selector.AuxInt)))
|
locs = append(locs, x.f.SplitStruct(l, int(selector.AuxInt)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -662,7 +662,7 @@ outer:
|
||||||
func (x *expandState) decomposeArg(pos src.XPos, b *Block, source, mem *Value, t *types.Type, storeOffset int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
|
func (x *expandState) decomposeArg(pos src.XPos, b *Block, source, mem *Value, t *types.Type, storeOffset int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
|
||||||
|
|
||||||
pa := x.prAssignForArg(source)
|
pa := x.prAssignForArg(source)
|
||||||
var locs []LocalSlot
|
var locs []*LocalSlot
|
||||||
for _, s := range x.namedSelects[source] {
|
for _, s := range x.namedSelects[source] {
|
||||||
locs = append(locs, x.f.Names[s.locIndex])
|
locs = append(locs, x.f.Names[s.locIndex])
|
||||||
}
|
}
|
||||||
|
|
@ -756,12 +756,15 @@ func (x *expandState) decomposeArg(pos src.XPos, b *Block, source, mem *Value, t
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *expandState) splitSlotsIntoNames(locs []LocalSlot, suffix string, off int64, rt *types.Type, w *Value) {
|
func (x *expandState) splitSlotsIntoNames(locs []*LocalSlot, suffix string, off int64, rt *types.Type, w *Value) {
|
||||||
wlocs := x.splitSlots(locs, suffix, off, rt)
|
wlocs := x.splitSlots(locs, suffix, off, rt)
|
||||||
for _, l := range wlocs {
|
for _, l := range wlocs {
|
||||||
x.f.NamedValues[l] = append(x.f.NamedValues[l], w)
|
old, ok := x.f.NamedValues[*l]
|
||||||
|
x.f.NamedValues[*l] = append(old, w)
|
||||||
|
if !ok {
|
||||||
|
x.f.Names = append(x.f.Names, l)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
x.f.Names = append(x.f.Names, wlocs...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// decomposeLoad is a helper for storeArgOrLoad.
|
// decomposeLoad is a helper for storeArgOrLoad.
|
||||||
|
|
@ -826,7 +829,7 @@ func (x *expandState) decomposeLoad(pos src.XPos, b *Block, source, mem *Value,
|
||||||
// storeOneArg creates a decomposed (one step) arg that is then stored.
|
// storeOneArg creates a decomposed (one step) arg that is then stored.
|
||||||
// pos and b locate the store instruction, source is the "base" of the value input,
|
// pos and b locate the store instruction, source is the "base" of the value input,
|
||||||
// mem is the input mem, t is the type in question, and offArg and offStore are the offsets from the respective bases.
|
// mem is the input mem, t is the type in question, and offArg and offStore are the offsets from the respective bases.
|
||||||
func storeOneArg(x *expandState, pos src.XPos, b *Block, locs []LocalSlot, suffix string, source, mem *Value, t *types.Type, argOffset, storeOffset int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
|
func storeOneArg(x *expandState, pos src.XPos, b *Block, locs []*LocalSlot, suffix string, source, mem *Value, t *types.Type, argOffset, storeOffset int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
|
||||||
if x.debug {
|
if x.debug {
|
||||||
x.indent(3)
|
x.indent(3)
|
||||||
defer x.indent(-3)
|
defer x.indent(-3)
|
||||||
|
|
@ -848,7 +851,7 @@ func storeOneLoad(x *expandState, pos src.XPos, b *Block, source, mem *Value, t
|
||||||
return x.storeArgOrLoad(pos, b, w, mem, t, offStore, loadRegOffset, storeRc)
|
return x.storeArgOrLoad(pos, b, w, mem, t, offStore, loadRegOffset, storeRc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func storeTwoArg(x *expandState, pos src.XPos, b *Block, locs []LocalSlot, suffix1 string, suffix2 string, source, mem *Value, t1, t2 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
|
func storeTwoArg(x *expandState, pos src.XPos, b *Block, locs []*LocalSlot, suffix1 string, suffix2 string, source, mem *Value, t1, t2 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
|
||||||
mem = storeOneArg(x, pos, b, locs, suffix1, source, mem, t1, offArg, offStore, loadRegOffset, storeRc.next(t1))
|
mem = storeOneArg(x, pos, b, locs, suffix1, source, mem, t1, offArg, offStore, loadRegOffset, storeRc.next(t1))
|
||||||
pos = pos.WithNotStmt()
|
pos = pos.WithNotStmt()
|
||||||
t1Size := t1.Size()
|
t1Size := t1.Size()
|
||||||
|
|
@ -1168,7 +1171,7 @@ func expandCalls(f *Func) {
|
||||||
for i, name := range f.Names {
|
for i, name := range f.Names {
|
||||||
t := name.Type
|
t := name.Type
|
||||||
if x.isAlreadyExpandedAggregateType(t) {
|
if x.isAlreadyExpandedAggregateType(t) {
|
||||||
for j, v := range f.NamedValues[name] {
|
for j, v := range f.NamedValues[*name] {
|
||||||
if v.Op == OpSelectN || v.Op == OpArg && x.isAlreadyExpandedAggregateType(v.Type) {
|
if v.Op == OpSelectN || v.Op == OpArg && x.isAlreadyExpandedAggregateType(v.Type) {
|
||||||
ns := x.namedSelects[v]
|
ns := x.namedSelects[v]
|
||||||
x.namedSelects[v] = append(ns, namedVal{locIndex: i, valIndex: j})
|
x.namedSelects[v] = append(ns, namedVal{locIndex: i, valIndex: j})
|
||||||
|
|
@ -1477,10 +1480,10 @@ func expandCalls(f *Func) {
|
||||||
// Leaf types may have debug locations
|
// Leaf types may have debug locations
|
||||||
if !x.isAlreadyExpandedAggregateType(v.Type) {
|
if !x.isAlreadyExpandedAggregateType(v.Type) {
|
||||||
for _, l := range locs {
|
for _, l := range locs {
|
||||||
if _, ok := f.NamedValues[l]; !ok {
|
if _, ok := f.NamedValues[*l]; !ok {
|
||||||
f.Names = append(f.Names, l)
|
f.Names = append(f.Names, l)
|
||||||
}
|
}
|
||||||
f.NamedValues[l] = append(f.NamedValues[l], v)
|
f.NamedValues[*l] = append(f.NamedValues[*l], v)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -1553,7 +1556,7 @@ func expandCalls(f *Func) {
|
||||||
// Step 6: elide any copies introduced.
|
// Step 6: elide any copies introduced.
|
||||||
// Update named values.
|
// Update named values.
|
||||||
for _, name := range f.Names {
|
for _, name := range f.Names {
|
||||||
values := f.NamedValues[name]
|
values := f.NamedValues[*name]
|
||||||
for i, v := range values {
|
for i, v := range values {
|
||||||
if v.Op == OpCopy {
|
if v.Op == OpCopy {
|
||||||
a := v.Args[0]
|
a := v.Args[0]
|
||||||
|
|
@ -1725,7 +1728,8 @@ func (x *expandState) newArgToMemOrRegs(baseArg, toReplace *Value, offset int64,
|
||||||
loc := LocalSlot{N: aux.Name, Type: t, Off: 0}
|
loc := LocalSlot{N: aux.Name, Type: t, Off: 0}
|
||||||
values, ok := x.f.NamedValues[loc]
|
values, ok := x.f.NamedValues[loc]
|
||||||
if !ok {
|
if !ok {
|
||||||
x.f.Names = append(x.f.Names, loc)
|
ploc := x.f.localSlotAddr(loc)
|
||||||
|
x.f.Names = append(x.f.Names, ploc)
|
||||||
}
|
}
|
||||||
x.f.NamedValues[loc] = append(values, w)
|
x.f.NamedValues[loc] = append(values, w)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -73,36 +73,6 @@ func (TestFrontend) Auto(pos src.XPos, t *types.Type) *ir.Name {
|
||||||
n.Class = ir.PAUTO
|
n.Class = ir.PAUTO
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
func (d TestFrontend) SplitString(s LocalSlot) (LocalSlot, LocalSlot) {
|
|
||||||
return LocalSlot{N: s.N, Type: testTypes.BytePtr, Off: s.Off}, LocalSlot{N: s.N, Type: testTypes.Int, Off: s.Off + 8}
|
|
||||||
}
|
|
||||||
func (d TestFrontend) SplitInterface(s LocalSlot) (LocalSlot, LocalSlot) {
|
|
||||||
return LocalSlot{N: s.N, Type: testTypes.BytePtr, Off: s.Off}, LocalSlot{N: s.N, Type: testTypes.BytePtr, Off: s.Off + 8}
|
|
||||||
}
|
|
||||||
func (d TestFrontend) SplitSlice(s LocalSlot) (LocalSlot, LocalSlot, LocalSlot) {
|
|
||||||
return LocalSlot{N: s.N, Type: s.Type.Elem().PtrTo(), Off: s.Off},
|
|
||||||
LocalSlot{N: s.N, Type: testTypes.Int, Off: s.Off + 8},
|
|
||||||
LocalSlot{N: s.N, Type: testTypes.Int, Off: s.Off + 16}
|
|
||||||
}
|
|
||||||
func (d TestFrontend) SplitComplex(s LocalSlot) (LocalSlot, LocalSlot) {
|
|
||||||
if s.Type.Size() == 16 {
|
|
||||||
return LocalSlot{N: s.N, Type: testTypes.Float64, Off: s.Off}, LocalSlot{N: s.N, Type: testTypes.Float64, Off: s.Off + 8}
|
|
||||||
}
|
|
||||||
return LocalSlot{N: s.N, Type: testTypes.Float32, Off: s.Off}, LocalSlot{N: s.N, Type: testTypes.Float32, Off: s.Off + 4}
|
|
||||||
}
|
|
||||||
func (d TestFrontend) SplitInt64(s LocalSlot) (LocalSlot, LocalSlot) {
|
|
||||||
if s.Type.IsSigned() {
|
|
||||||
return LocalSlot{N: s.N, Type: testTypes.Int32, Off: s.Off + 4}, LocalSlot{N: s.N, Type: testTypes.UInt32, Off: s.Off}
|
|
||||||
}
|
|
||||||
return LocalSlot{N: s.N, Type: testTypes.UInt32, Off: s.Off + 4}, LocalSlot{N: s.N, Type: testTypes.UInt32, Off: s.Off}
|
|
||||||
}
|
|
||||||
func (d TestFrontend) SplitStruct(s LocalSlot, i int) LocalSlot {
|
|
||||||
return LocalSlot{N: s.N, Type: s.Type.FieldType(i), Off: s.Off + s.Type.FieldOff(i)}
|
|
||||||
}
|
|
||||||
func (d TestFrontend) SplitArray(s LocalSlot) LocalSlot {
|
|
||||||
return LocalSlot{N: s.N, Type: s.Type.Elem(), Off: s.Off}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d TestFrontend) SplitSlot(parent *LocalSlot, suffix string, offset int64, t *types.Type) LocalSlot {
|
func (d TestFrontend) SplitSlot(parent *LocalSlot, suffix string, offset int64, t *types.Type) LocalSlot {
|
||||||
return LocalSlot{N: parent.N, Type: t, Off: offset}
|
return LocalSlot{N: parent.N, Type: t, Off: offset}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ package ssa
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"cmd/compile/internal/abi"
|
"cmd/compile/internal/abi"
|
||||||
|
"cmd/compile/internal/base"
|
||||||
"cmd/compile/internal/types"
|
"cmd/compile/internal/types"
|
||||||
"cmd/internal/src"
|
"cmd/internal/src"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
|
|
@ -61,7 +62,11 @@ type Func struct {
|
||||||
NamedValues map[LocalSlot][]*Value
|
NamedValues map[LocalSlot][]*Value
|
||||||
// Names is a copy of NamedValues.Keys. We keep a separate list
|
// Names is a copy of NamedValues.Keys. We keep a separate list
|
||||||
// of keys to make iteration order deterministic.
|
// of keys to make iteration order deterministic.
|
||||||
Names []LocalSlot
|
Names []*LocalSlot
|
||||||
|
// Canonicalize root/top-level local slots, and canonicalize their pieces.
|
||||||
|
// Because LocalSlot pieces refer to their parents with a pointer, this ensures that equivalent slots really are equal.
|
||||||
|
CanonicalLocalSlots map[LocalSlot]*LocalSlot
|
||||||
|
CanonicalLocalSplits map[LocalSlotSplitKey]*LocalSlot
|
||||||
|
|
||||||
// RegArgs is a slice of register-memory pairs that must be spilled and unspilled in the uncommon path of function entry.
|
// RegArgs is a slice of register-memory pairs that must be spilled and unspilled in the uncommon path of function entry.
|
||||||
RegArgs []Spill
|
RegArgs []Spill
|
||||||
|
|
@ -87,10 +92,16 @@ type Func struct {
|
||||||
constants map[int64][]*Value // constants cache, keyed by constant value; users must check value's Op and Type
|
constants map[int64][]*Value // constants cache, keyed by constant value; users must check value's Op and Type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LocalSlotSplitKey struct {
|
||||||
|
parent *LocalSlot
|
||||||
|
Off int64 // offset of slot in N
|
||||||
|
Type *types.Type // type of slot
|
||||||
|
}
|
||||||
|
|
||||||
// NewFunc returns a new, empty function object.
|
// NewFunc returns a new, empty function object.
|
||||||
// Caller must set f.Config and f.Cache before using f.
|
// Caller must set f.Config and f.Cache before using f.
|
||||||
func NewFunc(fe Frontend) *Func {
|
func NewFunc(fe Frontend) *Func {
|
||||||
return &Func{fe: fe, NamedValues: make(map[LocalSlot][]*Value)}
|
return &Func{fe: fe, NamedValues: make(map[LocalSlot][]*Value), CanonicalLocalSlots: make(map[LocalSlot]*LocalSlot), CanonicalLocalSplits: make(map[LocalSlotSplitKey]*LocalSlot)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NumBlocks returns an integer larger than the id of any Block in the Func.
|
// NumBlocks returns an integer larger than the id of any Block in the Func.
|
||||||
|
|
@ -193,6 +204,101 @@ func (f *Func) retDeadcodeLiveOrderStmts(liveOrderStmts []*Value) {
|
||||||
f.Cache.deadcode.liveOrderStmts = liveOrderStmts
|
f.Cache.deadcode.liveOrderStmts = liveOrderStmts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *Func) localSlotAddr(slot LocalSlot) *LocalSlot {
|
||||||
|
a, ok := f.CanonicalLocalSlots[slot]
|
||||||
|
if !ok {
|
||||||
|
a = new(LocalSlot)
|
||||||
|
*a = slot // don't escape slot
|
||||||
|
f.CanonicalLocalSlots[slot] = a
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Func) SplitString(name *LocalSlot) (*LocalSlot, *LocalSlot) {
|
||||||
|
ptrType := types.NewPtr(types.Types[types.TUINT8])
|
||||||
|
lenType := types.Types[types.TINT]
|
||||||
|
// Split this string up into two separate variables.
|
||||||
|
p := f.SplitSlot(name, ".ptr", 0, ptrType)
|
||||||
|
l := f.SplitSlot(name, ".len", ptrType.Size(), lenType)
|
||||||
|
return p, l
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Func) SplitInterface(name *LocalSlot) (*LocalSlot, *LocalSlot) {
|
||||||
|
n := name.N
|
||||||
|
u := types.Types[types.TUINTPTR]
|
||||||
|
t := types.NewPtr(types.Types[types.TUINT8])
|
||||||
|
// Split this interface up into two separate variables.
|
||||||
|
sfx := ".itab"
|
||||||
|
if n.Type().IsEmptyInterface() {
|
||||||
|
sfx = ".type"
|
||||||
|
}
|
||||||
|
c := f.SplitSlot(name, sfx, 0, u) // see comment in typebits.Set
|
||||||
|
d := f.SplitSlot(name, ".data", u.Size(), t)
|
||||||
|
return c, d
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Func) SplitSlice(name *LocalSlot) (*LocalSlot, *LocalSlot, *LocalSlot) {
|
||||||
|
ptrType := types.NewPtr(name.Type.Elem())
|
||||||
|
lenType := types.Types[types.TINT]
|
||||||
|
p := f.SplitSlot(name, ".ptr", 0, ptrType)
|
||||||
|
l := f.SplitSlot(name, ".len", ptrType.Size(), lenType)
|
||||||
|
c := f.SplitSlot(name, ".cap", ptrType.Size()+lenType.Size(), lenType)
|
||||||
|
return p, l, c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Func) SplitComplex(name *LocalSlot) (*LocalSlot, *LocalSlot) {
|
||||||
|
s := name.Type.Size() / 2
|
||||||
|
var t *types.Type
|
||||||
|
if s == 8 {
|
||||||
|
t = types.Types[types.TFLOAT64]
|
||||||
|
} else {
|
||||||
|
t = types.Types[types.TFLOAT32]
|
||||||
|
}
|
||||||
|
r := f.SplitSlot(name, ".real", 0, t)
|
||||||
|
i := f.SplitSlot(name, ".imag", t.Size(), t)
|
||||||
|
return r, i
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Func) SplitInt64(name *LocalSlot) (*LocalSlot, *LocalSlot) {
|
||||||
|
var t *types.Type
|
||||||
|
if name.Type.IsSigned() {
|
||||||
|
t = types.Types[types.TINT32]
|
||||||
|
} else {
|
||||||
|
t = types.Types[types.TUINT32]
|
||||||
|
}
|
||||||
|
if f.Config.BigEndian {
|
||||||
|
return f.SplitSlot(name, ".hi", 0, t), f.SplitSlot(name, ".lo", t.Size(), types.Types[types.TUINT32])
|
||||||
|
}
|
||||||
|
return f.SplitSlot(name, ".hi", t.Size(), t), f.SplitSlot(name, ".lo", 0, types.Types[types.TUINT32])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Func) SplitStruct(name *LocalSlot, i int) *LocalSlot {
|
||||||
|
st := name.Type
|
||||||
|
return f.SplitSlot(name, st.FieldName(i), st.FieldOff(i), st.FieldType(i))
|
||||||
|
}
|
||||||
|
func (f *Func) SplitArray(name *LocalSlot) *LocalSlot {
|
||||||
|
n := name.N
|
||||||
|
at := name.Type
|
||||||
|
if at.NumElem() != 1 {
|
||||||
|
base.FatalfAt(n.Pos(), "bad array size")
|
||||||
|
}
|
||||||
|
et := at.Elem()
|
||||||
|
return f.SplitSlot(name, "[0]", 0, et)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Func) SplitSlot(name *LocalSlot, sfx string, offset int64, t *types.Type) *LocalSlot {
|
||||||
|
lssk := LocalSlotSplitKey{name, offset, t}
|
||||||
|
if als, ok := f.CanonicalLocalSplits[lssk]; ok {
|
||||||
|
return als
|
||||||
|
}
|
||||||
|
// Note: the _ field may appear several times. But
|
||||||
|
// have no fear, identically-named but distinct Autos are
|
||||||
|
// ok, albeit maybe confusing for a debugger.
|
||||||
|
ls := f.fe.SplitSlot(name, sfx, offset, t)
|
||||||
|
f.CanonicalLocalSplits[lssk] = &ls
|
||||||
|
return &ls
|
||||||
|
}
|
||||||
|
|
||||||
// newValue allocates a new Value with the given fields and places it at the end of b.Values.
|
// newValue allocates a new Value with the given fields and places it at the end of b.Values.
|
||||||
func (f *Func) newValue(op Op, t *types.Type, b *Block, pos src.XPos) *Value {
|
func (f *Func) newValue(op Op, t *types.Type, b *Block, pos src.XPos) *Value {
|
||||||
var v *Value
|
var v *Value
|
||||||
|
|
|
||||||
|
|
@ -12,26 +12,10 @@ func layout(f *Func) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register allocation may use a different order which has constraints
|
// Register allocation may use a different order which has constraints
|
||||||
// imposed by the linear-scan algorithm. Note that f.pass here is
|
// imposed by the linear-scan algorithm.
|
||||||
// regalloc, so the switch is conditional on -d=ssa/regalloc/test=N
|
|
||||||
func layoutRegallocOrder(f *Func) []*Block {
|
func layoutRegallocOrder(f *Func) []*Block {
|
||||||
|
// remnant of an experiment; perhaps there will be another.
|
||||||
switch f.pass.test {
|
|
||||||
case 0: // layout order
|
|
||||||
return layoutOrder(f)
|
return layoutOrder(f)
|
||||||
case 1: // existing block order
|
|
||||||
return f.Blocks
|
|
||||||
case 2: // reverse of postorder; legal, but usually not good.
|
|
||||||
po := f.postorder()
|
|
||||||
visitOrder := make([]*Block, len(po))
|
|
||||||
for i, b := range po {
|
|
||||||
j := len(po) - i - 1
|
|
||||||
visitOrder[j] = b
|
|
||||||
}
|
|
||||||
return visitOrder
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func layoutOrder(f *Func) []*Block {
|
func layoutOrder(f *Func) []*Block {
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,6 @@ func fprintFunc(p funcPrinter, f *Func) {
|
||||||
p.endBlock(b)
|
p.endBlock(b)
|
||||||
}
|
}
|
||||||
for _, name := range f.Names {
|
for _, name := range f.Names {
|
||||||
p.named(name, f.NamedValues[name])
|
p.named(*name, f.NamedValues[*name])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -141,10 +141,11 @@ func (s *stackAllocState) stackalloc() {
|
||||||
s.names = make([]LocalSlot, n)
|
s.names = make([]LocalSlot, n)
|
||||||
}
|
}
|
||||||
names := s.names
|
names := s.names
|
||||||
|
empty := LocalSlot{}
|
||||||
for _, name := range f.Names {
|
for _, name := range f.Names {
|
||||||
// Note: not "range f.NamedValues" above, because
|
// Note: not "range f.NamedValues" above, because
|
||||||
// that would be nondeterministic.
|
// that would be nondeterministic.
|
||||||
for _, v := range f.NamedValues[name] {
|
for _, v := range f.NamedValues[*name] {
|
||||||
if v.Op == OpArgIntReg || v.Op == OpArgFloatReg {
|
if v.Op == OpArgIntReg || v.Op == OpArgFloatReg {
|
||||||
aux := v.Aux.(*AuxNameOffset)
|
aux := v.Aux.(*AuxNameOffset)
|
||||||
// Never let an arg be bound to a differently named thing.
|
// Never let an arg be bound to a differently named thing.
|
||||||
|
|
@ -162,10 +163,12 @@ func (s *stackAllocState) stackalloc() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if names[v.ID] == empty {
|
||||||
if f.pass.debug > stackDebug {
|
if f.pass.debug > stackDebug {
|
||||||
fmt.Printf("stackalloc value %s to name %s\n", v, name)
|
fmt.Printf("stackalloc value %s to name %s\n", v, *name)
|
||||||
|
}
|
||||||
|
names[v.ID] = *name
|
||||||
}
|
}
|
||||||
names[v.ID] = name
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"cmd/compile/internal/abi"
|
"cmd/compile/internal/abi"
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/constant"
|
"go/constant"
|
||||||
"html"
|
"html"
|
||||||
|
|
@ -6463,7 +6462,8 @@ func (s *state) addNamedValue(n *ir.Name, v *ssa.Value) {
|
||||||
loc := ssa.LocalSlot{N: n, Type: n.Type(), Off: 0}
|
loc := ssa.LocalSlot{N: n, Type: n.Type(), Off: 0}
|
||||||
values, ok := s.f.NamedValues[loc]
|
values, ok := s.f.NamedValues[loc]
|
||||||
if !ok {
|
if !ok {
|
||||||
s.f.Names = append(s.f.Names, loc)
|
s.f.Names = append(s.f.Names, &loc)
|
||||||
|
s.f.CanonicalLocalSlots[loc] = &loc
|
||||||
}
|
}
|
||||||
s.f.NamedValues[loc] = append(values, v)
|
s.f.NamedValues[loc] = append(values, v)
|
||||||
}
|
}
|
||||||
|
|
@ -7552,82 +7552,6 @@ func (e *ssafn) Auto(pos src.XPos, t *types.Type) *ir.Name {
|
||||||
return typecheck.TempAt(pos, e.curfn, t) // Note: adds new auto to e.curfn.Func.Dcl list
|
return typecheck.TempAt(pos, e.curfn, t) // Note: adds new auto to e.curfn.Func.Dcl list
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ssafn) SplitString(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
|
|
||||||
ptrType := types.NewPtr(types.Types[types.TUINT8])
|
|
||||||
lenType := types.Types[types.TINT]
|
|
||||||
// Split this string up into two separate variables.
|
|
||||||
p := e.SplitSlot(&name, ".ptr", 0, ptrType)
|
|
||||||
l := e.SplitSlot(&name, ".len", ptrType.Size(), lenType)
|
|
||||||
return p, l
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ssafn) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
|
|
||||||
n := name.N
|
|
||||||
u := types.Types[types.TUINTPTR]
|
|
||||||
t := types.NewPtr(types.Types[types.TUINT8])
|
|
||||||
// Split this interface up into two separate variables.
|
|
||||||
f := ".itab"
|
|
||||||
if n.Type().IsEmptyInterface() {
|
|
||||||
f = ".type"
|
|
||||||
}
|
|
||||||
c := e.SplitSlot(&name, f, 0, u) // see comment in typebits.Set
|
|
||||||
d := e.SplitSlot(&name, ".data", u.Size(), t)
|
|
||||||
return c, d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ssafn) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot, ssa.LocalSlot) {
|
|
||||||
ptrType := types.NewPtr(name.Type.Elem())
|
|
||||||
lenType := types.Types[types.TINT]
|
|
||||||
p := e.SplitSlot(&name, ".ptr", 0, ptrType)
|
|
||||||
l := e.SplitSlot(&name, ".len", ptrType.Size(), lenType)
|
|
||||||
c := e.SplitSlot(&name, ".cap", ptrType.Size()+lenType.Size(), lenType)
|
|
||||||
return p, l, c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ssafn) SplitComplex(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
|
|
||||||
s := name.Type.Size() / 2
|
|
||||||
var t *types.Type
|
|
||||||
if s == 8 {
|
|
||||||
t = types.Types[types.TFLOAT64]
|
|
||||||
} else {
|
|
||||||
t = types.Types[types.TFLOAT32]
|
|
||||||
}
|
|
||||||
r := e.SplitSlot(&name, ".real", 0, t)
|
|
||||||
i := e.SplitSlot(&name, ".imag", t.Size(), t)
|
|
||||||
return r, i
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ssafn) SplitInt64(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
|
|
||||||
var t *types.Type
|
|
||||||
if name.Type.IsSigned() {
|
|
||||||
t = types.Types[types.TINT32]
|
|
||||||
} else {
|
|
||||||
t = types.Types[types.TUINT32]
|
|
||||||
}
|
|
||||||
if Arch.LinkArch.ByteOrder == binary.BigEndian {
|
|
||||||
return e.SplitSlot(&name, ".hi", 0, t), e.SplitSlot(&name, ".lo", t.Size(), types.Types[types.TUINT32])
|
|
||||||
}
|
|
||||||
return e.SplitSlot(&name, ".hi", t.Size(), t), e.SplitSlot(&name, ".lo", 0, types.Types[types.TUINT32])
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ssafn) SplitStruct(name ssa.LocalSlot, i int) ssa.LocalSlot {
|
|
||||||
st := name.Type
|
|
||||||
// Note: the _ field may appear several times. But
|
|
||||||
// have no fear, identically-named but distinct Autos are
|
|
||||||
// ok, albeit maybe confusing for a debugger.
|
|
||||||
return e.SplitSlot(&name, "."+st.FieldName(i), st.FieldOff(i), st.FieldType(i))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ssafn) SplitArray(name ssa.LocalSlot) ssa.LocalSlot {
|
|
||||||
n := name.N
|
|
||||||
at := name.Type
|
|
||||||
if at.NumElem() != 1 {
|
|
||||||
e.Fatalf(n.Pos(), "bad array size")
|
|
||||||
}
|
|
||||||
et := at.Elem()
|
|
||||||
return e.SplitSlot(&name, "[0]", 0, et)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ssafn) DerefItab(it *obj.LSym, offset int64) *obj.LSym {
|
func (e *ssafn) DerefItab(it *obj.LSym, offset int64) *obj.LSym {
|
||||||
return reflectdata.ITabSym(it, offset)
|
return reflectdata.ITabSym(it, offset)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue