github.com/gocuntian/go@v0.0.0-20160610041250-fee02d270bf8/src/cmd/compile/internal/ssa/cse.go (about) 1 // Copyright 2015 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 import ( 8 "fmt" 9 "sort" 10 ) 11 12 const ( 13 cmpDepth = 4 14 ) 15 16 // cse does common-subexpression elimination on the Function. 17 // Values are just relinked, nothing is deleted. A subsequent deadcode 18 // pass is required to actually remove duplicate expressions. 19 func cse(f *Func) { 20 // Two values are equivalent if they satisfy the following definition: 21 // equivalent(v, w): 22 // v.op == w.op 23 // v.type == w.type 24 // v.aux == w.aux 25 // v.auxint == w.auxint 26 // len(v.args) == len(w.args) 27 // v.block == w.block if v.op == OpPhi 28 // equivalent(v.args[i], w.args[i]) for i in 0..len(v.args)-1 29 30 // The algorithm searches for a partition of f's values into 31 // equivalence classes using the above definition. 32 // It starts with a coarse partition and iteratively refines it 33 // until it reaches a fixed point. 34 35 // Make initial coarse partitions by using a subset of the conditions above. 36 a := make([]*Value, 0, f.NumValues()) 37 auxIDs := auxmap{} 38 for _, b := range f.Blocks { 39 for _, v := range b.Values { 40 if auxIDs[v.Aux] == 0 { 41 auxIDs[v.Aux] = int32(len(auxIDs)) + 1 42 } 43 if v.Type.IsMemory() { 44 continue // memory values can never cse 45 } 46 if opcodeTable[v.Op].commutative && len(v.Args) == 2 && v.Args[1].ID < v.Args[0].ID { 47 // Order the arguments of binary commutative operations. 48 v.Args[0], v.Args[1] = v.Args[1], v.Args[0] 49 } 50 a = append(a, v) 51 } 52 } 53 partition := partitionValues(a, auxIDs) 54 55 // map from value id back to eqclass id 56 valueEqClass := make([]ID, f.NumValues()) 57 for _, b := range f.Blocks { 58 for _, v := range b.Values { 59 // Use negative equivalence class #s for unique values. 60 valueEqClass[v.ID] = -v.ID 61 } 62 } 63 for i, e := range partition { 64 if f.pass.debug > 1 && len(e) > 500 { 65 fmt.Printf("CSE.large partition (%d): ", len(e)) 66 for j := 0; j < 3; j++ { 67 fmt.Printf("%s ", e[j].LongString()) 68 } 69 fmt.Println() 70 } 71 72 for _, v := range e { 73 valueEqClass[v.ID] = ID(i) 74 } 75 if f.pass.debug > 2 && len(e) > 1 { 76 fmt.Printf("CSE.partition #%d:", i) 77 for _, v := range e { 78 fmt.Printf(" %s", v.String()) 79 } 80 fmt.Printf("\n") 81 } 82 } 83 84 // Find an equivalence class where some members of the class have 85 // non-equivalent arguments. Split the equivalence class appropriately. 86 // Repeat until we can't find any more splits. 87 for { 88 changed := false 89 90 // partition can grow in the loop. By not using a range loop here, 91 // we process new additions as they arrive, avoiding O(n^2) behavior. 92 for i := 0; i < len(partition); i++ { 93 e := partition[i] 94 v := e[0] 95 // all values in this equiv class that are not equivalent to v get moved 96 // into another equiv class. 97 // To avoid allocating while building that equivalence class, 98 // move the values equivalent to v to the beginning of e 99 // and other values to the end of e. 100 allvals := e 101 eqloop: 102 for j := 1; j < len(e); { 103 w := e[j] 104 equivalent := true 105 for i := 0; i < len(v.Args); i++ { 106 if valueEqClass[v.Args[i].ID] != valueEqClass[w.Args[i].ID] { 107 equivalent = false 108 break 109 } 110 } 111 if !equivalent || v.Type.Compare(w.Type) != CMPeq { 112 // w is not equivalent to v. 113 // move it to the end and shrink e. 114 e[j], e[len(e)-1] = e[len(e)-1], e[j] 115 e = e[:len(e)-1] 116 valueEqClass[w.ID] = ID(len(partition)) 117 changed = true 118 continue eqloop 119 } 120 // v and w are equivalent. Keep w in e. 121 j++ 122 } 123 partition[i] = e 124 if len(e) < len(allvals) { 125 partition = append(partition, allvals[len(e):]) 126 } 127 } 128 129 if !changed { 130 break 131 } 132 } 133 134 // Dominator tree (f.sdom) is computed by the generic domtree pass. 135 136 // Compute substitutions we would like to do. We substitute v for w 137 // if v and w are in the same equivalence class and v dominates w. 138 rewrite := make([]*Value, f.NumValues()) 139 for _, e := range partition { 140 sort.Sort(partitionByDom{e, f.sdom}) 141 for i := 0; i < len(e)-1; i++ { 142 // e is sorted by domorder, so a maximal dominant element is first in the slice 143 v := e[i] 144 if v == nil { 145 continue 146 } 147 148 e[i] = nil 149 // Replace all elements of e which v dominates 150 for j := i + 1; j < len(e); j++ { 151 w := e[j] 152 if w == nil { 153 continue 154 } 155 if f.sdom.isAncestorEq(v.Block, w.Block) { 156 rewrite[w.ID] = v 157 e[j] = nil 158 } else { 159 // e is sorted by domorder, so v.Block doesn't dominate any subsequent blocks in e 160 break 161 } 162 } 163 } 164 } 165 166 rewrites := int64(0) 167 168 // Apply substitutions 169 for _, b := range f.Blocks { 170 for _, v := range b.Values { 171 for i, w := range v.Args { 172 if x := rewrite[w.ID]; x != nil { 173 v.SetArg(i, x) 174 rewrites++ 175 } 176 } 177 } 178 if v := b.Control; v != nil { 179 if x := rewrite[v.ID]; x != nil { 180 if v.Op == OpNilCheck { 181 // nilcheck pass will remove the nil checks and log 182 // them appropriately, so don't mess with them here. 183 continue 184 } 185 b.SetControl(x) 186 } 187 } 188 } 189 if f.pass.stats > 0 { 190 f.LogStat("CSE REWRITES", rewrites) 191 } 192 } 193 194 // An eqclass approximates an equivalence class. During the 195 // algorithm it may represent the union of several of the 196 // final equivalence classes. 197 type eqclass []*Value 198 199 // partitionValues partitions the values into equivalence classes 200 // based on having all the following features match: 201 // - opcode 202 // - type 203 // - auxint 204 // - aux 205 // - nargs 206 // - block # if a phi op 207 // - first two arg's opcodes and auxint 208 // - NOT first two arg's aux; that can break CSE. 209 // partitionValues returns a list of equivalence classes, each 210 // being a sorted by ID list of *Values. The eqclass slices are 211 // backed by the same storage as the input slice. 212 // Equivalence classes of size 1 are ignored. 213 func partitionValues(a []*Value, auxIDs auxmap) []eqclass { 214 sort.Sort(sortvalues{a, auxIDs}) 215 216 var partition []eqclass 217 for len(a) > 0 { 218 v := a[0] 219 j := 1 220 for ; j < len(a); j++ { 221 w := a[j] 222 if cmpVal(v, w, auxIDs, cmpDepth) != CMPeq { 223 break 224 } 225 } 226 if j > 1 { 227 partition = append(partition, a[:j]) 228 } 229 a = a[j:] 230 } 231 232 return partition 233 } 234 func lt2Cmp(isLt bool) Cmp { 235 if isLt { 236 return CMPlt 237 } 238 return CMPgt 239 } 240 241 type auxmap map[interface{}]int32 242 243 func cmpVal(v, w *Value, auxIDs auxmap, depth int) Cmp { 244 // Try to order these comparison by cost (cheaper first) 245 if v.Op != w.Op { 246 return lt2Cmp(v.Op < w.Op) 247 } 248 if v.AuxInt != w.AuxInt { 249 return lt2Cmp(v.AuxInt < w.AuxInt) 250 } 251 if len(v.Args) != len(w.Args) { 252 return lt2Cmp(len(v.Args) < len(w.Args)) 253 } 254 if v.Op == OpPhi && v.Block != w.Block { 255 return lt2Cmp(v.Block.ID < w.Block.ID) 256 } 257 if v.Type.IsMemory() { 258 // We will never be able to CSE two values 259 // that generate memory. 260 return lt2Cmp(v.ID < w.ID) 261 } 262 263 if tc := v.Type.Compare(w.Type); tc != CMPeq { 264 return tc 265 } 266 267 if v.Aux != w.Aux { 268 if v.Aux == nil { 269 return CMPlt 270 } 271 if w.Aux == nil { 272 return CMPgt 273 } 274 return lt2Cmp(auxIDs[v.Aux] < auxIDs[w.Aux]) 275 } 276 277 if depth > 0 { 278 for i := range v.Args { 279 if v.Args[i] == w.Args[i] { 280 // skip comparing equal args 281 continue 282 } 283 if ac := cmpVal(v.Args[i], w.Args[i], auxIDs, depth-1); ac != CMPeq { 284 return ac 285 } 286 } 287 } 288 289 return CMPeq 290 } 291 292 // Sort values to make the initial partition. 293 type sortvalues struct { 294 a []*Value // array of values 295 auxIDs auxmap // aux -> aux ID map 296 } 297 298 func (sv sortvalues) Len() int { return len(sv.a) } 299 func (sv sortvalues) Swap(i, j int) { sv.a[i], sv.a[j] = sv.a[j], sv.a[i] } 300 func (sv sortvalues) Less(i, j int) bool { 301 v := sv.a[i] 302 w := sv.a[j] 303 if cmp := cmpVal(v, w, sv.auxIDs, cmpDepth); cmp != CMPeq { 304 return cmp == CMPlt 305 } 306 307 // Sort by value ID last to keep the sort result deterministic. 308 return v.ID < w.ID 309 } 310 311 type partitionByDom struct { 312 a []*Value // array of values 313 sdom SparseTree 314 } 315 316 func (sv partitionByDom) Len() int { return len(sv.a) } 317 func (sv partitionByDom) Swap(i, j int) { sv.a[i], sv.a[j] = sv.a[j], sv.a[i] } 318 func (sv partitionByDom) Less(i, j int) bool { 319 v := sv.a[i] 320 w := sv.a[j] 321 return sv.sdom.domorder(v.Block) < sv.sdom.domorder(w.Block) 322 }