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