{"early copyelim", copyelim, false},
{"early deadcode", deadcode, false}, // remove generated dead code to avoid doing pointless work during opt
{"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 deadcode", deadcode, false}, // remove any blocks orphaned during opt
{"generic cse", cse, true},
// tighten will be most effective when as many values have been removed as possible
{"generic deadcode", "tighten"},
{"generic cse", "tighten"},
- // don't run optimization pass until we've decomposed compound objects
- {"decompose", "opt"},
+ // don't run optimization pass until we've decomposed builtin objects
+ {"decompose builtin", "opt"},
// don't layout blocks until critical edges have been removed
{"critical", "layout"},
// regalloc requires the removal of all critical edges
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.
// (The remaining compound ops are decomposed with rewrite rules.)
-func decompose(f *Func) {
+func decomposeBuiltIn(f *Func) {
for _, b := range f.Blocks {
for _, v := range b.Values {
if v.Op != OpPhi {
continue
}
- decomposePhi(v)
+ decomposeBuiltInPhi(v)
}
}
f.NamedValues[typeName] = append(f.NamedValues[typeName], typ)
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:
f.Unimplementedf("undecomposed named type %s", t)
}
}
}
-func decomposePhi(v *Value) {
+func decomposeBuiltInPhi(v *Value) {
// TODO: decompose 64-bit ops on 32-bit archs?
switch {
case v.Type.IsComplex():
decomposeSlicePhi(v)
case v.Type.IsInterface():
decomposeInterfacePhi(v)
- case v.Type.IsStruct():
- decomposeStructPhi(v)
case v.Type.Size() > v.Block.Func.Config.IntSize:
v.Unimplementedf("undecomposed type %s", v.Type)
}
v.AddArg(itab)
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) {
t := v.Type
n := t.NumFields()
// Recursively decompose phis for each field.
for _, f := range fields[:n] {
- decomposePhi(f)
+ if f.Type.IsStruct() {
+ decomposeStructPhi(f)
+ }
}
}