github.com/hlts2/go@v0.0.0-20170904000733-812b34efaed8/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 "cmd/compile/internal/types" 9 "cmd/internal/obj" 10 "fmt" 11 "io" 12 "math" 13 "os" 14 "path/filepath" 15 ) 16 17 func applyRewrite(f *Func, rb blockRewriter, rv valueRewriter) { 18 // repeat rewrites until we find no more rewrites 19 for { 20 change := false 21 for _, b := range f.Blocks { 22 if b.Control != nil && b.Control.Op == OpCopy { 23 for b.Control.Op == OpCopy { 24 b.SetControl(b.Control.Args[0]) 25 } 26 } 27 if rb(b) { 28 change = true 29 } 30 for _, v := range b.Values { 31 change = phielimValue(v) || change 32 33 // Eliminate copy inputs. 34 // If any copy input becomes unused, mark it 35 // as invalid and discard its argument. Repeat 36 // recursively on the discarded argument. 37 // This phase helps remove phantom "dead copy" uses 38 // of a value so that a x.Uses==1 rule condition 39 // fires reliably. 40 for i, a := range v.Args { 41 if a.Op != OpCopy { 42 continue 43 } 44 v.SetArg(i, copySource(a)) 45 change = true 46 for a.Uses == 0 { 47 b := a.Args[0] 48 a.reset(OpInvalid) 49 a = b 50 } 51 } 52 53 // apply rewrite function 54 if rv(v) { 55 change = true 56 } 57 } 58 } 59 if !change { 60 break 61 } 62 } 63 // remove clobbered values 64 for _, b := range f.Blocks { 65 j := 0 66 for i, v := range b.Values { 67 if v.Op == OpInvalid { 68 f.freeValue(v) 69 continue 70 } 71 if i != j { 72 b.Values[j] = v 73 } 74 j++ 75 } 76 if j != len(b.Values) { 77 tail := b.Values[j:] 78 for j := range tail { 79 tail[j] = nil 80 } 81 b.Values = b.Values[:j] 82 } 83 } 84 } 85 86 // Common functions called from rewriting rules 87 88 func is64BitFloat(t *types.Type) bool { 89 return t.Size() == 8 && t.IsFloat() 90 } 91 92 func is32BitFloat(t *types.Type) bool { 93 return t.Size() == 4 && t.IsFloat() 94 } 95 96 func is64BitInt(t *types.Type) bool { 97 return t.Size() == 8 && t.IsInteger() 98 } 99 100 func is32BitInt(t *types.Type) bool { 101 return t.Size() == 4 && t.IsInteger() 102 } 103 104 func is16BitInt(t *types.Type) bool { 105 return t.Size() == 2 && t.IsInteger() 106 } 107 108 func is8BitInt(t *types.Type) bool { 109 return t.Size() == 1 && t.IsInteger() 110 } 111 112 func isPtr(t *types.Type) bool { 113 return t.IsPtrShaped() 114 } 115 116 func isSigned(t *types.Type) bool { 117 return t.IsSigned() 118 } 119 120 func typeSize(t *types.Type) int64 { 121 return t.Size() 122 } 123 124 // mergeSym merges two symbolic offsets. There is no real merging of 125 // offsets, we just pick the non-nil one. 126 func mergeSym(x, y interface{}) interface{} { 127 if x == nil { 128 return y 129 } 130 if y == nil { 131 return x 132 } 133 panic(fmt.Sprintf("mergeSym with two non-nil syms %s %s", x, y)) 134 } 135 func canMergeSym(x, y interface{}) bool { 136 return x == nil || y == nil 137 } 138 139 // canMergeLoad reports whether the load can be merged into target without 140 // invalidating the schedule. 141 // It also checks that the other non-load argument x is something we 142 // are ok with clobbering (all our current load+op instructions clobber 143 // their input register). 144 func canMergeLoad(target, load, x *Value) bool { 145 if target.Block.ID != load.Block.ID { 146 // If the load is in a different block do not merge it. 147 return false 148 } 149 150 // We can't merge the load into the target if the load 151 // has more than one use. 152 if load.Uses != 1 { 153 return false 154 } 155 156 // The register containing x is going to get clobbered. 157 // Don't merge if we still need the value of x. 158 // We don't have liveness information here, but we can 159 // approximate x dying with: 160 // 1) target is x's only use. 161 // 2) target is not in a deeper loop than x. 162 if x.Uses != 1 { 163 return false 164 } 165 loopnest := x.Block.Func.loopnest() 166 loopnest.calculateDepths() 167 if loopnest.depth(target.Block.ID) > loopnest.depth(x.Block.ID) { 168 return false 169 } 170 171 mem := load.MemoryArg() 172 173 // We need the load's memory arg to still be alive at target. That 174 // can't be the case if one of target's args depends on a memory 175 // state that is a successor of load's memory arg. 176 // 177 // For example, it would be invalid to merge load into target in 178 // the following situation because newmem has killed oldmem 179 // before target is reached: 180 // load = read ... oldmem 181 // newmem = write ... oldmem 182 // arg0 = read ... newmem 183 // target = add arg0 load 184 // 185 // If the argument comes from a different block then we can exclude 186 // it immediately because it must dominate load (which is in the 187 // same block as target). 188 var args []*Value 189 for _, a := range target.Args { 190 if a != load && a.Block.ID == target.Block.ID { 191 args = append(args, a) 192 } 193 } 194 195 // memPreds contains memory states known to be predecessors of load's 196 // memory state. It is lazily initialized. 197 var memPreds map[*Value]bool 198 search: 199 for i := 0; len(args) > 0; i++ { 200 const limit = 100 201 if i >= limit { 202 // Give up if we have done a lot of iterations. 203 return false 204 } 205 v := args[len(args)-1] 206 args = args[:len(args)-1] 207 if target.Block.ID != v.Block.ID { 208 // Since target and load are in the same block 209 // we can stop searching when we leave the block. 210 continue search 211 } 212 if v.Op == OpPhi { 213 // A Phi implies we have reached the top of the block. 214 // The memory phi, if it exists, is always 215 // the first logical store in the block. 216 continue search 217 } 218 if v.Type.IsTuple() && v.Type.FieldType(1).IsMemory() { 219 // We could handle this situation however it is likely 220 // to be very rare. 221 return false 222 } 223 if v.Type.IsMemory() { 224 if memPreds == nil { 225 // Initialise a map containing memory states 226 // known to be predecessors of load's memory 227 // state. 228 memPreds = make(map[*Value]bool) 229 m := mem 230 const limit = 50 231 for i := 0; i < limit; i++ { 232 if m.Op == OpPhi { 233 // The memory phi, if it exists, is always 234 // the first logical store in the block. 235 break 236 } 237 if m.Block.ID != target.Block.ID { 238 break 239 } 240 if !m.Type.IsMemory() { 241 break 242 } 243 memPreds[m] = true 244 if len(m.Args) == 0 { 245 break 246 } 247 m = m.MemoryArg() 248 } 249 } 250 251 // We can merge if v is a predecessor of mem. 252 // 253 // For example, we can merge load into target in the 254 // following scenario: 255 // x = read ... v 256 // mem = write ... v 257 // load = read ... mem 258 // target = add x load 259 if memPreds[v] { 260 continue search 261 } 262 return false 263 } 264 if len(v.Args) > 0 && v.Args[len(v.Args)-1] == mem { 265 // If v takes mem as an input then we know mem 266 // is valid at this point. 267 continue search 268 } 269 for _, a := range v.Args { 270 if target.Block.ID == a.Block.ID { 271 args = append(args, a) 272 } 273 } 274 } 275 276 return true 277 } 278 279 // isArg returns whether s is an arg symbol 280 func isArg(s interface{}) bool { 281 _, ok := s.(*ArgSymbol) 282 return ok 283 } 284 285 // isAuto returns whether s is an auto symbol 286 func isAuto(s interface{}) bool { 287 _, ok := s.(*AutoSymbol) 288 return ok 289 } 290 291 // isSameSym returns whether sym is the same as the given named symbol 292 func isSameSym(sym interface{}, name string) bool { 293 s, ok := sym.(fmt.Stringer) 294 return ok && s.String() == name 295 } 296 297 // nlz returns the number of leading zeros. 298 func nlz(x int64) int64 { 299 // log2(0) == 1, so nlz(0) == 64 300 return 63 - log2(x) 301 } 302 303 // ntz returns the number of trailing zeros. 304 func ntz(x int64) int64 { 305 return 64 - nlz(^x&(x-1)) 306 } 307 308 func oneBit(x int64) bool { 309 return nlz(x)+ntz(x) == 63 310 } 311 312 // nlo returns the number of leading ones. 313 func nlo(x int64) int64 { 314 return nlz(^x) 315 } 316 317 // nto returns the number of trailing ones. 318 func nto(x int64) int64 { 319 return ntz(^x) 320 } 321 322 // log2 returns logarithm in base 2 of uint64(n), with log2(0) = -1. 323 // Rounds down. 324 func log2(n int64) (l int64) { 325 l = -1 326 x := uint64(n) 327 for ; x >= 0x8000; x >>= 16 { 328 l += 16 329 } 330 if x >= 0x80 { 331 x >>= 8 332 l += 8 333 } 334 if x >= 0x8 { 335 x >>= 4 336 l += 4 337 } 338 if x >= 0x2 { 339 x >>= 2 340 l += 2 341 } 342 if x >= 0x1 { 343 l++ 344 } 345 return 346 } 347 348 // isPowerOfTwo reports whether n is a power of 2. 349 func isPowerOfTwo(n int64) bool { 350 return n > 0 && n&(n-1) == 0 351 } 352 353 // is32Bit reports whether n can be represented as a signed 32 bit integer. 354 func is32Bit(n int64) bool { 355 return n == int64(int32(n)) 356 } 357 358 // is16Bit reports whether n can be represented as a signed 16 bit integer. 359 func is16Bit(n int64) bool { 360 return n == int64(int16(n)) 361 } 362 363 // isU12Bit reports whether n can be represented as an unsigned 12 bit integer. 364 func isU12Bit(n int64) bool { 365 return 0 <= n && n < (1<<12) 366 } 367 368 // isU16Bit reports whether n can be represented as an unsigned 16 bit integer. 369 func isU16Bit(n int64) bool { 370 return n == int64(uint16(n)) 371 } 372 373 // isU32Bit reports whether n can be represented as an unsigned 32 bit integer. 374 func isU32Bit(n int64) bool { 375 return n == int64(uint32(n)) 376 } 377 378 // is20Bit reports whether n can be represented as a signed 20 bit integer. 379 func is20Bit(n int64) bool { 380 return -(1<<19) <= n && n < (1<<19) 381 } 382 383 // b2i translates a boolean value to 0 or 1 for assigning to auxInt. 384 func b2i(b bool) int64 { 385 if b { 386 return 1 387 } 388 return 0 389 } 390 391 // i2f is used in rules for converting from an AuxInt to a float. 392 func i2f(i int64) float64 { 393 return math.Float64frombits(uint64(i)) 394 } 395 396 // i2f32 is used in rules for converting from an AuxInt to a float32. 397 func i2f32(i int64) float32 { 398 return float32(math.Float64frombits(uint64(i))) 399 } 400 401 // f2i is used in the rules for storing a float in AuxInt. 402 func f2i(f float64) int64 { 403 return int64(math.Float64bits(f)) 404 } 405 406 // uaddOvf returns true if unsigned a+b would overflow. 407 func uaddOvf(a, b int64) bool { 408 return uint64(a)+uint64(b) < uint64(a) 409 } 410 411 // de-virtualize an InterCall 412 // 'sym' is the symbol for the itab 413 func devirt(v *Value, sym interface{}, offset int64) *obj.LSym { 414 f := v.Block.Func 415 ext, ok := sym.(*ExternSymbol) 416 if !ok { 417 return nil 418 } 419 lsym := f.fe.DerefItab(ext.Sym, offset) 420 if f.pass.debug > 0 { 421 if lsym != nil { 422 f.Warnl(v.Pos, "de-virtualizing call") 423 } else { 424 f.Warnl(v.Pos, "couldn't de-virtualize call") 425 } 426 } 427 return lsym 428 } 429 430 // isSamePtr reports whether p1 and p2 point to the same address. 431 func isSamePtr(p1, p2 *Value) bool { 432 if p1 == p2 { 433 return true 434 } 435 if p1.Op != p2.Op { 436 return false 437 } 438 switch p1.Op { 439 case OpOffPtr: 440 return p1.AuxInt == p2.AuxInt && isSamePtr(p1.Args[0], p2.Args[0]) 441 case OpAddr: 442 // OpAddr's 0th arg is either OpSP or OpSB, which means that it is uniquely identified by its Op. 443 // Checking for value equality only works after [z]cse has run. 444 return p1.Aux == p2.Aux && p1.Args[0].Op == p2.Args[0].Op 445 case OpAddPtr: 446 return p1.Args[1] == p2.Args[1] && isSamePtr(p1.Args[0], p2.Args[0]) 447 } 448 return false 449 } 450 451 // moveSize returns the number of bytes an aligned MOV instruction moves 452 func moveSize(align int64, c *Config) int64 { 453 switch { 454 case align%8 == 0 && c.PtrSize == 8: 455 return 8 456 case align%4 == 0: 457 return 4 458 case align%2 == 0: 459 return 2 460 } 461 return 1 462 } 463 464 // mergePoint finds a block among a's blocks which dominates b and is itself 465 // dominated by all of a's blocks. Returns nil if it can't find one. 466 // Might return nil even if one does exist. 467 func mergePoint(b *Block, a ...*Value) *Block { 468 // Walk backward from b looking for one of the a's blocks. 469 470 // Max distance 471 d := 100 472 473 for d > 0 { 474 for _, x := range a { 475 if b == x.Block { 476 goto found 477 } 478 } 479 if len(b.Preds) > 1 { 480 // Don't know which way to go back. Abort. 481 return nil 482 } 483 b = b.Preds[0].b 484 d-- 485 } 486 return nil // too far away 487 found: 488 // At this point, r is the first value in a that we find by walking backwards. 489 // if we return anything, r will be it. 490 r := b 491 492 // Keep going, counting the other a's that we find. They must all dominate r. 493 na := 0 494 for d > 0 { 495 for _, x := range a { 496 if b == x.Block { 497 na++ 498 } 499 } 500 if na == len(a) { 501 // Found all of a in a backwards walk. We can return r. 502 return r 503 } 504 if len(b.Preds) > 1 { 505 return nil 506 } 507 b = b.Preds[0].b 508 d-- 509 510 } 511 return nil // too far away 512 } 513 514 // clobber invalidates v. Returns true. 515 // clobber is used by rewrite rules to: 516 // A) make sure v is really dead and never used again. 517 // B) decrement use counts of v's args. 518 func clobber(v *Value) bool { 519 v.reset(OpInvalid) 520 // Note: leave v.Block intact. The Block field is used after clobber. 521 return true 522 } 523 524 // noteRule is an easy way to track if a rule is matched when writing 525 // new ones. Make the rule of interest also conditional on 526 // noteRule("note to self: rule of interest matched") 527 // and that message will print when the rule matches. 528 func noteRule(s string) bool { 529 fmt.Println(s) 530 return true 531 } 532 533 // warnRule generates a compiler debug output with string s when 534 // cond is true and the rule is fired. 535 func warnRule(cond bool, v *Value, s string) bool { 536 if cond { 537 v.Block.Func.Warnl(v.Pos, s) 538 } 539 return true 540 } 541 542 // logRule logs the use of the rule s. This will only be enabled if 543 // rewrite rules were generated with the -log option, see gen/rulegen.go. 544 func logRule(s string) { 545 if ruleFile == nil { 546 // Open a log file to write log to. We open in append 547 // mode because all.bash runs the compiler lots of times, 548 // and we want the concatenation of all of those logs. 549 // This means, of course, that users need to rm the old log 550 // to get fresh data. 551 // TODO: all.bash runs compilers in parallel. Need to synchronize logging somehow? 552 w, err := os.OpenFile(filepath.Join(os.Getenv("GOROOT"), "src", "rulelog"), 553 os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) 554 if err != nil { 555 panic(err) 556 } 557 ruleFile = w 558 } 559 _, err := fmt.Fprintf(ruleFile, "rewrite %s\n", s) 560 if err != nil { 561 panic(err) 562 } 563 } 564 565 var ruleFile io.Writer 566 567 func min(x, y int64) int64 { 568 if x < y { 569 return x 570 } 571 return y 572 } 573 574 func isConstZero(v *Value) bool { 575 switch v.Op { 576 case OpConstNil: 577 return true 578 case OpConst64, OpConst32, OpConst16, OpConst8, OpConstBool, OpConst32F, OpConst64F: 579 return v.AuxInt == 0 580 } 581 return false 582 } 583 584 // reciprocalExact64 reports whether 1/c is exactly representable. 585 func reciprocalExact64(c float64) bool { 586 b := math.Float64bits(c) 587 man := b & (1<<52 - 1) 588 if man != 0 { 589 return false // not a power of 2, denormal, or NaN 590 } 591 exp := b >> 52 & (1<<11 - 1) 592 // exponent bias is 0x3ff. So taking the reciprocal of a number 593 // changes the exponent to 0x7fe-exp. 594 switch exp { 595 case 0: 596 return false // ±0 597 case 0x7ff: 598 return false // ±inf 599 case 0x7fe: 600 return false // exponent is not representable 601 default: 602 return true 603 } 604 } 605 606 // reciprocalExact32 reports whether 1/c is exactly representable. 607 func reciprocalExact32(c float32) bool { 608 b := math.Float32bits(c) 609 man := b & (1<<23 - 1) 610 if man != 0 { 611 return false // not a power of 2, denormal, or NaN 612 } 613 exp := b >> 23 & (1<<8 - 1) 614 // exponent bias is 0x7f. So taking the reciprocal of a number 615 // changes the exponent to 0xfe-exp. 616 switch exp { 617 case 0: 618 return false // ±0 619 case 0xff: 620 return false // ±inf 621 case 0xfe: 622 return false // exponent is not representable 623 default: 624 return true 625 } 626 } 627 628 // check if an immediate can be directly encoded into an ARM's instruction 629 func isARMImmRot(v uint32) bool { 630 for i := 0; i < 16; i++ { 631 if v&^0xff == 0 { 632 return true 633 } 634 v = v<<2 | v>>30 635 } 636 637 return false 638 } 639 640 // overlap reports whether the ranges given by the given offset and 641 // size pairs overlap. 642 func overlap(offset1, size1, offset2, size2 int64) bool { 643 if offset1 >= offset2 && offset2+size2 > offset1 { 644 return true 645 } 646 if offset2 >= offset1 && offset1+size1 > offset2 { 647 return true 648 } 649 return false 650 } 651 652 // check if value zeroes out upper 32-bit of 64-bit register. 653 // depth limits recursion depth. In AMD64.rules 3 is used as limit, 654 // because it catches same amount of cases as 4. 655 func zeroUpper32Bits(x *Value, depth int) bool { 656 switch x.Op { 657 case OpAMD64MOVLconst, OpAMD64MOVLload, OpAMD64MOVLQZX, OpAMD64MOVLloadidx1, 658 OpAMD64MOVWload, OpAMD64MOVWloadidx1, OpAMD64MOVBload, OpAMD64MOVBloadidx1, 659 OpAMD64MOVLloadidx4, OpAMD64ADDLmem, OpAMD64SUBLmem, OpAMD64ANDLmem, 660 OpAMD64ORLmem, OpAMD64XORLmem, OpAMD64CVTTSD2SL, 661 OpAMD64ADDL, OpAMD64ADDLconst, OpAMD64SUBL, OpAMD64SUBLconst, 662 OpAMD64ANDL, OpAMD64ANDLconst, OpAMD64ORL, OpAMD64ORLconst, 663 OpAMD64XORL, OpAMD64XORLconst, OpAMD64NEGL, OpAMD64NOTL: 664 return true 665 case OpArg, OpSelect0, OpSelect1: 666 return x.Type.Width == 4 667 case OpPhi: 668 // Phis can use each-other as an arguments, instead of tracking visited values, 669 // just limit recursion depth. 670 if depth <= 0 { 671 return false 672 } 673 for i := range x.Args { 674 if !zeroUpper32Bits(x.Args[i], depth-1) { 675 return false 676 } 677 } 678 return true 679 680 } 681 return false 682 }