github.com/FenixAra/go@v0.0.0-20170127160404-96ea0918e670/src/cmd/compile/internal/ssa/prove.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 import ( 8 "fmt" 9 "math" 10 ) 11 12 type branch int 13 14 const ( 15 unknown = iota 16 positive 17 negative 18 ) 19 20 // relation represents the set of possible relations between 21 // pairs of variables (v, w). Without a priori knowledge the 22 // mask is lt | eq | gt meaning v can be less than, equal to or 23 // greater than w. When the execution path branches on the condition 24 // `v op w` the set of relations is updated to exclude any 25 // relation not possible due to `v op w` being true (or false). 26 // 27 // E.g. 28 // 29 // r := relation(...) 30 // 31 // if v < w { 32 // newR := r & lt 33 // } 34 // if v >= w { 35 // newR := r & (eq|gt) 36 // } 37 // if v != w { 38 // newR := r & (lt|gt) 39 // } 40 type relation uint 41 42 const ( 43 lt relation = 1 << iota 44 eq 45 gt 46 ) 47 48 // domain represents the domain of a variable pair in which a set 49 // of relations is known. For example, relations learned for unsigned 50 // pairs cannot be transferred to signed pairs because the same bit 51 // representation can mean something else. 52 type domain uint 53 54 const ( 55 signed domain = 1 << iota 56 unsigned 57 pointer 58 boolean 59 ) 60 61 type pair struct { 62 v, w *Value // a pair of values, ordered by ID. 63 // v can be nil, to mean the zero value. 64 // for booleans the zero value (v == nil) is false. 65 d domain 66 } 67 68 // fact is a pair plus a relation for that pair. 69 type fact struct { 70 p pair 71 r relation 72 } 73 74 // a limit records known upper and lower bounds for a value. 75 type limit struct { 76 min, max int64 // min <= value <= max, signed 77 umin, umax uint64 // umin <= value <= umax, unsigned 78 } 79 80 func (l limit) String() string { 81 return fmt.Sprintf("sm,SM,um,UM=%d,%d,%d,%d", l.min, l.max, l.umin, l.umax) 82 } 83 84 var noLimit = limit{math.MinInt64, math.MaxInt64, 0, math.MaxUint64} 85 86 // a limitFact is a limit known for a particular value. 87 type limitFact struct { 88 vid ID 89 limit limit 90 } 91 92 // factsTable keeps track of relations between pairs of values. 93 type factsTable struct { 94 facts map[pair]relation // current known set of relation 95 stack []fact // previous sets of relations 96 97 // known lower and upper bounds on individual values. 98 limits map[ID]limit 99 limitStack []limitFact // previous entries 100 } 101 102 // checkpointFact is an invalid value used for checkpointing 103 // and restoring factsTable. 104 var checkpointFact = fact{} 105 var checkpointBound = limitFact{} 106 107 func newFactsTable() *factsTable { 108 ft := &factsTable{} 109 ft.facts = make(map[pair]relation) 110 ft.stack = make([]fact, 4) 111 ft.limits = make(map[ID]limit) 112 ft.limitStack = make([]limitFact, 4) 113 return ft 114 } 115 116 // get returns the known possible relations between v and w. 117 // If v and w are not in the map it returns lt|eq|gt, i.e. any order. 118 func (ft *factsTable) get(v, w *Value, d domain) relation { 119 if v.isGenericIntConst() || w.isGenericIntConst() { 120 reversed := false 121 if v.isGenericIntConst() { 122 v, w = w, v 123 reversed = true 124 } 125 r := lt | eq | gt 126 lim, ok := ft.limits[v.ID] 127 if !ok { 128 return r 129 } 130 c := w.AuxInt 131 switch d { 132 case signed: 133 switch { 134 case c < lim.min: 135 r = gt 136 case c > lim.max: 137 r = lt 138 case c == lim.min && c == lim.max: 139 r = eq 140 case c == lim.min: 141 r = gt | eq 142 case c == lim.max: 143 r = lt | eq 144 } 145 case unsigned: 146 // TODO: also use signed data if lim.min >= 0? 147 var uc uint64 148 switch w.Op { 149 case OpConst64: 150 uc = uint64(c) 151 case OpConst32: 152 uc = uint64(uint32(c)) 153 case OpConst16: 154 uc = uint64(uint16(c)) 155 case OpConst8: 156 uc = uint64(uint8(c)) 157 } 158 switch { 159 case uc < lim.umin: 160 r = gt 161 case uc > lim.umax: 162 r = lt 163 case uc == lim.umin && uc == lim.umax: 164 r = eq 165 case uc == lim.umin: 166 r = gt | eq 167 case uc == lim.umax: 168 r = lt | eq 169 } 170 } 171 if reversed { 172 return reverseBits[r] 173 } 174 return r 175 } 176 177 reversed := false 178 if lessByID(w, v) { 179 v, w = w, v 180 reversed = !reversed 181 } 182 183 p := pair{v, w, d} 184 r, ok := ft.facts[p] 185 if !ok { 186 if p.v == p.w { 187 r = eq 188 } else { 189 r = lt | eq | gt 190 } 191 } 192 193 if reversed { 194 return reverseBits[r] 195 } 196 return r 197 } 198 199 // update updates the set of relations between v and w in domain d 200 // restricting it to r. 201 func (ft *factsTable) update(parent *Block, v, w *Value, d domain, r relation) { 202 if lessByID(w, v) { 203 v, w = w, v 204 r = reverseBits[r] 205 } 206 207 p := pair{v, w, d} 208 oldR := ft.get(v, w, d) 209 ft.stack = append(ft.stack, fact{p, oldR}) 210 ft.facts[p] = oldR & r 211 212 // Extract bounds when comparing against constants 213 if v.isGenericIntConst() { 214 v, w = w, v 215 r = reverseBits[r] 216 } 217 if v != nil && w.isGenericIntConst() { 218 c := w.AuxInt 219 // Note: all the +1/-1 below could overflow/underflow. Either will 220 // still generate correct results, it will just lead to imprecision. 221 // In fact if there is overflow/underflow, the corresponding 222 // code is unreachable because the known range is outside the range 223 // of the value's type. 224 old, ok := ft.limits[v.ID] 225 if !ok { 226 old = noLimit 227 } 228 lim := old 229 // Update lim with the new information we know. 230 switch d { 231 case signed: 232 switch r { 233 case lt: 234 if c-1 < lim.max { 235 lim.max = c - 1 236 } 237 case lt | eq: 238 if c < lim.max { 239 lim.max = c 240 } 241 case gt | eq: 242 if c > lim.min { 243 lim.min = c 244 } 245 case gt: 246 if c+1 > lim.min { 247 lim.min = c + 1 248 } 249 case lt | gt: 250 if c == lim.min { 251 lim.min++ 252 } 253 if c == lim.max { 254 lim.max-- 255 } 256 case eq: 257 lim.min = c 258 lim.max = c 259 } 260 case unsigned: 261 var uc uint64 262 switch w.Op { 263 case OpConst64: 264 uc = uint64(c) 265 case OpConst32: 266 uc = uint64(uint32(c)) 267 case OpConst16: 268 uc = uint64(uint16(c)) 269 case OpConst8: 270 uc = uint64(uint8(c)) 271 } 272 switch r { 273 case lt: 274 if uc-1 < lim.umax { 275 lim.umax = uc - 1 276 } 277 case lt | eq: 278 if uc < lim.umax { 279 lim.umax = uc 280 } 281 case gt | eq: 282 if uc > lim.umin { 283 lim.umin = uc 284 } 285 case gt: 286 if uc+1 > lim.umin { 287 lim.umin = uc + 1 288 } 289 case lt | gt: 290 if uc == lim.umin { 291 lim.umin++ 292 } 293 if uc == lim.umax { 294 lim.umax-- 295 } 296 case eq: 297 lim.umin = uc 298 lim.umax = uc 299 } 300 } 301 ft.limitStack = append(ft.limitStack, limitFact{v.ID, old}) 302 ft.limits[v.ID] = lim 303 if v.Block.Func.pass.debug > 2 { 304 v.Block.Func.Config.Warnl(parent.Line, "parent=%s, new limits %s %s %s", parent, v, w, lim.String()) 305 } 306 } 307 } 308 309 // isNonNegative returns true if v is known to be non-negative. 310 func (ft *factsTable) isNonNegative(v *Value) bool { 311 if isNonNegative(v) { 312 return true 313 } 314 l, has := ft.limits[v.ID] 315 return has && (l.min >= 0 || l.umax <= math.MaxInt64) 316 } 317 318 // checkpoint saves the current state of known relations. 319 // Called when descending on a branch. 320 func (ft *factsTable) checkpoint() { 321 ft.stack = append(ft.stack, checkpointFact) 322 ft.limitStack = append(ft.limitStack, checkpointBound) 323 } 324 325 // restore restores known relation to the state just 326 // before the previous checkpoint. 327 // Called when backing up on a branch. 328 func (ft *factsTable) restore() { 329 for { 330 old := ft.stack[len(ft.stack)-1] 331 ft.stack = ft.stack[:len(ft.stack)-1] 332 if old == checkpointFact { 333 break 334 } 335 if old.r == lt|eq|gt { 336 delete(ft.facts, old.p) 337 } else { 338 ft.facts[old.p] = old.r 339 } 340 } 341 for { 342 old := ft.limitStack[len(ft.limitStack)-1] 343 ft.limitStack = ft.limitStack[:len(ft.limitStack)-1] 344 if old.vid == 0 { // checkpointBound 345 break 346 } 347 if old.limit == noLimit { 348 delete(ft.limits, old.vid) 349 } else { 350 ft.limits[old.vid] = old.limit 351 } 352 } 353 } 354 355 func lessByID(v, w *Value) bool { 356 if v == nil && w == nil { 357 // Should not happen, but just in case. 358 return false 359 } 360 if v == nil { 361 return true 362 } 363 return w != nil && v.ID < w.ID 364 } 365 366 var ( 367 reverseBits = [...]relation{0, 4, 2, 6, 1, 5, 3, 7} 368 369 // maps what we learn when the positive branch is taken. 370 // For example: 371 // OpLess8: {signed, lt}, 372 // v1 = (OpLess8 v2 v3). 373 // If v1 branch is taken than we learn that the rangeMaks 374 // can be at most lt. 375 domainRelationTable = map[Op]struct { 376 d domain 377 r relation 378 }{ 379 OpEq8: {signed | unsigned, eq}, 380 OpEq16: {signed | unsigned, eq}, 381 OpEq32: {signed | unsigned, eq}, 382 OpEq64: {signed | unsigned, eq}, 383 OpEqPtr: {pointer, eq}, 384 385 OpNeq8: {signed | unsigned, lt | gt}, 386 OpNeq16: {signed | unsigned, lt | gt}, 387 OpNeq32: {signed | unsigned, lt | gt}, 388 OpNeq64: {signed | unsigned, lt | gt}, 389 OpNeqPtr: {pointer, lt | gt}, 390 391 OpLess8: {signed, lt}, 392 OpLess8U: {unsigned, lt}, 393 OpLess16: {signed, lt}, 394 OpLess16U: {unsigned, lt}, 395 OpLess32: {signed, lt}, 396 OpLess32U: {unsigned, lt}, 397 OpLess64: {signed, lt}, 398 OpLess64U: {unsigned, lt}, 399 400 OpLeq8: {signed, lt | eq}, 401 OpLeq8U: {unsigned, lt | eq}, 402 OpLeq16: {signed, lt | eq}, 403 OpLeq16U: {unsigned, lt | eq}, 404 OpLeq32: {signed, lt | eq}, 405 OpLeq32U: {unsigned, lt | eq}, 406 OpLeq64: {signed, lt | eq}, 407 OpLeq64U: {unsigned, lt | eq}, 408 409 OpGeq8: {signed, eq | gt}, 410 OpGeq8U: {unsigned, eq | gt}, 411 OpGeq16: {signed, eq | gt}, 412 OpGeq16U: {unsigned, eq | gt}, 413 OpGeq32: {signed, eq | gt}, 414 OpGeq32U: {unsigned, eq | gt}, 415 OpGeq64: {signed, eq | gt}, 416 OpGeq64U: {unsigned, eq | gt}, 417 418 OpGreater8: {signed, gt}, 419 OpGreater8U: {unsigned, gt}, 420 OpGreater16: {signed, gt}, 421 OpGreater16U: {unsigned, gt}, 422 OpGreater32: {signed, gt}, 423 OpGreater32U: {unsigned, gt}, 424 OpGreater64: {signed, gt}, 425 OpGreater64U: {unsigned, gt}, 426 427 // TODO: OpIsInBounds actually test 0 <= a < b. This means 428 // that the positive branch learns signed/LT and unsigned/LT 429 // but the negative branch only learns unsigned/GE. 430 OpIsInBounds: {unsigned, lt}, 431 OpIsSliceInBounds: {unsigned, lt | eq}, 432 } 433 ) 434 435 // prove removes redundant BlockIf controls that can be inferred in a straight line. 436 // 437 // By far, the most common redundant pair are generated by bounds checking. 438 // For example for the code: 439 // 440 // a[i] = 4 441 // foo(a[i]) 442 // 443 // The compiler will generate the following code: 444 // 445 // if i >= len(a) { 446 // panic("not in bounds") 447 // } 448 // a[i] = 4 449 // if i >= len(a) { 450 // panic("not in bounds") 451 // } 452 // foo(a[i]) 453 // 454 // The second comparison i >= len(a) is clearly redundant because if the 455 // else branch of the first comparison is executed, we already know that i < len(a). 456 // The code for the second panic can be removed. 457 func prove(f *Func) { 458 // current node state 459 type walkState int 460 const ( 461 descend walkState = iota 462 simplify 463 ) 464 // work maintains the DFS stack. 465 type bp struct { 466 block *Block // current handled block 467 state walkState // what's to do 468 } 469 work := make([]bp, 0, 256) 470 work = append(work, bp{ 471 block: f.Entry, 472 state: descend, 473 }) 474 475 ft := newFactsTable() 476 idom := f.Idom() 477 sdom := f.sdom() 478 479 // DFS on the dominator tree. 480 for len(work) > 0 { 481 node := work[len(work)-1] 482 work = work[:len(work)-1] 483 parent := idom[node.block.ID] 484 branch := getBranch(sdom, parent, node.block) 485 486 switch node.state { 487 case descend: 488 if branch != unknown { 489 ft.checkpoint() 490 c := parent.Control 491 updateRestrictions(parent, ft, boolean, nil, c, lt|gt, branch) 492 if tr, has := domainRelationTable[parent.Control.Op]; has { 493 // When we branched from parent we learned a new set of 494 // restrictions. Update the factsTable accordingly. 495 updateRestrictions(parent, ft, tr.d, c.Args[0], c.Args[1], tr.r, branch) 496 } 497 } 498 499 work = append(work, bp{ 500 block: node.block, 501 state: simplify, 502 }) 503 for s := sdom.Child(node.block); s != nil; s = sdom.Sibling(s) { 504 work = append(work, bp{ 505 block: s, 506 state: descend, 507 }) 508 } 509 510 case simplify: 511 succ := simplifyBlock(ft, node.block) 512 if succ != unknown { 513 b := node.block 514 b.Kind = BlockFirst 515 b.SetControl(nil) 516 if succ == negative { 517 b.swapSuccessors() 518 } 519 } 520 521 if branch != unknown { 522 ft.restore() 523 } 524 } 525 } 526 } 527 528 // getBranch returns the range restrictions added by p 529 // when reaching b. p is the immediate dominator of b. 530 func getBranch(sdom SparseTree, p *Block, b *Block) branch { 531 if p == nil || p.Kind != BlockIf { 532 return unknown 533 } 534 // If p and p.Succs[0] are dominators it means that every path 535 // from entry to b passes through p and p.Succs[0]. We care that 536 // no path from entry to b passes through p.Succs[1]. If p.Succs[0] 537 // has one predecessor then (apart from the degenerate case), 538 // there is no path from entry that can reach b through p.Succs[1]. 539 // TODO: how about p->yes->b->yes, i.e. a loop in yes. 540 if sdom.isAncestorEq(p.Succs[0].b, b) && len(p.Succs[0].b.Preds) == 1 { 541 return positive 542 } 543 if sdom.isAncestorEq(p.Succs[1].b, b) && len(p.Succs[1].b.Preds) == 1 { 544 return negative 545 } 546 return unknown 547 } 548 549 // updateRestrictions updates restrictions from the immediate 550 // dominating block (p) using r. r is adjusted according to the branch taken. 551 func updateRestrictions(parent *Block, ft *factsTable, t domain, v, w *Value, r relation, branch branch) { 552 if t == 0 || branch == unknown { 553 // Trivial case: nothing to do, or branch unknown. 554 // Shoult not happen, but just in case. 555 return 556 } 557 if branch == negative { 558 // Negative branch taken, complement the relations. 559 r = (lt | eq | gt) ^ r 560 } 561 for i := domain(1); i <= t; i <<= 1 { 562 if t&i != 0 { 563 ft.update(parent, v, w, i, r) 564 } 565 } 566 } 567 568 // simplifyBlock simplifies block known the restrictions in ft. 569 // Returns which branch must always be taken. 570 func simplifyBlock(ft *factsTable, b *Block) branch { 571 for _, v := range b.Values { 572 if v.Op != OpSlicemask { 573 continue 574 } 575 add := v.Args[0] 576 if add.Op != OpAdd64 && add.Op != OpAdd32 { 577 continue 578 } 579 // Note that the arg of slicemask was originally a sub, but 580 // was rewritten to an add by generic.rules (if the thing 581 // being subtracted was a constant). 582 x := add.Args[0] 583 y := add.Args[1] 584 if x.Op == OpConst64 || x.Op == OpConst32 { 585 x, y = y, x 586 } 587 if y.Op != OpConst64 && y.Op != OpConst32 { 588 continue 589 } 590 // slicemask(x + y) 591 // if x is larger than -y (y is negative), then slicemask is -1. 592 lim, ok := ft.limits[x.ID] 593 if !ok { 594 continue 595 } 596 if lim.umin > uint64(-y.AuxInt) { 597 if v.Args[0].Op == OpAdd64 { 598 v.reset(OpConst64) 599 } else { 600 v.reset(OpConst32) 601 } 602 if b.Func.pass.debug > 0 { 603 b.Func.Config.Warnl(v.Line, "Proved slicemask not needed") 604 } 605 v.AuxInt = -1 606 } 607 } 608 609 if b.Kind != BlockIf { 610 return unknown 611 } 612 613 // First, checks if the condition itself is redundant. 614 m := ft.get(nil, b.Control, boolean) 615 if m == lt|gt { 616 if b.Func.pass.debug > 0 { 617 if b.Func.pass.debug > 1 { 618 b.Func.Config.Warnl(b.Line, "Proved boolean %s (%s)", b.Control.Op, b.Control) 619 } else { 620 b.Func.Config.Warnl(b.Line, "Proved boolean %s", b.Control.Op) 621 } 622 } 623 return positive 624 } 625 if m == eq { 626 if b.Func.pass.debug > 0 { 627 if b.Func.pass.debug > 1 { 628 b.Func.Config.Warnl(b.Line, "Disproved boolean %s (%s)", b.Control.Op, b.Control) 629 } else { 630 b.Func.Config.Warnl(b.Line, "Disproved boolean %s", b.Control.Op) 631 } 632 } 633 return negative 634 } 635 636 // Next look check equalities. 637 c := b.Control 638 tr, has := domainRelationTable[c.Op] 639 if !has { 640 return unknown 641 } 642 643 a0, a1 := c.Args[0], c.Args[1] 644 for d := domain(1); d <= tr.d; d <<= 1 { 645 if d&tr.d == 0 { 646 continue 647 } 648 649 // tr.r represents in which case the positive branch is taken. 650 // m represents which cases are possible because of previous relations. 651 // If the set of possible relations m is included in the set of relations 652 // need to take the positive branch (or negative) then that branch will 653 // always be taken. 654 // For shortcut, if m == 0 then this block is dead code. 655 m := ft.get(a0, a1, d) 656 if m != 0 && tr.r&m == m { 657 if b.Func.pass.debug > 0 { 658 if b.Func.pass.debug > 1 { 659 b.Func.Config.Warnl(b.Line, "Proved %s (%s)", c.Op, c) 660 } else { 661 b.Func.Config.Warnl(b.Line, "Proved %s", c.Op) 662 } 663 } 664 return positive 665 } 666 if m != 0 && ((lt|eq|gt)^tr.r)&m == m { 667 if b.Func.pass.debug > 0 { 668 if b.Func.pass.debug > 1 { 669 b.Func.Config.Warnl(b.Line, "Disproved %s (%s)", c.Op, c) 670 } else { 671 b.Func.Config.Warnl(b.Line, "Disproved %s", c.Op) 672 } 673 } 674 return negative 675 } 676 } 677 678 // HACK: If the first argument of IsInBounds or IsSliceInBounds 679 // is a constant and we already know that constant is smaller (or equal) 680 // to the upper bound than this is proven. Most useful in cases such as: 681 // if len(a) <= 1 { return } 682 // do something with a[1] 683 if (c.Op == OpIsInBounds || c.Op == OpIsSliceInBounds) && ft.isNonNegative(c.Args[0]) { 684 m := ft.get(a0, a1, signed) 685 if m != 0 && tr.r&m == m { 686 if b.Func.pass.debug > 0 { 687 if b.Func.pass.debug > 1 { 688 b.Func.Config.Warnl(b.Line, "Proved non-negative bounds %s (%s)", c.Op, c) 689 } else { 690 b.Func.Config.Warnl(b.Line, "Proved non-negative bounds %s", c.Op) 691 } 692 } 693 return positive 694 } 695 } 696 697 return unknown 698 } 699 700 // isNonNegative returns true is v is known to be greater or equal to zero. 701 func isNonNegative(v *Value) bool { 702 switch v.Op { 703 case OpConst64: 704 return v.AuxInt >= 0 705 706 case OpConst32: 707 return int32(v.AuxInt) >= 0 708 709 case OpStringLen, OpSliceLen, OpSliceCap, 710 OpZeroExt8to64, OpZeroExt16to64, OpZeroExt32to64: 711 return true 712 713 case OpRsh64x64: 714 return isNonNegative(v.Args[0]) 715 } 716 return false 717 }