Source file src/cmd/compile/internal/ssa/shortcircuit.go
1 // Copyright 2016 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package ssa 6 7 // ReplaceUses replaces all uses of old in b with new. 8 func (b *Block) ReplaceUses(old, new *Value) { 9 for _, v := range b.Values { 10 for i, a := range v.Args { 11 if a == old { 12 v.SetArg(i, new) 13 } 14 } 15 } 16 for i, v := range b.ControlValues() { 17 if v == old { 18 b.ReplaceControl(i, new) 19 } 20 } 21 } 22 23 // MoveTo moves v to dst, adjusting the appropriate Block.Values slices. 24 // The caller is responsible for ensuring that this is safe. 25 // i is the index of v in v.Block.Values. 26 func (v *Value) MoveTo(dst *Block, i int) { 27 if dst.Func.Scheduled { 28 v.Fatalf("moveTo after scheduling") 29 } 30 src := v.Block 31 if src.Values[i] != v { 32 v.Fatalf("moveTo bad index %d", v, i) 33 } 34 if src == dst { 35 return 36 } 37 v.Block = dst 38 dst.Values = append(dst.Values, v) 39 last := len(src.Values) - 1 40 src.Values[i] = src.Values[last] 41 src.Values[last] = nil 42 src.Values = src.Values[:last] 43 } 44 45 // FlowsTo checks that the subgraph starting from v and ends at t is a DAG, with 46 // the following constraints: 47 // 48 // (1) v can reach t. 49 // (2) v's connected component removing the paths containing t is a DAG. 50 // (3) The blocks in the subgraph G defined in (2) has all their preds also in G, 51 // except v. 52 // (4) The subgraph defined in (2) has a size smaller than cap. 53 // 54 // We know that the subgraph G defined in constraint (2)(3) has the property that v 55 // dominates all the blocks in G: 56 // If there exist a block x in G that is not dominated by v, then there exist a 57 // path P from entry to x that does not contain v. Denote x's predecessor in P 58 // as x', then x' must also be in G given constraint (3), same to its pred x'' 59 // in P. Given constraint (2), by going back in P we will in the end reach v, 60 // which conflicts with the definition of P. 61 // 62 // Constraint (2)'s DAG requirement could be further relaxed to contain "internal" 63 // loops that doesn't change the dominance relation of v. But that is more subtle 64 // and requires another constraint on the source block v, and a more complex proof. 65 // Furthermore optimizing the branch guarding a loop might bring less gains as the 66 // loop itself might be the bottleneck. 67 func (v *Block) FlowsTo(t *Block, cap int) map[*Block]struct{} { 68 seen := map[*Block]struct{}{} 69 var boundedDFS func(b *Block) 70 hasPathToT := false 71 fullyExplored := true 72 isDAG := true 73 visited := map[*Block]struct{}{} 74 boundedDFS = func(b *Block) { 75 if _, ok := seen[b]; ok { 76 return 77 } 78 if _, ok := visited[b]; ok { 79 isDAG = false 80 return 81 } 82 if b == t { 83 // do not put t into seen, this way 84 // if v can reach t's connected component without going through t, 85 // it will fail the pred check after boundedDFSUntil. 86 hasPathToT = true 87 return 88 } 89 if len(seen) > cap { 90 fullyExplored = false 91 return 92 } 93 seen[b] = struct{}{} 94 visited[b] = struct{}{} 95 for _, se := range b.Succs { 96 boundedDFS(se.B) 97 if !(isDAG && fullyExplored) { 98 return 99 } 100 } 101 delete(visited, b) 102 } 103 boundedDFS(v) 104 if hasPathToT && fullyExplored && isDAG { 105 for b := range seen { 106 if b != v { 107 for _, se := range b.Preds { 108 if _, ok := seen[se.B]; !ok { 109 return nil 110 } 111 } 112 } 113 } 114 return seen 115 } 116 return nil 117 } 118