| | |
| | |
| | |
| |
|
| | package ssa |
| |
|
| | |
| | |
| | |
| | func flagalloc(f *Func) { |
| | |
| | |
| | |
| | end := f.Cache.allocValueSlice(f.NumBlocks()) |
| | defer f.Cache.freeValueSlice(end) |
| | po := f.postorder() |
| | for n := 0; n < 2; n++ { |
| | for _, b := range po { |
| | |
| | |
| | |
| | var flag *Value |
| | for _, c := range b.ControlValues() { |
| | if c.Type.IsFlags() { |
| | if flag != nil { |
| | panic("cannot have multiple controls using flags") |
| | } |
| | flag = c |
| | } |
| | } |
| | if flag == nil { |
| | flag = end[b.ID] |
| | } |
| | for j := len(b.Values) - 1; j >= 0; j-- { |
| | v := b.Values[j] |
| | if v == flag { |
| | flag = nil |
| | } |
| | if v.clobbersFlags() { |
| | flag = nil |
| | } |
| | for _, a := range v.Args { |
| | if a.Type.IsFlags() { |
| | flag = a |
| | } |
| | } |
| | } |
| | if flag != nil { |
| | for _, e := range b.Preds { |
| | p := e.b |
| | end[p.ID] = flag |
| | } |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | for _, b := range f.Blocks { |
| | if b.Kind == BlockDefer { |
| | |
| | end[b.ID] = nil |
| | continue |
| | } |
| | for _, v := range b.ControlValues() { |
| | if v.Type.IsFlags() && end[b.ID] != v { |
| | end[b.ID] = nil |
| | } |
| | } |
| | } |
| |
|
| | |
| | spill := map[ID]bool{} |
| | for _, b := range f.Blocks { |
| | var flag *Value |
| | if len(b.Preds) > 0 { |
| | flag = end[b.Preds[0].b.ID] |
| | } |
| | for _, v := range b.Values { |
| | for _, a := range v.Args { |
| | if !a.Type.IsFlags() { |
| | continue |
| | } |
| | if a == flag { |
| | continue |
| | } |
| | |
| | spill[a.ID] = true |
| | flag = a |
| | } |
| | if v.clobbersFlags() { |
| | flag = nil |
| | } |
| | if v.Type.IsFlags() { |
| | flag = v |
| | } |
| | } |
| | for _, v := range b.ControlValues() { |
| | if v != flag && v.Type.IsFlags() { |
| | spill[v.ID] = true |
| | } |
| | } |
| | if v := end[b.ID]; v != nil && v != flag { |
| | spill[v.ID] = true |
| | } |
| | } |
| |
|
| | |
| | var remove []*Value |
| | var oldSched []*Value |
| | for _, b := range f.Blocks { |
| | oldSched = append(oldSched[:0], b.Values...) |
| | b.Values = b.Values[:0] |
| | |
| | var flag *Value |
| | if len(b.Preds) > 0 { |
| | flag = end[b.Preds[0].b.ID] |
| | |
| | for _, e := range b.Preds[1:] { |
| | p := e.b |
| | if end[p.ID] != flag { |
| | f.Fatalf("live flag in %s's predecessors not consistent", b) |
| | } |
| | } |
| | } |
| | for _, v := range oldSched { |
| | if v.Op == OpPhi && v.Type.IsFlags() { |
| | f.Fatalf("phi of flags not supported: %s", v.LongString()) |
| | } |
| |
|
| | |
| | |
| | if spill[v.ID] && v.MemoryArg() != nil { |
| | remove = append(remove, v) |
| | if !f.Config.splitLoad(v) { |
| | f.Fatalf("can't split flag generator: %s", v.LongString()) |
| | } |
| | } |
| |
|
| | |
| | |
| | for i, a := range v.Args { |
| | if !a.Type.IsFlags() { |
| | continue |
| | } |
| | if a == flag { |
| | continue |
| | } |
| | |
| | c := copyFlags(a, b) |
| | |
| | v.SetArg(i, c) |
| | |
| | flag = a |
| | } |
| | |
| | b.Values = append(b.Values, v) |
| | if v.clobbersFlags() { |
| | flag = nil |
| | } |
| | if v.Type.IsFlags() { |
| | flag = v |
| | } |
| | } |
| | for i, v := range b.ControlValues() { |
| | if v != flag && v.Type.IsFlags() { |
| | |
| | remove = append(remove, v) |
| | c := copyFlags(v, b) |
| | b.ReplaceControl(i, c) |
| | flag = v |
| | } |
| | } |
| | if v := end[b.ID]; v != nil && v != flag { |
| | |
| | |
| | remove = append(remove, v) |
| | copyFlags(v, b) |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | } |
| | } |
| |
|
| | |
| | for _, b := range f.Blocks { |
| | b.FlagsLiveAtEnd = end[b.ID] != nil |
| | } |
| |
|
| | |
| | |
| | |
| | |
| |
|
| | |
| | for i := 0; i < len(remove); i++ { |
| | v := remove[i] |
| | if v.Uses == 0 { |
| | v.reset(OpInvalid) |
| | continue |
| | } |
| | |
| | last := len(remove) - 1 |
| | remove[i] = remove[last] |
| | remove[last] = nil |
| | remove = remove[:last] |
| | i-- |
| | } |
| |
|
| | if len(remove) == 0 { |
| | return |
| | } |
| |
|
| | removeBlocks := f.newSparseSet(f.NumBlocks()) |
| | defer f.retSparseSet(removeBlocks) |
| | for _, v := range remove { |
| | removeBlocks.add(v.Block.ID) |
| | } |
| |
|
| | |
| | for _, b := range f.Blocks { |
| | if !removeBlocks.contains(b.ID) { |
| | continue |
| | } |
| | i := 0 |
| | for j := 0; j < len(b.Values); j++ { |
| | v := b.Values[j] |
| | if v.Op == OpInvalid { |
| | continue |
| | } |
| | b.Values[i] = v |
| | i++ |
| | } |
| | b.truncateValues(i) |
| | } |
| | } |
| |
|
| | func (v *Value) clobbersFlags() bool { |
| | if opcodeTable[v.Op].clobberFlags { |
| | return true |
| | } |
| | if v.Type.IsTuple() && (v.Type.FieldType(0).IsFlags() || v.Type.FieldType(1).IsFlags()) { |
| | |
| | |
| | |
| | return true |
| | } |
| | return false |
| | } |
| |
|
| | |
| | |
| | func copyFlags(v *Value, b *Block) *Value { |
| | flagsArgs := make(map[int]*Value) |
| | for i, a := range v.Args { |
| | if a.Type.IsFlags() || a.Type.IsTuple() { |
| | flagsArgs[i] = copyFlags(a, b) |
| | } |
| | } |
| | c := v.copyInto(b) |
| | for i, a := range flagsArgs { |
| | c.SetArg(i, a) |
| | } |
| | return c |
| | } |
| |
|