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 return sub || mod
1770 case OpNeg64, OpNeg32, OpNeg16, OpNeg8:
1771 a := ft.limits[v.Args[0].ID]
1772 bitsize := uint(v.Type.Size()) * 8
1773 return ft.newLimit(v, a.com(bitsize).add(limit{min: 1, max: 1, umin: 1, umax: 1}, bitsize))
1774 case OpMul64, OpMul32, OpMul16, OpMul8:
1775 a := ft.limits[v.Args[0].ID]
1776 b := ft.limits[v.Args[1].ID]
1777 return ft.newLimit(v, a.mul(b, uint(v.Type.Size())*8))
1778 case OpLsh64x64, OpLsh64x32, OpLsh64x16, OpLsh64x8,
1779 OpLsh32x64, OpLsh32x32, OpLsh32x16, OpLsh32x8,
1780 OpLsh16x64, OpLsh16x32, OpLsh16x16, OpLsh16x8,
1781 OpLsh8x64, OpLsh8x32, OpLsh8x16, OpLsh8x8:
1782 a := ft.limits[v.Args[0].ID]
1783 b := ft.limits[v.Args[1].ID]
1784 bitsize := uint(v.Type.Size()) * 8
1785 return ft.newLimit(v, a.mul(b.exp2(bitsize), bitsize))
1786 case OpMod64, OpMod32, OpMod16, OpMod8:
1787 a := ft.limits[v.Args[0].ID]
1788 b := ft.limits[v.Args[1].ID]
1789 if !(a.nonnegative() && b.nonnegative()) {
1790
1791 break
1792 }
1793 fallthrough
1794 case OpMod64u, OpMod32u, OpMod16u, OpMod8u:
1795 a := ft.limits[v.Args[0].ID]
1796 b := ft.limits[v.Args[1].ID]
1797
1798 return ft.unsignedMax(v, min(a.umax, b.umax-1))
1799 case OpDiv64, OpDiv32, OpDiv16, OpDiv8:
1800 a := ft.limits[v.Args[0].ID]
1801 b := ft.limits[v.Args[1].ID]
1802 if !(a.nonnegative() && b.nonnegative()) {
1803
1804 break
1805 }
1806 fallthrough
1807 case OpDiv64u, OpDiv32u, OpDiv16u, OpDiv8u:
1808 a := ft.limits[v.Args[0].ID]
1809 b := ft.limits[v.Args[1].ID]
1810 lim := noLimit
1811 if b.umax > 0 {
1812 lim = lim.unsignedMin(a.umin / b.umax)
1813 }
1814 if b.umin > 0 {
1815 lim = lim.unsignedMax(a.umax / b.umin)
1816 }
1817 return ft.newLimit(v, lim)
1818
1819 case OpPhi:
1820 {
1821
1822 b := v.Block
1823 if len(b.Preds) != 2 {
1824 goto notMinNorMax
1825 }
1826
1827
1828
1829
1830
1831
1832
1833
1834 firstBlock, secondBlock := b.Preds[0].b, b.Preds[1].b
1835 if firstBlock.Kind != BlockPlain || secondBlock.Kind != BlockPlain {
1836 goto notMinNorMax
1837 }
1838 if len(firstBlock.Preds) != 1 || len(secondBlock.Preds) != 1 {
1839 goto notMinNorMax
1840 }
1841 conditionBlock := firstBlock.Preds[0].b
1842 if conditionBlock != secondBlock.Preds[0].b {
1843 goto notMinNorMax
1844 }
1845 if conditionBlock.Kind != BlockIf {
1846 goto notMinNorMax
1847 }
1848
1849 less := conditionBlock.Controls[0]
1850 var unsigned bool
1851 switch less.Op {
1852 case OpLess64U, OpLess32U, OpLess16U, OpLess8U,
1853 OpLeq64U, OpLeq32U, OpLeq16U, OpLeq8U:
1854 unsigned = true
1855 case OpLess64, OpLess32, OpLess16, OpLess8,
1856 OpLeq64, OpLeq32, OpLeq16, OpLeq8:
1857 default:
1858 goto notMinNorMax
1859 }
1860 small, big := less.Args[0], less.Args[1]
1861 truev, falsev := v.Args[0], v.Args[1]
1862 if conditionBlock.Succs[0].b == secondBlock {
1863 truev, falsev = falsev, truev
1864 }
1865
1866 bigl, smalll := ft.limits[big.ID], ft.limits[small.ID]
1867 if truev == big {
1868 if falsev == small {
1869
1870 if unsigned {
1871 maximum := max(bigl.umax, smalll.umax)
1872 minimum := max(bigl.umin, smalll.umin)
1873 return ft.unsignedMinMax(v, minimum, maximum)
1874 } else {
1875 maximum := max(bigl.max, smalll.max)
1876 minimum := max(bigl.min, smalll.min)
1877 return ft.signedMinMax(v, minimum, maximum)
1878 }
1879 } else {
1880 goto notMinNorMax
1881 }
1882 } else if truev == small {
1883 if falsev == big {
1884
1885 if unsigned {
1886 maximum := min(bigl.umax, smalll.umax)
1887 minimum := min(bigl.umin, smalll.umin)
1888 return ft.unsignedMinMax(v, minimum, maximum)
1889 } else {
1890 maximum := min(bigl.max, smalll.max)
1891 minimum := min(bigl.min, smalll.min)
1892 return ft.signedMinMax(v, minimum, maximum)
1893 }
1894 } else {
1895 goto notMinNorMax
1896 }
1897 } else {
1898 goto notMinNorMax
1899 }
1900 }
1901 notMinNorMax:
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912 l := ft.limits[v.Args[0].ID]
1913 for _, a := range v.Args[1:] {
1914 l2 := ft.limits[a.ID]
1915 l.min = min(l.min, l2.min)
1916 l.max = max(l.max, l2.max)
1917 l.umin = min(l.umin, l2.umin)
1918 l.umax = max(l.umax, l2.umax)
1919 }
1920 return ft.newLimit(v, l)
1921 }
1922 return false
1923 }
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943 func (ft *factsTable) detectSignedMod(v *Value) bool {
1944 if ft.detectSignedModByPowerOfTwo(v) {
1945 return true
1946 }
1947
1948 return false
1949 }
1950 func (ft *factsTable) detectSignedModByPowerOfTwo(v *Value) bool {
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964 var w int64
1965 var addOp, andOp, constOp, sshiftOp, ushiftOp Op
1966 switch v.Op {
1967 case OpSub64:
1968 w = 64
1969 addOp = OpAdd64
1970 andOp = OpAnd64
1971 constOp = OpConst64
1972 sshiftOp = OpRsh64x64
1973 ushiftOp = OpRsh64Ux64
1974 case OpSub32:
1975 w = 32
1976 addOp = OpAdd32
1977 andOp = OpAnd32
1978 constOp = OpConst32
1979 sshiftOp = OpRsh32x64
1980 ushiftOp = OpRsh32Ux64
1981 case OpSub16:
1982 w = 16
1983 addOp = OpAdd16
1984 andOp = OpAnd16
1985 constOp = OpConst16
1986 sshiftOp = OpRsh16x64
1987 ushiftOp = OpRsh16Ux64
1988 case OpSub8:
1989 w = 8
1990 addOp = OpAdd8
1991 andOp = OpAnd8
1992 constOp = OpConst8
1993 sshiftOp = OpRsh8x64
1994 ushiftOp = OpRsh8Ux64
1995 default:
1996 return false
1997 }
1998
1999 x := v.Args[0]
2000 and := v.Args[1]
2001 if and.Op != andOp {
2002 return false
2003 }
2004 var add, mask *Value
2005 if and.Args[0].Op == addOp && and.Args[1].Op == constOp {
2006 add = and.Args[0]
2007 mask = and.Args[1]
2008 } else if and.Args[1].Op == addOp && and.Args[0].Op == constOp {
2009 add = and.Args[1]
2010 mask = and.Args[0]
2011 } else {
2012 return false
2013 }
2014 var ushift *Value
2015 if add.Args[0] == x {
2016 ushift = add.Args[1]
2017 } else if add.Args[1] == x {
2018 ushift = add.Args[0]
2019 } else {
2020 return false
2021 }
2022 if ushift.Op != ushiftOp {
2023 return false
2024 }
2025 if ushift.Args[1].Op != OpConst64 {
2026 return false
2027 }
2028 k := w - ushift.Args[1].AuxInt
2029 d := int64(1) << k
2030 sshift := ushift.Args[0]
2031 if sshift.Op != sshiftOp {
2032 return false
2033 }
2034 if sshift.Args[0] != x {
2035 return false
2036 }
2037 if sshift.Args[1].Op != OpConst64 || sshift.Args[1].AuxInt != w-1 {
2038 return false
2039 }
2040 if mask.AuxInt != -d {
2041 return false
2042 }
2043
2044
2045 return ft.signedMinMax(v, -d+1, d-1)
2046 }
2047
2048
2049
2050 func getBranch(sdom SparseTree, p *Block, b *Block) branch {
2051 if p == nil {
2052 return unknown
2053 }
2054 switch p.Kind {
2055 case BlockIf:
2056
2057
2058
2059
2060
2061
2062 if sdom.IsAncestorEq(p.Succs[0].b, b) && len(p.Succs[0].b.Preds) == 1 {
2063 return positive
2064 }
2065 if sdom.IsAncestorEq(p.Succs[1].b, b) && len(p.Succs[1].b.Preds) == 1 {
2066 return negative
2067 }
2068 case BlockJumpTable:
2069
2070
2071 for i, e := range p.Succs {
2072 if sdom.IsAncestorEq(e.b, b) && len(e.b.Preds) == 1 {
2073 return jumpTable0 + branch(i)
2074 }
2075 }
2076 }
2077 return unknown
2078 }
2079
2080
2081
2082
2083 func addIndVarRestrictions(ft *factsTable, b *Block, iv indVar) {
2084 d := signed
2085 if ft.isNonNegative(iv.min) && ft.isNonNegative(iv.max) {
2086 d |= unsigned
2087 }
2088
2089 if iv.flags&indVarMinExc == 0 {
2090 addRestrictions(b, ft, d, iv.min, iv.ind, lt|eq)
2091 } else {
2092 addRestrictions(b, ft, d, iv.min, iv.ind, lt)
2093 }
2094
2095 if iv.flags&indVarMaxInc == 0 {
2096 addRestrictions(b, ft, d, iv.ind, iv.max, lt)
2097 } else {
2098 addRestrictions(b, ft, d, iv.ind, iv.max, lt|eq)
2099 }
2100 }
2101
2102
2103
2104 func addBranchRestrictions(ft *factsTable, b *Block, br branch) {
2105 c := b.Controls[0]
2106 switch {
2107 case br == negative:
2108 ft.booleanFalse(c)
2109 case br == positive:
2110 ft.booleanTrue(c)
2111 case br >= jumpTable0:
2112 idx := br - jumpTable0
2113 val := int64(idx)
2114 if v, off := isConstDelta(c); v != nil {
2115
2116
2117 c = v
2118 val -= off
2119 }
2120 ft.newLimit(c, limit{min: val, max: val, umin: uint64(val), umax: uint64(val)})
2121 default:
2122 panic("unknown branch")
2123 }
2124 }
2125
2126
2127
2128 func addRestrictions(parent *Block, ft *factsTable, t domain, v, w *Value, r relation) {
2129 if t == 0 {
2130
2131
2132 return
2133 }
2134 for i := domain(1); i <= t; i <<= 1 {
2135 if t&i == 0 {
2136 continue
2137 }
2138 ft.update(parent, v, w, i, r)
2139 }
2140 }
2141
2142 func unsignedAddOverflows(a, b uint64, t *types.Type) bool {
2143 switch t.Size() {
2144 case 8:
2145 return a+b < a
2146 case 4:
2147 return a+b > math.MaxUint32
2148 case 2:
2149 return a+b > math.MaxUint16
2150 case 1:
2151 return a+b > math.MaxUint8
2152 default:
2153 panic("unreachable")
2154 }
2155 }
2156
2157 func signedAddOverflowsOrUnderflows(a, b int64, t *types.Type) bool {
2158 r := a + b
2159 switch t.Size() {
2160 case 8:
2161 return (a >= 0 && b >= 0 && r < 0) || (a < 0 && b < 0 && r >= 0)
2162 case 4:
2163 return r < math.MinInt32 || math.MaxInt32 < r
2164 case 2:
2165 return r < math.MinInt16 || math.MaxInt16 < r
2166 case 1:
2167 return r < math.MinInt8 || math.MaxInt8 < r
2168 default:
2169 panic("unreachable")
2170 }
2171 }
2172
2173 func unsignedSubUnderflows(a, b uint64) bool {
2174 return a < b
2175 }
2176
2177 func addLocalFacts(ft *factsTable, b *Block) {
2178
2179
2180
2181 for {
2182 changed := false
2183 for _, v := range b.Values {
2184 changed = ft.flowLimit(v) || changed
2185 }
2186 if !changed {
2187 break
2188 }
2189 }
2190
2191
2192 for _, v := range b.Values {
2193
2194
2195 switch v.Op {
2196 case OpAdd64, OpAdd32, OpAdd16, OpAdd8:
2197 x := ft.limits[v.Args[0].ID]
2198 y := ft.limits[v.Args[1].ID]
2199 if !unsignedAddOverflows(x.umax, y.umax, v.Type) {
2200 r := gt
2201 if !x.nonzero() {
2202 r |= eq
2203 }
2204 ft.update(b, v, v.Args[1], unsigned, r)
2205 r = gt
2206 if !y.nonzero() {
2207 r |= eq
2208 }
2209 ft.update(b, v, v.Args[0], unsigned, r)
2210 }
2211 if x.min >= 0 && !signedAddOverflowsOrUnderflows(x.max, y.max, v.Type) {
2212 r := gt
2213 if !x.nonzero() {
2214 r |= eq
2215 }
2216 ft.update(b, v, v.Args[1], signed, r)
2217 }
2218 if y.min >= 0 && !signedAddOverflowsOrUnderflows(x.max, y.max, v.Type) {
2219 r := gt
2220 if !y.nonzero() {
2221 r |= eq
2222 }
2223 ft.update(b, v, v.Args[0], signed, r)
2224 }
2225 if x.max <= 0 && !signedAddOverflowsOrUnderflows(x.min, y.min, v.Type) {
2226 r := lt
2227 if !x.nonzero() {
2228 r |= eq
2229 }
2230 ft.update(b, v, v.Args[1], signed, r)
2231 }
2232 if y.max <= 0 && !signedAddOverflowsOrUnderflows(x.min, y.min, v.Type) {
2233 r := lt
2234 if !y.nonzero() {
2235 r |= eq
2236 }
2237 ft.update(b, v, v.Args[0], signed, r)
2238 }
2239 case OpSub64, OpSub32, OpSub16, OpSub8:
2240 x := ft.limits[v.Args[0].ID]
2241 y := ft.limits[v.Args[1].ID]
2242 if !unsignedSubUnderflows(x.umin, y.umax) {
2243 r := lt
2244 if !y.nonzero() {
2245 r |= eq
2246 }
2247 ft.update(b, v, v.Args[0], unsigned, r)
2248 }
2249
2250 case OpAnd64, OpAnd32, OpAnd16, OpAnd8:
2251 ft.update(b, v, v.Args[0], unsigned, lt|eq)
2252 ft.update(b, v, v.Args[1], unsigned, lt|eq)
2253 if ft.isNonNegative(v.Args[0]) {
2254 ft.update(b, v, v.Args[0], signed, lt|eq)
2255 }
2256 if ft.isNonNegative(v.Args[1]) {
2257 ft.update(b, v, v.Args[1], signed, lt|eq)
2258 }
2259 case OpOr64, OpOr32, OpOr16, OpOr8:
2260
2261
2262
2263 case OpDiv64u, OpDiv32u, OpDiv16u, OpDiv8u,
2264 OpRsh8Ux64, OpRsh8Ux32, OpRsh8Ux16, OpRsh8Ux8,
2265 OpRsh16Ux64, OpRsh16Ux32, OpRsh16Ux16, OpRsh16Ux8,
2266 OpRsh32Ux64, OpRsh32Ux32, OpRsh32Ux16, OpRsh32Ux8,
2267 OpRsh64Ux64, OpRsh64Ux32, OpRsh64Ux16, OpRsh64Ux8:
2268 ft.update(b, v, v.Args[0], unsigned, lt|eq)
2269 case OpMod64u, OpMod32u, OpMod16u, OpMod8u:
2270 ft.update(b, v, v.Args[0], unsigned, lt|eq)
2271
2272
2273
2274
2275 ft.update(b, v, v.Args[1], unsigned, lt)
2276 case OpStringLen:
2277 if v.Args[0].Op == OpStringMake {
2278 ft.update(b, v, v.Args[0].Args[1], signed, eq)
2279 }
2280 case OpSliceLen:
2281 if v.Args[0].Op == OpSliceMake {
2282 ft.update(b, v, v.Args[0].Args[1], signed, eq)
2283 }
2284 case OpSliceCap:
2285 if v.Args[0].Op == OpSliceMake {
2286 ft.update(b, v, v.Args[0].Args[2], signed, eq)
2287 }
2288 case OpPhi:
2289 addLocalFactsPhi(ft, v)
2290 }
2291 }
2292 }
2293
2294 func addLocalFactsPhi(ft *factsTable, v *Value) {
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309 if len(v.Args) != 2 {
2310 return
2311 }
2312 b := v.Block
2313 x := v.Args[0]
2314 y := v.Args[1]
2315 bx := b.Preds[0].b
2316 by := b.Preds[1].b
2317 var z *Block
2318 switch {
2319 case bx == by:
2320 z = bx
2321 case by.uniquePred() == bx:
2322 z = bx
2323 case bx.uniquePred() == by:
2324 z = by
2325 case bx.uniquePred() == by.uniquePred():
2326 z = bx.uniquePred()
2327 }
2328 if z == nil || z.Kind != BlockIf {
2329 return
2330 }
2331 c := z.Controls[0]
2332 if len(c.Args) != 2 {
2333 return
2334 }
2335 var isMin bool
2336 if bx == z {
2337 isMin = b.Preds[0].i == 0
2338 } else {
2339 isMin = bx.Preds[0].i == 0
2340 }
2341 if c.Args[0] == x && c.Args[1] == y {
2342
2343 } else if c.Args[0] == y && c.Args[1] == x {
2344
2345 isMin = !isMin
2346 } else {
2347
2348 return
2349 }
2350 var dom domain
2351 switch c.Op {
2352 case OpLess64, OpLess32, OpLess16, OpLess8, OpLeq64, OpLeq32, OpLeq16, OpLeq8:
2353 dom = signed
2354 case OpLess64U, OpLess32U, OpLess16U, OpLess8U, OpLeq64U, OpLeq32U, OpLeq16U, OpLeq8U:
2355 dom = unsigned
2356 default:
2357 return
2358 }
2359 var rel relation
2360 if isMin {
2361 rel = lt | eq
2362 } else {
2363 rel = gt | eq
2364 }
2365 ft.update(b, v, x, dom, rel)
2366 ft.update(b, v, y, dom, rel)
2367 }
2368
2369 var ctzNonZeroOp = map[Op]Op{OpCtz8: OpCtz8NonZero, OpCtz16: OpCtz16NonZero, OpCtz32: OpCtz32NonZero, OpCtz64: OpCtz64NonZero}
2370 var mostNegativeDividend = map[Op]int64{
2371 OpDiv16: -1 << 15,
2372 OpMod16: -1 << 15,
2373 OpDiv32: -1 << 31,
2374 OpMod32: -1 << 31,
2375 OpDiv64: -1 << 63,
2376 OpMod64: -1 << 63}
2377
2378
2379
2380 func simplifyBlock(sdom SparseTree, ft *factsTable, b *Block) {
2381 for _, v := range b.Values {
2382 switch v.Op {
2383 case OpSlicemask:
2384
2385 x, delta := isConstDelta(v.Args[0])
2386 if x == nil {
2387 break
2388 }
2389
2390
2391 lim := ft.limits[x.ID]
2392 if lim.umin > uint64(-delta) {
2393 if v.Args[0].Op == OpAdd64 {
2394 v.reset(OpConst64)
2395 } else {
2396 v.reset(OpConst32)
2397 }
2398 if b.Func.pass.debug > 0 {
2399 b.Func.Warnl(v.Pos, "Proved slicemask not needed")
2400 }
2401 v.AuxInt = -1
2402 }
2403 case OpCtz8, OpCtz16, OpCtz32, OpCtz64:
2404
2405
2406
2407 x := v.Args[0]
2408 lim := ft.limits[x.ID]
2409 if lim.umin > 0 || lim.min > 0 || lim.max < 0 {
2410 if b.Func.pass.debug > 0 {
2411 b.Func.Warnl(v.Pos, "Proved %v non-zero", v.Op)
2412 }
2413 v.Op = ctzNonZeroOp[v.Op]
2414 }
2415 case OpRsh8x8, OpRsh8x16, OpRsh8x32, OpRsh8x64,
2416 OpRsh16x8, OpRsh16x16, OpRsh16x32, OpRsh16x64,
2417 OpRsh32x8, OpRsh32x16, OpRsh32x32, OpRsh32x64,
2418 OpRsh64x8, OpRsh64x16, OpRsh64x32, OpRsh64x64:
2419
2420
2421 bits := 8 * v.Args[0].Type.Size()
2422 if v.Args[1].isGenericIntConst() && v.Args[1].AuxInt >= bits-1 && ft.isNonNegative(v.Args[0]) {
2423 if b.Func.pass.debug > 0 {
2424 b.Func.Warnl(v.Pos, "Proved %v shifts to zero", v.Op)
2425 }
2426 switch bits {
2427 case 64:
2428 v.reset(OpConst64)
2429 case 32:
2430 v.reset(OpConst32)
2431 case 16:
2432 v.reset(OpConst16)
2433 case 8:
2434 v.reset(OpConst8)
2435 default:
2436 panic("unexpected integer size")
2437 }
2438 v.AuxInt = 0
2439 break
2440 }
2441
2442 fallthrough
2443 case OpLsh8x8, OpLsh8x16, OpLsh8x32, OpLsh8x64,
2444 OpLsh16x8, OpLsh16x16, OpLsh16x32, OpLsh16x64,
2445 OpLsh32x8, OpLsh32x16, OpLsh32x32, OpLsh32x64,
2446 OpLsh64x8, OpLsh64x16, OpLsh64x32, OpLsh64x64,
2447 OpRsh8Ux8, OpRsh8Ux16, OpRsh8Ux32, OpRsh8Ux64,
2448 OpRsh16Ux8, OpRsh16Ux16, OpRsh16Ux32, OpRsh16Ux64,
2449 OpRsh32Ux8, OpRsh32Ux16, OpRsh32Ux32, OpRsh32Ux64,
2450 OpRsh64Ux8, OpRsh64Ux16, OpRsh64Ux32, OpRsh64Ux64:
2451
2452
2453 by := v.Args[1]
2454 lim := ft.limits[by.ID]
2455 bits := 8 * v.Args[0].Type.Size()
2456 if lim.umax < uint64(bits) || (lim.max < bits && ft.isNonNegative(by)) {
2457 v.AuxInt = 1
2458 if b.Func.pass.debug > 0 && !by.isGenericIntConst() {
2459 b.Func.Warnl(v.Pos, "Proved %v bounded", v.Op)
2460 }
2461 }
2462 case OpDiv16, OpDiv32, OpDiv64, OpMod16, OpMod32, OpMod64:
2463
2464
2465
2466
2467
2468 if b.Func.Config.arch != "386" && b.Func.Config.arch != "amd64" {
2469 break
2470 }
2471 divr := v.Args[1]
2472 divrLim := ft.limits[divr.ID]
2473 divd := v.Args[0]
2474 divdLim := ft.limits[divd.ID]
2475 if divrLim.max < -1 || divrLim.min > -1 || divdLim.min > mostNegativeDividend[v.Op] {
2476
2477
2478
2479
2480 v.AuxInt = 1
2481 if b.Func.pass.debug > 0 {
2482 b.Func.Warnl(v.Pos, "Proved %v does not need fix-up", v.Op)
2483 }
2484 }
2485 }
2486
2487
2488 for i, arg := range v.Args {
2489 lim := ft.limits[arg.ID]
2490 var constValue int64
2491 switch {
2492 case lim.min == lim.max:
2493 constValue = lim.min
2494 case lim.umin == lim.umax:
2495 constValue = int64(lim.umin)
2496 default:
2497 continue
2498 }
2499 switch arg.Op {
2500 case OpConst64, OpConst32, OpConst16, OpConst8, OpConstBool, OpConstNil:
2501 continue
2502 }
2503 typ := arg.Type
2504 f := b.Func
2505 var c *Value
2506 switch {
2507 case typ.IsBoolean():
2508 c = f.ConstBool(typ, constValue != 0)
2509 case typ.IsInteger() && typ.Size() == 1:
2510 c = f.ConstInt8(typ, int8(constValue))
2511 case typ.IsInteger() && typ.Size() == 2:
2512 c = f.ConstInt16(typ, int16(constValue))
2513 case typ.IsInteger() && typ.Size() == 4:
2514 c = f.ConstInt32(typ, int32(constValue))
2515 case typ.IsInteger() && typ.Size() == 8:
2516 c = f.ConstInt64(typ, constValue)
2517 case typ.IsPtrShaped():
2518 if constValue == 0 {
2519 c = f.ConstNil(typ)
2520 } else {
2521
2522
2523 continue
2524 }
2525 default:
2526
2527
2528 continue
2529 }
2530 v.SetArg(i, c)
2531 ft.initLimitForNewValue(c)
2532 if b.Func.pass.debug > 1 {
2533 b.Func.Warnl(v.Pos, "Proved %v's arg %d (%v) is constant %d", v, i, arg, constValue)
2534 }
2535 }
2536 }
2537
2538 if b.Kind != BlockIf {
2539 return
2540 }
2541
2542
2543 parent := b
2544 for i, branch := range [...]branch{positive, negative} {
2545 child := parent.Succs[i].b
2546 if getBranch(sdom, parent, child) != unknown {
2547
2548
2549 continue
2550 }
2551
2552
2553 ft.checkpoint()
2554 addBranchRestrictions(ft, parent, branch)
2555 unsat := ft.unsat
2556 ft.restore()
2557 if unsat {
2558
2559
2560 removeBranch(parent, branch)
2561
2562
2563
2564
2565
2566 break
2567 }
2568 }
2569 }
2570
2571 func removeBranch(b *Block, branch branch) {
2572 c := b.Controls[0]
2573 if b.Func.pass.debug > 0 {
2574 verb := "Proved"
2575 if branch == positive {
2576 verb = "Disproved"
2577 }
2578 if b.Func.pass.debug > 1 {
2579 b.Func.Warnl(b.Pos, "%s %s (%s)", verb, c.Op, c)
2580 } else {
2581 b.Func.Warnl(b.Pos, "%s %s", verb, c.Op)
2582 }
2583 }
2584 if c != nil && c.Pos.IsStmt() == src.PosIsStmt && c.Pos.SameFileAndLine(b.Pos) {
2585
2586 b.Pos = b.Pos.WithIsStmt()
2587 }
2588 if branch == positive || branch == negative {
2589 b.Kind = BlockFirst
2590 b.ResetControls()
2591 if branch == positive {
2592 b.swapSuccessors()
2593 }
2594 } else {
2595
2596 }
2597 }
2598
2599
2600 func isConstDelta(v *Value) (w *Value, delta int64) {
2601 cop := OpConst64
2602 switch v.Op {
2603 case OpAdd32, OpSub32:
2604 cop = OpConst32
2605 case OpAdd16, OpSub16:
2606 cop = OpConst16
2607 case OpAdd8, OpSub8:
2608 cop = OpConst8
2609 }
2610 switch v.Op {
2611 case OpAdd64, OpAdd32, OpAdd16, OpAdd8:
2612 if v.Args[0].Op == cop {
2613 return v.Args[1], v.Args[0].AuxInt
2614 }
2615 if v.Args[1].Op == cop {
2616 return v.Args[0], v.Args[1].AuxInt
2617 }
2618 case OpSub64, OpSub32, OpSub16, OpSub8:
2619 if v.Args[1].Op == cop {
2620 aux := v.Args[1].AuxInt
2621 if aux != -aux {
2622 return v.Args[0], -aux
2623 }
2624 }
2625 }
2626 return nil, 0
2627 }
2628
2629
2630
2631 func isCleanExt(v *Value) bool {
2632 switch v.Op {
2633 case OpSignExt8to16, OpSignExt8to32, OpSignExt8to64,
2634 OpSignExt16to32, OpSignExt16to64, OpSignExt32to64:
2635
2636 return v.Args[0].Type.IsSigned() && v.Type.IsSigned()
2637
2638 case OpZeroExt8to16, OpZeroExt8to32, OpZeroExt8to64,
2639 OpZeroExt16to32, OpZeroExt16to64, OpZeroExt32to64:
2640
2641 return !v.Args[0].Type.IsSigned()
2642 }
2643 return false
2644 }
2645
View as plain text