1
2
3
4
5 package ssa
6
7 import (
8 "cmd/compile/internal/types"
9 "cmd/internal/src"
10 "fmt"
11 "math"
12 "math/bits"
13 )
14
15 type branch int
16
17 const (
18 unknown branch = iota
19 positive
20 negative
21
22
23
24 jumpTable0
25 )
26
27 func (b branch) String() string {
28 switch b {
29 case unknown:
30 return "unk"
31 case positive:
32 return "pos"
33 case negative:
34 return "neg"
35 default:
36 return fmt.Sprintf("jmp%d", b-jumpTable0)
37 }
38 }
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60 type relation uint
61
62 const (
63 lt relation = 1 << iota
64 eq
65 gt
66 )
67
68 var relationStrings = [...]string{
69 0: "none", lt: "<", eq: "==", lt | eq: "<=",
70 gt: ">", gt | lt: "!=", gt | eq: ">=", gt | eq | lt: "any",
71 }
72
73 func (r relation) String() string {
74 if r < relation(len(relationStrings)) {
75 return relationStrings[r]
76 }
77 return fmt.Sprintf("relation(%d)", uint(r))
78 }
79
80
81
82
83
84 type domain uint
85
86 const (
87 signed domain = 1 << iota
88 unsigned
89 pointer
90 boolean
91 )
92
93 var domainStrings = [...]string{
94 "signed", "unsigned", "pointer", "boolean",
95 }
96
97 func (d domain) String() string {
98 s := ""
99 for i, ds := range domainStrings {
100 if d&(1<<uint(i)) != 0 {
101 if len(s) != 0 {
102 s += "|"
103 }
104 s += ds
105 d &^= 1 << uint(i)
106 }
107 }
108 if d != 0 {
109 if len(s) != 0 {
110 s += "|"
111 }
112 s += fmt.Sprintf("0x%x", uint(d))
113 }
114 return s
115 }
116
117
118
119
120
121
122
123
124
125 type limit struct {
126 min, max int64
127 umin, umax uint64
128
129
130 }
131
132 func (l limit) String() string {
133 return fmt.Sprintf("sm,SM,um,UM=%d,%d,%d,%d", l.min, l.max, l.umin, l.umax)
134 }
135
136 func (l limit) intersect(l2 limit) limit {
137 l.min = max(l.min, l2.min)
138 l.umin = max(l.umin, l2.umin)
139 l.max = min(l.max, l2.max)
140 l.umax = min(l.umax, l2.umax)
141 return l
142 }
143
144 func (l limit) signedMin(m int64) limit {
145 l.min = max(l.min, m)
146 return l
147 }
148
149 func (l limit) signedMinMax(minimum, maximum int64) limit {
150 l.min = max(l.min, minimum)
151 l.max = min(l.max, maximum)
152 return l
153 }
154
155 func (l limit) unsignedMin(m uint64) limit {
156 l.umin = max(l.umin, m)
157 return l
158 }
159 func (l limit) unsignedMax(m uint64) limit {
160 l.umax = min(l.umax, m)
161 return l
162 }
163 func (l limit) unsignedMinMax(minimum, maximum uint64) limit {
164 l.umin = max(l.umin, minimum)
165 l.umax = min(l.umax, maximum)
166 return l
167 }
168
169 func (l limit) nonzero() bool {
170 return l.min > 0 || l.umin > 0 || l.max < 0
171 }
172 func (l limit) nonnegative() bool {
173 return l.min >= 0
174 }
175 func (l limit) unsat() bool {
176 return l.min > l.max || l.umin > l.umax
177 }
178
179
180
181
182 func safeAdd(x, y int64, b uint) (int64, bool) {
183 s := x + y
184 if x >= 0 && y >= 0 && s < 0 {
185 return 0, false
186 }
187 if x < 0 && y < 0 && s >= 0 {
188 return 0, false
189 }
190 if !fitsInBits(s, b) {
191 return 0, false
192 }
193 return s, true
194 }
195
196
197 func safeAddU(x, y uint64, b uint) (uint64, bool) {
198 s := x + y
199 if s < x || s < y {
200 return 0, false
201 }
202 if !fitsInBitsU(s, b) {
203 return 0, false
204 }
205 return s, true
206 }
207
208
209 func safeSub(x, y int64, b uint) (int64, bool) {
210 if y == math.MinInt64 {
211 if x == math.MaxInt64 {
212 return 0, false
213 }
214 x++
215 y++
216 }
217 return safeAdd(x, -y, b)
218 }
219
220
221 func safeSubU(x, y uint64, b uint) (uint64, bool) {
222 if x < y {
223 return 0, false
224 }
225 s := x - y
226 if !fitsInBitsU(s, b) {
227 return 0, false
228 }
229 return s, true
230 }
231
232
233 func fitsInBits(x int64, b uint) bool {
234 if b == 64 {
235 return true
236 }
237 m := int64(-1) << (b - 1)
238 M := -m - 1
239 return x >= m && x <= M
240 }
241
242
243 func fitsInBitsU(x uint64, b uint) bool {
244 return x>>b == 0
245 }
246
247
248
249 func (l limit) add(l2 limit, b uint) limit {
250 r := noLimit
251 min, minOk := safeAdd(l.min, l2.min, b)
252 max, maxOk := safeAdd(l.max, l2.max, b)
253 if minOk && maxOk {
254 r.min = min
255 r.max = max
256 }
257 umin, uminOk := safeAddU(l.umin, l2.umin, b)
258 umax, umaxOk := safeAddU(l.umax, l2.umax, b)
259 if uminOk && umaxOk {
260 r.umin = umin
261 r.umax = umax
262 }
263 return r
264 }
265
266
267 func (l limit) sub(l2 limit, b uint) limit {
268 r := noLimit
269 min, minOk := safeSub(l.min, l2.max, b)
270 max, maxOk := safeSub(l.max, l2.min, b)
271 if minOk && maxOk {
272 r.min = min
273 r.max = max
274 }
275 umin, uminOk := safeSubU(l.umin, l2.umax, b)
276 umax, umaxOk := safeSubU(l.umax, l2.umin, b)
277 if uminOk && umaxOk {
278 r.umin = umin
279 r.umax = umax
280 }
281 return r
282 }
283
284
285 func (l limit) mul(l2 limit, b uint) limit {
286 r := noLimit
287 umaxhi, umaxlo := bits.Mul64(l.umax, l2.umax)
288 if umaxhi == 0 && fitsInBitsU(umaxlo, b) {
289 r.umax = umaxlo
290 r.umin = l.umin * l2.umin
291
292
293
294
295
296
297 }
298
299
300
301
302
303 return r
304 }
305
306
307 func (l limit) exp2(b uint) limit {
308 r := noLimit
309 if l.umax < uint64(b) {
310 r.umin = 1 << l.umin
311 r.umax = 1 << l.umax
312
313
314 }
315 return r
316 }
317
318
319 func (l limit) com(b uint) limit {
320 switch b {
321 case 64:
322 return limit{
323 min: ^l.max,
324 max: ^l.min,
325 umin: ^l.umax,
326 umax: ^l.umin,
327 }
328 case 32:
329 return limit{
330 min: int64(^int32(l.max)),
331 max: int64(^int32(l.min)),
332 umin: uint64(^uint32(l.umax)),
333 umax: uint64(^uint32(l.umin)),
334 }
335 case 16:
336 return limit{
337 min: int64(^int16(l.max)),
338 max: int64(^int16(l.min)),
339 umin: uint64(^uint16(l.umax)),
340 umax: uint64(^uint16(l.umin)),
341 }
342 case 8:
343 return limit{
344 min: int64(^int8(l.max)),
345 max: int64(^int8(l.min)),
346 umin: uint64(^uint8(l.umax)),
347 umax: uint64(^uint8(l.umin)),
348 }
349 default:
350 panic("unreachable")
351 }
352 }
353
354 var noLimit = limit{math.MinInt64, math.MaxInt64, 0, math.MaxUint64}
355
356
357 type limitFact struct {
358 vid ID
359 limit limit
360 }
361
362
363 type ordering struct {
364 next *ordering
365
366 w *Value
367 d domain
368 r relation
369
370 }
371
372
373
374
375
376
377
378
379 type factsTable struct {
380
381
382
383
384
385 unsat bool
386 unsatDepth int
387
388
389
390
391 orderS *poset
392 orderU *poset
393
394
395
396
397
398
399 orderings map[ID]*ordering
400
401
402 orderingsStack []ID
403 orderingCache *ordering
404
405
406 limits []limit
407 limitStack []limitFact
408 recurseCheck []bool
409
410
411
412
413 lens map[ID]*Value
414 caps map[ID]*Value
415 }
416
417
418
419 var checkpointBound = limitFact{}
420
421 func newFactsTable(f *Func) *factsTable {
422 ft := &factsTable{}
423 ft.orderS = f.newPoset()
424 ft.orderU = f.newPoset()
425 ft.orderS.SetUnsigned(false)
426 ft.orderU.SetUnsigned(true)
427 ft.orderings = make(map[ID]*ordering)
428 ft.limits = f.Cache.allocLimitSlice(f.NumValues())
429 for _, b := range f.Blocks {
430 for _, v := range b.Values {
431 ft.limits[v.ID] = initLimit(v)
432 }
433 }
434 ft.limitStack = make([]limitFact, 4)
435 ft.recurseCheck = f.Cache.allocBoolSlice(f.NumValues())
436 return ft
437 }
438
439
440
441
442 func (ft *factsTable) initLimitForNewValue(v *Value) {
443 if int(v.ID) >= len(ft.limits) {
444 f := v.Block.Func
445 n := f.NumValues()
446 if cap(ft.limits) >= n {
447 ft.limits = ft.limits[:n]
448 } else {
449 old := ft.limits
450 ft.limits = f.Cache.allocLimitSlice(n)
451 copy(ft.limits, old)
452 f.Cache.freeLimitSlice(old)
453 }
454 }
455 ft.limits[v.ID] = initLimit(v)
456 }
457
458
459
460 func (ft *factsTable) signedMin(v *Value, min int64) bool {
461 return ft.newLimit(v, limit{min: min, max: math.MaxInt64, umin: 0, umax: math.MaxUint64})
462 }
463
464
465
466 func (ft *factsTable) signedMax(v *Value, max int64) bool {
467 return ft.newLimit(v, limit{min: math.MinInt64, max: max, umin: 0, umax: math.MaxUint64})
468 }
469 func (ft *factsTable) signedMinMax(v *Value, min, max int64) bool {
470 return ft.newLimit(v, limit{min: min, max: max, umin: 0, umax: math.MaxUint64})
471 }
472
473
474 func (ft *factsTable) setNonNegative(v *Value) bool {
475 return ft.signedMin(v, 0)
476 }
477
478
479
480 func (ft *factsTable) unsignedMin(v *Value, min uint64) bool {
481 return ft.newLimit(v, limit{min: math.MinInt64, max: math.MaxInt64, umin: min, umax: math.MaxUint64})
482 }
483
484
485
486 func (ft *factsTable) unsignedMax(v *Value, max uint64) bool {
487 return ft.newLimit(v, limit{min: math.MinInt64, max: math.MaxInt64, umin: 0, umax: max})
488 }
489 func (ft *factsTable) unsignedMinMax(v *Value, min, max uint64) bool {
490 return ft.newLimit(v, limit{min: math.MinInt64, max: math.MaxInt64, umin: min, umax: max})
491 }
492
493 func (ft *factsTable) booleanFalse(v *Value) bool {
494 return ft.newLimit(v, limit{min: 0, max: 0, umin: 0, umax: 0})
495 }
496 func (ft *factsTable) booleanTrue(v *Value) bool {
497 return ft.newLimit(v, limit{min: 1, max: 1, umin: 1, umax: 1})
498 }
499 func (ft *factsTable) pointerNil(v *Value) bool {
500 return ft.newLimit(v, limit{min: 0, max: 0, umin: 0, umax: 0})
501 }
502 func (ft *factsTable) pointerNonNil(v *Value) bool {
503 l := noLimit
504 l.umin = 1
505 return ft.newLimit(v, l)
506 }
507
508
509
510 func (ft *factsTable) newLimit(v *Value, newLim limit) bool {
511 oldLim := ft.limits[v.ID]
512
513
514 lim := oldLim.intersect(newLim)
515
516
517 if lim.min >= 0 {
518 lim = lim.unsignedMinMax(uint64(lim.min), uint64(lim.max))
519 }
520 if fitsInBitsU(lim.umax, uint(8*v.Type.Size()-1)) {
521 lim = lim.signedMinMax(int64(lim.umin), int64(lim.umax))
522 }
523
524 if lim == oldLim {
525 return false
526 }
527
528 if lim.unsat() {
529 r := !ft.unsat
530 ft.unsat = true
531 return r
532 }
533
534
535
536
537
538
539
540 if ft.recurseCheck[v.ID] {
541
542 return false
543 }
544 ft.recurseCheck[v.ID] = true
545 defer func() {
546 ft.recurseCheck[v.ID] = false
547 }()
548
549
550 ft.limitStack = append(ft.limitStack, limitFact{v.ID, oldLim})
551
552 ft.limits[v.ID] = lim
553 if v.Block.Func.pass.debug > 2 {
554
555
556
557 v.Block.Func.Warnl(v.Pos, "new limit %s %s unsat=%v", v, lim.String(), ft.unsat)
558 }
559
560
561
562
563
564 for o := ft.orderings[v.ID]; o != nil; o = o.next {
565 switch o.d {
566 case signed:
567 switch o.r {
568 case eq:
569 ft.signedMinMax(o.w, lim.min, lim.max)
570 case lt | eq:
571 ft.signedMin(o.w, lim.min)
572 case lt:
573 ft.signedMin(o.w, lim.min+1)
574 case gt | eq:
575 ft.signedMax(o.w, lim.max)
576 case gt:
577 ft.signedMax(o.w, lim.max-1)
578 case lt | gt:
579 if lim.min == lim.max {
580 c := lim.min
581 if ft.limits[o.w.ID].min == c {
582 ft.signedMin(o.w, c+1)
583 }
584 if ft.limits[o.w.ID].max == c {
585 ft.signedMax(o.w, c-1)
586 }
587 }
588 }
589 case unsigned:
590 switch o.r {
591 case eq:
592 ft.unsignedMinMax(o.w, lim.umin, lim.umax)
593 case lt | eq:
594 ft.unsignedMin(o.w, lim.umin)
595 case lt:
596 ft.unsignedMin(o.w, lim.umin+1)
597 case gt | eq:
598 ft.unsignedMax(o.w, lim.umax)
599 case gt:
600 ft.unsignedMax(o.w, lim.umax-1)
601 case lt | gt:
602 if lim.umin == lim.umax {
603 c := lim.umin
604 if ft.limits[o.w.ID].umin == c {
605 ft.unsignedMin(o.w, c+1)
606 }
607 if ft.limits[o.w.ID].umax == c {
608 ft.unsignedMax(o.w, c-1)
609 }
610 }
611 }
612 case boolean:
613 switch o.r {
614 case eq:
615 if lim.min == 0 && lim.max == 0 {
616 ft.booleanFalse(o.w)
617 }
618 if lim.min == 1 && lim.max == 1 {
619 ft.booleanTrue(o.w)
620 }
621 case lt | gt:
622 if lim.min == 0 && lim.max == 0 {
623 ft.booleanTrue(o.w)
624 }
625 if lim.min == 1 && lim.max == 1 {
626 ft.booleanFalse(o.w)
627 }
628 }
629 case pointer:
630 switch o.r {
631 case eq:
632 if lim.umax == 0 {
633 ft.pointerNil(o.w)
634 }
635 if lim.umin > 0 {
636 ft.pointerNonNil(o.w)
637 }
638 case lt | gt:
639 if lim.umax == 0 {
640 ft.pointerNonNil(o.w)
641 }
642
643 }
644 }
645 }
646
647
648
649
650 if v.Type.IsBoolean() {
651
652
653
654 if lim.min != lim.max {
655 v.Block.Func.Fatalf("boolean not constant %v", v)
656 }
657 isTrue := lim.min == 1
658 if dr, ok := domainRelationTable[v.Op]; ok && v.Op != OpIsInBounds && v.Op != OpIsSliceInBounds {
659 d := dr.d
660 r := dr.r
661 if d == signed && ft.isNonNegative(v.Args[0]) && ft.isNonNegative(v.Args[1]) {
662 d |= unsigned
663 }
664 if !isTrue {
665 r ^= lt | gt | eq
666 }
667
668 addRestrictions(v.Block, ft, d, v.Args[0], v.Args[1], r)
669 }
670 switch v.Op {
671 case OpIsNonNil:
672 if isTrue {
673 ft.pointerNonNil(v.Args[0])
674 } else {
675 ft.pointerNil(v.Args[0])
676 }
677 case OpIsInBounds, OpIsSliceInBounds:
678
679 r := lt
680 if v.Op == OpIsSliceInBounds {
681 r |= eq
682 }
683 if isTrue {
684
685
686
687 ft.setNonNegative(v.Args[0])
688 ft.update(v.Block, v.Args[0], v.Args[1], signed, r)
689 ft.update(v.Block, v.Args[0], v.Args[1], unsigned, r)
690 } else {
691
692
693
694
695
696
697
698 r ^= lt | gt | eq
699 if ft.isNonNegative(v.Args[0]) {
700 ft.update(v.Block, v.Args[0], v.Args[1], signed, r)
701 }
702 ft.update(v.Block, v.Args[0], v.Args[1], unsigned, r)
703
704 }
705 }
706 }
707
708 return true
709 }
710
711 func (ft *factsTable) addOrdering(v, w *Value, d domain, r relation) {
712 o := ft.orderingCache
713 if o == nil {
714 o = &ordering{}
715 } else {
716 ft.orderingCache = o.next
717 }
718 o.w = w
719 o.d = d
720 o.r = r
721 o.next = ft.orderings[v.ID]
722 ft.orderings[v.ID] = o
723 ft.orderingsStack = append(ft.orderingsStack, v.ID)
724 }
725
726
727
728 func (ft *factsTable) update(parent *Block, v, w *Value, d domain, r relation) {
729 if parent.Func.pass.debug > 2 {
730 parent.Func.Warnl(parent.Pos, "parent=%s, update %s %s %s", parent, v, w, r)
731 }
732
733 if ft.unsat {
734 return
735 }
736
737
738
739 if v == w {
740 if r&eq == 0 {
741 ft.unsat = true
742 }
743 return
744 }
745
746 if d == signed || d == unsigned {
747 var ok bool
748 order := ft.orderS
749 if d == unsigned {
750 order = ft.orderU
751 }
752 switch r {
753 case lt:
754 ok = order.SetOrder(v, w)
755 case gt:
756 ok = order.SetOrder(w, v)
757 case lt | eq:
758 ok = order.SetOrderOrEqual(v, w)
759 case gt | eq:
760 ok = order.SetOrderOrEqual(w, v)
761 case eq:
762 ok = order.SetEqual(v, w)
763 case lt | gt:
764 ok = order.SetNonEqual(v, w)
765 default:
766 panic("unknown relation")
767 }
768 ft.addOrdering(v, w, d, r)
769 ft.addOrdering(w, v, d, reverseBits[r])
770
771 if !ok {
772 if parent.Func.pass.debug > 2 {
773 parent.Func.Warnl(parent.Pos, "unsat %s %s %s", v, w, r)
774 }
775 ft.unsat = true
776 return
777 }
778 }
779 if d == boolean || d == pointer {
780 for o := ft.orderings[v.ID]; o != nil; o = o.next {
781 if o.d == d && o.w == w {
782
783
784
785 if o.r != r {
786 ft.unsat = true
787 }
788 return
789 }
790 }
791
792
793 ft.addOrdering(v, w, d, r)
794 ft.addOrdering(w, v, d, r)
795 }
796
797
798 vLimit := ft.limits[v.ID]
799 wLimit := ft.limits[w.ID]
800
801
802
803
804
805 switch d {
806 case signed:
807 switch r {
808 case eq:
809 ft.signedMinMax(v, wLimit.min, wLimit.max)
810 ft.signedMinMax(w, vLimit.min, vLimit.max)
811 case lt:
812 ft.signedMax(v, wLimit.max-1)
813 ft.signedMin(w, vLimit.min+1)
814 case lt | eq:
815 ft.signedMax(v, wLimit.max)
816 ft.signedMin(w, vLimit.min)
817 case gt:
818 ft.signedMin(v, wLimit.min+1)
819 ft.signedMax(w, vLimit.max-1)
820 case gt | eq:
821 ft.signedMin(v, wLimit.min)
822 ft.signedMax(w, vLimit.max)
823 case lt | gt:
824 if vLimit.min == vLimit.max {
825 c := vLimit.min
826 if wLimit.min == c {
827 ft.signedMin(w, c+1)
828 }
829 if wLimit.max == c {
830 ft.signedMax(w, c-1)
831 }
832 }
833 if wLimit.min == wLimit.max {
834 c := wLimit.min
835 if vLimit.min == c {
836 ft.signedMin(v, c+1)
837 }
838 if vLimit.max == c {
839 ft.signedMax(v, c-1)
840 }
841 }
842 }
843 case unsigned:
844 switch r {
845 case eq:
846 ft.unsignedMinMax(v, wLimit.umin, wLimit.umax)
847 ft.unsignedMinMax(w, vLimit.umin, vLimit.umax)
848 case lt:
849 ft.unsignedMax(v, wLimit.umax-1)
850 ft.unsignedMin(w, vLimit.umin+1)
851 case lt | eq:
852 ft.unsignedMax(v, wLimit.umax)
853 ft.unsignedMin(w, vLimit.umin)
854 case gt:
855 ft.unsignedMin(v, wLimit.umin+1)
856 ft.unsignedMax(w, vLimit.umax-1)
857 case gt | eq:
858 ft.unsignedMin(v, wLimit.umin)
859 ft.unsignedMax(w, vLimit.umax)
860 case lt | gt:
861 if vLimit.umin == vLimit.umax {
862 c := vLimit.umin
863 if wLimit.umin == c {
864 ft.unsignedMin(w, c+1)
865 }
866 if wLimit.umax == c {
867 ft.unsignedMax(w, c-1)
868 }
869 }
870 if wLimit.umin == wLimit.umax {
871 c := wLimit.umin
872 if vLimit.umin == c {
873 ft.unsignedMin(v, c+1)
874 }
875 if vLimit.umax == c {
876 ft.unsignedMax(v, c-1)
877 }
878 }
879 }
880 case boolean:
881 switch r {
882 case eq:
883 if vLimit.min == 1 {
884 ft.booleanTrue(w)
885 }
886 if vLimit.max == 0 {
887 ft.booleanFalse(w)
888 }
889 if wLimit.min == 1 {
890 ft.booleanTrue(v)
891 }
892 if wLimit.max == 0 {
893 ft.booleanFalse(v)
894 }
895 case lt | gt:
896 if vLimit.min == 1 {
897 ft.booleanFalse(w)
898 }
899 if vLimit.max == 0 {
900 ft.booleanTrue(w)
901 }
902 if wLimit.min == 1 {
903 ft.booleanFalse(v)
904 }
905 if wLimit.max == 0 {
906 ft.booleanTrue(v)
907 }
908 }
909 case pointer:
910 switch r {
911 case eq:
912 if vLimit.umax == 0 {
913 ft.pointerNil(w)
914 }
915 if vLimit.umin > 0 {
916 ft.pointerNonNil(w)
917 }
918 if wLimit.umax == 0 {
919 ft.pointerNil(v)
920 }
921 if wLimit.umin > 0 {
922 ft.pointerNonNil(v)
923 }
924 case lt | gt:
925 if vLimit.umax == 0 {
926 ft.pointerNonNil(w)
927 }
928 if wLimit.umax == 0 {
929 ft.pointerNonNil(v)
930 }
931
932
933
934 }
935 }
936
937
938 if d != signed && d != unsigned {
939 return
940 }
941
942
943
944
945
946
947 if v.Op == OpSliceLen && r< == 0 && ft.caps[v.Args[0].ID] != nil {
948
949
950
951 ft.update(parent, ft.caps[v.Args[0].ID], w, d, r|gt)
952 }
953 if w.Op == OpSliceLen && r> == 0 && ft.caps[w.Args[0].ID] != nil {
954
955 ft.update(parent, v, ft.caps[w.Args[0].ID], d, r|lt)
956 }
957 if v.Op == OpSliceCap && r> == 0 && ft.lens[v.Args[0].ID] != nil {
958
959
960
961 ft.update(parent, ft.lens[v.Args[0].ID], w, d, r|lt)
962 }
963 if w.Op == OpSliceCap && r< == 0 && ft.lens[w.Args[0].ID] != nil {
964
965 ft.update(parent, v, ft.lens[w.Args[0].ID], d, r|gt)
966 }
967
968
969
970
971 if r == lt || r == lt|eq {
972 v, w = w, v
973 r = reverseBits[r]
974 }
975 switch r {
976 case gt:
977 if x, delta := isConstDelta(v); x != nil && delta == 1 {
978
979
980
981
982 ft.update(parent, x, w, d, gt|eq)
983 } else if x, delta := isConstDelta(w); x != nil && delta == -1 {
984
985 ft.update(parent, v, x, d, gt|eq)
986 }
987 case gt | eq:
988 if x, delta := isConstDelta(v); x != nil && delta == -1 {
989
990
991
992 lim := ft.limits[x.ID]
993 if (d == signed && lim.min > opMin[v.Op]) || (d == unsigned && lim.umin > 0) {
994 ft.update(parent, x, w, d, gt)
995 }
996 } else if x, delta := isConstDelta(w); x != nil && delta == 1 {
997
998 lim := ft.limits[x.ID]
999 if (d == signed && lim.max < opMax[w.Op]) || (d == unsigned && lim.umax < opUMax[w.Op]) {
1000 ft.update(parent, v, x, d, gt)
1001 }
1002 }
1003 }
1004
1005
1006
1007 if r == gt || r == gt|eq {
1008 if x, delta := isConstDelta(v); x != nil && d == signed {
1009 if parent.Func.pass.debug > 1 {
1010 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)
1011 }
1012 underflow := true
1013 if delta < 0 {
1014 l := ft.limits[x.ID]
1015 if (x.Type.Size() == 8 && l.min >= math.MinInt64-delta) ||
1016 (x.Type.Size() == 4 && l.min >= math.MinInt32-delta) {
1017 underflow = false
1018 }
1019 }
1020 if delta < 0 && !underflow {
1021
1022 ft.update(parent, x, v, signed, gt)
1023 }
1024 if !w.isGenericIntConst() {
1025
1026
1027
1028 if delta < 0 && !underflow {
1029 ft.update(parent, x, w, signed, r)
1030 }
1031 } else {
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049 var min, max int64
1050 switch x.Type.Size() {
1051 case 8:
1052 min = w.AuxInt - delta
1053 max = int64(^uint64(0)>>1) - delta
1054 case 4:
1055 min = int64(int32(w.AuxInt) - int32(delta))
1056 max = int64(int32(^uint32(0)>>1) - int32(delta))
1057 case 2:
1058 min = int64(int16(w.AuxInt) - int16(delta))
1059 max = int64(int16(^uint16(0)>>1) - int16(delta))
1060 case 1:
1061 min = int64(int8(w.AuxInt) - int8(delta))
1062 max = int64(int8(^uint8(0)>>1) - int8(delta))
1063 default:
1064 panic("unimplemented")
1065 }
1066
1067 if min < max {
1068
1069 if r == gt {
1070 min++
1071 }
1072 ft.signedMinMax(x, min, max)
1073 } else {
1074
1075
1076
1077 l := ft.limits[x.ID]
1078 if l.max <= min {
1079 if r&eq == 0 || l.max < min {
1080
1081 ft.signedMax(x, max)
1082 }
1083 } else if l.min > max {
1084
1085 if r == gt {
1086 min++
1087 }
1088 ft.signedMin(x, min)
1089 }
1090 }
1091 }
1092 }
1093 }
1094
1095
1096
1097
1098 if isCleanExt(v) {
1099 switch {
1100 case d == signed && v.Args[0].Type.IsSigned():
1101 fallthrough
1102 case d == unsigned && !v.Args[0].Type.IsSigned():
1103 ft.update(parent, v.Args[0], w, d, r)
1104 }
1105 }
1106 if isCleanExt(w) {
1107 switch {
1108 case d == signed && w.Args[0].Type.IsSigned():
1109 fallthrough
1110 case d == unsigned && !w.Args[0].Type.IsSigned():
1111 ft.update(parent, v, w.Args[0], d, r)
1112 }
1113 }
1114 }
1115
1116 var opMin = map[Op]int64{
1117 OpAdd64: math.MinInt64, OpSub64: math.MinInt64,
1118 OpAdd32: math.MinInt32, OpSub32: math.MinInt32,
1119 }
1120
1121 var opMax = map[Op]int64{
1122 OpAdd64: math.MaxInt64, OpSub64: math.MaxInt64,
1123 OpAdd32: math.MaxInt32, OpSub32: math.MaxInt32,
1124 }
1125
1126 var opUMax = map[Op]uint64{
1127 OpAdd64: math.MaxUint64, OpSub64: math.MaxUint64,
1128 OpAdd32: math.MaxUint32, OpSub32: math.MaxUint32,
1129 }
1130
1131
1132 func (ft *factsTable) isNonNegative(v *Value) bool {
1133 return ft.limits[v.ID].min >= 0
1134 }
1135
1136
1137
1138 func (ft *factsTable) checkpoint() {
1139 if ft.unsat {
1140 ft.unsatDepth++
1141 }
1142 ft.limitStack = append(ft.limitStack, checkpointBound)
1143 ft.orderS.Checkpoint()
1144 ft.orderU.Checkpoint()
1145 ft.orderingsStack = append(ft.orderingsStack, 0)
1146 }
1147
1148
1149
1150
1151 func (ft *factsTable) restore() {
1152 if ft.unsatDepth > 0 {
1153 ft.unsatDepth--
1154 } else {
1155 ft.unsat = false
1156 }
1157 for {
1158 old := ft.limitStack[len(ft.limitStack)-1]
1159 ft.limitStack = ft.limitStack[:len(ft.limitStack)-1]
1160 if old.vid == 0 {
1161 break
1162 }
1163 ft.limits[old.vid] = old.limit
1164 }
1165 ft.orderS.Undo()
1166 ft.orderU.Undo()
1167 for {
1168 id := ft.orderingsStack[len(ft.orderingsStack)-1]
1169 ft.orderingsStack = ft.orderingsStack[:len(ft.orderingsStack)-1]
1170 if id == 0 {
1171 break
1172 }
1173 o := ft.orderings[id]
1174 ft.orderings[id] = o.next
1175 o.next = ft.orderingCache
1176 ft.orderingCache = o
1177 }
1178 }
1179
1180 var (
1181 reverseBits = [...]relation{0, 4, 2, 6, 1, 5, 3, 7}
1182
1183
1184
1185
1186
1187
1188
1189 domainRelationTable = map[Op]struct {
1190 d domain
1191 r relation
1192 }{
1193 OpEq8: {signed | unsigned, eq},
1194 OpEq16: {signed | unsigned, eq},
1195 OpEq32: {signed | unsigned, eq},
1196 OpEq64: {signed | unsigned, eq},
1197 OpEqPtr: {pointer, eq},
1198 OpEqB: {boolean, eq},
1199
1200 OpNeq8: {signed | unsigned, lt | gt},
1201 OpNeq16: {signed | unsigned, lt | gt},
1202 OpNeq32: {signed | unsigned, lt | gt},
1203 OpNeq64: {signed | unsigned, lt | gt},
1204 OpNeqPtr: {pointer, lt | gt},
1205 OpNeqB: {boolean, lt | gt},
1206
1207 OpLess8: {signed, lt},
1208 OpLess8U: {unsigned, lt},
1209 OpLess16: {signed, lt},
1210 OpLess16U: {unsigned, lt},
1211 OpLess32: {signed, lt},
1212 OpLess32U: {unsigned, lt},
1213 OpLess64: {signed, lt},
1214 OpLess64U: {unsigned, lt},
1215
1216 OpLeq8: {signed, lt | eq},
1217 OpLeq8U: {unsigned, lt | eq},
1218 OpLeq16: {signed, lt | eq},
1219 OpLeq16U: {unsigned, lt | eq},
1220 OpLeq32: {signed, lt | eq},
1221 OpLeq32U: {unsigned, lt | eq},
1222 OpLeq64: {signed, lt | eq},
1223 OpLeq64U: {unsigned, lt | eq},
1224 }
1225 )
1226
1227
1228 func (ft *factsTable) cleanup(f *Func) {
1229 for _, po := range []*poset{ft.orderS, ft.orderU} {
1230
1231
1232 if checkEnabled {
1233 if err := po.CheckEmpty(); err != nil {
1234 f.Fatalf("poset not empty after function %s: %v", f.Name, err)
1235 }
1236 }
1237 f.retPoset(po)
1238 }
1239 f.Cache.freeLimitSlice(ft.limits)
1240 f.Cache.freeBoolSlice(ft.recurseCheck)
1241 }
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274 func prove(f *Func) {
1275
1276
1277 var indVars map[*Block]indVar
1278 for _, v := range findIndVar(f) {
1279 ind := v.ind
1280 if len(ind.Args) != 2 {
1281
1282 panic("unexpected induction with too many parents")
1283 }
1284
1285 nxt := v.nxt
1286 if !(ind.Uses == 2 &&
1287 nxt.Uses == 1) {
1288
1289 if indVars == nil {
1290 indVars = make(map[*Block]indVar)
1291 }
1292 indVars[v.entry] = v
1293 continue
1294 } else {
1295
1296
1297 }
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335 start, end := v.min, v.max
1336 if v.flags&indVarCountDown != 0 {
1337 start, end = end, start
1338 }
1339
1340 if !start.isGenericIntConst() {
1341
1342 continue
1343 }
1344 if end.isGenericIntConst() {
1345
1346
1347
1348
1349
1350
1351 continue
1352 }
1353
1354 if end.Block == ind.Block {
1355
1356
1357 continue
1358 }
1359
1360 check := ind.Block.Controls[0]
1361
1362 check.Args[0], check.Args[1] = check.Args[1], check.Args[0]
1363
1364
1365 for i, v := range check.Args {
1366 if v != end {
1367 continue
1368 }
1369
1370 check.SetArg(i, start)
1371 goto replacedEnd
1372 }
1373 panic(fmt.Sprintf("unreachable, ind: %v, start: %v, end: %v", ind, start, end))
1374 replacedEnd:
1375
1376 for i, v := range ind.Args {
1377 if v != start {
1378 continue
1379 }
1380
1381 ind.SetArg(i, end)
1382 goto replacedStart
1383 }
1384 panic(fmt.Sprintf("unreachable, ind: %v, start: %v, end: %v", ind, start, end))
1385 replacedStart:
1386
1387 if nxt.Args[0] != ind {
1388
1389 nxt.Args[0], nxt.Args[1] = nxt.Args[1], nxt.Args[0]
1390 }
1391
1392 switch nxt.Op {
1393 case OpAdd8:
1394 nxt.Op = OpSub8
1395 case OpAdd16:
1396 nxt.Op = OpSub16
1397 case OpAdd32:
1398 nxt.Op = OpSub32
1399 case OpAdd64:
1400 nxt.Op = OpSub64
1401 case OpSub8:
1402 nxt.Op = OpAdd8
1403 case OpSub16:
1404 nxt.Op = OpAdd16
1405 case OpSub32:
1406 nxt.Op = OpAdd32
1407 case OpSub64:
1408 nxt.Op = OpAdd64
1409 default:
1410 panic("unreachable")
1411 }
1412
1413 if f.pass.debug > 0 {
1414 f.Warnl(ind.Pos, "Inverted loop iteration")
1415 }
1416 }
1417
1418 ft := newFactsTable(f)
1419 ft.checkpoint()
1420
1421
1422 for _, b := range f.Blocks {
1423 for _, v := range b.Values {
1424 if v.Uses == 0 {
1425
1426
1427 continue
1428 }
1429 switch v.Op {
1430 case OpSliceLen:
1431 if ft.lens == nil {
1432 ft.lens = map[ID]*Value{}
1433 }
1434
1435
1436
1437 if l, ok := ft.lens[v.Args[0].ID]; ok {
1438 ft.update(b, v, l, signed, eq)
1439 } else {
1440 ft.lens[v.Args[0].ID] = v
1441 }
1442 case OpSliceCap:
1443 if ft.caps == nil {
1444 ft.caps = map[ID]*Value{}
1445 }
1446
1447 if c, ok := ft.caps[v.Args[0].ID]; ok {
1448 ft.update(b, v, c, signed, eq)
1449 } else {
1450 ft.caps[v.Args[0].ID] = v
1451 }
1452 }
1453 }
1454 }
1455
1456
1457 type walkState int
1458 const (
1459 descend walkState = iota
1460 simplify
1461 )
1462
1463 type bp struct {
1464 block *Block
1465 state walkState
1466 }
1467 work := make([]bp, 0, 256)
1468 work = append(work, bp{
1469 block: f.Entry,
1470 state: descend,
1471 })
1472
1473 idom := f.Idom()
1474 sdom := f.Sdom()
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486 for len(work) > 0 {
1487 node := work[len(work)-1]
1488 work = work[:len(work)-1]
1489 parent := idom[node.block.ID]
1490 branch := getBranch(sdom, parent, node.block)
1491
1492 switch node.state {
1493 case descend:
1494 ft.checkpoint()
1495
1496
1497
1498 if iv, ok := indVars[node.block]; ok {
1499 addIndVarRestrictions(ft, parent, iv)
1500 }
1501
1502
1503
1504 if branch != unknown {
1505 addBranchRestrictions(ft, parent, branch)
1506 }
1507
1508 if ft.unsat {
1509
1510
1511
1512 removeBranch(parent, branch)
1513 ft.restore()
1514 break
1515 }
1516
1517
1518
1519
1520
1521 addLocalFacts(ft, node.block)
1522
1523 work = append(work, bp{
1524 block: node.block,
1525 state: simplify,
1526 })
1527 for s := sdom.Child(node.block); s != nil; s = sdom.Sibling(s) {
1528 work = append(work, bp{
1529 block: s,
1530 state: descend,
1531 })
1532 }
1533
1534 case simplify:
1535 simplifyBlock(sdom, ft, node.block)
1536 ft.restore()
1537 }
1538 }
1539
1540 ft.restore()
1541
1542 ft.cleanup(f)
1543 }
1544
1545
1546
1547
1548
1549
1550
1551 func initLimit(v *Value) limit {
1552 if v.Type.IsBoolean() {
1553 switch v.Op {
1554 case OpConstBool:
1555 b := v.AuxInt
1556 return limit{min: b, max: b, umin: uint64(b), umax: uint64(b)}
1557 default:
1558 return limit{min: 0, max: 1, umin: 0, umax: 1}
1559 }
1560 }
1561 if v.Type.IsPtrShaped() {
1562 switch v.Op {
1563 case OpConstNil:
1564 return limit{min: 0, max: 0, umin: 0, umax: 0}
1565 case OpAddr, OpLocalAddr:
1566 l := noLimit
1567 l.umin = 1
1568 return l
1569 default:
1570 return noLimit
1571 }
1572 }
1573 if !v.Type.IsInteger() {
1574 return noLimit
1575 }
1576
1577
1578 bitsize := v.Type.Size() * 8
1579 lim := limit{min: -(1 << (bitsize - 1)), max: 1<<(bitsize-1) - 1, umin: 0, umax: 1<<bitsize - 1}
1580
1581
1582 switch v.Op {
1583
1584 case OpConst64:
1585 lim = limit{min: v.AuxInt, max: v.AuxInt, umin: uint64(v.AuxInt), umax: uint64(v.AuxInt)}
1586 case OpConst32:
1587 lim = limit{min: v.AuxInt, max: v.AuxInt, umin: uint64(uint32(v.AuxInt)), umax: uint64(uint32(v.AuxInt))}
1588 case OpConst16:
1589 lim = limit{min: v.AuxInt, max: v.AuxInt, umin: uint64(uint16(v.AuxInt)), umax: uint64(uint16(v.AuxInt))}
1590 case OpConst8:
1591 lim = limit{min: v.AuxInt, max: v.AuxInt, umin: uint64(uint8(v.AuxInt)), umax: uint64(uint8(v.AuxInt))}
1592
1593
1594 case OpZeroExt8to64, OpZeroExt8to32, OpZeroExt8to16:
1595 lim = lim.signedMinMax(0, 1<<8-1)
1596 lim = lim.unsignedMax(1<<8 - 1)
1597 case OpZeroExt16to64, OpZeroExt16to32:
1598 lim = lim.signedMinMax(0, 1<<16-1)
1599 lim = lim.unsignedMax(1<<16 - 1)
1600 case OpZeroExt32to64:
1601 lim = lim.signedMinMax(0, 1<<32-1)
1602 lim = lim.unsignedMax(1<<32 - 1)
1603 case OpSignExt8to64, OpSignExt8to32, OpSignExt8to16:
1604 lim = lim.signedMinMax(math.MinInt8, math.MaxInt8)
1605 case OpSignExt16to64, OpSignExt16to32:
1606 lim = lim.signedMinMax(math.MinInt16, math.MaxInt16)
1607 case OpSignExt32to64:
1608 lim = lim.signedMinMax(math.MinInt32, math.MaxInt32)
1609
1610
1611 case OpCtz64, OpBitLen64, OpPopCount64,
1612 OpCtz32, OpBitLen32, OpPopCount32,
1613 OpCtz16, OpBitLen16, OpPopCount16,
1614 OpCtz8, OpBitLen8, OpPopCount8:
1615 lim = lim.unsignedMax(uint64(v.Args[0].Type.Size() * 8))
1616
1617
1618 case OpCvtBoolToUint8:
1619 lim = lim.unsignedMax(1)
1620
1621
1622 case OpSliceLen, OpSliceCap:
1623 f := v.Block.Func
1624 elemSize := uint64(v.Args[0].Type.Elem().Size())
1625 if elemSize > 0 {
1626 heapSize := uint64(1)<<(uint64(f.Config.PtrSize)*8) - 1
1627 maximumElementsFittingInHeap := heapSize / elemSize
1628 lim = lim.unsignedMax(maximumElementsFittingInHeap)
1629 }
1630 fallthrough
1631 case OpStringLen:
1632 lim = lim.signedMin(0)
1633 }
1634
1635
1636 if lim.min >= 0 {
1637 lim = lim.unsignedMinMax(uint64(lim.min), uint64(lim.max))
1638 }
1639 if fitsInBitsU(lim.umax, uint(8*v.Type.Size()-1)) {
1640 lim = lim.signedMinMax(int64(lim.umin), int64(lim.umax))
1641 }
1642
1643 return lim
1644 }
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659 func (ft *factsTable) flowLimit(v *Value) bool {
1660 if !v.Type.IsInteger() {
1661
1662 return false
1663 }
1664
1665
1666
1667 switch v.Op {
1668
1669
1670 case OpZeroExt8to64, OpZeroExt8to32, OpZeroExt8to16, OpZeroExt16to64, OpZeroExt16to32, OpZeroExt32to64:
1671 a := ft.limits[v.Args[0].ID]
1672 return ft.unsignedMinMax(v, a.umin, a.umax)
1673 case OpSignExt8to64, OpSignExt8to32, OpSignExt8to16, OpSignExt16to64, OpSignExt16to32, OpSignExt32to64:
1674 a := ft.limits[v.Args[0].ID]
1675 return ft.signedMinMax(v, a.min, a.max)
1676 case OpTrunc64to8, OpTrunc64to16, OpTrunc64to32, OpTrunc32to8, OpTrunc32to16, OpTrunc16to8:
1677 a := ft.limits[v.Args[0].ID]
1678 if a.umax <= 1<<(uint64(v.Type.Size())*8)-1 {
1679 return ft.unsignedMinMax(v, a.umin, a.umax)
1680 }
1681
1682
1683 case OpCtz64:
1684 a := ft.limits[v.Args[0].ID]
1685 if a.nonzero() {
1686 return ft.unsignedMax(v, uint64(bits.Len64(a.umax)-1))
1687 }
1688 case OpCtz32:
1689 a := ft.limits[v.Args[0].ID]
1690 if a.nonzero() {
1691 return ft.unsignedMax(v, uint64(bits.Len32(uint32(a.umax))-1))
1692 }
1693 case OpCtz16:
1694 a := ft.limits[v.Args[0].ID]
1695 if a.nonzero() {
1696 return ft.unsignedMax(v, uint64(bits.Len16(uint16(a.umax))-1))
1697 }
1698 case OpCtz8:
1699 a := ft.limits[v.Args[0].ID]
1700 if a.nonzero() {
1701 return ft.unsignedMax(v, uint64(bits.Len8(uint8(a.umax))-1))
1702 }
1703
1704 case OpPopCount64, OpPopCount32, OpPopCount16, OpPopCount8:
1705 a := ft.limits[v.Args[0].ID]
1706 changingBitsCount := uint64(bits.Len64(a.umax ^ a.umin))
1707 sharedLeadingMask := ^(uint64(1)<<changingBitsCount - 1)
1708 fixedBits := a.umax & sharedLeadingMask
1709 min := uint64(bits.OnesCount64(fixedBits))
1710 return ft.unsignedMinMax(v, min, min+changingBitsCount)
1711
1712 case OpBitLen64:
1713 a := ft.limits[v.Args[0].ID]
1714 return ft.unsignedMinMax(v,
1715 uint64(bits.Len64(a.umin)),
1716 uint64(bits.Len64(a.umax)))
1717 case OpBitLen32:
1718 a := ft.limits[v.Args[0].ID]
1719 return ft.unsignedMinMax(v,
1720 uint64(bits.Len32(uint32(a.umin))),
1721 uint64(bits.Len32(uint32(a.umax))))
1722 case OpBitLen16:
1723 a := ft.limits[v.Args[0].ID]
1724 return ft.unsignedMinMax(v,
1725 uint64(bits.Len16(uint16(a.umin))),
1726 uint64(bits.Len16(uint16(a.umax))))
1727 case OpBitLen8:
1728 a := ft.limits[v.Args[0].ID]
1729 return ft.unsignedMinMax(v,
1730 uint64(bits.Len8(uint8(a.umin))),
1731 uint64(bits.Len8(uint8(a.umax))))
1732
1733
1734
1735
1736
1737
1738 case OpAnd64, OpAnd32, OpAnd16, OpAnd8:
1739
1740 a := ft.limits[v.Args[0].ID]
1741 b := ft.limits[v.Args[1].ID]
1742 return ft.unsignedMax(v, min(a.umax, b.umax))
1743 case OpOr64, OpOr32, OpOr16, OpOr8:
1744
1745 a := ft.limits[v.Args[0].ID]
1746 b := ft.limits[v.Args[1].ID]
1747 return ft.unsignedMinMax(v,
1748 max(a.umin, b.umin),
1749 1<<bits.Len64(a.umax|b.umax)-1)
1750 case OpXor64, OpXor32, OpXor16, OpXor8:
1751
1752 a := ft.limits[v.Args[0].ID]
1753 b := ft.limits[v.Args[1].ID]
1754 return ft.unsignedMax(v, 1<<bits.Len64(a.umax|b.umax)-1)
1755 case OpCom64, OpCom32, OpCom16, OpCom8:
1756 a := ft.limits[v.Args[0].ID]
1757 return ft.newLimit(v, a.com(uint(v.Type.Size())*8))
1758
1759
1760 case OpAdd64, OpAdd32, OpAdd16, OpAdd8:
1761 a := ft.limits[v.Args[0].ID]
1762 b := ft.limits[v.Args[1].ID]
1763 return ft.newLimit(v, a.add(b, uint(v.Type.Size())*8))
1764 case OpSub64, OpSub32, OpSub16, OpSub8:
1765 a := ft.limits[v.Args[0].ID]
1766 b := ft.limits[v.Args[1].ID]
1767 sub := ft.newLimit(v, a.sub(b, uint(v.Type.Size())*8))
1768 mod := ft.detectSignedMod(v)
1769 inferred := ft.detectSliceLenRelation(v)
1770 return sub || mod || inferred
1771 case OpNeg64, OpNeg32, OpNeg16, OpNeg8:
1772 a := ft.limits[v.Args[0].ID]
1773 bitsize := uint(v.Type.Size()) * 8
1774 return ft.newLimit(v, a.com(bitsize).add(limit{min: 1, max: 1, umin: 1, umax: 1}, bitsize))
1775 case OpMul64, OpMul32, OpMul16, OpMul8:
1776 a := ft.limits[v.Args[0].ID]
1777 b := ft.limits[v.Args[1].ID]
1778 return ft.newLimit(v, a.mul(b, uint(v.Type.Size())*8))
1779 case OpLsh64x64, OpLsh64x32, OpLsh64x16, OpLsh64x8,
1780 OpLsh32x64, OpLsh32x32, OpLsh32x16, OpLsh32x8,
1781 OpLsh16x64, OpLsh16x32, OpLsh16x16, OpLsh16x8,
1782 OpLsh8x64, OpLsh8x32, OpLsh8x16, OpLsh8x8:
1783 a := ft.limits[v.Args[0].ID]
1784 b := ft.limits[v.Args[1].ID]
1785 bitsize := uint(v.Type.Size()) * 8
1786 return ft.newLimit(v, a.mul(b.exp2(bitsize), bitsize))
1787 case OpMod64, OpMod32, OpMod16, OpMod8:
1788 a := ft.limits[v.Args[0].ID]
1789 b := ft.limits[v.Args[1].ID]
1790 if !(a.nonnegative() && b.nonnegative()) {
1791
1792 break
1793 }
1794 fallthrough
1795 case OpMod64u, OpMod32u, OpMod16u, OpMod8u:
1796 a := ft.limits[v.Args[0].ID]
1797 b := ft.limits[v.Args[1].ID]
1798
1799 return ft.unsignedMax(v, min(a.umax, b.umax-1))
1800 case OpDiv64, OpDiv32, OpDiv16, OpDiv8:
1801 a := ft.limits[v.Args[0].ID]
1802 b := ft.limits[v.Args[1].ID]
1803 if !(a.nonnegative() && b.nonnegative()) {
1804
1805 break
1806 }
1807 fallthrough
1808 case OpDiv64u, OpDiv32u, OpDiv16u, OpDiv8u:
1809 a := ft.limits[v.Args[0].ID]
1810 b := ft.limits[v.Args[1].ID]
1811 lim := noLimit
1812 if b.umax > 0 {
1813 lim = lim.unsignedMin(a.umin / b.umax)
1814 }
1815 if b.umin > 0 {
1816 lim = lim.unsignedMax(a.umax / b.umin)
1817 }
1818 return ft.newLimit(v, lim)
1819
1820 case OpPhi:
1821 {
1822
1823 b := v.Block
1824 if len(b.Preds) != 2 {
1825 goto notMinNorMax
1826 }
1827
1828
1829
1830
1831
1832
1833
1834
1835 firstBlock, secondBlock := b.Preds[0].b, b.Preds[1].b
1836 if firstBlock.Kind != BlockPlain || secondBlock.Kind != BlockPlain {
1837 goto notMinNorMax
1838 }
1839 if len(firstBlock.Preds) != 1 || len(secondBlock.Preds) != 1 {
1840 goto notMinNorMax
1841 }
1842 conditionBlock := firstBlock.Preds[0].b
1843 if conditionBlock != secondBlock.Preds[0].b {
1844 goto notMinNorMax
1845 }
1846 if conditionBlock.Kind != BlockIf {
1847 goto notMinNorMax
1848 }
1849
1850 less := conditionBlock.Controls[0]
1851 var unsigned bool
1852 switch less.Op {
1853 case OpLess64U, OpLess32U, OpLess16U, OpLess8U,
1854 OpLeq64U, OpLeq32U, OpLeq16U, OpLeq8U:
1855 unsigned = true
1856 case OpLess64, OpLess32, OpLess16, OpLess8,
1857 OpLeq64, OpLeq32, OpLeq16, OpLeq8:
1858 default:
1859 goto notMinNorMax
1860 }
1861 small, big := less.Args[0], less.Args[1]
1862 truev, falsev := v.Args[0], v.Args[1]
1863 if conditionBlock.Succs[0].b == secondBlock {
1864 truev, falsev = falsev, truev
1865 }
1866
1867 bigl, smalll := ft.limits[big.ID], ft.limits[small.ID]
1868 if truev == big {
1869 if falsev == small {
1870
1871 if unsigned {
1872 maximum := max(bigl.umax, smalll.umax)
1873 minimum := max(bigl.umin, smalll.umin)
1874 return ft.unsignedMinMax(v, minimum, maximum)
1875 } else {
1876 maximum := max(bigl.max, smalll.max)
1877 minimum := max(bigl.min, smalll.min)
1878 return ft.signedMinMax(v, minimum, maximum)
1879 }
1880 } else {
1881 goto notMinNorMax
1882 }
1883 } else if truev == small {
1884 if falsev == big {
1885
1886 if unsigned {
1887 maximum := min(bigl.umax, smalll.umax)
1888 minimum := min(bigl.umin, smalll.umin)
1889 return ft.unsignedMinMax(v, minimum, maximum)
1890 } else {
1891 maximum := min(bigl.max, smalll.max)
1892 minimum := min(bigl.min, smalll.min)
1893 return ft.signedMinMax(v, minimum, maximum)
1894 }
1895 } else {
1896 goto notMinNorMax
1897 }
1898 } else {
1899 goto notMinNorMax
1900 }
1901 }
1902 notMinNorMax:
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913 l := ft.limits[v.Args[0].ID]
1914 for _, a := range v.Args[1:] {
1915 l2 := ft.limits[a.ID]
1916 l.min = min(l.min, l2.min)
1917 l.max = max(l.max, l2.max)
1918 l.umin = min(l.umin, l2.umin)
1919 l.umax = max(l.umax, l2.umax)
1920 }
1921 return ft.newLimit(v, l)
1922 }
1923 return false
1924 }
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944 func (ft *factsTable) detectSignedMod(v *Value) bool {
1945 if ft.detectSignedModByPowerOfTwo(v) {
1946 return true
1947 }
1948
1949 return false
1950 }
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962 func (ft *factsTable) detectSliceLenRelation(v *Value) (inferred bool) {
1963 if v.Op != OpSub64 {
1964 return false
1965 }
1966
1967 if !(v.Args[0].Op == OpSliceLen || v.Args[0].Op == OpSliceCap) {
1968 return false
1969 }
1970
1971 slice := v.Args[0].Args[0]
1972 index := v.Args[1]
1973
1974 for o := ft.orderings[index.ID]; o != nil; o = o.next {
1975 if o.d != signed {
1976 continue
1977 }
1978 or := o.r
1979 if or != lt && or != lt|eq {
1980 continue
1981 }
1982 ow := o.w
1983 if ow.Op != OpAdd64 && ow.Op != OpSub64 {
1984 continue
1985 }
1986 var lenOffset *Value
1987 if bound := ow.Args[0]; bound.Op == OpSliceLen && bound.Args[0] == slice {
1988 lenOffset = ow.Args[1]
1989 } else if bound := ow.Args[1]; bound.Op == OpSliceLen && bound.Args[0] == slice {
1990 lenOffset = ow.Args[0]
1991 }
1992 if lenOffset == nil || lenOffset.Op != OpConst64 {
1993 continue
1994 }
1995 K := lenOffset.AuxInt
1996 if ow.Op == OpAdd64 {
1997 K = -K
1998 }
1999 if K < 0 {
2000 continue
2001 }
2002 if or == lt {
2003 K++
2004 }
2005 if K < 0 {
2006 continue
2007 }
2008 inferred = inferred || ft.signedMin(v, K)
2009 }
2010 return inferred
2011 }
2012
2013 func (ft *factsTable) detectSignedModByPowerOfTwo(v *Value) bool {
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027 var w int64
2028 var addOp, andOp, constOp, sshiftOp, ushiftOp Op
2029 switch v.Op {
2030 case OpSub64:
2031 w = 64
2032 addOp = OpAdd64
2033 andOp = OpAnd64
2034 constOp = OpConst64
2035 sshiftOp = OpRsh64x64
2036 ushiftOp = OpRsh64Ux64
2037 case OpSub32:
2038 w = 32
2039 addOp = OpAdd32
2040 andOp = OpAnd32
2041 constOp = OpConst32
2042 sshiftOp = OpRsh32x64
2043 ushiftOp = OpRsh32Ux64
2044 case OpSub16:
2045 w = 16
2046 addOp = OpAdd16
2047 andOp = OpAnd16
2048 constOp = OpConst16
2049 sshiftOp = OpRsh16x64
2050 ushiftOp = OpRsh16Ux64
2051 case OpSub8:
2052 w = 8
2053 addOp = OpAdd8
2054 andOp = OpAnd8
2055 constOp = OpConst8
2056 sshiftOp = OpRsh8x64
2057 ushiftOp = OpRsh8Ux64
2058 default:
2059 return false
2060 }
2061
2062 x := v.Args[0]
2063 and := v.Args[1]
2064 if and.Op != andOp {
2065 return false
2066 }
2067 var add, mask *Value
2068 if and.Args[0].Op == addOp && and.Args[1].Op == constOp {
2069 add = and.Args[0]
2070 mask = and.Args[1]
2071 } else if and.Args[1].Op == addOp && and.Args[0].Op == constOp {
2072 add = and.Args[1]
2073 mask = and.Args[0]
2074 } else {
2075 return false
2076 }
2077 var ushift *Value
2078 if add.Args[0] == x {
2079 ushift = add.Args[1]
2080 } else if add.Args[1] == x {
2081 ushift = add.Args[0]
2082 } else {
2083 return false
2084 }
2085 if ushift.Op != ushiftOp {
2086 return false
2087 }
2088 if ushift.Args[1].Op != OpConst64 {
2089 return false
2090 }
2091 k := w - ushift.Args[1].AuxInt
2092 d := int64(1) << k
2093 sshift := ushift.Args[0]
2094 if sshift.Op != sshiftOp {
2095 return false
2096 }
2097 if sshift.Args[0] != x {
2098 return false
2099 }
2100 if sshift.Args[1].Op != OpConst64 || sshift.Args[1].AuxInt != w-1 {
2101 return false
2102 }
2103 if mask.AuxInt != -d {
2104 return false
2105 }
2106
2107
2108 return ft.signedMinMax(v, -d+1, d-1)
2109 }
2110
2111
2112
2113 func getBranch(sdom SparseTree, p *Block, b *Block) branch {
2114 if p == nil {
2115 return unknown
2116 }
2117 switch p.Kind {
2118 case BlockIf:
2119
2120
2121
2122
2123
2124
2125 if sdom.IsAncestorEq(p.Succs[0].b, b) && len(p.Succs[0].b.Preds) == 1 {
2126 return positive
2127 }
2128 if sdom.IsAncestorEq(p.Succs[1].b, b) && len(p.Succs[1].b.Preds) == 1 {
2129 return negative
2130 }
2131 case BlockJumpTable:
2132
2133
2134 for i, e := range p.Succs {
2135 if sdom.IsAncestorEq(e.b, b) && len(e.b.Preds) == 1 {
2136 return jumpTable0 + branch(i)
2137 }
2138 }
2139 }
2140 return unknown
2141 }
2142
2143
2144
2145
2146 func addIndVarRestrictions(ft *factsTable, b *Block, iv indVar) {
2147 d := signed
2148 if ft.isNonNegative(iv.min) && ft.isNonNegative(iv.max) {
2149 d |= unsigned
2150 }
2151
2152 if iv.flags&indVarMinExc == 0 {
2153 addRestrictions(b, ft, d, iv.min, iv.ind, lt|eq)
2154 } else {
2155 addRestrictions(b, ft, d, iv.min, iv.ind, lt)
2156 }
2157
2158 if iv.flags&indVarMaxInc == 0 {
2159 addRestrictions(b, ft, d, iv.ind, iv.max, lt)
2160 } else {
2161 addRestrictions(b, ft, d, iv.ind, iv.max, lt|eq)
2162 }
2163 }
2164
2165
2166
2167 func addBranchRestrictions(ft *factsTable, b *Block, br branch) {
2168 c := b.Controls[0]
2169 switch {
2170 case br == negative:
2171 ft.booleanFalse(c)
2172 case br == positive:
2173 ft.booleanTrue(c)
2174 case br >= jumpTable0:
2175 idx := br - jumpTable0
2176 val := int64(idx)
2177 if v, off := isConstDelta(c); v != nil {
2178
2179
2180 c = v
2181 val -= off
2182 }
2183 ft.newLimit(c, limit{min: val, max: val, umin: uint64(val), umax: uint64(val)})
2184 default:
2185 panic("unknown branch")
2186 }
2187 }
2188
2189
2190
2191 func addRestrictions(parent *Block, ft *factsTable, t domain, v, w *Value, r relation) {
2192 if t == 0 {
2193
2194
2195 return
2196 }
2197 for i := domain(1); i <= t; i <<= 1 {
2198 if t&i == 0 {
2199 continue
2200 }
2201 ft.update(parent, v, w, i, r)
2202 }
2203 }
2204
2205 func unsignedAddOverflows(a, b uint64, t *types.Type) bool {
2206 switch t.Size() {
2207 case 8:
2208 return a+b < a
2209 case 4:
2210 return a+b > math.MaxUint32
2211 case 2:
2212 return a+b > math.MaxUint16
2213 case 1:
2214 return a+b > math.MaxUint8
2215 default:
2216 panic("unreachable")
2217 }
2218 }
2219
2220 func signedAddOverflowsOrUnderflows(a, b int64, t *types.Type) bool {
2221 r := a + b
2222 switch t.Size() {
2223 case 8:
2224 return (a >= 0 && b >= 0 && r < 0) || (a < 0 && b < 0 && r >= 0)
2225 case 4:
2226 return r < math.MinInt32 || math.MaxInt32 < r
2227 case 2:
2228 return r < math.MinInt16 || math.MaxInt16 < r
2229 case 1:
2230 return r < math.MinInt8 || math.MaxInt8 < r
2231 default:
2232 panic("unreachable")
2233 }
2234 }
2235
2236 func unsignedSubUnderflows(a, b uint64) bool {
2237 return a < b
2238 }
2239
2240
2241
2242
2243
2244 func checkForChunkedIndexBounds(ft *factsTable, b *Block, index, bound *Value, isReslice bool) bool {
2245 if bound.Op != OpSliceLen && bound.Op != OpSliceCap {
2246 return false
2247 }
2248
2249
2250
2251
2252
2253
2254 slice := bound.Args[0]
2255 lim := ft.limits[index.ID]
2256 if lim.min < 0 {
2257 return false
2258 }
2259 i, delta := isConstDelta(index)
2260 if i == nil {
2261 return false
2262 }
2263 if delta < 0 {
2264 return false
2265 }
2266
2267
2268
2269
2270
2271
2272
2273
2274 for o := ft.orderings[i.ID]; o != nil; o = o.next {
2275 if o.d != signed {
2276 continue
2277 }
2278 if ow := o.w; ow.Op == OpAdd64 {
2279 var lenOffset *Value
2280 if bound := ow.Args[0]; bound.Op == OpSliceLen && bound.Args[0] == slice {
2281 lenOffset = ow.Args[1]
2282 } else if bound := ow.Args[1]; bound.Op == OpSliceLen && bound.Args[0] == slice {
2283 lenOffset = ow.Args[0]
2284 }
2285 if lenOffset == nil || lenOffset.Op != OpConst64 {
2286 continue
2287 }
2288 if K := -lenOffset.AuxInt; K >= 0 {
2289 or := o.r
2290 if isReslice {
2291 K++
2292 }
2293 if or == lt {
2294 or = lt | eq
2295 K++
2296 }
2297 if K < 0 {
2298 continue
2299 }
2300
2301 if delta < K && or == lt|eq {
2302 return true
2303 }
2304 }
2305 }
2306 }
2307 return false
2308 }
2309
2310 func addLocalFacts(ft *factsTable, b *Block) {
2311
2312
2313
2314 for {
2315 changed := false
2316 for _, v := range b.Values {
2317 changed = ft.flowLimit(v) || changed
2318 }
2319 if !changed {
2320 break
2321 }
2322 }
2323
2324
2325 for _, v := range b.Values {
2326
2327
2328 switch v.Op {
2329 case OpAdd64, OpAdd32, OpAdd16, OpAdd8:
2330 x := ft.limits[v.Args[0].ID]
2331 y := ft.limits[v.Args[1].ID]
2332 if !unsignedAddOverflows(x.umax, y.umax, v.Type) {
2333 r := gt
2334 if !x.nonzero() {
2335 r |= eq
2336 }
2337 ft.update(b, v, v.Args[1], unsigned, r)
2338 r = gt
2339 if !y.nonzero() {
2340 r |= eq
2341 }
2342 ft.update(b, v, v.Args[0], unsigned, r)
2343 }
2344 if x.min >= 0 && !signedAddOverflowsOrUnderflows(x.max, y.max, v.Type) {
2345 r := gt
2346 if !x.nonzero() {
2347 r |= eq
2348 }
2349 ft.update(b, v, v.Args[1], signed, r)
2350 }
2351 if y.min >= 0 && !signedAddOverflowsOrUnderflows(x.max, y.max, v.Type) {
2352 r := gt
2353 if !y.nonzero() {
2354 r |= eq
2355 }
2356 ft.update(b, v, v.Args[0], signed, r)
2357 }
2358 if x.max <= 0 && !signedAddOverflowsOrUnderflows(x.min, y.min, v.Type) {
2359 r := lt
2360 if !x.nonzero() {
2361 r |= eq
2362 }
2363 ft.update(b, v, v.Args[1], signed, r)
2364 }
2365 if y.max <= 0 && !signedAddOverflowsOrUnderflows(x.min, y.min, v.Type) {
2366 r := lt
2367 if !y.nonzero() {
2368 r |= eq
2369 }
2370 ft.update(b, v, v.Args[0], signed, r)
2371 }
2372 case OpSub64, OpSub32, OpSub16, OpSub8:
2373 x := ft.limits[v.Args[0].ID]
2374 y := ft.limits[v.Args[1].ID]
2375 if !unsignedSubUnderflows(x.umin, y.umax) {
2376 r := lt
2377 if !y.nonzero() {
2378 r |= eq
2379 }
2380 ft.update(b, v, v.Args[0], unsigned, r)
2381 }
2382
2383 case OpAnd64, OpAnd32, OpAnd16, OpAnd8:
2384 ft.update(b, v, v.Args[0], unsigned, lt|eq)
2385 ft.update(b, v, v.Args[1], unsigned, lt|eq)
2386 if ft.isNonNegative(v.Args[0]) {
2387 ft.update(b, v, v.Args[0], signed, lt|eq)
2388 }
2389 if ft.isNonNegative(v.Args[1]) {
2390 ft.update(b, v, v.Args[1], signed, lt|eq)
2391 }
2392 case OpOr64, OpOr32, OpOr16, OpOr8:
2393
2394
2395
2396 case OpDiv64u, OpDiv32u, OpDiv16u, OpDiv8u,
2397 OpRsh8Ux64, OpRsh8Ux32, OpRsh8Ux16, OpRsh8Ux8,
2398 OpRsh16Ux64, OpRsh16Ux32, OpRsh16Ux16, OpRsh16Ux8,
2399 OpRsh32Ux64, OpRsh32Ux32, OpRsh32Ux16, OpRsh32Ux8,
2400 OpRsh64Ux64, OpRsh64Ux32, OpRsh64Ux16, OpRsh64Ux8:
2401 ft.update(b, v, v.Args[0], unsigned, lt|eq)
2402 case OpMod64u, OpMod32u, OpMod16u, OpMod8u:
2403 ft.update(b, v, v.Args[0], unsigned, lt|eq)
2404
2405
2406
2407
2408 ft.update(b, v, v.Args[1], unsigned, lt)
2409 case OpStringLen:
2410 if v.Args[0].Op == OpStringMake {
2411 ft.update(b, v, v.Args[0].Args[1], signed, eq)
2412 }
2413 case OpSliceLen:
2414 if v.Args[0].Op == OpSliceMake {
2415 ft.update(b, v, v.Args[0].Args[1], signed, eq)
2416 }
2417 case OpSliceCap:
2418 if v.Args[0].Op == OpSliceMake {
2419 ft.update(b, v, v.Args[0].Args[2], signed, eq)
2420 }
2421 case OpIsInBounds:
2422 if checkForChunkedIndexBounds(ft, b, v.Args[0], v.Args[1], false) {
2423 if b.Func.pass.debug > 0 {
2424 b.Func.Warnl(v.Pos, "Proved %s for blocked indexing", v.Op)
2425 }
2426 ft.booleanTrue(v)
2427 }
2428 case OpIsSliceInBounds:
2429 if checkForChunkedIndexBounds(ft, b, v.Args[0], v.Args[1], true) {
2430 if b.Func.pass.debug > 0 {
2431 b.Func.Warnl(v.Pos, "Proved %s for blocked reslicing", v.Op)
2432 }
2433 ft.booleanTrue(v)
2434 }
2435 case OpPhi:
2436 addLocalFactsPhi(ft, v)
2437 }
2438 }
2439 }
2440
2441 func addLocalFactsPhi(ft *factsTable, v *Value) {
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456 if len(v.Args) != 2 {
2457 return
2458 }
2459 b := v.Block
2460 x := v.Args[0]
2461 y := v.Args[1]
2462 bx := b.Preds[0].b
2463 by := b.Preds[1].b
2464 var z *Block
2465 switch {
2466 case bx == by:
2467 z = bx
2468 case by.uniquePred() == bx:
2469 z = bx
2470 case bx.uniquePred() == by:
2471 z = by
2472 case bx.uniquePred() == by.uniquePred():
2473 z = bx.uniquePred()
2474 }
2475 if z == nil || z.Kind != BlockIf {
2476 return
2477 }
2478 c := z.Controls[0]
2479 if len(c.Args) != 2 {
2480 return
2481 }
2482 var isMin bool
2483 if bx == z {
2484 isMin = b.Preds[0].i == 0
2485 } else {
2486 isMin = bx.Preds[0].i == 0
2487 }
2488 if c.Args[0] == x && c.Args[1] == y {
2489
2490 } else if c.Args[0] == y && c.Args[1] == x {
2491
2492 isMin = !isMin
2493 } else {
2494
2495 return
2496 }
2497 var dom domain
2498 switch c.Op {
2499 case OpLess64, OpLess32, OpLess16, OpLess8, OpLeq64, OpLeq32, OpLeq16, OpLeq8:
2500 dom = signed
2501 case OpLess64U, OpLess32U, OpLess16U, OpLess8U, OpLeq64U, OpLeq32U, OpLeq16U, OpLeq8U:
2502 dom = unsigned
2503 default:
2504 return
2505 }
2506 var rel relation
2507 if isMin {
2508 rel = lt | eq
2509 } else {
2510 rel = gt | eq
2511 }
2512 ft.update(b, v, x, dom, rel)
2513 ft.update(b, v, y, dom, rel)
2514 }
2515
2516 var ctzNonZeroOp = map[Op]Op{OpCtz8: OpCtz8NonZero, OpCtz16: OpCtz16NonZero, OpCtz32: OpCtz32NonZero, OpCtz64: OpCtz64NonZero}
2517 var mostNegativeDividend = map[Op]int64{
2518 OpDiv16: -1 << 15,
2519 OpMod16: -1 << 15,
2520 OpDiv32: -1 << 31,
2521 OpMod32: -1 << 31,
2522 OpDiv64: -1 << 63,
2523 OpMod64: -1 << 63}
2524
2525
2526
2527 func simplifyBlock(sdom SparseTree, ft *factsTable, b *Block) {
2528 for _, v := range b.Values {
2529 switch v.Op {
2530 case OpSlicemask:
2531
2532 cap := v.Args[0]
2533 x, delta := isConstDelta(cap)
2534 if x != nil {
2535
2536
2537 lim := ft.limits[x.ID]
2538 if lim.umin > uint64(-delta) {
2539 if cap.Op == OpAdd64 {
2540 v.reset(OpConst64)
2541 } else {
2542 v.reset(OpConst32)
2543 }
2544 if b.Func.pass.debug > 0 {
2545 b.Func.Warnl(v.Pos, "Proved slicemask not needed")
2546 }
2547 v.AuxInt = -1
2548 }
2549 break
2550 }
2551 lim := ft.limits[cap.ID]
2552 if lim.umin > 0 {
2553 if cap.Type.Size() == 8 {
2554 v.reset(OpConst64)
2555 } else {
2556 v.reset(OpConst32)
2557 }
2558 if b.Func.pass.debug > 0 {
2559 b.Func.Warnl(v.Pos, "Proved slicemask not needed (by limit)")
2560 }
2561 v.AuxInt = -1
2562 }
2563
2564 case OpCtz8, OpCtz16, OpCtz32, OpCtz64:
2565
2566
2567
2568 x := v.Args[0]
2569 lim := ft.limits[x.ID]
2570 if lim.umin > 0 || lim.min > 0 || lim.max < 0 {
2571 if b.Func.pass.debug > 0 {
2572 b.Func.Warnl(v.Pos, "Proved %v non-zero", v.Op)
2573 }
2574 v.Op = ctzNonZeroOp[v.Op]
2575 }
2576 case OpRsh8x8, OpRsh8x16, OpRsh8x32, OpRsh8x64,
2577 OpRsh16x8, OpRsh16x16, OpRsh16x32, OpRsh16x64,
2578 OpRsh32x8, OpRsh32x16, OpRsh32x32, OpRsh32x64,
2579 OpRsh64x8, OpRsh64x16, OpRsh64x32, OpRsh64x64:
2580
2581
2582 bits := 8 * v.Args[0].Type.Size()
2583 if v.Args[1].isGenericIntConst() && v.Args[1].AuxInt >= bits-1 && ft.isNonNegative(v.Args[0]) {
2584 if b.Func.pass.debug > 0 {
2585 b.Func.Warnl(v.Pos, "Proved %v shifts to zero", v.Op)
2586 }
2587 switch bits {
2588 case 64:
2589 v.reset(OpConst64)
2590 case 32:
2591 v.reset(OpConst32)
2592 case 16:
2593 v.reset(OpConst16)
2594 case 8:
2595 v.reset(OpConst8)
2596 default:
2597 panic("unexpected integer size")
2598 }
2599 v.AuxInt = 0
2600 break
2601 }
2602
2603 fallthrough
2604 case OpLsh8x8, OpLsh8x16, OpLsh8x32, OpLsh8x64,
2605 OpLsh16x8, OpLsh16x16, OpLsh16x32, OpLsh16x64,
2606 OpLsh32x8, OpLsh32x16, OpLsh32x32, OpLsh32x64,
2607 OpLsh64x8, OpLsh64x16, OpLsh64x32, OpLsh64x64,
2608 OpRsh8Ux8, OpRsh8Ux16, OpRsh8Ux32, OpRsh8Ux64,
2609 OpRsh16Ux8, OpRsh16Ux16, OpRsh16Ux32, OpRsh16Ux64,
2610 OpRsh32Ux8, OpRsh32Ux16, OpRsh32Ux32, OpRsh32Ux64,
2611 OpRsh64Ux8, OpRsh64Ux16, OpRsh64Ux32, OpRsh64Ux64:
2612
2613
2614 by := v.Args[1]
2615 lim := ft.limits[by.ID]
2616 bits := 8 * v.Args[0].Type.Size()
2617 if lim.umax < uint64(bits) || (lim.max < bits && ft.isNonNegative(by)) {
2618 v.AuxInt = 1
2619 if b.Func.pass.debug > 0 && !by.isGenericIntConst() {
2620 b.Func.Warnl(v.Pos, "Proved %v bounded", v.Op)
2621 }
2622 }
2623 case OpDiv16, OpDiv32, OpDiv64, OpMod16, OpMod32, OpMod64:
2624
2625
2626
2627
2628
2629 if b.Func.Config.arch != "386" && b.Func.Config.arch != "amd64" {
2630 break
2631 }
2632 divr := v.Args[1]
2633 divrLim := ft.limits[divr.ID]
2634 divd := v.Args[0]
2635 divdLim := ft.limits[divd.ID]
2636 if divrLim.max < -1 || divrLim.min > -1 || divdLim.min > mostNegativeDividend[v.Op] {
2637
2638
2639
2640
2641 v.AuxInt = 1
2642 if b.Func.pass.debug > 0 {
2643 b.Func.Warnl(v.Pos, "Proved %v does not need fix-up", v.Op)
2644 }
2645 }
2646 }
2647
2648
2649 for i, arg := range v.Args {
2650 lim := ft.limits[arg.ID]
2651 var constValue int64
2652 switch {
2653 case lim.min == lim.max:
2654 constValue = lim.min
2655 case lim.umin == lim.umax:
2656 constValue = int64(lim.umin)
2657 default:
2658 continue
2659 }
2660 switch arg.Op {
2661 case OpConst64, OpConst32, OpConst16, OpConst8, OpConstBool, OpConstNil:
2662 continue
2663 }
2664 typ := arg.Type
2665 f := b.Func
2666 var c *Value
2667 switch {
2668 case typ.IsBoolean():
2669 c = f.ConstBool(typ, constValue != 0)
2670 case typ.IsInteger() && typ.Size() == 1:
2671 c = f.ConstInt8(typ, int8(constValue))
2672 case typ.IsInteger() && typ.Size() == 2:
2673 c = f.ConstInt16(typ, int16(constValue))
2674 case typ.IsInteger() && typ.Size() == 4:
2675 c = f.ConstInt32(typ, int32(constValue))
2676 case typ.IsInteger() && typ.Size() == 8:
2677 c = f.ConstInt64(typ, constValue)
2678 case typ.IsPtrShaped():
2679 if constValue == 0 {
2680 c = f.ConstNil(typ)
2681 } else {
2682
2683
2684 continue
2685 }
2686 default:
2687
2688
2689 continue
2690 }
2691 v.SetArg(i, c)
2692 ft.initLimitForNewValue(c)
2693 if b.Func.pass.debug > 1 {
2694 b.Func.Warnl(v.Pos, "Proved %v's arg %d (%v) is constant %d", v, i, arg, constValue)
2695 }
2696 }
2697 }
2698
2699 if b.Kind != BlockIf {
2700 return
2701 }
2702
2703
2704 parent := b
2705 for i, branch := range [...]branch{positive, negative} {
2706 child := parent.Succs[i].b
2707 if getBranch(sdom, parent, child) != unknown {
2708
2709
2710 continue
2711 }
2712
2713
2714 ft.checkpoint()
2715 addBranchRestrictions(ft, parent, branch)
2716 unsat := ft.unsat
2717 ft.restore()
2718 if unsat {
2719
2720
2721 removeBranch(parent, branch)
2722
2723
2724
2725
2726
2727 break
2728 }
2729 }
2730 }
2731
2732 func removeBranch(b *Block, branch branch) {
2733 c := b.Controls[0]
2734 if b.Func.pass.debug > 0 {
2735 verb := "Proved"
2736 if branch == positive {
2737 verb = "Disproved"
2738 }
2739 if b.Func.pass.debug > 1 {
2740 b.Func.Warnl(b.Pos, "%s %s (%s)", verb, c.Op, c)
2741 } else {
2742 b.Func.Warnl(b.Pos, "%s %s", verb, c.Op)
2743 }
2744 }
2745 if c != nil && c.Pos.IsStmt() == src.PosIsStmt && c.Pos.SameFileAndLine(b.Pos) {
2746
2747 b.Pos = b.Pos.WithIsStmt()
2748 }
2749 if branch == positive || branch == negative {
2750 b.Kind = BlockFirst
2751 b.ResetControls()
2752 if branch == positive {
2753 b.swapSuccessors()
2754 }
2755 } else {
2756
2757 }
2758 }
2759
2760
2761 func isConstDelta(v *Value) (w *Value, delta int64) {
2762 cop := OpConst64
2763 switch v.Op {
2764 case OpAdd32, OpSub32:
2765 cop = OpConst32
2766 case OpAdd16, OpSub16:
2767 cop = OpConst16
2768 case OpAdd8, OpSub8:
2769 cop = OpConst8
2770 }
2771 switch v.Op {
2772 case OpAdd64, OpAdd32, OpAdd16, OpAdd8:
2773 if v.Args[0].Op == cop {
2774 return v.Args[1], v.Args[0].AuxInt
2775 }
2776 if v.Args[1].Op == cop {
2777 return v.Args[0], v.Args[1].AuxInt
2778 }
2779 case OpSub64, OpSub32, OpSub16, OpSub8:
2780 if v.Args[1].Op == cop {
2781 aux := v.Args[1].AuxInt
2782 if aux != -aux {
2783 return v.Args[0], -aux
2784 }
2785 }
2786 }
2787 return nil, 0
2788 }
2789
2790
2791
2792 func isCleanExt(v *Value) bool {
2793 switch v.Op {
2794 case OpSignExt8to16, OpSignExt8to32, OpSignExt8to64,
2795 OpSignExt16to32, OpSignExt16to64, OpSignExt32to64:
2796
2797 return v.Args[0].Type.IsSigned() && v.Type.IsSigned()
2798
2799 case OpZeroExt8to16, OpZeroExt8to32, OpZeroExt8to64,
2800 OpZeroExt16to32, OpZeroExt16to64, OpZeroExt32to64:
2801
2802 return !v.Args[0].Type.IsSigned()
2803 }
2804 return false
2805 }
2806
View as plain text