| | |
| | |
| | |
| |
|
| | package ssa |
| |
|
| | import ( |
| | "cmd/internal/src" |
| | ) |
| |
|
| | |
| | |
| | func findlive(f *Func) (reachable []bool, live []bool) { |
| | reachable = ReachableBlocks(f) |
| | var order []*Value |
| | live, order = liveValues(f, reachable) |
| | f.Cache.freeValueSlice(order) |
| | return |
| | } |
| |
|
| | |
| | func ReachableBlocks(f *Func) []bool { |
| | reachable := make([]bool, f.NumBlocks()) |
| | reachable[f.Entry.ID] = true |
| | p := make([]*Block, 0, 64) |
| | p = append(p, f.Entry) |
| | for len(p) > 0 { |
| | |
| | b := p[len(p)-1] |
| | p = p[:len(p)-1] |
| | |
| | s := b.Succs |
| | if b.Kind == BlockFirst { |
| | s = s[:1] |
| | } |
| | for _, e := range s { |
| | c := e.b |
| | if int(c.ID) >= len(reachable) { |
| | f.Fatalf("block %s >= f.NumBlocks()=%d?", c, len(reachable)) |
| | } |
| | if !reachable[c.ID] { |
| | reachable[c.ID] = true |
| | p = append(p, c) |
| | } |
| | } |
| | } |
| | return reachable |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | func liveValues(f *Func, reachable []bool) (live []bool, liveOrderStmts []*Value) { |
| | live = f.Cache.allocBoolSlice(f.NumValues()) |
| | liveOrderStmts = f.Cache.allocValueSlice(f.NumValues())[:0] |
| |
|
| | |
| | |
| | if f.RegAlloc != nil { |
| | for i := range live { |
| | live[i] = true |
| | } |
| | return |
| | } |
| |
|
| | |
| | var liveInlIdx map[int]bool |
| | pt := f.Config.ctxt.PosTable |
| | for _, b := range f.Blocks { |
| | for _, v := range b.Values { |
| | i := pt.Pos(v.Pos).Base().InliningIndex() |
| | if i < 0 { |
| | continue |
| | } |
| | if liveInlIdx == nil { |
| | liveInlIdx = map[int]bool{} |
| | } |
| | liveInlIdx[i] = true |
| | } |
| | i := pt.Pos(b.Pos).Base().InliningIndex() |
| | if i < 0 { |
| | continue |
| | } |
| | if liveInlIdx == nil { |
| | liveInlIdx = map[int]bool{} |
| | } |
| | liveInlIdx[i] = true |
| | } |
| |
|
| | |
| | q := f.Cache.allocValueSlice(f.NumValues())[:0] |
| | defer f.Cache.freeValueSlice(q) |
| |
|
| | |
| | |
| | for _, b := range f.Blocks { |
| | if !reachable[b.ID] { |
| | continue |
| | } |
| | for _, v := range b.ControlValues() { |
| | if !live[v.ID] { |
| | live[v.ID] = true |
| | q = append(q, v) |
| | if v.Pos.IsStmt() != src.PosNotStmt { |
| | liveOrderStmts = append(liveOrderStmts, v) |
| | } |
| | } |
| | } |
| | for _, v := range b.Values { |
| | if (opcodeTable[v.Op].call || opcodeTable[v.Op].hasSideEffects || opcodeTable[v.Op].nilCheck) && !live[v.ID] { |
| | live[v.ID] = true |
| | q = append(q, v) |
| | if v.Pos.IsStmt() != src.PosNotStmt { |
| | liveOrderStmts = append(liveOrderStmts, v) |
| | } |
| | } |
| | if v.Op == OpInlMark { |
| | if !liveInlIdx[int(v.AuxInt)] { |
| | |
| | |
| | |
| | |
| | continue |
| | } |
| | live[v.ID] = true |
| | q = append(q, v) |
| | if v.Pos.IsStmt() != src.PosNotStmt { |
| | liveOrderStmts = append(liveOrderStmts, v) |
| | } |
| | } |
| | } |
| | } |
| |
|
| | |
| | for len(q) > 0 { |
| | |
| | v := q[len(q)-1] |
| | q[len(q)-1] = nil |
| | q = q[:len(q)-1] |
| | for i, x := range v.Args { |
| | if v.Op == OpPhi && !reachable[v.Block.Preds[i].b.ID] { |
| | continue |
| | } |
| | if !live[x.ID] { |
| | live[x.ID] = true |
| | q = append(q, x) |
| | if x.Pos.IsStmt() != src.PosNotStmt { |
| | liveOrderStmts = append(liveOrderStmts, x) |
| | } |
| | } |
| | } |
| | } |
| |
|
| | return |
| | } |
| |
|
| | |
| | func deadcode(f *Func) { |
| | |
| | |
| | |
| | |
| | if f.RegAlloc != nil { |
| | f.Fatalf("deadcode after regalloc") |
| | } |
| |
|
| | |
| | reachable := ReachableBlocks(f) |
| |
|
| | |
| | for _, b := range f.Blocks { |
| | if reachable[b.ID] { |
| | continue |
| | } |
| | for i := 0; i < len(b.Succs); { |
| | e := b.Succs[i] |
| | if reachable[e.b.ID] { |
| | b.removeEdge(i) |
| | } else { |
| | i++ |
| | } |
| | } |
| | } |
| |
|
| | |
| | for _, b := range f.Blocks { |
| | if !reachable[b.ID] { |
| | continue |
| | } |
| | if b.Kind != BlockFirst { |
| | continue |
| | } |
| | b.removeEdge(1) |
| | b.Kind = BlockPlain |
| | b.Likely = BranchUnknown |
| | } |
| |
|
| | |
| | copyelim(f) |
| |
|
| | |
| | live, order := liveValues(f, reachable) |
| | defer func() { f.Cache.freeBoolSlice(live) }() |
| | defer func() { f.Cache.freeValueSlice(order) }() |
| |
|
| | |
| | s := f.newSparseSet(f.NumValues()) |
| | defer f.retSparseSet(s) |
| | i := 0 |
| | for _, name := range f.Names { |
| | j := 0 |
| | s.clear() |
| | values := f.NamedValues[*name] |
| | for _, v := range values { |
| | if live[v.ID] && !s.contains(v.ID) { |
| | values[j] = v |
| | j++ |
| | s.add(v.ID) |
| | } |
| | } |
| | if j == 0 { |
| | 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] |
| | } |
| | } |
| | clear(f.Names[i:]) |
| | f.Names = f.Names[:i] |
| |
|
| | pendingLines := f.cachedLineStarts |
| | pendingLines.clear() |
| |
|
| | |
| | for i, b := range f.Blocks { |
| | if !reachable[b.ID] { |
| | |
| | b.ResetControls() |
| | } |
| | for _, v := range b.Values { |
| | if !live[v.ID] { |
| | v.resetArgs() |
| | if v.Pos.IsStmt() == src.PosIsStmt && reachable[b.ID] { |
| | pendingLines.set(v.Pos, int32(i)) |
| | } |
| | } |
| | } |
| | } |
| |
|
| | |
| | for i := len(order) - 1; i >= 0; i-- { |
| | w := order[i] |
| | if j, ok := pendingLines.get(w.Pos); ok && f.Blocks[j] == w.Block { |
| | w.Pos = w.Pos.WithIsStmt() |
| | pendingLines.remove(w.Pos) |
| | } |
| | } |
| |
|
| | |
| | pendingLines.foreachEntry(func(j int32, l uint, bi int32) { |
| | b := f.Blocks[bi] |
| | if b.Pos.Line() == l && b.Pos.FileIndex() == j { |
| | b.Pos = b.Pos.WithIsStmt() |
| | } |
| | }) |
| |
|
| | |
| | |
| | for _, b := range f.Blocks { |
| | i := 0 |
| | for _, v := range b.Values { |
| | if live[v.ID] { |
| | b.Values[i] = v |
| | i++ |
| | } else { |
| | f.freeValue(v) |
| | } |
| | } |
| | b.truncateValues(i) |
| | } |
| |
|
| | |
| | i = 0 |
| | for _, b := range f.Blocks { |
| | if reachable[b.ID] { |
| | f.Blocks[i] = b |
| | i++ |
| | } else { |
| | if len(b.Values) > 0 { |
| | b.Fatalf("live values in unreachable block %v: %v", b, b.Values) |
| | } |
| | f.freeBlock(b) |
| | } |
| | } |
| | |
| | clear(f.Blocks[i:]) |
| | f.Blocks = f.Blocks[:i] |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | func (b *Block) removeEdge(i int) { |
| | e := b.Succs[i] |
| | c := e.b |
| | j := e.i |
| |
|
| | |
| | b.removeSucc(i) |
| |
|
| | |
| | c.removePred(j) |
| |
|
| | |
| | for _, v := range c.Values { |
| | if v.Op != OpPhi { |
| | continue |
| | } |
| | c.removePhiArg(v, j) |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | } |
| | } |
| |
|