github.com/robhaswell/grandperspective-scan@v0.1.0/test/go-go1.7.1/src/cmd/compile/internal/ssa/rewrite.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 "math" 10 "os" 11 "path/filepath" 12 ) 13 14 func applyRewrite(f *Func, rb func(*Block) bool, rv func(*Value, *Config) bool) { 15 // repeat rewrites until we find no more rewrites 16 var curb *Block 17 var curv *Value 18 defer func() { 19 if curb != nil { 20 curb.Fatalf("panic during rewrite of block %s\n", curb.LongString()) 21 } 22 if curv != nil { 23 curv.Fatalf("panic during rewrite of value %s\n", curv.LongString()) 24 // TODO(khr): print source location also 25 } 26 }() 27 config := f.Config 28 for { 29 change := false 30 for _, b := range f.Blocks { 31 if b.Control != nil && b.Control.Op == OpCopy { 32 for b.Control.Op == OpCopy { 33 b.SetControl(b.Control.Args[0]) 34 } 35 } 36 curb = b 37 if rb(b) { 38 change = true 39 } 40 curb = nil 41 for _, v := range b.Values { 42 change = phielimValue(v) || change 43 44 // Eliminate copy inputs. 45 // If any copy input becomes unused, mark it 46 // as invalid and discard its argument. Repeat 47 // recursively on the discarded argument. 48 // This phase helps remove phantom "dead copy" uses 49 // of a value so that a x.Uses==1 rule condition 50 // fires reliably. 51 for i, a := range v.Args { 52 if a.Op != OpCopy { 53 continue 54 } 55 v.SetArg(i, copySource(a)) 56 change = true 57 for a.Uses == 0 { 58 b := a.Args[0] 59 a.reset(OpInvalid) 60 a = b 61 } 62 } 63 64 // apply rewrite function 65 curv = v 66 if rv(v, config) { 67 change = true 68 } 69 curv = nil 70 } 71 } 72 if !change { 73 break 74 } 75 } 76 // remove clobbered values 77 for _, b := range f.Blocks { 78 j := 0 79 for i, v := range b.Values { 80 if v.Op == OpInvalid { 81 f.freeValue(v) 82 continue 83 } 84 if i != j { 85 b.Values[j] = v 86 } 87 j++ 88 } 89 if j != len(b.Values) { 90 tail := b.Values[j:] 91 for j := range tail { 92 tail[j] = nil 93 } 94 b.Values = b.Values[:j] 95 } 96 } 97 } 98 99 // Common functions called from rewriting rules 100 101 func is64BitFloat(t Type) bool { 102 return t.Size() == 8 && t.IsFloat() 103 } 104 105 func is32BitFloat(t Type) bool { 106 return t.Size() == 4 && t.IsFloat() 107 } 108 109 func is64BitInt(t Type) bool { 110 return t.Size() == 8 && t.IsInteger() 111 } 112 113 func is32BitInt(t Type) bool { 114 return t.Size() == 4 && t.IsInteger() 115 } 116 117 func is16BitInt(t Type) bool { 118 return t.Size() == 2 && t.IsInteger() 119 } 120 121 func is8BitInt(t Type) bool { 122 return t.Size() == 1 && t.IsInteger() 123 } 124 125 func isPtr(t Type) bool { 126 return t.IsPtrShaped() 127 } 128 129 func isSigned(t Type) bool { 130 return t.IsSigned() 131 } 132 133 func typeSize(t Type) int64 { 134 return t.Size() 135 } 136 137 // mergeSym merges two symbolic offsets. There is no real merging of 138 // offsets, we just pick the non-nil one. 139 func mergeSym(x, y interface{}) interface{} { 140 if x == nil { 141 return y 142 } 143 if y == nil { 144 return x 145 } 146 panic(fmt.Sprintf("mergeSym with two non-nil syms %s %s", x, y)) 147 } 148 func canMergeSym(x, y interface{}) bool { 149 return x == nil || y == nil 150 } 151 152 // nlz returns the number of leading zeros. 153 func nlz(x int64) int64 { 154 // log2(0) == 1, so nlz(0) == 64 155 return 63 - log2(x) 156 } 157 158 // ntz returns the number of trailing zeros. 159 func ntz(x int64) int64 { 160 return 64 - nlz(^x&(x-1)) 161 } 162 163 // nlo returns the number of leading ones. 164 func nlo(x int64) int64 { 165 return nlz(^x) 166 } 167 168 // nto returns the number of trailing ones. 169 func nto(x int64) int64 { 170 return ntz(^x) 171 } 172 173 // log2 returns logarithm in base of uint64(n), with log2(0) = -1. 174 func log2(n int64) (l int64) { 175 l = -1 176 x := uint64(n) 177 for ; x >= 0x8000; x >>= 16 { 178 l += 16 179 } 180 if x >= 0x80 { 181 x >>= 8 182 l += 8 183 } 184 if x >= 0x8 { 185 x >>= 4 186 l += 4 187 } 188 if x >= 0x2 { 189 x >>= 2 190 l += 2 191 } 192 if x >= 0x1 { 193 l++ 194 } 195 return 196 } 197 198 // isPowerOfTwo reports whether n is a power of 2. 199 func isPowerOfTwo(n int64) bool { 200 return n > 0 && n&(n-1) == 0 201 } 202 203 // is32Bit reports whether n can be represented as a signed 32 bit integer. 204 func is32Bit(n int64) bool { 205 return n == int64(int32(n)) 206 } 207 208 // b2i translates a boolean value to 0 or 1 for assigning to auxInt. 209 func b2i(b bool) int64 { 210 if b { 211 return 1 212 } 213 return 0 214 } 215 216 // i2f is used in rules for converting from an AuxInt to a float. 217 func i2f(i int64) float64 { 218 return math.Float64frombits(uint64(i)) 219 } 220 221 // i2f32 is used in rules for converting from an AuxInt to a float32. 222 func i2f32(i int64) float32 { 223 return float32(math.Float64frombits(uint64(i))) 224 } 225 226 // f2i is used in the rules for storing a float in AuxInt. 227 func f2i(f float64) int64 { 228 return int64(math.Float64bits(f)) 229 } 230 231 // uaddOvf returns true if unsigned a+b would overflow. 232 func uaddOvf(a, b int64) bool { 233 return uint64(a)+uint64(b) < uint64(a) 234 } 235 236 // isSamePtr reports whether p1 and p2 point to the same address. 237 func isSamePtr(p1, p2 *Value) bool { 238 if p1 == p2 { 239 return true 240 } 241 if p1.Op != p2.Op { 242 return false 243 } 244 switch p1.Op { 245 case OpOffPtr: 246 return p1.AuxInt == p2.AuxInt && isSamePtr(p1.Args[0], p2.Args[0]) 247 case OpAddr: 248 // OpAddr's 0th arg is either OpSP or OpSB, which means that it is uniquely identified by its Op. 249 // Checking for value equality only works after [z]cse has run. 250 return p1.Aux == p2.Aux && p1.Args[0].Op == p2.Args[0].Op 251 case OpAddPtr: 252 return p1.Args[1] == p2.Args[1] && isSamePtr(p1.Args[0], p2.Args[0]) 253 } 254 return false 255 } 256 257 // mergePoint finds a block among a's blocks which dominates b and is itself 258 // dominated by all of a's blocks. Returns nil if it can't find one. 259 // Might return nil even if one does exist. 260 func mergePoint(b *Block, a ...*Value) *Block { 261 // Walk backward from b looking for one of the a's blocks. 262 263 // Max distance 264 d := 100 265 266 for d > 0 { 267 for _, x := range a { 268 if b == x.Block { 269 goto found 270 } 271 } 272 if len(b.Preds) > 1 { 273 // Don't know which way to go back. Abort. 274 return nil 275 } 276 b = b.Preds[0].b 277 d-- 278 } 279 return nil // too far away 280 found: 281 // At this point, r is the first value in a that we find by walking backwards. 282 // if we return anything, r will be it. 283 r := b 284 285 // Keep going, counting the other a's that we find. They must all dominate r. 286 na := 0 287 for d > 0 { 288 for _, x := range a { 289 if b == x.Block { 290 na++ 291 } 292 } 293 if na == len(a) { 294 // Found all of a in a backwards walk. We can return r. 295 return r 296 } 297 if len(b.Preds) > 1 { 298 return nil 299 } 300 b = b.Preds[0].b 301 d-- 302 303 } 304 return nil // too far away 305 } 306 307 // clobber invalidates v. Returns true. 308 // clobber is used by rewrite rules to: 309 // A) make sure v is really dead and never used again. 310 // B) decrement use counts of v's args. 311 func clobber(v *Value) bool { 312 v.reset(OpInvalid) 313 // Note: leave v.Block intact. The Block field is used after clobber. 314 return true 315 } 316 317 // logRule logs the use of the rule s. This will only be enabled if 318 // rewrite rules were generated with the -log option, see gen/rulegen.go. 319 func logRule(s string) { 320 if ruleFile == nil { 321 // Open a log file to write log to. We open in append 322 // mode because all.bash runs the compiler lots of times, 323 // and we want the concatenation of all of those logs. 324 // This means, of course, that users need to rm the old log 325 // to get fresh data. 326 // TODO: all.bash runs compilers in parallel. Need to synchronize logging somehow? 327 w, err := os.OpenFile(filepath.Join(os.Getenv("GOROOT"), "src", "rulelog"), 328 os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) 329 if err != nil { 330 panic(err) 331 } 332 ruleFile = w 333 } 334 _, err := fmt.Fprintf(ruleFile, "rewrite %s\n", s) 335 if err != nil { 336 panic(err) 337 } 338 } 339 340 var ruleFile *os.File