github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/src/cmd/compile/internal/ssa/trim.go (about) 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 // trim removes blocks with no code in them. 8 // These blocks were inserted to remove critical edges. 9 func trim(f *Func) { 10 n := 0 11 for _, b := range f.Blocks { 12 if !trimmableBlock(b) { 13 f.Blocks[n] = b 14 n++ 15 continue 16 } 17 18 // Splice b out of the graph. NOTE: `mergePhi` depends on the 19 // order, in which the predecessors edges are merged here. 20 p, i := b.Preds[0].b, b.Preds[0].i 21 s, j := b.Succs[0].b, b.Succs[0].i 22 ns := len(s.Preds) 23 p.Succs[i] = Edge{s, j} 24 s.Preds[j] = Edge{p, i} 25 26 for _, e := range b.Preds[1:] { 27 p, i := e.b, e.i 28 p.Succs[i] = Edge{s, len(s.Preds)} 29 s.Preds = append(s.Preds, Edge{p, i}) 30 } 31 32 // If `s` had more than one predecessor, update its phi-ops to 33 // account for the merge. 34 if ns > 1 { 35 for _, v := range s.Values { 36 if v.Op == OpPhi { 37 mergePhi(v, j, b) 38 } 39 } 40 // Remove the phi-ops from `b` if they were merged into the 41 // phi-ops of `s`. 42 k := 0 43 for _, v := range b.Values { 44 if v.Op == OpPhi { 45 if v.Uses == 0 { 46 v.resetArgs() 47 continue 48 } 49 // Pad the arguments of the remaining phi-ops so 50 // they match the new predecessor count of `s`. 51 // Since s did not have a Phi op corresponding to 52 // the phi op in b, the other edges coming into s 53 // must be loopback edges from s, so v is the right 54 // argument to v! 55 args := make([]*Value, len(v.Args)) 56 copy(args, v.Args) 57 v.resetArgs() 58 for x := 0; x < j; x++ { 59 v.AddArg(v) 60 } 61 v.AddArg(args[0]) 62 for x := j + 1; x < ns; x++ { 63 v.AddArg(v) 64 } 65 for _, a := range args[1:] { 66 v.AddArg(a) 67 } 68 } 69 b.Values[k] = v 70 k++ 71 } 72 b.Values = b.Values[:k] 73 } 74 75 // Merge the blocks' values. 76 for _, v := range b.Values { 77 v.Block = s 78 } 79 k := len(b.Values) 80 m := len(s.Values) 81 for i := 0; i < k; i++ { 82 s.Values = append(s.Values, nil) 83 } 84 copy(s.Values[k:], s.Values[:m]) 85 copy(s.Values, b.Values) 86 } 87 if n < len(f.Blocks) { 88 f.invalidateCFG() 89 tail := f.Blocks[n:] 90 for i := range tail { 91 tail[i] = nil 92 } 93 f.Blocks = f.Blocks[:n] 94 } 95 } 96 97 // emptyBlock returns true if the block does not contain actual 98 // instructions 99 func emptyBlock(b *Block) bool { 100 for _, v := range b.Values { 101 if v.Op != OpPhi { 102 return false 103 } 104 } 105 return true 106 } 107 108 // trimmableBlock returns true if the block can be trimmed from the CFG, 109 // subject to the following criteria: 110 // - it should not be the first block 111 // - it should be BlockPlain 112 // - it should not loop back to itself 113 // - it either is the single predecessor of the successor block or 114 // contains no actual instructions 115 func trimmableBlock(b *Block) bool { 116 if b.Kind != BlockPlain || b == b.Func.Entry { 117 return false 118 } 119 s := b.Succs[0].b 120 return s != b && (len(s.Preds) == 1 || emptyBlock(b)) 121 } 122 123 // mergePhi adjusts the number of `v`s arguments to account for merge 124 // of `b`, which was `i`th predecessor of the `v`s block. Returns 125 // `v`. 126 func mergePhi(v *Value, i int, b *Block) *Value { 127 u := v.Args[i] 128 if u.Block == b { 129 if u.Op != OpPhi { 130 b.Func.Fatalf("value %s is not a phi operation", u.LongString()) 131 } 132 // If the original block contained u = φ(u0, u1, ..., un) and 133 // the current phi is 134 // v = φ(v0, v1, ..., u, ..., vk) 135 // then the merged phi is 136 // v = φ(v0, v1, ..., u0, ..., vk, u1, ..., un) 137 v.SetArg(i, u.Args[0]) 138 v.AddArgs(u.Args[1:]...) 139 } else { 140 // If the original block contained u = φ(u0, u1, ..., un) and 141 // the current phi is 142 // v = φ(v0, v1, ..., vi, ..., vk) 143 // i.e. it does not use a value from the predecessor block, 144 // then the merged phi is 145 // v = φ(v0, v1, ..., vk, vi, vi, ...) 146 for j := 1; j < len(b.Preds); j++ { 147 v.AddArg(v.Args[i]) 148 } 149 } 150 return v 151 }