1
2
3
4
5 package ssa
6
7 import (
8 "cmd/internal/src"
9 "fmt"
10 "math"
11 )
12
13 type branch int
14
15 const (
16 unknown branch = iota
17 positive
18 negative
19 )
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 type relation uint
42
43 const (
44 lt relation = 1 << iota
45 eq
46 gt
47 )
48
49 var relationStrings = [...]string{
50 0: "none", lt: "<", eq: "==", lt | eq: "<=",
51 gt: ">", gt | lt: "!=", gt | eq: ">=", gt | eq | lt: "any",
52 }
53
54 func (r relation) String() string {
55 if r < relation(len(relationStrings)) {
56 return relationStrings[r]
57 }
58 return fmt.Sprintf("relation(%d)", uint(r))
59 }
60
61
62
63
64
65 type domain uint
66
67 const (
68 signed domain = 1 << iota
69 unsigned
70 pointer
71 boolean
72 )
73
74 var domainStrings = [...]string{
75 "signed", "unsigned", "pointer", "boolean",
76 }
77
78 func (d domain) String() string {
79 s := ""
80 for i, ds := range domainStrings {
81 if d&(1<<uint(i)) != 0 {
82 if len(s) != 0 {
83 s += "|"
84 }
85 s += ds
86 d &^= 1 << uint(i)
87 }
88 }
89 if d != 0 {
90 if len(s) != 0 {
91 s += "|"
92 }
93 s += fmt.Sprintf("0x%x", uint(d))
94 }
95 return s
96 }
97
98 type pair struct {
99 v, w *Value
100
101
102 d domain
103 }
104
105
106 type fact struct {
107 p pair
108 r relation
109 }
110
111
112 type limit struct {
113 min, max int64
114 umin, umax uint64
115 }
116
117 func (l limit) String() string {
118 return fmt.Sprintf("sm,SM,um,UM=%d,%d,%d,%d", l.min, l.max, l.umin, l.umax)
119 }
120
121 func (l limit) intersect(l2 limit) limit {
122 if l.min < l2.min {
123 l.min = l2.min
124 }
125 if l.umin < l2.umin {
126 l.umin = l2.umin
127 }
128 if l.max > l2.max {
129 l.max = l2.max
130 }
131 if l.umax > l2.umax {
132 l.umax = l2.umax
133 }
134 return l
135 }
136
137 var noLimit = limit{math.MinInt64, math.MaxInt64, 0, math.MaxUint64}
138
139
140 type limitFact struct {
141 vid ID
142 limit limit
143 }
144
145
146
147
148
149
150
151
152 type factsTable struct {
153
154
155
156
157
158 unsat bool
159 unsatDepth int
160
161 facts map[pair]relation
162 stack []fact
163
164
165
166
167 orderS *poset
168 orderU *poset
169
170
171 limits map[ID]limit
172 limitStack []limitFact
173
174
175
176
177 lens map[ID]*Value
178 caps map[ID]*Value
179
180
181 zero *Value
182 }
183
184
185
186 var checkpointFact = fact{}
187 var checkpointBound = limitFact{}
188
189 func newFactsTable(f *Func) *factsTable {
190 ft := &factsTable{}
191 ft.orderS = f.newPoset()
192 ft.orderU = f.newPoset()
193 ft.orderS.SetUnsigned(false)
194 ft.orderU.SetUnsigned(true)
195 ft.facts = make(map[pair]relation)
196 ft.stack = make([]fact, 4)
197 ft.limits = make(map[ID]limit)
198 ft.limitStack = make([]limitFact, 4)
199 ft.zero = f.ConstInt64(f.Config.Types.Int64, 0)
200 return ft
201 }
202
203
204
205 func (ft *factsTable) update(parent *Block, v, w *Value, d domain, r relation) {
206 if parent.Func.pass.debug > 2 {
207 parent.Func.Warnl(parent.Pos, "parent=%s, update %s %s %s", parent, v, w, r)
208 }
209
210 if ft.unsat {
211 return
212 }
213
214
215
216 if v == w {
217 if r&eq == 0 {
218 ft.unsat = true
219 }
220 return
221 }
222
223 if d == signed || d == unsigned {
224 var ok bool
225 order := ft.orderS
226 if d == unsigned {
227 order = ft.orderU
228 }
229 switch r {
230 case lt:
231 ok = order.SetOrder(v, w)
232 case gt:
233 ok = order.SetOrder(w, v)
234 case lt | eq:
235 ok = order.SetOrderOrEqual(v, w)
236 case gt | eq:
237 ok = order.SetOrderOrEqual(w, v)
238 case eq:
239 ok = order.SetEqual(v, w)
240 case lt | gt:
241 ok = order.SetNonEqual(v, w)
242 default:
243 panic("unknown relation")
244 }
245 if !ok {
246 if parent.Func.pass.debug > 2 {
247 parent.Func.Warnl(parent.Pos, "unsat %s %s %s", v, w, r)
248 }
249 ft.unsat = true
250 return
251 }
252 } else {
253 if lessByID(w, v) {
254 v, w = w, v
255 r = reverseBits[r]
256 }
257
258 p := pair{v, w, d}
259 oldR, ok := ft.facts[p]
260 if !ok {
261 if v == w {
262 oldR = eq
263 } else {
264 oldR = lt | eq | gt
265 }
266 }
267
268 if oldR == r {
269 return
270 }
271 ft.stack = append(ft.stack, fact{p, oldR})
272 ft.facts[p] = oldR & r
273
274 if oldR&r == 0 {
275 if parent.Func.pass.debug > 2 {
276 parent.Func.Warnl(parent.Pos, "unsat %s %s %s", v, w, r)
277 }
278 ft.unsat = true
279 return
280 }
281 }
282
283
284 if v.isGenericIntConst() {
285 v, w = w, v
286 r = reverseBits[r]
287 }
288 if v != nil && w.isGenericIntConst() {
289
290
291
292
293
294 old, ok := ft.limits[v.ID]
295 if !ok {
296 old = noLimit
297 if v.isGenericIntConst() {
298 switch d {
299 case signed:
300 old.min, old.max = v.AuxInt, v.AuxInt
301 if v.AuxInt >= 0 {
302 old.umin, old.umax = uint64(v.AuxInt), uint64(v.AuxInt)
303 }
304 case unsigned:
305 old.umin = v.AuxUnsigned()
306 old.umax = old.umin
307 if int64(old.umin) >= 0 {
308 old.min, old.max = int64(old.umin), int64(old.umin)
309 }
310 }
311 }
312 }
313 lim := noLimit
314 switch d {
315 case signed:
316 c := w.AuxInt
317 switch r {
318 case lt:
319 lim.max = c - 1
320 case lt | eq:
321 lim.max = c
322 case gt | eq:
323 lim.min = c
324 case gt:
325 lim.min = c + 1
326 case lt | gt:
327 lim = old
328 if c == lim.min {
329 lim.min++
330 }
331 if c == lim.max {
332 lim.max--
333 }
334 case eq:
335 lim.min = c
336 lim.max = c
337 }
338 if lim.min >= 0 {
339
340 lim.umin = uint64(lim.min)
341 }
342 if lim.max != noLimit.max && old.min >= 0 && lim.max >= 0 {
343
344
345
346 lim.umax = uint64(lim.max)
347 }
348 case unsigned:
349 uc := w.AuxUnsigned()
350 switch r {
351 case lt:
352 lim.umax = uc - 1
353 case lt | eq:
354 lim.umax = uc
355 case gt | eq:
356 lim.umin = uc
357 case gt:
358 lim.umin = uc + 1
359 case lt | gt:
360 lim = old
361 if uc == lim.umin {
362 lim.umin++
363 }
364 if uc == lim.umax {
365 lim.umax--
366 }
367 case eq:
368 lim.umin = uc
369 lim.umax = uc
370 }
371
372
373
374 }
375 ft.limitStack = append(ft.limitStack, limitFact{v.ID, old})
376 lim = old.intersect(lim)
377 ft.limits[v.ID] = lim
378 if v.Block.Func.pass.debug > 2 {
379 v.Block.Func.Warnl(parent.Pos, "parent=%s, new limits %s %s %s %s", parent, v, w, r, lim.String())
380 }
381 if lim.min > lim.max || lim.umin > lim.umax {
382 ft.unsat = true
383 return
384 }
385 }
386
387
388 if d != signed && d != unsigned {
389 return
390 }
391
392
393
394
395
396
397 if v.Op == OpSliceLen && r< == 0 && ft.caps[v.Args[0].ID] != nil {
398
399
400
401 ft.update(parent, ft.caps[v.Args[0].ID], w, d, r|gt)
402 }
403 if w.Op == OpSliceLen && r> == 0 && ft.caps[w.Args[0].ID] != nil {
404
405 ft.update(parent, v, ft.caps[w.Args[0].ID], d, r|lt)
406 }
407 if v.Op == OpSliceCap && r> == 0 && ft.lens[v.Args[0].ID] != nil {
408
409
410
411 ft.update(parent, ft.lens[v.Args[0].ID], w, d, r|lt)
412 }
413 if w.Op == OpSliceCap && r< == 0 && ft.lens[w.Args[0].ID] != nil {
414
415 ft.update(parent, v, ft.lens[w.Args[0].ID], d, r|gt)
416 }
417
418
419
420
421 if r == lt || r == lt|eq {
422 v, w = w, v
423 r = reverseBits[r]
424 }
425 switch r {
426 case gt:
427 if x, delta := isConstDelta(v); x != nil && delta == 1 {
428
429
430
431
432 ft.update(parent, x, w, d, gt|eq)
433 } else if x, delta := isConstDelta(w); x != nil && delta == -1 {
434
435 ft.update(parent, v, x, d, gt|eq)
436 }
437 case gt | eq:
438 if x, delta := isConstDelta(v); x != nil && delta == -1 {
439
440
441
442 lim, ok := ft.limits[x.ID]
443 if ok && ((d == signed && lim.min > opMin[v.Op]) || (d == unsigned && lim.umin > 0)) {
444 ft.update(parent, x, w, d, gt)
445 }
446 } else if x, delta := isConstDelta(w); x != nil && delta == 1 {
447
448 lim, ok := ft.limits[x.ID]
449 if ok && ((d == signed && lim.max < opMax[w.Op]) || (d == unsigned && lim.umax < opUMax[w.Op])) {
450 ft.update(parent, v, x, d, gt)
451 }
452 }
453 }
454
455
456
457 if r == gt || r == gt|eq {
458 if x, delta := isConstDelta(v); x != nil && d == signed {
459 if parent.Func.pass.debug > 1 {
460 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)
461 }
462 if !w.isGenericIntConst() {
463
464
465
466 if l, has := ft.limits[x.ID]; has && delta < 0 {
467 if (x.Type.Size() == 8 && l.min >= math.MinInt64-delta) ||
468 (x.Type.Size() == 4 && l.min >= math.MinInt32-delta) {
469 ft.update(parent, x, w, signed, r)
470 }
471 }
472 } else {
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490 var min, max int64
491 var vmin, vmax *Value
492 switch x.Type.Size() {
493 case 8:
494 min = w.AuxInt - delta
495 max = int64(^uint64(0)>>1) - delta
496
497 vmin = parent.NewValue0I(parent.Pos, OpConst64, parent.Func.Config.Types.Int64, min)
498 vmax = parent.NewValue0I(parent.Pos, OpConst64, parent.Func.Config.Types.Int64, max)
499
500 case 4:
501 min = int64(int32(w.AuxInt) - int32(delta))
502 max = int64(int32(^uint32(0)>>1) - int32(delta))
503
504 vmin = parent.NewValue0I(parent.Pos, OpConst32, parent.Func.Config.Types.Int32, min)
505 vmax = parent.NewValue0I(parent.Pos, OpConst32, parent.Func.Config.Types.Int32, max)
506
507 default:
508 panic("unimplemented")
509 }
510
511 if min < max {
512
513 ft.update(parent, x, vmin, d, r)
514 ft.update(parent, vmax, x, d, r|eq)
515 } else {
516
517
518
519 if l, has := ft.limits[x.ID]; has {
520 if l.max <= min {
521 if r&eq == 0 || l.max < min {
522
523 ft.update(parent, vmax, x, d, r|eq)
524 }
525 } else if l.min > max {
526
527 ft.update(parent, x, vmin, d, r)
528 }
529 }
530 }
531 }
532 }
533 }
534
535
536
537
538 if isCleanExt(v) {
539 switch {
540 case d == signed && v.Args[0].Type.IsSigned():
541 fallthrough
542 case d == unsigned && !v.Args[0].Type.IsSigned():
543 ft.update(parent, v.Args[0], w, d, r)
544 }
545 }
546 if isCleanExt(w) {
547 switch {
548 case d == signed && w.Args[0].Type.IsSigned():
549 fallthrough
550 case d == unsigned && !w.Args[0].Type.IsSigned():
551 ft.update(parent, v, w.Args[0], d, r)
552 }
553 }
554 }
555
556 var opMin = map[Op]int64{
557 OpAdd64: math.MinInt64, OpSub64: math.MinInt64,
558 OpAdd32: math.MinInt32, OpSub32: math.MinInt32,
559 }
560
561 var opMax = map[Op]int64{
562 OpAdd64: math.MaxInt64, OpSub64: math.MaxInt64,
563 OpAdd32: math.MaxInt32, OpSub32: math.MaxInt32,
564 }
565
566 var opUMax = map[Op]uint64{
567 OpAdd64: math.MaxUint64, OpSub64: math.MaxUint64,
568 OpAdd32: math.MaxUint32, OpSub32: math.MaxUint32,
569 }
570
571
572 func (ft *factsTable) isNonNegative(v *Value) bool {
573 if isNonNegative(v) {
574 return true
575 }
576
577 var max int64
578 switch v.Type.Size() {
579 case 1:
580 max = math.MaxInt8
581 case 2:
582 max = math.MaxInt16
583 case 4:
584 max = math.MaxInt32
585 case 8:
586 max = math.MaxInt64
587 default:
588 panic("unexpected integer size")
589 }
590
591
592
593 if l, has := ft.limits[v.ID]; has && (l.min >= 0 || l.umax <= uint64(max)) {
594 return true
595 }
596
597
598 if x, delta := isConstDelta(v); x != nil {
599 if l, has := ft.limits[x.ID]; has {
600 if delta > 0 && l.min >= -delta && l.max <= max-delta {
601 return true
602 }
603 if delta < 0 && l.min >= -delta {
604 return true
605 }
606 }
607 }
608
609
610 if isCleanExt(v) && ft.isNonNegative(v.Args[0]) {
611 return true
612 }
613
614
615 return ft.orderS.OrderedOrEqual(ft.zero, v)
616 }
617
618
619
620 func (ft *factsTable) checkpoint() {
621 if ft.unsat {
622 ft.unsatDepth++
623 }
624 ft.stack = append(ft.stack, checkpointFact)
625 ft.limitStack = append(ft.limitStack, checkpointBound)
626 ft.orderS.Checkpoint()
627 ft.orderU.Checkpoint()
628 }
629
630
631
632
633 func (ft *factsTable) restore() {
634 if ft.unsatDepth > 0 {
635 ft.unsatDepth--
636 } else {
637 ft.unsat = false
638 }
639 for {
640 old := ft.stack[len(ft.stack)-1]
641 ft.stack = ft.stack[:len(ft.stack)-1]
642 if old == checkpointFact {
643 break
644 }
645 if old.r == lt|eq|gt {
646 delete(ft.facts, old.p)
647 } else {
648 ft.facts[old.p] = old.r
649 }
650 }
651 for {
652 old := ft.limitStack[len(ft.limitStack)-1]
653 ft.limitStack = ft.limitStack[:len(ft.limitStack)-1]
654 if old.vid == 0 {
655 break
656 }
657 if old.limit == noLimit {
658 delete(ft.limits, old.vid)
659 } else {
660 ft.limits[old.vid] = old.limit
661 }
662 }
663 ft.orderS.Undo()
664 ft.orderU.Undo()
665 }
666
667 func lessByID(v, w *Value) bool {
668 if v == nil && w == nil {
669
670 return false
671 }
672 if v == nil {
673 return true
674 }
675 return w != nil && v.ID < w.ID
676 }
677
678 var (
679 reverseBits = [...]relation{0, 4, 2, 6, 1, 5, 3, 7}
680
681
682
683
684
685
686
687 domainRelationTable = map[Op]struct {
688 d domain
689 r relation
690 }{
691 OpEq8: {signed | unsigned, eq},
692 OpEq16: {signed | unsigned, eq},
693 OpEq32: {signed | unsigned, eq},
694 OpEq64: {signed | unsigned, eq},
695 OpEqPtr: {pointer, eq},
696
697 OpNeq8: {signed | unsigned, lt | gt},
698 OpNeq16: {signed | unsigned, lt | gt},
699 OpNeq32: {signed | unsigned, lt | gt},
700 OpNeq64: {signed | unsigned, lt | gt},
701 OpNeqPtr: {pointer, lt | gt},
702
703 OpLess8: {signed, lt},
704 OpLess8U: {unsigned, lt},
705 OpLess16: {signed, lt},
706 OpLess16U: {unsigned, lt},
707 OpLess32: {signed, lt},
708 OpLess32U: {unsigned, lt},
709 OpLess64: {signed, lt},
710 OpLess64U: {unsigned, lt},
711
712 OpLeq8: {signed, lt | eq},
713 OpLeq8U: {unsigned, lt | eq},
714 OpLeq16: {signed, lt | eq},
715 OpLeq16U: {unsigned, lt | eq},
716 OpLeq32: {signed, lt | eq},
717 OpLeq32U: {unsigned, lt | eq},
718 OpLeq64: {signed, lt | eq},
719 OpLeq64U: {unsigned, lt | eq},
720
721
722
723
724 OpIsInBounds: {signed | unsigned, lt},
725 OpIsSliceInBounds: {signed | unsigned, lt | eq},
726 }
727 )
728
729
730 func (ft *factsTable) cleanup(f *Func) {
731 for _, po := range []*poset{ft.orderS, ft.orderU} {
732
733
734 if checkEnabled {
735 if err := po.CheckEmpty(); err != nil {
736 f.Fatalf("poset not empty after function %s: %v", f.Name, err)
737 }
738 }
739 f.retPoset(po)
740 }
741 }
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774 func prove(f *Func) {
775 ft := newFactsTable(f)
776 ft.checkpoint()
777
778 var lensVars map[*Block][]*Value
779
780
781 for _, b := range f.Blocks {
782 for _, v := range b.Values {
783 if v.Uses == 0 {
784
785
786 continue
787 }
788 switch v.Op {
789 case OpStringLen:
790 ft.update(b, v, ft.zero, signed, gt|eq)
791 case OpSliceLen:
792 if ft.lens == nil {
793 ft.lens = map[ID]*Value{}
794 }
795
796
797
798 if l, ok := ft.lens[v.Args[0].ID]; ok {
799 ft.update(b, v, l, signed, eq)
800 } else {
801 ft.lens[v.Args[0].ID] = v
802 }
803 ft.update(b, v, ft.zero, signed, gt|eq)
804 if v.Args[0].Op == OpSliceMake {
805 if lensVars == nil {
806 lensVars = make(map[*Block][]*Value)
807 }
808 lensVars[b] = append(lensVars[b], v)
809 }
810 case OpSliceCap:
811 if ft.caps == nil {
812 ft.caps = map[ID]*Value{}
813 }
814
815 if c, ok := ft.caps[v.Args[0].ID]; ok {
816 ft.update(b, v, c, signed, eq)
817 } else {
818 ft.caps[v.Args[0].ID] = v
819 }
820 ft.update(b, v, ft.zero, signed, gt|eq)
821 if v.Args[0].Op == OpSliceMake {
822 if lensVars == nil {
823 lensVars = make(map[*Block][]*Value)
824 }
825 lensVars[b] = append(lensVars[b], v)
826 }
827 }
828 }
829 }
830
831
832
833 var indVars map[*Block]indVar
834 for _, v := range findIndVar(f) {
835 if indVars == nil {
836 indVars = make(map[*Block]indVar)
837 }
838 indVars[v.entry] = v
839 }
840
841
842 type walkState int
843 const (
844 descend walkState = iota
845 simplify
846 )
847
848 type bp struct {
849 block *Block
850 state walkState
851 }
852 work := make([]bp, 0, 256)
853 work = append(work, bp{
854 block: f.Entry,
855 state: descend,
856 })
857
858 idom := f.Idom()
859 sdom := f.Sdom()
860
861
862
863
864
865
866
867
868
869
870
871 for len(work) > 0 {
872 node := work[len(work)-1]
873 work = work[:len(work)-1]
874 parent := idom[node.block.ID]
875 branch := getBranch(sdom, parent, node.block)
876
877 switch node.state {
878 case descend:
879 ft.checkpoint()
880
881
882
883 if iv, ok := indVars[node.block]; ok {
884 addIndVarRestrictions(ft, parent, iv)
885 }
886 if lens, ok := lensVars[node.block]; ok {
887 for _, v := range lens {
888 switch v.Op {
889 case OpSliceLen:
890 ft.update(node.block, v, v.Args[0].Args[1], signed, eq)
891 case OpSliceCap:
892 ft.update(node.block, v, v.Args[0].Args[2], signed, eq)
893 }
894 }
895 }
896
897 if branch != unknown {
898 addBranchRestrictions(ft, parent, branch)
899 if ft.unsat {
900
901
902
903 removeBranch(parent, branch)
904 ft.restore()
905 break
906 }
907
908
909
910 }
911
912
913 addLocalInductiveFacts(ft, node.block)
914
915 work = append(work, bp{
916 block: node.block,
917 state: simplify,
918 })
919 for s := sdom.Child(node.block); s != nil; s = sdom.Sibling(s) {
920 work = append(work, bp{
921 block: s,
922 state: descend,
923 })
924 }
925
926 case simplify:
927 simplifyBlock(sdom, ft, node.block)
928 ft.restore()
929 }
930 }
931
932 ft.restore()
933
934 ft.cleanup(f)
935 }
936
937
938
939 func getBranch(sdom SparseTree, p *Block, b *Block) branch {
940 if p == nil || p.Kind != BlockIf {
941 return unknown
942 }
943
944
945
946
947
948
949 if sdom.IsAncestorEq(p.Succs[0].b, b) && len(p.Succs[0].b.Preds) == 1 {
950 return positive
951 }
952 if sdom.IsAncestorEq(p.Succs[1].b, b) && len(p.Succs[1].b.Preds) == 1 {
953 return negative
954 }
955 return unknown
956 }
957
958
959
960
961 func addIndVarRestrictions(ft *factsTable, b *Block, iv indVar) {
962 d := signed
963 if ft.isNonNegative(iv.min) && ft.isNonNegative(iv.max) {
964 d |= unsigned
965 }
966
967 if iv.flags&indVarMinExc == 0 {
968 addRestrictions(b, ft, d, iv.min, iv.ind, lt|eq)
969 } else {
970 addRestrictions(b, ft, d, iv.min, iv.ind, lt)
971 }
972
973 if iv.flags&indVarMaxInc == 0 {
974 addRestrictions(b, ft, d, iv.ind, iv.max, lt)
975 } else {
976 addRestrictions(b, ft, d, iv.ind, iv.max, lt|eq)
977 }
978 }
979
980
981
982 func addBranchRestrictions(ft *factsTable, b *Block, br branch) {
983 c := b.Controls[0]
984 switch br {
985 case negative:
986 addRestrictions(b, ft, boolean, nil, c, eq)
987 case positive:
988 addRestrictions(b, ft, boolean, nil, c, lt|gt)
989 default:
990 panic("unknown branch")
991 }
992 if tr, has := domainRelationTable[c.Op]; has {
993
994
995 d := tr.d
996 if d == signed && ft.isNonNegative(c.Args[0]) && ft.isNonNegative(c.Args[1]) {
997 d |= unsigned
998 }
999 switch c.Op {
1000 case OpIsInBounds, OpIsSliceInBounds:
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014 switch br {
1015 case negative:
1016 d = unsigned
1017 if ft.isNonNegative(c.Args[0]) {
1018 d |= signed
1019 }
1020 addRestrictions(b, ft, d, c.Args[0], c.Args[1], tr.r^(lt|gt|eq))
1021 case positive:
1022 addRestrictions(b, ft, signed, ft.zero, c.Args[0], lt|eq)
1023 addRestrictions(b, ft, d, c.Args[0], c.Args[1], tr.r)
1024 }
1025 default:
1026 switch br {
1027 case negative:
1028 addRestrictions(b, ft, d, c.Args[0], c.Args[1], tr.r^(lt|gt|eq))
1029 case positive:
1030 addRestrictions(b, ft, d, c.Args[0], c.Args[1], tr.r)
1031 }
1032 }
1033
1034 }
1035 }
1036
1037
1038
1039 func addRestrictions(parent *Block, ft *factsTable, t domain, v, w *Value, r relation) {
1040 if t == 0 {
1041
1042
1043 return
1044 }
1045 for i := domain(1); i <= t; i <<= 1 {
1046 if t&i == 0 {
1047 continue
1048 }
1049 ft.update(parent, v, w, i, r)
1050 }
1051 }
1052
1053
1054
1055
1056
1057
1058
1059
1060 func addLocalInductiveFacts(ft *factsTable, b *Block) {
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071 if len(b.Preds) != 2 {
1072 return
1073 }
1074
1075 for _, i1 := range b.Values {
1076 if i1.Op != OpPhi {
1077 continue
1078 }
1079
1080
1081
1082 min, i2 := i1.Args[0], i1.Args[1]
1083 if i1q, delta := isConstDelta(i2); i1q != i1 || delta != 1 {
1084 continue
1085 }
1086
1087
1088
1089
1090
1091
1092
1093
1094 uniquePred := func(b *Block) *Block {
1095 if len(b.Preds) == 1 {
1096 return b.Preds[0].b
1097 }
1098 return nil
1099 }
1100 pred, child := b.Preds[1].b, b
1101 for ; pred != nil; pred, child = uniquePred(pred), pred {
1102 if pred.Kind != BlockIf {
1103 continue
1104 }
1105 control := pred.Controls[0]
1106
1107 br := unknown
1108 if pred.Succs[0].b == child {
1109 br = positive
1110 }
1111 if pred.Succs[1].b == child {
1112 if br != unknown {
1113 continue
1114 }
1115 br = negative
1116 }
1117 if br == unknown {
1118 continue
1119 }
1120
1121 tr, has := domainRelationTable[control.Op]
1122 if !has {
1123 continue
1124 }
1125 r := tr.r
1126 if br == negative {
1127
1128
1129 r = (lt | eq | gt) ^ r
1130 }
1131
1132
1133 var max *Value
1134 if r == lt && control.Args[0] == i2 {
1135 max = control.Args[1]
1136 } else if r == gt && control.Args[1] == i2 {
1137 max = control.Args[0]
1138 } else {
1139 continue
1140 }
1141
1142
1143
1144
1145
1146
1147 ft.checkpoint()
1148 ft.update(b, min, max, tr.d, gt|eq)
1149 proved := ft.unsat
1150 ft.restore()
1151
1152 if proved {
1153
1154 if b.Func.pass.debug > 0 {
1155 printIndVar(b, i1, min, max, 1, 0)
1156 }
1157 ft.update(b, min, i1, tr.d, lt|eq)
1158 ft.update(b, i1, max, tr.d, lt)
1159 }
1160 }
1161 }
1162 }
1163
1164 var ctzNonZeroOp = map[Op]Op{OpCtz8: OpCtz8NonZero, OpCtz16: OpCtz16NonZero, OpCtz32: OpCtz32NonZero, OpCtz64: OpCtz64NonZero}
1165 var mostNegativeDividend = map[Op]int64{
1166 OpDiv16: -1 << 15,
1167 OpMod16: -1 << 15,
1168 OpDiv32: -1 << 31,
1169 OpMod32: -1 << 31,
1170 OpDiv64: -1 << 63,
1171 OpMod64: -1 << 63}
1172
1173
1174
1175 func simplifyBlock(sdom SparseTree, ft *factsTable, b *Block) {
1176 for _, v := range b.Values {
1177 switch v.Op {
1178 case OpSlicemask:
1179
1180 x, delta := isConstDelta(v.Args[0])
1181 if x == nil {
1182 continue
1183 }
1184
1185
1186 lim, ok := ft.limits[x.ID]
1187 if !ok {
1188 continue
1189 }
1190 if lim.umin > uint64(-delta) {
1191 if v.Args[0].Op == OpAdd64 {
1192 v.reset(OpConst64)
1193 } else {
1194 v.reset(OpConst32)
1195 }
1196 if b.Func.pass.debug > 0 {
1197 b.Func.Warnl(v.Pos, "Proved slicemask not needed")
1198 }
1199 v.AuxInt = -1
1200 }
1201 case OpCtz8, OpCtz16, OpCtz32, OpCtz64:
1202
1203
1204
1205 x := v.Args[0]
1206 lim, ok := ft.limits[x.ID]
1207 if !ok {
1208 continue
1209 }
1210 if lim.umin > 0 || lim.min > 0 || lim.max < 0 {
1211 if b.Func.pass.debug > 0 {
1212 b.Func.Warnl(v.Pos, "Proved %v non-zero", v.Op)
1213 }
1214 v.Op = ctzNonZeroOp[v.Op]
1215 }
1216 case OpRsh8x8, OpRsh8x16, OpRsh8x32, OpRsh8x64,
1217 OpRsh16x8, OpRsh16x16, OpRsh16x32, OpRsh16x64,
1218 OpRsh32x8, OpRsh32x16, OpRsh32x32, OpRsh32x64,
1219 OpRsh64x8, OpRsh64x16, OpRsh64x32, OpRsh64x64:
1220
1221
1222 bits := 8 * v.Type.Size()
1223 if v.Args[1].isGenericIntConst() && v.Args[1].AuxInt >= bits-1 && ft.isNonNegative(v.Args[0]) {
1224 if b.Func.pass.debug > 0 {
1225 b.Func.Warnl(v.Pos, "Proved %v shifts to zero", v.Op)
1226 }
1227 switch bits {
1228 case 64:
1229 v.reset(OpConst64)
1230 case 32:
1231 v.reset(OpConst32)
1232 case 16:
1233 v.reset(OpConst16)
1234 case 8:
1235 v.reset(OpConst8)
1236 default:
1237 panic("unexpected integer size")
1238 }
1239 v.AuxInt = 0
1240 continue
1241 }
1242
1243 fallthrough
1244 case OpLsh8x8, OpLsh8x16, OpLsh8x32, OpLsh8x64,
1245 OpLsh16x8, OpLsh16x16, OpLsh16x32, OpLsh16x64,
1246 OpLsh32x8, OpLsh32x16, OpLsh32x32, OpLsh32x64,
1247 OpLsh64x8, OpLsh64x16, OpLsh64x32, OpLsh64x64,
1248 OpRsh8Ux8, OpRsh8Ux16, OpRsh8Ux32, OpRsh8Ux64,
1249 OpRsh16Ux8, OpRsh16Ux16, OpRsh16Ux32, OpRsh16Ux64,
1250 OpRsh32Ux8, OpRsh32Ux16, OpRsh32Ux32, OpRsh32Ux64,
1251 OpRsh64Ux8, OpRsh64Ux16, OpRsh64Ux32, OpRsh64Ux64:
1252
1253
1254 by := v.Args[1]
1255 lim, ok := ft.limits[by.ID]
1256 if !ok {
1257 continue
1258 }
1259 bits := 8 * v.Args[0].Type.Size()
1260 if lim.umax < uint64(bits) || (lim.max < bits && ft.isNonNegative(by)) {
1261 v.AuxInt = 1
1262 if b.Func.pass.debug > 0 {
1263 b.Func.Warnl(v.Pos, "Proved %v bounded", v.Op)
1264 }
1265 }
1266 case OpDiv16, OpDiv32, OpDiv64, OpMod16, OpMod32, OpMod64:
1267
1268
1269
1270
1271
1272 if b.Func.Config.arch != "386" && b.Func.Config.arch != "amd64" {
1273 break
1274 }
1275 divr := v.Args[1]
1276 divrLim, divrLimok := ft.limits[divr.ID]
1277 divd := v.Args[0]
1278 divdLim, divdLimok := ft.limits[divd.ID]
1279 if (divrLimok && (divrLim.max < -1 || divrLim.min > -1)) ||
1280 (divdLimok && divdLim.min > mostNegativeDividend[v.Op]) {
1281
1282
1283
1284
1285 v.AuxInt = 1
1286 if b.Func.pass.debug > 0 {
1287 b.Func.Warnl(v.Pos, "Proved %v does not need fix-up", v.Op)
1288 }
1289 }
1290 }
1291 }
1292
1293 if b.Kind != BlockIf {
1294 return
1295 }
1296
1297
1298 parent := b
1299 for i, branch := range [...]branch{positive, negative} {
1300 child := parent.Succs[i].b
1301 if getBranch(sdom, parent, child) != unknown {
1302
1303
1304 continue
1305 }
1306
1307
1308 ft.checkpoint()
1309 addBranchRestrictions(ft, parent, branch)
1310 unsat := ft.unsat
1311 ft.restore()
1312 if unsat {
1313
1314
1315 removeBranch(parent, branch)
1316
1317
1318
1319
1320
1321 break
1322 }
1323 }
1324 }
1325
1326 func removeBranch(b *Block, branch branch) {
1327 c := b.Controls[0]
1328 if b.Func.pass.debug > 0 {
1329 verb := "Proved"
1330 if branch == positive {
1331 verb = "Disproved"
1332 }
1333 if b.Func.pass.debug > 1 {
1334 b.Func.Warnl(b.Pos, "%s %s (%s)", verb, c.Op, c)
1335 } else {
1336 b.Func.Warnl(b.Pos, "%s %s", verb, c.Op)
1337 }
1338 }
1339 if c != nil && c.Pos.IsStmt() == src.PosIsStmt && c.Pos.SameFileAndLine(b.Pos) {
1340
1341 b.Pos = b.Pos.WithIsStmt()
1342 }
1343 b.Kind = BlockFirst
1344 b.ResetControls()
1345 if branch == positive {
1346 b.swapSuccessors()
1347 }
1348 }
1349
1350
1351 func isNonNegative(v *Value) bool {
1352 if !v.Type.IsInteger() {
1353 v.Fatalf("isNonNegative bad type: %v", v.Type)
1354 }
1355
1356
1357
1358
1359 switch v.Op {
1360 case OpConst64:
1361 return v.AuxInt >= 0
1362
1363 case OpConst32:
1364 return int32(v.AuxInt) >= 0
1365
1366 case OpConst16:
1367 return int16(v.AuxInt) >= 0
1368
1369 case OpConst8:
1370 return int8(v.AuxInt) >= 0
1371
1372 case OpStringLen, OpSliceLen, OpSliceCap,
1373 OpZeroExt8to64, OpZeroExt16to64, OpZeroExt32to64,
1374 OpZeroExt8to32, OpZeroExt16to32, OpZeroExt8to16,
1375 OpCtz64, OpCtz32, OpCtz16, OpCtz8:
1376 return true
1377
1378 case OpRsh64Ux64, OpRsh32Ux64:
1379 by := v.Args[1]
1380 return by.Op == OpConst64 && by.AuxInt > 0
1381
1382 case OpRsh64x64, OpRsh32x64, OpRsh8x64, OpRsh16x64, OpRsh32x32, OpRsh64x32,
1383 OpSignExt32to64, OpSignExt16to64, OpSignExt8to64, OpSignExt16to32, OpSignExt8to32:
1384 return isNonNegative(v.Args[0])
1385
1386 case OpAnd64, OpAnd32, OpAnd16, OpAnd8:
1387 return isNonNegative(v.Args[0]) || isNonNegative(v.Args[1])
1388
1389 case OpMod64, OpMod32, OpMod16, OpMod8,
1390 OpDiv64, OpDiv32, OpDiv16, OpDiv8,
1391 OpOr64, OpOr32, OpOr16, OpOr8,
1392 OpXor64, OpXor32, OpXor16, OpXor8:
1393 return isNonNegative(v.Args[0]) && isNonNegative(v.Args[1])
1394
1395
1396
1397 }
1398 return false
1399 }
1400
1401
1402 func isConstDelta(v *Value) (w *Value, delta int64) {
1403 cop := OpConst64
1404 switch v.Op {
1405 case OpAdd32, OpSub32:
1406 cop = OpConst32
1407 }
1408 switch v.Op {
1409 case OpAdd64, OpAdd32:
1410 if v.Args[0].Op == cop {
1411 return v.Args[1], v.Args[0].AuxInt
1412 }
1413 if v.Args[1].Op == cop {
1414 return v.Args[0], v.Args[1].AuxInt
1415 }
1416 case OpSub64, OpSub32:
1417 if v.Args[1].Op == cop {
1418 aux := v.Args[1].AuxInt
1419 if aux != -aux {
1420 return v.Args[0], -aux
1421 }
1422 }
1423 }
1424 return nil, 0
1425 }
1426
1427
1428
1429 func isCleanExt(v *Value) bool {
1430 switch v.Op {
1431 case OpSignExt8to16, OpSignExt8to32, OpSignExt8to64,
1432 OpSignExt16to32, OpSignExt16to64, OpSignExt32to64:
1433
1434 return v.Args[0].Type.IsSigned() && v.Type.IsSigned()
1435
1436 case OpZeroExt8to16, OpZeroExt8to32, OpZeroExt8to64,
1437 OpZeroExt16to32, OpZeroExt16to64, OpZeroExt32to64:
1438
1439 return !v.Args[0].Type.IsSigned()
1440 }
1441 return false
1442 }
1443
View as plain text