github.com/bir3/gocompiler@v0.9.2202/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 "github.com/bir3/gocompiler/src/cmd/internal/src" 9 "fmt" 10 "math" 11 ) 12 13 type branch int 14 15 const ( 16 unknown branch = iota 17 positive 18 negative 19 // The outedges from a jump table are jumpTable0, 20 // jumpTable0+1, jumpTable0+2, etc. There could be an 21 // arbitrary number so we can't list them all here. 22 jumpTable0 23 ) 24 25 // relation represents the set of possible relations between 26 // pairs of variables (v, w). Without a priori knowledge the 27 // mask is lt | eq | gt meaning v can be less than, equal to or 28 // greater than w. When the execution path branches on the condition 29 // `v op w` the set of relations is updated to exclude any 30 // relation not possible due to `v op w` being true (or false). 31 // 32 // E.g. 33 // 34 // r := relation(...) 35 // 36 // if v < w { 37 // newR := r & lt 38 // } 39 // if v >= w { 40 // newR := r & (eq|gt) 41 // } 42 // if v != w { 43 // newR := r & (lt|gt) 44 // } 45 type relation uint 46 47 const ( 48 lt relation = 1 << iota 49 eq 50 gt 51 ) 52 53 var relationStrings = [...]string{ 54 0: "none", lt: "<", eq: "==", lt | eq: "<=", 55 gt: ">", gt | lt: "!=", gt | eq: ">=", gt | eq | lt: "any", 56 } 57 58 func (r relation) String() string { 59 if r < relation(len(relationStrings)) { 60 return relationStrings[r] 61 } 62 return fmt.Sprintf("relation(%d)", uint(r)) 63 } 64 65 // domain represents the domain of a variable pair in which a set 66 // of relations is known. For example, relations learned for unsigned 67 // pairs cannot be transferred to signed pairs because the same bit 68 // representation can mean something else. 69 type domain uint 70 71 const ( 72 signed domain = 1 << iota 73 unsigned 74 pointer 75 boolean 76 ) 77 78 var domainStrings = [...]string{ 79 "signed", "unsigned", "pointer", "boolean", 80 } 81 82 func (d domain) String() string { 83 s := "" 84 for i, ds := range domainStrings { 85 if d&(1<<uint(i)) != 0 { 86 if len(s) != 0 { 87 s += "|" 88 } 89 s += ds 90 d &^= 1 << uint(i) 91 } 92 } 93 if d != 0 { 94 if len(s) != 0 { 95 s += "|" 96 } 97 s += fmt.Sprintf("0x%x", uint(d)) 98 } 99 return s 100 } 101 102 type pair struct { 103 // a pair of values, ordered by ID. 104 // v can be nil, to mean the zero value. 105 // for booleans the zero value (v == nil) is false. 106 v, w *Value 107 d domain 108 } 109 110 // fact is a pair plus a relation for that pair. 111 type fact struct { 112 p pair 113 r relation 114 } 115 116 // a limit records known upper and lower bounds for a value. 117 type limit struct { 118 min, max int64 // min <= value <= max, signed 119 umin, umax uint64 // umin <= value <= umax, unsigned 120 } 121 122 func (l limit) String() string { 123 return fmt.Sprintf("sm,SM,um,UM=%d,%d,%d,%d", l.min, l.max, l.umin, l.umax) 124 } 125 126 func (l limit) intersect(l2 limit) limit { 127 if l.min < l2.min { 128 l.min = l2.min 129 } 130 if l.umin < l2.umin { 131 l.umin = l2.umin 132 } 133 if l.max > l2.max { 134 l.max = l2.max 135 } 136 if l.umax > l2.umax { 137 l.umax = l2.umax 138 } 139 return l 140 } 141 142 var noLimit = limit{math.MinInt64, math.MaxInt64, 0, math.MaxUint64} 143 144 // a limitFact is a limit known for a particular value. 145 type limitFact struct { 146 vid ID 147 limit limit 148 } 149 150 // factsTable keeps track of relations between pairs of values. 151 // 152 // The fact table logic is sound, but incomplete. Outside of a few 153 // special cases, it performs no deduction or arithmetic. While there 154 // are known decision procedures for this, the ad hoc approach taken 155 // by the facts table is effective for real code while remaining very 156 // efficient. 157 type factsTable struct { 158 // unsat is true if facts contains a contradiction. 159 // 160 // Note that the factsTable logic is incomplete, so if unsat 161 // is false, the assertions in factsTable could be satisfiable 162 // *or* unsatisfiable. 163 unsat bool // true if facts contains a contradiction 164 unsatDepth int // number of unsat checkpoints 165 166 facts map[pair]relation // current known set of relation 167 stack []fact // previous sets of relations 168 169 // order* is a couple of partial order sets that record information 170 // about relations between SSA values in the signed and unsigned 171 // domain. 172 orderS *poset 173 orderU *poset 174 175 // known lower and upper bounds on individual values. 176 limits map[ID]limit 177 limitStack []limitFact // previous entries 178 179 // For each slice s, a map from s to a len(s)/cap(s) value (if any) 180 // TODO: check if there are cases that matter where we have 181 // more than one len(s) for a slice. We could keep a list if necessary. 182 lens map[ID]*Value 183 caps map[ID]*Value 184 185 // zero is a zero-valued constant 186 zero *Value 187 } 188 189 // checkpointFact is an invalid value used for checkpointing 190 // and restoring factsTable. 191 var checkpointFact = fact{} 192 var checkpointBound = limitFact{} 193 194 func newFactsTable(f *Func) *factsTable { 195 ft := &factsTable{} 196 ft.orderS = f.newPoset() 197 ft.orderU = f.newPoset() 198 ft.orderS.SetUnsigned(false) 199 ft.orderU.SetUnsigned(true) 200 ft.facts = make(map[pair]relation) 201 ft.stack = make([]fact, 4) 202 ft.limits = make(map[ID]limit) 203 ft.limitStack = make([]limitFact, 4) 204 ft.zero = f.ConstInt64(f.Config.Types.Int64, 0) 205 return ft 206 } 207 208 // update updates the set of relations between v and w in domain d 209 // restricting it to r. 210 func (ft *factsTable) update(parent *Block, v, w *Value, d domain, r relation) { 211 if parent.Func.pass.debug > 2 { 212 parent.Func.Warnl(parent.Pos, "parent=%s, update %s %s %s", parent, v, w, r) 213 } 214 // No need to do anything else if we already found unsat. 215 if ft.unsat { 216 return 217 } 218 219 // Self-fact. It's wasteful to register it into the facts 220 // table, so just note whether it's satisfiable 221 if v == w { 222 if r&eq == 0 { 223 ft.unsat = true 224 } 225 return 226 } 227 228 if d == signed || d == unsigned { 229 var ok bool 230 order := ft.orderS 231 if d == unsigned { 232 order = ft.orderU 233 } 234 switch r { 235 case lt: 236 ok = order.SetOrder(v, w) 237 case gt: 238 ok = order.SetOrder(w, v) 239 case lt | eq: 240 ok = order.SetOrderOrEqual(v, w) 241 case gt | eq: 242 ok = order.SetOrderOrEqual(w, v) 243 case eq: 244 ok = order.SetEqual(v, w) 245 case lt | gt: 246 ok = order.SetNonEqual(v, w) 247 default: 248 panic("unknown relation") 249 } 250 if !ok { 251 if parent.Func.pass.debug > 2 { 252 parent.Func.Warnl(parent.Pos, "unsat %s %s %s", v, w, r) 253 } 254 ft.unsat = true 255 return 256 } 257 } else { 258 if lessByID(w, v) { 259 v, w = w, v 260 r = reverseBits[r] 261 } 262 263 p := pair{v, w, d} 264 oldR, ok := ft.facts[p] 265 if !ok { 266 if v == w { 267 oldR = eq 268 } else { 269 oldR = lt | eq | gt 270 } 271 } 272 // No changes compared to information already in facts table. 273 if oldR == r { 274 return 275 } 276 ft.stack = append(ft.stack, fact{p, oldR}) 277 ft.facts[p] = oldR & r 278 // If this relation is not satisfiable, mark it and exit right away 279 if oldR&r == 0 { 280 if parent.Func.pass.debug > 2 { 281 parent.Func.Warnl(parent.Pos, "unsat %s %s %s", v, w, r) 282 } 283 ft.unsat = true 284 return 285 } 286 } 287 288 // Extract bounds when comparing against constants 289 if v.isGenericIntConst() { 290 v, w = w, v 291 r = reverseBits[r] 292 } 293 if v != nil && w.isGenericIntConst() { 294 // Note: all the +1/-1 below could overflow/underflow. Either will 295 // still generate correct results, it will just lead to imprecision. 296 // In fact if there is overflow/underflow, the corresponding 297 // code is unreachable because the known range is outside the range 298 // of the value's type. 299 old, ok := ft.limits[v.ID] 300 if !ok { 301 old = noLimit 302 if v.isGenericIntConst() { 303 switch d { 304 case signed: 305 old.min, old.max = v.AuxInt, v.AuxInt 306 if v.AuxInt >= 0 { 307 old.umin, old.umax = uint64(v.AuxInt), uint64(v.AuxInt) 308 } 309 case unsigned: 310 old.umin = v.AuxUnsigned() 311 old.umax = old.umin 312 if int64(old.umin) >= 0 { 313 old.min, old.max = int64(old.umin), int64(old.umin) 314 } 315 } 316 } 317 } 318 lim := noLimit 319 switch d { 320 case signed: 321 c := w.AuxInt 322 switch r { 323 case lt: 324 lim.max = c - 1 325 case lt | eq: 326 lim.max = c 327 case gt | eq: 328 lim.min = c 329 case gt: 330 lim.min = c + 1 331 case lt | gt: 332 lim = old 333 if c == lim.min { 334 lim.min++ 335 } 336 if c == lim.max { 337 lim.max-- 338 } 339 case eq: 340 lim.min = c 341 lim.max = c 342 } 343 if lim.min >= 0 { 344 // int(x) >= 0 && int(x) >= N ⇒ uint(x) >= N 345 lim.umin = uint64(lim.min) 346 } 347 if lim.max != noLimit.max && old.min >= 0 && lim.max >= 0 { 348 // 0 <= int(x) <= N ⇒ 0 <= uint(x) <= N 349 // This is for a max update, so the lower bound 350 // comes from what we already know (old). 351 lim.umax = uint64(lim.max) 352 } 353 case unsigned: 354 uc := w.AuxUnsigned() 355 switch r { 356 case lt: 357 lim.umax = uc - 1 358 case lt | eq: 359 lim.umax = uc 360 case gt | eq: 361 lim.umin = uc 362 case gt: 363 lim.umin = uc + 1 364 case lt | gt: 365 lim = old 366 if uc == lim.umin { 367 lim.umin++ 368 } 369 if uc == lim.umax { 370 lim.umax-- 371 } 372 case eq: 373 lim.umin = uc 374 lim.umax = uc 375 } 376 // We could use the contrapositives of the 377 // signed implications to derive signed facts, 378 // but it turns out not to matter. 379 } 380 ft.limitStack = append(ft.limitStack, limitFact{v.ID, old}) 381 lim = old.intersect(lim) 382 ft.limits[v.ID] = lim 383 if v.Block.Func.pass.debug > 2 { 384 v.Block.Func.Warnl(parent.Pos, "parent=%s, new limits %s %s %s %s", parent, v, w, r, lim.String()) 385 } 386 if lim.min > lim.max || lim.umin > lim.umax { 387 ft.unsat = true 388 return 389 } 390 } 391 392 // Derived facts below here are only about numbers. 393 if d != signed && d != unsigned { 394 return 395 } 396 397 // Additional facts we know given the relationship between len and cap. 398 // 399 // TODO: Since prove now derives transitive relations, it 400 // should be sufficient to learn that len(w) <= cap(w) at the 401 // beginning of prove where we look for all len/cap ops. 402 if v.Op == OpSliceLen && r< == 0 && ft.caps[v.Args[0].ID] != nil { 403 // len(s) > w implies cap(s) > w 404 // len(s) >= w implies cap(s) >= w 405 // len(s) == w implies cap(s) >= w 406 ft.update(parent, ft.caps[v.Args[0].ID], w, d, r|gt) 407 } 408 if w.Op == OpSliceLen && r> == 0 && ft.caps[w.Args[0].ID] != nil { 409 // same, length on the RHS. 410 ft.update(parent, v, ft.caps[w.Args[0].ID], d, r|lt) 411 } 412 if v.Op == OpSliceCap && r> == 0 && ft.lens[v.Args[0].ID] != nil { 413 // cap(s) < w implies len(s) < w 414 // cap(s) <= w implies len(s) <= w 415 // cap(s) == w implies len(s) <= w 416 ft.update(parent, ft.lens[v.Args[0].ID], w, d, r|lt) 417 } 418 if w.Op == OpSliceCap && r< == 0 && ft.lens[w.Args[0].ID] != nil { 419 // same, capacity on the RHS. 420 ft.update(parent, v, ft.lens[w.Args[0].ID], d, r|gt) 421 } 422 423 // Process fence-post implications. 424 // 425 // First, make the condition > or >=. 426 if r == lt || r == lt|eq { 427 v, w = w, v 428 r = reverseBits[r] 429 } 430 switch r { 431 case gt: 432 if x, delta := isConstDelta(v); x != nil && delta == 1 { 433 // x+1 > w ⇒ x >= w 434 // 435 // This is useful for eliminating the 436 // growslice branch of append. 437 ft.update(parent, x, w, d, gt|eq) 438 } else if x, delta := isConstDelta(w); x != nil && delta == -1 { 439 // v > x-1 ⇒ v >= x 440 ft.update(parent, v, x, d, gt|eq) 441 } 442 case gt | eq: 443 if x, delta := isConstDelta(v); x != nil && delta == -1 { 444 // x-1 >= w && x > min ⇒ x > w 445 // 446 // Useful for i > 0; s[i-1]. 447 lim, ok := ft.limits[x.ID] 448 if ok && ((d == signed && lim.min > opMin[v.Op]) || (d == unsigned && lim.umin > 0)) { 449 ft.update(parent, x, w, d, gt) 450 } 451 } else if x, delta := isConstDelta(w); x != nil && delta == 1 { 452 // v >= x+1 && x < max ⇒ v > x 453 lim, ok := ft.limits[x.ID] 454 if ok && ((d == signed && lim.max < opMax[w.Op]) || (d == unsigned && lim.umax < opUMax[w.Op])) { 455 ft.update(parent, v, x, d, gt) 456 } 457 } 458 } 459 460 // Process: x+delta > w (with delta constant) 461 // Only signed domain for now (useful for accesses to slices in loops). 462 if r == gt || r == gt|eq { 463 if x, delta := isConstDelta(v); x != nil && d == signed { 464 if parent.Func.pass.debug > 1 { 465 parent.Func.Warnl(parent.Pos, "x+d %s w; x:%v %v delta:%v w:%v d:%v", r, x, parent.String(), delta, w.AuxInt, d) 466 } 467 underflow := true 468 if l, has := ft.limits[x.ID]; has && delta < 0 { 469 if (x.Type.Size() == 8 && l.min >= math.MinInt64-delta) || 470 (x.Type.Size() == 4 && l.min >= math.MinInt32-delta) { 471 underflow = false 472 } 473 } 474 if delta < 0 && !underflow { 475 // If delta < 0 and x+delta cannot underflow then x > x+delta (that is, x > v) 476 ft.update(parent, x, v, signed, gt) 477 } 478 if !w.isGenericIntConst() { 479 // If we know that x+delta > w but w is not constant, we can derive: 480 // if delta < 0 and x+delta cannot underflow, then x > w 481 // This is useful for loops with bounds "len(slice)-K" (delta = -K) 482 if delta < 0 && !underflow { 483 ft.update(parent, x, w, signed, r) 484 } 485 } else { 486 // With w,delta constants, we want to derive: x+delta > w ⇒ x > w-delta 487 // 488 // We compute (using integers of the correct size): 489 // min = w - delta 490 // max = MaxInt - delta 491 // 492 // And we prove that: 493 // if min<max: min < x AND x <= max 494 // if min>max: min < x OR x <= max 495 // 496 // This is always correct, even in case of overflow. 497 // 498 // If the initial fact is x+delta >= w instead, the derived conditions are: 499 // if min<max: min <= x AND x <= max 500 // if min>max: min <= x OR x <= max 501 // 502 // Notice the conditions for max are still <=, as they handle overflows. 503 var min, max int64 504 var vmin, vmax *Value 505 switch x.Type.Size() { 506 case 8: 507 min = w.AuxInt - delta 508 max = int64(^uint64(0)>>1) - delta 509 510 vmin = parent.NewValue0I(parent.Pos, OpConst64, parent.Func.Config.Types.Int64, min) 511 vmax = parent.NewValue0I(parent.Pos, OpConst64, parent.Func.Config.Types.Int64, max) 512 513 case 4: 514 min = int64(int32(w.AuxInt) - int32(delta)) 515 max = int64(int32(^uint32(0)>>1) - int32(delta)) 516 517 vmin = parent.NewValue0I(parent.Pos, OpConst32, parent.Func.Config.Types.Int32, min) 518 vmax = parent.NewValue0I(parent.Pos, OpConst32, parent.Func.Config.Types.Int32, max) 519 520 case 2: 521 min = int64(int16(w.AuxInt) - int16(delta)) 522 max = int64(int16(^uint16(0)>>1) - int16(delta)) 523 524 vmin = parent.NewValue0I(parent.Pos, OpConst16, parent.Func.Config.Types.Int16, min) 525 vmax = parent.NewValue0I(parent.Pos, OpConst16, parent.Func.Config.Types.Int16, max) 526 527 case 1: 528 min = int64(int8(w.AuxInt) - int8(delta)) 529 max = int64(int8(^uint8(0)>>1) - int8(delta)) 530 531 vmin = parent.NewValue0I(parent.Pos, OpConst8, parent.Func.Config.Types.Int8, min) 532 vmax = parent.NewValue0I(parent.Pos, OpConst8, parent.Func.Config.Types.Int8, max) 533 534 default: 535 panic("unimplemented") 536 } 537 538 if min < max { 539 // Record that x > min and max >= x 540 ft.update(parent, x, vmin, d, r) 541 ft.update(parent, vmax, x, d, r|eq) 542 } else { 543 // We know that either x>min OR x<=max. factsTable cannot record OR conditions, 544 // so let's see if we can already prove that one of them is false, in which case 545 // the other must be true 546 if l, has := ft.limits[x.ID]; has { 547 if l.max <= min { 548 if r&eq == 0 || l.max < min { 549 // x>min (x>=min) is impossible, so it must be x<=max 550 ft.update(parent, vmax, x, d, r|eq) 551 } 552 } else if l.min > max { 553 // x<=max is impossible, so it must be x>min 554 ft.update(parent, x, vmin, d, r) 555 } 556 } 557 } 558 } 559 } 560 } 561 562 // Look through value-preserving extensions. 563 // If the domain is appropriate for the pre-extension Type, 564 // repeat the update with the pre-extension Value. 565 if isCleanExt(v) { 566 switch { 567 case d == signed && v.Args[0].Type.IsSigned(): 568 fallthrough 569 case d == unsigned && !v.Args[0].Type.IsSigned(): 570 ft.update(parent, v.Args[0], w, d, r) 571 } 572 } 573 if isCleanExt(w) { 574 switch { 575 case d == signed && w.Args[0].Type.IsSigned(): 576 fallthrough 577 case d == unsigned && !w.Args[0].Type.IsSigned(): 578 ft.update(parent, v, w.Args[0], d, r) 579 } 580 } 581 } 582 583 var opMin = map[Op]int64{ 584 OpAdd64: math.MinInt64, OpSub64: math.MinInt64, 585 OpAdd32: math.MinInt32, OpSub32: math.MinInt32, 586 } 587 588 var opMax = map[Op]int64{ 589 OpAdd64: math.MaxInt64, OpSub64: math.MaxInt64, 590 OpAdd32: math.MaxInt32, OpSub32: math.MaxInt32, 591 } 592 593 var opUMax = map[Op]uint64{ 594 OpAdd64: math.MaxUint64, OpSub64: math.MaxUint64, 595 OpAdd32: math.MaxUint32, OpSub32: math.MaxUint32, 596 } 597 598 // isNonNegative reports whether v is known to be non-negative. 599 func (ft *factsTable) isNonNegative(v *Value) bool { 600 if isNonNegative(v) { 601 return true 602 } 603 604 var max int64 605 switch v.Type.Size() { 606 case 1: 607 max = math.MaxInt8 608 case 2: 609 max = math.MaxInt16 610 case 4: 611 max = math.MaxInt32 612 case 8: 613 max = math.MaxInt64 614 default: 615 panic("unexpected integer size") 616 } 617 618 // Check if the recorded limits can prove that the value is positive 619 620 if l, has := ft.limits[v.ID]; has && (l.min >= 0 || l.umax <= uint64(max)) { 621 return true 622 } 623 624 // Check if v = x+delta, and we can use x's limits to prove that it's positive 625 if x, delta := isConstDelta(v); x != nil { 626 if l, has := ft.limits[x.ID]; has { 627 if delta > 0 && l.min >= -delta && l.max <= max-delta { 628 return true 629 } 630 if delta < 0 && l.min >= -delta { 631 return true 632 } 633 } 634 } 635 636 // Check if v is a value-preserving extension of a non-negative value. 637 if isCleanExt(v) && ft.isNonNegative(v.Args[0]) { 638 return true 639 } 640 641 // Check if the signed poset can prove that the value is >= 0 642 return ft.orderS.OrderedOrEqual(ft.zero, v) 643 } 644 645 // checkpoint saves the current state of known relations. 646 // Called when descending on a branch. 647 func (ft *factsTable) checkpoint() { 648 if ft.unsat { 649 ft.unsatDepth++ 650 } 651 ft.stack = append(ft.stack, checkpointFact) 652 ft.limitStack = append(ft.limitStack, checkpointBound) 653 ft.orderS.Checkpoint() 654 ft.orderU.Checkpoint() 655 } 656 657 // restore restores known relation to the state just 658 // before the previous checkpoint. 659 // Called when backing up on a branch. 660 func (ft *factsTable) restore() { 661 if ft.unsatDepth > 0 { 662 ft.unsatDepth-- 663 } else { 664 ft.unsat = false 665 } 666 for { 667 old := ft.stack[len(ft.stack)-1] 668 ft.stack = ft.stack[:len(ft.stack)-1] 669 if old == checkpointFact { 670 break 671 } 672 if old.r == lt|eq|gt { 673 delete(ft.facts, old.p) 674 } else { 675 ft.facts[old.p] = old.r 676 } 677 } 678 for { 679 old := ft.limitStack[len(ft.limitStack)-1] 680 ft.limitStack = ft.limitStack[:len(ft.limitStack)-1] 681 if old.vid == 0 { // checkpointBound 682 break 683 } 684 if old.limit == noLimit { 685 delete(ft.limits, old.vid) 686 } else { 687 ft.limits[old.vid] = old.limit 688 } 689 } 690 ft.orderS.Undo() 691 ft.orderU.Undo() 692 } 693 694 func lessByID(v, w *Value) bool { 695 if v == nil && w == nil { 696 // Should not happen, but just in case. 697 return false 698 } 699 if v == nil { 700 return true 701 } 702 return w != nil && v.ID < w.ID 703 } 704 705 var ( 706 reverseBits = [...]relation{0, 4, 2, 6, 1, 5, 3, 7} 707 708 // maps what we learn when the positive branch is taken. 709 // For example: 710 // OpLess8: {signed, lt}, 711 // v1 = (OpLess8 v2 v3). 712 // If v1 branch is taken then we learn that the rangeMask 713 // can be at most lt. 714 domainRelationTable = map[Op]struct { 715 d domain 716 r relation 717 }{ 718 OpEq8: {signed | unsigned, eq}, 719 OpEq16: {signed | unsigned, eq}, 720 OpEq32: {signed | unsigned, eq}, 721 OpEq64: {signed | unsigned, eq}, 722 OpEqPtr: {pointer, eq}, 723 724 OpNeq8: {signed | unsigned, lt | gt}, 725 OpNeq16: {signed | unsigned, lt | gt}, 726 OpNeq32: {signed | unsigned, lt | gt}, 727 OpNeq64: {signed | unsigned, lt | gt}, 728 OpNeqPtr: {pointer, lt | gt}, 729 730 OpLess8: {signed, lt}, 731 OpLess8U: {unsigned, lt}, 732 OpLess16: {signed, lt}, 733 OpLess16U: {unsigned, lt}, 734 OpLess32: {signed, lt}, 735 OpLess32U: {unsigned, lt}, 736 OpLess64: {signed, lt}, 737 OpLess64U: {unsigned, lt}, 738 739 OpLeq8: {signed, lt | eq}, 740 OpLeq8U: {unsigned, lt | eq}, 741 OpLeq16: {signed, lt | eq}, 742 OpLeq16U: {unsigned, lt | eq}, 743 OpLeq32: {signed, lt | eq}, 744 OpLeq32U: {unsigned, lt | eq}, 745 OpLeq64: {signed, lt | eq}, 746 OpLeq64U: {unsigned, lt | eq}, 747 748 // For these ops, the negative branch is different: we can only 749 // prove signed/GE (signed/GT) if we can prove that arg0 is non-negative. 750 // See the special case in addBranchRestrictions. 751 OpIsInBounds: {signed | unsigned, lt}, // 0 <= arg0 < arg1 752 OpIsSliceInBounds: {signed | unsigned, lt | eq}, // 0 <= arg0 <= arg1 753 } 754 ) 755 756 // cleanup returns the posets to the free list 757 func (ft *factsTable) cleanup(f *Func) { 758 for _, po := range []*poset{ft.orderS, ft.orderU} { 759 // Make sure it's empty as it should be. A non-empty poset 760 // might cause errors and miscompilations if reused. 761 if checkEnabled { 762 if err := po.CheckEmpty(); err != nil { 763 f.Fatalf("poset not empty after function %s: %v", f.Name, err) 764 } 765 } 766 f.retPoset(po) 767 } 768 } 769 770 // prove removes redundant BlockIf branches that can be inferred 771 // from previous dominating comparisons. 772 // 773 // By far, the most common redundant pair are generated by bounds checking. 774 // For example for the code: 775 // 776 // a[i] = 4 777 // foo(a[i]) 778 // 779 // The compiler will generate the following code: 780 // 781 // if i >= len(a) { 782 // panic("not in bounds") 783 // } 784 // a[i] = 4 785 // if i >= len(a) { 786 // panic("not in bounds") 787 // } 788 // foo(a[i]) 789 // 790 // The second comparison i >= len(a) is clearly redundant because if the 791 // else branch of the first comparison is executed, we already know that i < len(a). 792 // The code for the second panic can be removed. 793 // 794 // prove works by finding contradictions and trimming branches whose 795 // conditions are unsatisfiable given the branches leading up to them. 796 // It tracks a "fact table" of branch conditions. For each branching 797 // block, it asserts the branch conditions that uniquely dominate that 798 // block, and then separately asserts the block's branch condition and 799 // its negation. If either leads to a contradiction, it can trim that 800 // successor. 801 func prove(f *Func) { 802 // Find induction variables. Currently, findIndVars 803 // is limited to one induction variable per block. 804 var indVars map[*Block]indVar 805 for _, v := range findIndVar(f) { 806 ind := v.ind 807 if len(ind.Args) != 2 { 808 // the rewrite code assumes there is only ever two parents to loops 809 panic("unexpected induction with too many parents") 810 } 811 812 nxt := v.nxt 813 if !(ind.Uses == 2 && // 2 used by comparison and next 814 nxt.Uses == 1) { // 1 used by induction 815 // ind or nxt is used inside the loop, add it for the facts table 816 if indVars == nil { 817 indVars = make(map[*Block]indVar) 818 } 819 indVars[v.entry] = v 820 continue 821 } else { 822 // Since this induction variable is not used for anything but counting the iterations, 823 // no point in putting it into the facts table. 824 } 825 826 // try to rewrite to a downward counting loop checking against start if the 827 // loop body does not depends on ind or nxt and end is known before the loop. 828 // This reduce pressure on the register allocator because this do not need 829 // to use end on each iteration anymore. We compare against the start constant instead. 830 // That means this code: 831 // 832 // loop: 833 // ind = (Phi (Const [x]) nxt), 834 // if ind < end 835 // then goto enter_loop 836 // else goto exit_loop 837 // 838 // enter_loop: 839 // do something without using ind nor nxt 840 // nxt = inc + ind 841 // goto loop 842 // 843 // exit_loop: 844 // 845 // is rewritten to: 846 // 847 // loop: 848 // ind = (Phi end nxt) 849 // if (Const [x]) < ind 850 // then goto enter_loop 851 // else goto exit_loop 852 // 853 // enter_loop: 854 // do something without using ind nor nxt 855 // nxt = ind - inc 856 // goto loop 857 // 858 // exit_loop: 859 // 860 // this is better because it only require to keep ind then nxt alive while looping, 861 // while the original form keeps ind then nxt and end alive 862 start, end := v.min, v.max 863 if v.flags&indVarCountDown != 0 { 864 start, end = end, start 865 } 866 867 if !(start.Op == OpConst8 || start.Op == OpConst16 || start.Op == OpConst32 || start.Op == OpConst64) { 868 // if start is not a constant we would be winning nothing from inverting the loop 869 continue 870 } 871 if end.Op == OpConst8 || end.Op == OpConst16 || end.Op == OpConst32 || end.Op == OpConst64 { 872 // TODO: if both start and end are constants we should rewrite such that the comparison 873 // is against zero and nxt is ++ or -- operation 874 // That means: 875 // for i := 2; i < 11; i += 2 { 876 // should be rewritten to: 877 // for i := 5; 0 < i; i-- { 878 continue 879 } 880 881 header := ind.Block 882 check := header.Controls[0] 883 if check == nil { 884 // we don't know how to rewrite a loop that not simple comparison 885 continue 886 } 887 switch check.Op { 888 case OpLeq64, OpLeq32, OpLeq16, OpLeq8, 889 OpLess64, OpLess32, OpLess16, OpLess8: 890 default: 891 // we don't know how to rewrite a loop that not simple comparison 892 continue 893 } 894 if !((check.Args[0] == ind && check.Args[1] == end) || 895 (check.Args[1] == ind && check.Args[0] == end)) { 896 // we don't know how to rewrite a loop that not simple comparison 897 continue 898 } 899 if end.Block == ind.Block { 900 // we can't rewrite loops where the condition depends on the loop body 901 // this simple check is forced to work because if this is true a Phi in ind.Block must exists 902 continue 903 } 904 905 // invert the check 906 check.Args[0], check.Args[1] = check.Args[1], check.Args[0] 907 908 // invert start and end in the loop 909 for i, v := range check.Args { 910 if v != end { 911 continue 912 } 913 914 check.SetArg(i, start) 915 goto replacedEnd 916 } 917 panic(fmt.Sprintf("unreachable, ind: %v, start: %v, end: %v", ind, start, end)) 918 replacedEnd: 919 920 for i, v := range ind.Args { 921 if v != start { 922 continue 923 } 924 925 ind.SetArg(i, end) 926 goto replacedStart 927 } 928 panic(fmt.Sprintf("unreachable, ind: %v, start: %v, end: %v", ind, start, end)) 929 replacedStart: 930 931 if nxt.Args[0] != ind { 932 // unlike additions subtractions are not commutative so be sure we get it right 933 nxt.Args[0], nxt.Args[1] = nxt.Args[1], nxt.Args[0] 934 } 935 936 switch nxt.Op { 937 case OpAdd8: 938 nxt.Op = OpSub8 939 case OpAdd16: 940 nxt.Op = OpSub16 941 case OpAdd32: 942 nxt.Op = OpSub32 943 case OpAdd64: 944 nxt.Op = OpSub64 945 case OpSub8: 946 nxt.Op = OpAdd8 947 case OpSub16: 948 nxt.Op = OpAdd16 949 case OpSub32: 950 nxt.Op = OpAdd32 951 case OpSub64: 952 nxt.Op = OpAdd64 953 default: 954 panic("unreachable") 955 } 956 957 if f.pass.debug > 0 { 958 f.Warnl(ind.Pos, "Inverted loop iteration") 959 } 960 } 961 962 ft := newFactsTable(f) 963 ft.checkpoint() 964 965 var lensVars map[*Block][]*Value 966 var logicVars map[*Block][]*Value 967 968 // Find length and capacity ops. 969 for _, b := range f.Blocks { 970 for _, v := range b.Values { 971 if v.Uses == 0 { 972 // We don't care about dead values. 973 // (There can be some that are CSEd but not removed yet.) 974 continue 975 } 976 switch v.Op { 977 case OpStringLen: 978 ft.update(b, v, ft.zero, signed, gt|eq) 979 case OpSliceLen: 980 if ft.lens == nil { 981 ft.lens = map[ID]*Value{} 982 } 983 // Set all len Values for the same slice as equal in the poset. 984 // The poset handles transitive relations, so Values related to 985 // any OpSliceLen for this slice will be correctly related to others. 986 if l, ok := ft.lens[v.Args[0].ID]; ok { 987 ft.update(b, v, l, signed, eq) 988 } else { 989 ft.lens[v.Args[0].ID] = v 990 } 991 ft.update(b, v, ft.zero, signed, gt|eq) 992 if v.Args[0].Op == OpSliceMake { 993 if lensVars == nil { 994 lensVars = make(map[*Block][]*Value) 995 } 996 lensVars[b] = append(lensVars[b], v) 997 } 998 case OpSliceCap: 999 if ft.caps == nil { 1000 ft.caps = map[ID]*Value{} 1001 } 1002 // Same as case OpSliceLen above, but for slice cap. 1003 if c, ok := ft.caps[v.Args[0].ID]; ok { 1004 ft.update(b, v, c, signed, eq) 1005 } else { 1006 ft.caps[v.Args[0].ID] = v 1007 } 1008 ft.update(b, v, ft.zero, signed, gt|eq) 1009 if v.Args[0].Op == OpSliceMake { 1010 if lensVars == nil { 1011 lensVars = make(map[*Block][]*Value) 1012 } 1013 lensVars[b] = append(lensVars[b], v) 1014 } 1015 case OpCtz64, OpCtz32, OpCtz16, OpCtz8, OpBitLen64, OpBitLen32, OpBitLen16, OpBitLen8: 1016 ft.update(b, v, ft.zero, signed, gt|eq) 1017 // TODO: we could also do <= 64/32/16/8, if that helped. 1018 case OpAnd64, OpAnd32, OpAnd16, OpAnd8: 1019 ft.update(b, v, v.Args[1], unsigned, lt|eq) 1020 ft.update(b, v, v.Args[0], unsigned, lt|eq) 1021 for i := 0; i < 2; i++ { 1022 if isNonNegative(v.Args[i]) { 1023 ft.update(b, v, v.Args[i], signed, lt|eq) 1024 ft.update(b, v, ft.zero, signed, gt|eq) 1025 } 1026 } 1027 if logicVars == nil { 1028 logicVars = make(map[*Block][]*Value) 1029 } 1030 logicVars[b] = append(logicVars[b], v) 1031 case OpOr64, OpOr32, OpOr16, OpOr8: 1032 // TODO: investigate how to always add facts without much slowdown, see issue #57959. 1033 if v.Args[0].isGenericIntConst() { 1034 ft.update(b, v, v.Args[0], unsigned, gt|eq) 1035 } 1036 if v.Args[1].isGenericIntConst() { 1037 ft.update(b, v, v.Args[1], unsigned, gt|eq) 1038 } 1039 case OpDiv64u, OpDiv32u, OpDiv16u, OpDiv8u, 1040 OpRsh8Ux64, OpRsh8Ux32, OpRsh8Ux16, OpRsh8Ux8, 1041 OpRsh16Ux64, OpRsh16Ux32, OpRsh16Ux16, OpRsh16Ux8, 1042 OpRsh32Ux64, OpRsh32Ux32, OpRsh32Ux16, OpRsh32Ux8, 1043 OpRsh64Ux64, OpRsh64Ux32, OpRsh64Ux16, OpRsh64Ux8: 1044 ft.update(b, v, v.Args[0], unsigned, lt|eq) 1045 case OpMod64u, OpMod32u, OpMod16u, OpMod8u: 1046 ft.update(b, v, v.Args[0], unsigned, lt|eq) 1047 ft.update(b, v, v.Args[1], unsigned, lt) 1048 case OpPhi: 1049 // Determine the min and max value of OpPhi composed entirely of integer constants. 1050 // 1051 // For example, for an OpPhi: 1052 // 1053 // v1 = OpConst64 [13] 1054 // v2 = OpConst64 [7] 1055 // v3 = OpConst64 [42] 1056 // 1057 // v4 = OpPhi(v1, v2, v3) 1058 // 1059 // We can prove: 1060 // 1061 // v4 >= 7 && v4 <= 42 1062 // 1063 // TODO(jake-ciolek): Handle nested constant OpPhi's 1064 sameConstOp := true 1065 min := 0 1066 max := 0 1067 1068 if !v.Args[min].isGenericIntConst() { 1069 break 1070 } 1071 1072 for k := range v.Args { 1073 if v.Args[k].Op != v.Args[min].Op { 1074 sameConstOp = false 1075 break 1076 } 1077 if v.Args[k].AuxInt < v.Args[min].AuxInt { 1078 min = k 1079 } 1080 if v.Args[k].AuxInt > v.Args[max].AuxInt { 1081 max = k 1082 } 1083 } 1084 1085 if sameConstOp { 1086 ft.update(b, v, v.Args[min], signed, gt|eq) 1087 ft.update(b, v, v.Args[max], signed, lt|eq) 1088 } 1089 // One might be tempted to create a v >= ft.zero relation for 1090 // all OpPhi's composed of only provably-positive values 1091 // but that bloats up the facts table for a very negligible gain. 1092 // In Go itself, very few functions get improved (< 5) at a cost of 5-7% total increase 1093 // of compile time. 1094 } 1095 } 1096 } 1097 1098 // current node state 1099 type walkState int 1100 const ( 1101 descend walkState = iota 1102 simplify 1103 ) 1104 // work maintains the DFS stack. 1105 type bp struct { 1106 block *Block // current handled block 1107 state walkState // what's to do 1108 } 1109 work := make([]bp, 0, 256) 1110 work = append(work, bp{ 1111 block: f.Entry, 1112 state: descend, 1113 }) 1114 1115 idom := f.Idom() 1116 sdom := f.Sdom() 1117 1118 // DFS on the dominator tree. 1119 // 1120 // For efficiency, we consider only the dominator tree rather 1121 // than the entire flow graph. On the way down, we consider 1122 // incoming branches and accumulate conditions that uniquely 1123 // dominate the current block. If we discover a contradiction, 1124 // we can eliminate the entire block and all of its children. 1125 // On the way back up, we consider outgoing branches that 1126 // haven't already been considered. This way we consider each 1127 // branch condition only once. 1128 for len(work) > 0 { 1129 node := work[len(work)-1] 1130 work = work[:len(work)-1] 1131 parent := idom[node.block.ID] 1132 branch := getBranch(sdom, parent, node.block) 1133 1134 switch node.state { 1135 case descend: 1136 ft.checkpoint() 1137 1138 // Entering the block, add the block-depending facts that we collected 1139 // at the beginning: induction variables and lens/caps of slices. 1140 if iv, ok := indVars[node.block]; ok { 1141 addIndVarRestrictions(ft, parent, iv) 1142 } 1143 if lens, ok := lensVars[node.block]; ok { 1144 for _, v := range lens { 1145 switch v.Op { 1146 case OpSliceLen: 1147 ft.update(node.block, v, v.Args[0].Args[1], signed, eq) 1148 case OpSliceCap: 1149 ft.update(node.block, v, v.Args[0].Args[2], signed, eq) 1150 } 1151 } 1152 } 1153 1154 if branch != unknown { 1155 addBranchRestrictions(ft, parent, branch) 1156 // After we add the branch restriction, re-check the logic operations in the parent block, 1157 // it may give us more info to omit some branches 1158 if logic, ok := logicVars[parent]; ok { 1159 for _, v := range logic { 1160 // we only have OpAnd for now 1161 ft.update(parent, v, v.Args[1], unsigned, lt|eq) 1162 ft.update(parent, v, v.Args[0], unsigned, lt|eq) 1163 for i := 0; i < 2; i++ { 1164 if isNonNegative(v.Args[i]) { 1165 ft.update(parent, v, v.Args[i], signed, lt|eq) 1166 ft.update(parent, v, ft.zero, signed, gt|eq) 1167 } 1168 } 1169 } 1170 } 1171 if ft.unsat { 1172 // node.block is unreachable. 1173 // Remove it and don't visit 1174 // its children. 1175 removeBranch(parent, branch) 1176 ft.restore() 1177 break 1178 } 1179 // Otherwise, we can now commit to 1180 // taking this branch. We'll restore 1181 // ft when we unwind. 1182 } 1183 1184 // Add inductive facts for phis in this block. 1185 addLocalInductiveFacts(ft, node.block) 1186 1187 work = append(work, bp{ 1188 block: node.block, 1189 state: simplify, 1190 }) 1191 for s := sdom.Child(node.block); s != nil; s = sdom.Sibling(s) { 1192 work = append(work, bp{ 1193 block: s, 1194 state: descend, 1195 }) 1196 } 1197 1198 case simplify: 1199 simplifyBlock(sdom, ft, node.block) 1200 ft.restore() 1201 } 1202 } 1203 1204 ft.restore() 1205 1206 ft.cleanup(f) 1207 } 1208 1209 // getBranch returns the range restrictions added by p 1210 // when reaching b. p is the immediate dominator of b. 1211 func getBranch(sdom SparseTree, p *Block, b *Block) branch { 1212 if p == nil { 1213 return unknown 1214 } 1215 switch p.Kind { 1216 case BlockIf: 1217 // If p and p.Succs[0] are dominators it means that every path 1218 // from entry to b passes through p and p.Succs[0]. We care that 1219 // no path from entry to b passes through p.Succs[1]. If p.Succs[0] 1220 // has one predecessor then (apart from the degenerate case), 1221 // there is no path from entry that can reach b through p.Succs[1]. 1222 // TODO: how about p->yes->b->yes, i.e. a loop in yes. 1223 if sdom.IsAncestorEq(p.Succs[0].b, b) && len(p.Succs[0].b.Preds) == 1 { 1224 return positive 1225 } 1226 if sdom.IsAncestorEq(p.Succs[1].b, b) && len(p.Succs[1].b.Preds) == 1 { 1227 return negative 1228 } 1229 case BlockJumpTable: 1230 // TODO: this loop can lead to quadratic behavior, as 1231 // getBranch can be called len(p.Succs) times. 1232 for i, e := range p.Succs { 1233 if sdom.IsAncestorEq(e.b, b) && len(e.b.Preds) == 1 { 1234 return jumpTable0 + branch(i) 1235 } 1236 } 1237 } 1238 return unknown 1239 } 1240 1241 // addIndVarRestrictions updates the factsTables ft with the facts 1242 // learned from the induction variable indVar which drives the loop 1243 // starting in Block b. 1244 func addIndVarRestrictions(ft *factsTable, b *Block, iv indVar) { 1245 d := signed 1246 if ft.isNonNegative(iv.min) && ft.isNonNegative(iv.max) { 1247 d |= unsigned 1248 } 1249 1250 if iv.flags&indVarMinExc == 0 { 1251 addRestrictions(b, ft, d, iv.min, iv.ind, lt|eq) 1252 } else { 1253 addRestrictions(b, ft, d, iv.min, iv.ind, lt) 1254 } 1255 1256 if iv.flags&indVarMaxInc == 0 { 1257 addRestrictions(b, ft, d, iv.ind, iv.max, lt) 1258 } else { 1259 addRestrictions(b, ft, d, iv.ind, iv.max, lt|eq) 1260 } 1261 } 1262 1263 // addBranchRestrictions updates the factsTables ft with the facts learned when 1264 // branching from Block b in direction br. 1265 func addBranchRestrictions(ft *factsTable, b *Block, br branch) { 1266 c := b.Controls[0] 1267 switch { 1268 case br == negative: 1269 addRestrictions(b, ft, boolean, nil, c, eq) 1270 case br == positive: 1271 addRestrictions(b, ft, boolean, nil, c, lt|gt) 1272 case br >= jumpTable0: 1273 idx := br - jumpTable0 1274 val := int64(idx) 1275 if v, off := isConstDelta(c); v != nil { 1276 // Establish the bound on the underlying value we're switching on, 1277 // not on the offset-ed value used as the jump table index. 1278 c = v 1279 val -= off 1280 } 1281 old, ok := ft.limits[c.ID] 1282 if !ok { 1283 old = noLimit 1284 } 1285 ft.limitStack = append(ft.limitStack, limitFact{c.ID, old}) 1286 if val < old.min || val > old.max || uint64(val) < old.umin || uint64(val) > old.umax { 1287 ft.unsat = true 1288 if b.Func.pass.debug > 2 { 1289 b.Func.Warnl(b.Pos, "block=%s outedge=%d %s=%d unsat", b, idx, c, val) 1290 } 1291 } else { 1292 ft.limits[c.ID] = limit{val, val, uint64(val), uint64(val)} 1293 if b.Func.pass.debug > 2 { 1294 b.Func.Warnl(b.Pos, "block=%s outedge=%d %s=%d", b, idx, c, val) 1295 } 1296 } 1297 default: 1298 panic("unknown branch") 1299 } 1300 if tr, has := domainRelationTable[c.Op]; has { 1301 // When we branched from parent we learned a new set of 1302 // restrictions. Update the factsTable accordingly. 1303 d := tr.d 1304 if d == signed && ft.isNonNegative(c.Args[0]) && ft.isNonNegative(c.Args[1]) { 1305 d |= unsigned 1306 } 1307 switch c.Op { 1308 case OpIsInBounds, OpIsSliceInBounds: 1309 // 0 <= a0 < a1 (or 0 <= a0 <= a1) 1310 // 1311 // On the positive branch, we learn: 1312 // signed: 0 <= a0 < a1 (or 0 <= a0 <= a1) 1313 // unsigned: a0 < a1 (or a0 <= a1) 1314 // 1315 // On the negative branch, we learn (0 > a0 || 1316 // a0 >= a1). In the unsigned domain, this is 1317 // simply a0 >= a1 (which is the reverse of the 1318 // positive branch, so nothing surprising). 1319 // But in the signed domain, we can't express the || 1320 // condition, so check if a0 is non-negative instead, 1321 // to be able to learn something. 1322 switch br { 1323 case negative: 1324 d = unsigned 1325 if ft.isNonNegative(c.Args[0]) { 1326 d |= signed 1327 } 1328 addRestrictions(b, ft, d, c.Args[0], c.Args[1], tr.r^(lt|gt|eq)) 1329 case positive: 1330 addRestrictions(b, ft, signed, ft.zero, c.Args[0], lt|eq) 1331 addRestrictions(b, ft, d, c.Args[0], c.Args[1], tr.r) 1332 } 1333 default: 1334 switch br { 1335 case negative: 1336 addRestrictions(b, ft, d, c.Args[0], c.Args[1], tr.r^(lt|gt|eq)) 1337 case positive: 1338 addRestrictions(b, ft, d, c.Args[0], c.Args[1], tr.r) 1339 } 1340 } 1341 1342 } 1343 } 1344 1345 // addRestrictions updates restrictions from the immediate 1346 // dominating block (p) using r. 1347 func addRestrictions(parent *Block, ft *factsTable, t domain, v, w *Value, r relation) { 1348 if t == 0 { 1349 // Trivial case: nothing to do. 1350 // Should not happen, but just in case. 1351 return 1352 } 1353 for i := domain(1); i <= t; i <<= 1 { 1354 if t&i == 0 { 1355 continue 1356 } 1357 ft.update(parent, v, w, i, r) 1358 } 1359 } 1360 1361 // addLocalInductiveFacts adds inductive facts when visiting b, where 1362 // b is a join point in a loop. In contrast with findIndVar, this 1363 // depends on facts established for b, which is why it happens when 1364 // visiting b. 1365 // 1366 // TODO: It would be nice to combine this with findIndVar. 1367 func addLocalInductiveFacts(ft *factsTable, b *Block) { 1368 // This looks for a specific pattern of induction: 1369 // 1370 // 1. i1 = OpPhi(min, i2) in b 1371 // 2. i2 = i1 + 1 1372 // 3. i2 < max at exit from b.Preds[1] 1373 // 4. min < max 1374 // 1375 // If all of these conditions are true, then i1 < max and i1 >= min. 1376 1377 // To ensure this is a loop header node. 1378 if len(b.Preds) != 2 { 1379 return 1380 } 1381 1382 for _, i1 := range b.Values { 1383 if i1.Op != OpPhi { 1384 continue 1385 } 1386 1387 // Check for conditions 1 and 2. This is easy to do 1388 // and will throw out most phis. 1389 min, i2 := i1.Args[0], i1.Args[1] 1390 if i1q, delta := isConstDelta(i2); i1q != i1 || delta != 1 { 1391 continue 1392 } 1393 1394 // Try to prove condition 3. We can't just query the 1395 // fact table for this because we don't know what the 1396 // facts of b.Preds[1] are (in general, b.Preds[1] is 1397 // a loop-back edge, so we haven't even been there 1398 // yet). As a conservative approximation, we look for 1399 // this condition in the predecessor chain until we 1400 // hit a join point. 1401 uniquePred := func(b *Block) *Block { 1402 if len(b.Preds) == 1 { 1403 return b.Preds[0].b 1404 } 1405 return nil 1406 } 1407 pred, child := b.Preds[1].b, b 1408 for ; pred != nil; pred, child = uniquePred(pred), pred { 1409 if pred.Kind != BlockIf { 1410 continue 1411 } 1412 control := pred.Controls[0] 1413 1414 br := unknown 1415 if pred.Succs[0].b == child { 1416 br = positive 1417 } 1418 if pred.Succs[1].b == child { 1419 if br != unknown { 1420 continue 1421 } 1422 br = negative 1423 } 1424 if br == unknown { 1425 continue 1426 } 1427 1428 tr, has := domainRelationTable[control.Op] 1429 if !has { 1430 continue 1431 } 1432 r := tr.r 1433 if br == negative { 1434 // Negative branch taken to reach b. 1435 // Complement the relations. 1436 r = (lt | eq | gt) ^ r 1437 } 1438 1439 // Check for i2 < max or max > i2. 1440 var max *Value 1441 if r == lt && control.Args[0] == i2 { 1442 max = control.Args[1] 1443 } else if r == gt && control.Args[1] == i2 { 1444 max = control.Args[0] 1445 } else { 1446 continue 1447 } 1448 1449 // Check condition 4 now that we have a 1450 // candidate max. For this we can query the 1451 // fact table. We "prove" min < max by showing 1452 // that min >= max is unsat. (This may simply 1453 // compare two constants; that's fine.) 1454 ft.checkpoint() 1455 ft.update(b, min, max, tr.d, gt|eq) 1456 proved := ft.unsat 1457 ft.restore() 1458 1459 if proved { 1460 // We know that min <= i1 < max. 1461 if b.Func.pass.debug > 0 { 1462 printIndVar(b, i1, min, max, 1, 0) 1463 } 1464 ft.update(b, min, i1, tr.d, lt|eq) 1465 ft.update(b, i1, max, tr.d, lt) 1466 } 1467 } 1468 } 1469 } 1470 1471 var ctzNonZeroOp = map[Op]Op{OpCtz8: OpCtz8NonZero, OpCtz16: OpCtz16NonZero, OpCtz32: OpCtz32NonZero, OpCtz64: OpCtz64NonZero} 1472 var mostNegativeDividend = map[Op]int64{ 1473 OpDiv16: -1 << 15, 1474 OpMod16: -1 << 15, 1475 OpDiv32: -1 << 31, 1476 OpMod32: -1 << 31, 1477 OpDiv64: -1 << 63, 1478 OpMod64: -1 << 63} 1479 1480 // simplifyBlock simplifies some constant values in b and evaluates 1481 // branches to non-uniquely dominated successors of b. 1482 func simplifyBlock(sdom SparseTree, ft *factsTable, b *Block) { 1483 for _, v := range b.Values { 1484 switch v.Op { 1485 case OpSlicemask: 1486 // Replace OpSlicemask operations in b with constants where possible. 1487 x, delta := isConstDelta(v.Args[0]) 1488 if x == nil { 1489 break 1490 } 1491 // slicemask(x + y) 1492 // if x is larger than -y (y is negative), then slicemask is -1. 1493 lim, ok := ft.limits[x.ID] 1494 if !ok { 1495 break 1496 } 1497 if lim.umin > uint64(-delta) { 1498 if v.Args[0].Op == OpAdd64 { 1499 v.reset(OpConst64) 1500 } else { 1501 v.reset(OpConst32) 1502 } 1503 if b.Func.pass.debug > 0 { 1504 b.Func.Warnl(v.Pos, "Proved slicemask not needed") 1505 } 1506 v.AuxInt = -1 1507 } 1508 case OpCtz8, OpCtz16, OpCtz32, OpCtz64: 1509 // On some architectures, notably amd64, we can generate much better 1510 // code for CtzNN if we know that the argument is non-zero. 1511 // Capture that information here for use in arch-specific optimizations. 1512 x := v.Args[0] 1513 lim, ok := ft.limits[x.ID] 1514 if !ok { 1515 break 1516 } 1517 if lim.umin > 0 || lim.min > 0 || lim.max < 0 { 1518 if b.Func.pass.debug > 0 { 1519 b.Func.Warnl(v.Pos, "Proved %v non-zero", v.Op) 1520 } 1521 v.Op = ctzNonZeroOp[v.Op] 1522 } 1523 case OpRsh8x8, OpRsh8x16, OpRsh8x32, OpRsh8x64, 1524 OpRsh16x8, OpRsh16x16, OpRsh16x32, OpRsh16x64, 1525 OpRsh32x8, OpRsh32x16, OpRsh32x32, OpRsh32x64, 1526 OpRsh64x8, OpRsh64x16, OpRsh64x32, OpRsh64x64: 1527 // Check whether, for a >> b, we know that a is non-negative 1528 // and b is all of a's bits except the MSB. If so, a is shifted to zero. 1529 bits := 8 * v.Type.Size() 1530 if v.Args[1].isGenericIntConst() && v.Args[1].AuxInt >= bits-1 && ft.isNonNegative(v.Args[0]) { 1531 if b.Func.pass.debug > 0 { 1532 b.Func.Warnl(v.Pos, "Proved %v shifts to zero", v.Op) 1533 } 1534 switch bits { 1535 case 64: 1536 v.reset(OpConst64) 1537 case 32: 1538 v.reset(OpConst32) 1539 case 16: 1540 v.reset(OpConst16) 1541 case 8: 1542 v.reset(OpConst8) 1543 default: 1544 panic("unexpected integer size") 1545 } 1546 v.AuxInt = 0 1547 break // Be sure not to fallthrough - this is no longer OpRsh. 1548 } 1549 // If the Rsh hasn't been replaced with 0, still check if it is bounded. 1550 fallthrough 1551 case OpLsh8x8, OpLsh8x16, OpLsh8x32, OpLsh8x64, 1552 OpLsh16x8, OpLsh16x16, OpLsh16x32, OpLsh16x64, 1553 OpLsh32x8, OpLsh32x16, OpLsh32x32, OpLsh32x64, 1554 OpLsh64x8, OpLsh64x16, OpLsh64x32, OpLsh64x64, 1555 OpRsh8Ux8, OpRsh8Ux16, OpRsh8Ux32, OpRsh8Ux64, 1556 OpRsh16Ux8, OpRsh16Ux16, OpRsh16Ux32, OpRsh16Ux64, 1557 OpRsh32Ux8, OpRsh32Ux16, OpRsh32Ux32, OpRsh32Ux64, 1558 OpRsh64Ux8, OpRsh64Ux16, OpRsh64Ux32, OpRsh64Ux64: 1559 // Check whether, for a << b, we know that b 1560 // is strictly less than the number of bits in a. 1561 by := v.Args[1] 1562 lim, ok := ft.limits[by.ID] 1563 if !ok { 1564 break 1565 } 1566 bits := 8 * v.Args[0].Type.Size() 1567 if lim.umax < uint64(bits) || (lim.max < bits && ft.isNonNegative(by)) { 1568 v.AuxInt = 1 // see shiftIsBounded 1569 if b.Func.pass.debug > 0 { 1570 b.Func.Warnl(v.Pos, "Proved %v bounded", v.Op) 1571 } 1572 } 1573 case OpDiv16, OpDiv32, OpDiv64, OpMod16, OpMod32, OpMod64: 1574 // On amd64 and 386 fix-up code can be avoided if we know 1575 // the divisor is not -1 or the dividend > MinIntNN. 1576 // Don't modify AuxInt on other architectures, 1577 // as that can interfere with CSE. 1578 // TODO: add other architectures? 1579 if b.Func.Config.arch != "386" && b.Func.Config.arch != "amd64" { 1580 break 1581 } 1582 divr := v.Args[1] 1583 divrLim, divrLimok := ft.limits[divr.ID] 1584 divd := v.Args[0] 1585 divdLim, divdLimok := ft.limits[divd.ID] 1586 if (divrLimok && (divrLim.max < -1 || divrLim.min > -1)) || 1587 (divdLimok && divdLim.min > mostNegativeDividend[v.Op]) { 1588 // See DivisionNeedsFixUp in rewrite.go. 1589 // v.AuxInt = 1 means we have proved both that the divisor is not -1 1590 // and that the dividend is not the most negative integer, 1591 // so we do not need to add fix-up code. 1592 v.AuxInt = 1 1593 if b.Func.pass.debug > 0 { 1594 b.Func.Warnl(v.Pos, "Proved %v does not need fix-up", v.Op) 1595 } 1596 } 1597 } 1598 // Fold provable constant results. 1599 // Helps in cases where we reuse a value after branching on its equality. 1600 for i, arg := range v.Args { 1601 switch arg.Op { 1602 case OpConst64, OpConst32, OpConst16, OpConst8: 1603 continue 1604 } 1605 lim, ok := ft.limits[arg.ID] 1606 if !ok { 1607 continue 1608 } 1609 1610 var constValue int64 1611 typ := arg.Type 1612 bits := 8 * typ.Size() 1613 switch { 1614 case lim.min == lim.max: 1615 constValue = lim.min 1616 case lim.umin == lim.umax: 1617 // truncate then sign extand 1618 switch bits { 1619 case 64: 1620 constValue = int64(lim.umin) 1621 case 32: 1622 constValue = int64(int32(lim.umin)) 1623 case 16: 1624 constValue = int64(int16(lim.umin)) 1625 case 8: 1626 constValue = int64(int8(lim.umin)) 1627 default: 1628 panic("unexpected integer size") 1629 } 1630 default: 1631 continue 1632 } 1633 var c *Value 1634 f := b.Func 1635 switch bits { 1636 case 64: 1637 c = f.ConstInt64(typ, constValue) 1638 case 32: 1639 c = f.ConstInt32(typ, int32(constValue)) 1640 case 16: 1641 c = f.ConstInt16(typ, int16(constValue)) 1642 case 8: 1643 c = f.ConstInt8(typ, int8(constValue)) 1644 default: 1645 panic("unexpected integer size") 1646 } 1647 v.SetArg(i, c) 1648 if b.Func.pass.debug > 1 { 1649 b.Func.Warnl(v.Pos, "Proved %v's arg %d (%v) is constant %d", v, i, arg, constValue) 1650 } 1651 } 1652 } 1653 1654 if b.Kind != BlockIf { 1655 return 1656 } 1657 1658 // Consider outgoing edges from this block. 1659 parent := b 1660 for i, branch := range [...]branch{positive, negative} { 1661 child := parent.Succs[i].b 1662 if getBranch(sdom, parent, child) != unknown { 1663 // For edges to uniquely dominated blocks, we 1664 // already did this when we visited the child. 1665 continue 1666 } 1667 // For edges to other blocks, this can trim a branch 1668 // even if we couldn't get rid of the child itself. 1669 ft.checkpoint() 1670 addBranchRestrictions(ft, parent, branch) 1671 unsat := ft.unsat 1672 ft.restore() 1673 if unsat { 1674 // This branch is impossible, so remove it 1675 // from the block. 1676 removeBranch(parent, branch) 1677 // No point in considering the other branch. 1678 // (It *is* possible for both to be 1679 // unsatisfiable since the fact table is 1680 // incomplete. We could turn this into a 1681 // BlockExit, but it doesn't seem worth it.) 1682 break 1683 } 1684 } 1685 } 1686 1687 func removeBranch(b *Block, branch branch) { 1688 c := b.Controls[0] 1689 if b.Func.pass.debug > 0 { 1690 verb := "Proved" 1691 if branch == positive { 1692 verb = "Disproved" 1693 } 1694 if b.Func.pass.debug > 1 { 1695 b.Func.Warnl(b.Pos, "%s %s (%s)", verb, c.Op, c) 1696 } else { 1697 b.Func.Warnl(b.Pos, "%s %s", verb, c.Op) 1698 } 1699 } 1700 if c != nil && c.Pos.IsStmt() == src.PosIsStmt && c.Pos.SameFileAndLine(b.Pos) { 1701 // attempt to preserve statement marker. 1702 b.Pos = b.Pos.WithIsStmt() 1703 } 1704 if branch == positive || branch == negative { 1705 b.Kind = BlockFirst 1706 b.ResetControls() 1707 if branch == positive { 1708 b.swapSuccessors() 1709 } 1710 } else { 1711 // TODO: figure out how to remove an entry from a jump table 1712 } 1713 } 1714 1715 // isNonNegative reports whether v is known to be greater or equal to zero. 1716 func isNonNegative(v *Value) bool { 1717 if !v.Type.IsInteger() { 1718 v.Fatalf("isNonNegative bad type: %v", v.Type) 1719 } 1720 // TODO: return true if !v.Type.IsSigned() 1721 // SSA isn't type-safe enough to do that now (issue 37753). 1722 // The checks below depend only on the pattern of bits. 1723 1724 switch v.Op { 1725 case OpConst64: 1726 return v.AuxInt >= 0 1727 1728 case OpConst32: 1729 return int32(v.AuxInt) >= 0 1730 1731 case OpConst16: 1732 return int16(v.AuxInt) >= 0 1733 1734 case OpConst8: 1735 return int8(v.AuxInt) >= 0 1736 1737 case OpStringLen, OpSliceLen, OpSliceCap, 1738 OpZeroExt8to64, OpZeroExt16to64, OpZeroExt32to64, 1739 OpZeroExt8to32, OpZeroExt16to32, OpZeroExt8to16, 1740 OpCtz64, OpCtz32, OpCtz16, OpCtz8, 1741 OpCtz64NonZero, OpCtz32NonZero, OpCtz16NonZero, OpCtz8NonZero, 1742 OpBitLen64, OpBitLen32, OpBitLen16, OpBitLen8: 1743 return true 1744 1745 case OpRsh64Ux64, OpRsh32Ux64: 1746 by := v.Args[1] 1747 return by.Op == OpConst64 && by.AuxInt > 0 1748 1749 case OpRsh64x64, OpRsh32x64, OpRsh8x64, OpRsh16x64, OpRsh32x32, OpRsh64x32, 1750 OpSignExt32to64, OpSignExt16to64, OpSignExt8to64, OpSignExt16to32, OpSignExt8to32: 1751 return isNonNegative(v.Args[0]) 1752 1753 case OpAnd64, OpAnd32, OpAnd16, OpAnd8: 1754 return isNonNegative(v.Args[0]) || isNonNegative(v.Args[1]) 1755 1756 case OpMod64, OpMod32, OpMod16, OpMod8, 1757 OpDiv64, OpDiv32, OpDiv16, OpDiv8, 1758 OpOr64, OpOr32, OpOr16, OpOr8, 1759 OpXor64, OpXor32, OpXor16, OpXor8: 1760 return isNonNegative(v.Args[0]) && isNonNegative(v.Args[1]) 1761 1762 // We could handle OpPhi here, but the improvements from doing 1763 // so are very minor, and it is neither simple nor cheap. 1764 } 1765 return false 1766 } 1767 1768 // isConstDelta returns non-nil if v is equivalent to w+delta (signed). 1769 func isConstDelta(v *Value) (w *Value, delta int64) { 1770 cop := OpConst64 1771 switch v.Op { 1772 case OpAdd32, OpSub32: 1773 cop = OpConst32 1774 case OpAdd16, OpSub16: 1775 cop = OpConst16 1776 case OpAdd8, OpSub8: 1777 cop = OpConst8 1778 } 1779 switch v.Op { 1780 case OpAdd64, OpAdd32, OpAdd16, OpAdd8: 1781 if v.Args[0].Op == cop { 1782 return v.Args[1], v.Args[0].AuxInt 1783 } 1784 if v.Args[1].Op == cop { 1785 return v.Args[0], v.Args[1].AuxInt 1786 } 1787 case OpSub64, OpSub32, OpSub16, OpSub8: 1788 if v.Args[1].Op == cop { 1789 aux := v.Args[1].AuxInt 1790 if aux != -aux { // Overflow; too bad 1791 return v.Args[0], -aux 1792 } 1793 } 1794 } 1795 return nil, 0 1796 } 1797 1798 // isCleanExt reports whether v is the result of a value-preserving 1799 // sign or zero extension. 1800 func isCleanExt(v *Value) bool { 1801 switch v.Op { 1802 case OpSignExt8to16, OpSignExt8to32, OpSignExt8to64, 1803 OpSignExt16to32, OpSignExt16to64, OpSignExt32to64: 1804 // signed -> signed is the only value-preserving sign extension 1805 return v.Args[0].Type.IsSigned() && v.Type.IsSigned() 1806 1807 case OpZeroExt8to16, OpZeroExt8to32, OpZeroExt8to64, 1808 OpZeroExt16to32, OpZeroExt16to64, OpZeroExt32to64: 1809 // unsigned -> signed/unsigned are value-preserving zero extensions 1810 return !v.Args[0].Type.IsSigned() 1811 } 1812 return false 1813 }