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