mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.ssa] cmd/compile: split decompose pass in two
A first pass to decompose user types (structs, maybe arrays someday), and a second pass to decompose builtin types (strings, interfaces, slices, complex). David wants this for value range analysis so he can have structs decomposed but slices and friends will still be intact and he can deduce things like the length of a slice is >= 0. Change-Id: Ia2300d07663329b51ed6270cfed21d31980daa7c Reviewed-on: https://go-review.googlesource.com/19340 Run-TryBot: David Chase <drchase@google.com> Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
parent
9763f6f8cf
commit
7f7f7cddec
2 changed files with 55 additions and 19 deletions
|
|
@ -99,7 +99,8 @@ var passes = [...]pass{
|
||||||
{"early copyelim", copyelim, false},
|
{"early copyelim", copyelim, false},
|
||||||
{"early deadcode", deadcode, false}, // remove generated dead code to avoid doing pointless work during opt
|
{"early deadcode", deadcode, false}, // remove generated dead code to avoid doing pointless work during opt
|
||||||
{"short circuit", shortcircuit, false},
|
{"short circuit", shortcircuit, false},
|
||||||
{"decompose", decompose, true},
|
{"decompose user", decomposeUser, true},
|
||||||
|
{"decompose builtin", decomposeBuiltIn, true},
|
||||||
{"opt", opt, true}, // TODO: split required rules and optimizing rules
|
{"opt", opt, true}, // TODO: split required rules and optimizing rules
|
||||||
{"opt deadcode", deadcode, false}, // remove any blocks orphaned during opt
|
{"opt deadcode", deadcode, false}, // remove any blocks orphaned during opt
|
||||||
{"generic cse", cse, true},
|
{"generic cse", cse, true},
|
||||||
|
|
@ -148,8 +149,8 @@ var passOrder = [...]constraint{
|
||||||
// tighten will be most effective when as many values have been removed as possible
|
// tighten will be most effective when as many values have been removed as possible
|
||||||
{"generic deadcode", "tighten"},
|
{"generic deadcode", "tighten"},
|
||||||
{"generic cse", "tighten"},
|
{"generic cse", "tighten"},
|
||||||
// don't run optimization pass until we've decomposed compound objects
|
// don't run optimization pass until we've decomposed builtin objects
|
||||||
{"decompose", "opt"},
|
{"decompose builtin", "opt"},
|
||||||
// don't layout blocks until critical edges have been removed
|
// don't layout blocks until critical edges have been removed
|
||||||
{"critical", "layout"},
|
{"critical", "layout"},
|
||||||
// regalloc requires the removal of all critical edges
|
// regalloc requires the removal of all critical edges
|
||||||
|
|
|
||||||
|
|
@ -4,16 +4,16 @@
|
||||||
|
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
// decompose converts phi ops on compound types into phi
|
// decompose converts phi ops on compound builtin types into phi
|
||||||
// ops on simple types.
|
// ops on simple types.
|
||||||
// (The remaining compound ops are decomposed with rewrite rules.)
|
// (The remaining compound ops are decomposed with rewrite rules.)
|
||||||
func decompose(f *Func) {
|
func decomposeBuiltIn(f *Func) {
|
||||||
for _, b := range f.Blocks {
|
for _, b := range f.Blocks {
|
||||||
for _, v := range b.Values {
|
for _, v := range b.Values {
|
||||||
if v.Op != OpPhi {
|
if v.Op != OpPhi {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
decomposePhi(v)
|
decomposeBuiltInPhi(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -78,22 +78,13 @@ func decompose(f *Func) {
|
||||||
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)
|
||||||
}
|
}
|
||||||
case t.IsStruct():
|
|
||||||
n := t.NumFields()
|
|
||||||
for _, v := range f.NamedValues[name] {
|
|
||||||
for i := int64(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), i, v)
|
|
||||||
f.NamedValues[fname] = append(f.NamedValues[fname], x)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func decomposePhi(v *Value) {
|
func decomposeBuiltInPhi(v *Value) {
|
||||||
// TODO: decompose 64-bit ops on 32-bit archs?
|
// TODO: decompose 64-bit ops on 32-bit archs?
|
||||||
switch {
|
switch {
|
||||||
case v.Type.IsComplex():
|
case v.Type.IsComplex():
|
||||||
|
|
@ -104,8 +95,6 @@ func decomposePhi(v *Value) {
|
||||||
decomposeSlicePhi(v)
|
decomposeSlicePhi(v)
|
||||||
case v.Type.IsInterface():
|
case v.Type.IsInterface():
|
||||||
decomposeInterfacePhi(v)
|
decomposeInterfacePhi(v)
|
||||||
case v.Type.IsStruct():
|
|
||||||
decomposeStructPhi(v)
|
|
||||||
case v.Type.Size() > v.Block.Func.Config.IntSize:
|
case v.Type.Size() > v.Block.Func.Config.IntSize:
|
||||||
v.Unimplementedf("undecomposed type %s", v.Type)
|
v.Unimplementedf("undecomposed type %s", v.Type)
|
||||||
}
|
}
|
||||||
|
|
@ -182,6 +171,50 @@ func decomposeInterfacePhi(v *Value) {
|
||||||
v.AddArg(itab)
|
v.AddArg(itab)
|
||||||
v.AddArg(data)
|
v.AddArg(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func decomposeUser(f *Func) {
|
||||||
|
for _, b := range f.Blocks {
|
||||||
|
for _, v := range b.Values {
|
||||||
|
if v.Op != OpPhi {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
decomposeUserPhi(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Split up named values into their components.
|
||||||
|
// 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.
|
||||||
|
i := 0
|
||||||
|
for _, name := range f.Names {
|
||||||
|
t := name.Type
|
||||||
|
switch {
|
||||||
|
case t.IsStruct():
|
||||||
|
n := t.NumFields()
|
||||||
|
for _, v := range f.NamedValues[name] {
|
||||||
|
for i := int64(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), i, v)
|
||||||
|
f.NamedValues[fname] = append(f.NamedValues[fname], x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete(f.NamedValues, name)
|
||||||
|
default:
|
||||||
|
f.Names[i] = name
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.Names = f.Names[:i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func decomposeUserPhi(v *Value) {
|
||||||
|
switch {
|
||||||
|
case v.Type.IsStruct():
|
||||||
|
decomposeStructPhi(v)
|
||||||
|
}
|
||||||
|
// TODO: Arrays of length 1?
|
||||||
|
}
|
||||||
|
|
||||||
func decomposeStructPhi(v *Value) {
|
func decomposeStructPhi(v *Value) {
|
||||||
t := v.Type
|
t := v.Type
|
||||||
n := t.NumFields()
|
n := t.NumFields()
|
||||||
|
|
@ -199,7 +232,9 @@ func decomposeStructPhi(v *Value) {
|
||||||
|
|
||||||
// Recursively decompose phis for each field.
|
// Recursively decompose phis for each field.
|
||||||
for _, f := range fields[:n] {
|
for _, f := range fields[:n] {
|
||||||
decomposePhi(f)
|
if f.Type.IsStruct() {
|
||||||
|
decomposeStructPhi(f)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue