github.com/euank/go@v0.0.0-20160829210321-495514729181/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 // isArg returns whether s is an arg symbol 153 func isArg(s interface{}) bool { 154 _, ok := s.(*ArgSymbol) 155 return ok 156 } 157 158 // isAuto returns whether s is an auto symbol 159 func isAuto(s interface{}) bool { 160 _, ok := s.(*AutoSymbol) 161 return ok 162 } 163 164 // nlz returns the number of leading zeros. 165 func nlz(x int64) int64 { 166 // log2(0) == 1, so nlz(0) == 64 167 return 63 - log2(x) 168 } 169 170 // ntz returns the number of trailing zeros. 171 func ntz(x int64) int64 { 172 return 64 - nlz(^x&(x-1)) 173 } 174 175 // nlo returns the number of leading ones. 176 func nlo(x int64) int64 { 177 return nlz(^x) 178 } 179 180 // nto returns the number of trailing ones. 181 func nto(x int64) int64 { 182 return ntz(^x) 183 } 184 185 // log2 returns logarithm in base of uint64(n), with log2(0) = -1. 186 func log2(n int64) (l int64) { 187 l = -1 188 x := uint64(n) 189 for ; x >= 0x8000; x >>= 16 { 190 l += 16 191 } 192 if x >= 0x80 { 193 x >>= 8 194 l += 8 195 } 196 if x >= 0x8 { 197 x >>= 4 198 l += 4 199 } 200 if x >= 0x2 { 201 x >>= 2 202 l += 2 203 } 204 if x >= 0x1 { 205 l++ 206 } 207 return 208 } 209 210 // isPowerOfTwo reports whether n is a power of 2. 211 func isPowerOfTwo(n int64) bool { 212 return n > 0 && n&(n-1) == 0 213 } 214 215 // is32Bit reports whether n can be represented as a signed 32 bit integer. 216 func is32Bit(n int64) bool { 217 return n == int64(int32(n)) 218 } 219 220 // is16Bit reports whether n can be represented as a signed 16 bit integer. 221 func is16Bit(n int64) bool { 222 return n == int64(int16(n)) 223 } 224 225 // b2i translates a boolean value to 0 or 1 for assigning to auxInt. 226 func b2i(b bool) int64 { 227 if b { 228 return 1 229 } 230 return 0 231 } 232 233 // i2f is used in rules for converting from an AuxInt to a float. 234 func i2f(i int64) float64 { 235 return math.Float64frombits(uint64(i)) 236 } 237 238 // i2f32 is used in rules for converting from an AuxInt to a float32. 239 func i2f32(i int64) float32 { 240 return float32(math.Float64frombits(uint64(i))) 241 } 242 243 // f2i is used in the rules for storing a float in AuxInt. 244 func f2i(f float64) int64 { 245 return int64(math.Float64bits(f)) 246 } 247 248 // uaddOvf returns true if unsigned a+b would overflow. 249 func uaddOvf(a, b int64) bool { 250 return uint64(a)+uint64(b) < uint64(a) 251 } 252 253 // isSamePtr reports whether p1 and p2 point to the same address. 254 func isSamePtr(p1, p2 *Value) bool { 255 if p1 == p2 { 256 return true 257 } 258 if p1.Op != p2.Op { 259 return false 260 } 261 switch p1.Op { 262 case OpOffPtr: 263 return p1.AuxInt == p2.AuxInt && isSamePtr(p1.Args[0], p2.Args[0]) 264 case OpAddr: 265 // OpAddr's 0th arg is either OpSP or OpSB, which means that it is uniquely identified by its Op. 266 // Checking for value equality only works after [z]cse has run. 267 return p1.Aux == p2.Aux && p1.Args[0].Op == p2.Args[0].Op 268 case OpAddPtr: 269 return p1.Args[1] == p2.Args[1] && isSamePtr(p1.Args[0], p2.Args[0]) 270 } 271 return false 272 } 273 274 // moveSize returns the number of bytes an aligned MOV instruction moves 275 func moveSize(align int64, c *Config) int64 { 276 switch { 277 case align%8 == 0 && c.IntSize == 8: 278 return 8 279 case align%4 == 0: 280 return 4 281 case align%2 == 0: 282 return 2 283 } 284 return 1 285 } 286 287 // mergePoint finds a block among a's blocks which dominates b and is itself 288 // dominated by all of a's blocks. Returns nil if it can't find one. 289 // Might return nil even if one does exist. 290 func mergePoint(b *Block, a ...*Value) *Block { 291 // Walk backward from b looking for one of the a's blocks. 292 293 // Max distance 294 d := 100 295 296 for d > 0 { 297 for _, x := range a { 298 if b == x.Block { 299 goto found 300 } 301 } 302 if len(b.Preds) > 1 { 303 // Don't know which way to go back. Abort. 304 return nil 305 } 306 b = b.Preds[0].b 307 d-- 308 } 309 return nil // too far away 310 found: 311 // At this point, r is the first value in a that we find by walking backwards. 312 // if we return anything, r will be it. 313 r := b 314 315 // Keep going, counting the other a's that we find. They must all dominate r. 316 na := 0 317 for d > 0 { 318 for _, x := range a { 319 if b == x.Block { 320 na++ 321 } 322 } 323 if na == len(a) { 324 // Found all of a in a backwards walk. We can return r. 325 return r 326 } 327 if len(b.Preds) > 1 { 328 return nil 329 } 330 b = b.Preds[0].b 331 d-- 332 333 } 334 return nil // too far away 335 } 336 337 // clobber invalidates v. Returns true. 338 // clobber is used by rewrite rules to: 339 // A) make sure v is really dead and never used again. 340 // B) decrement use counts of v's args. 341 func clobber(v *Value) bool { 342 v.reset(OpInvalid) 343 // Note: leave v.Block intact. The Block field is used after clobber. 344 return true 345 } 346 347 // logRule logs the use of the rule s. This will only be enabled if 348 // rewrite rules were generated with the -log option, see gen/rulegen.go. 349 func logRule(s string) { 350 if ruleFile == nil { 351 // Open a log file to write log to. We open in append 352 // mode because all.bash runs the compiler lots of times, 353 // and we want the concatenation of all of those logs. 354 // This means, of course, that users need to rm the old log 355 // to get fresh data. 356 // TODO: all.bash runs compilers in parallel. Need to synchronize logging somehow? 357 w, err := os.OpenFile(filepath.Join(os.Getenv("GOROOT"), "src", "rulelog"), 358 os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) 359 if err != nil { 360 panic(err) 361 } 362 ruleFile = w 363 } 364 _, err := fmt.Fprintf(ruleFile, "rewrite %s\n", s) 365 if err != nil { 366 panic(err) 367 } 368 } 369 370 var ruleFile *os.File