Source file src/pkg/cmd/compile/internal/ssa/poset.go
1
2
3
4
5 package ssa
6
7 import (
8 "errors"
9 "fmt"
10 "os"
11 )
12
13 const uintSize = 32 << (^uint(0) >> 32 & 1)
14
15
16 type bitset []uint
17
18 func newBitset(n int) bitset {
19 return make(bitset, (n+uintSize-1)/uintSize)
20 }
21
22 func (bs bitset) Reset() {
23 for i := range bs {
24 bs[i] = 0
25 }
26 }
27
28 func (bs bitset) Set(idx uint32) {
29 bs[idx/uintSize] |= 1 << (idx % uintSize)
30 }
31
32 func (bs bitset) Clear(idx uint32) {
33 bs[idx/uintSize] &^= 1 << (idx % uintSize)
34 }
35
36 func (bs bitset) Test(idx uint32) bool {
37 return bs[idx/uintSize]&(1<<(idx%uintSize)) != 0
38 }
39
40 type undoType uint8
41
42 const (
43 undoInvalid undoType = iota
44 undoCheckpoint
45 undoSetChl
46 undoSetChr
47 undoNonEqual
48 undoNewNode
49 undoAliasNode
50 undoNewRoot
51 undoChangeRoot
52 undoMergeRoot
53 )
54
55
56
57
58
59 type posetUndo struct {
60 typ undoType
61 idx uint32
62 ID ID
63 edge posetEdge
64 }
65
66 const (
67
68 posetFlagUnsigned = 1 << iota
69 )
70
71
72
73 type posetEdge uint32
74
75 func newedge(t uint32, strict bool) posetEdge {
76 s := uint32(0)
77 if strict {
78 s = 1
79 }
80 return posetEdge(t<<1 | s)
81 }
82 func (e posetEdge) Target() uint32 { return uint32(e) >> 1 }
83 func (e posetEdge) Strict() bool { return uint32(e)&1 != 0 }
84 func (e posetEdge) String() string {
85 s := fmt.Sprint(e.Target())
86 if e.Strict() {
87 s += "*"
88 }
89 return s
90 }
91
92
93 type posetNode struct {
94 l, r posetEdge
95 }
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144 type poset struct {
145 lastidx uint32
146 flags uint8
147 values map[ID]uint32
148 constants []*Value
149 nodes []posetNode
150 roots []uint32
151 noneq map[ID]bitset
152 undo []posetUndo
153 }
154
155 func newPoset() *poset {
156 return &poset{
157 values: make(map[ID]uint32),
158 constants: make([]*Value, 0, 8),
159 nodes: make([]posetNode, 1, 16),
160 roots: make([]uint32, 0, 4),
161 noneq: make(map[ID]bitset),
162 undo: make([]posetUndo, 0, 4),
163 }
164 }
165
166 func (po *poset) SetUnsigned(uns bool) {
167 if uns {
168 po.flags |= posetFlagUnsigned
169 } else {
170 po.flags &^= posetFlagUnsigned
171 }
172 }
173
174
175 func (po *poset) setchl(i uint32, l posetEdge) { po.nodes[i].l = l }
176 func (po *poset) setchr(i uint32, r posetEdge) { po.nodes[i].r = r }
177 func (po *poset) chl(i uint32) uint32 { return po.nodes[i].l.Target() }
178 func (po *poset) chr(i uint32) uint32 { return po.nodes[i].r.Target() }
179 func (po *poset) children(i uint32) (posetEdge, posetEdge) {
180 return po.nodes[i].l, po.nodes[i].r
181 }
182
183
184
185 func (po *poset) upush(typ undoType, p uint32, e posetEdge) {
186 po.undo = append(po.undo, posetUndo{typ: typ, idx: p, edge: e})
187 }
188
189
190 func (po *poset) upushnew(id ID, idx uint32) {
191 po.undo = append(po.undo, posetUndo{typ: undoNewNode, ID: id, idx: idx})
192 }
193
194
195 func (po *poset) upushneq(id1 ID, id2 ID) {
196 po.undo = append(po.undo, posetUndo{typ: undoNonEqual, ID: id1, idx: uint32(id2)})
197 }
198
199
200 func (po *poset) upushalias(id ID, i2 uint32) {
201 po.undo = append(po.undo, posetUndo{typ: undoAliasNode, ID: id, idx: i2})
202 }
203
204
205 func (po *poset) addchild(i1, i2 uint32, strict bool) {
206 i1l, i1r := po.children(i1)
207 e2 := newedge(i2, strict)
208
209 if i1l == 0 {
210 po.setchl(i1, e2)
211 po.upush(undoSetChl, i1, 0)
212 } else if i1r == 0 {
213 po.setchr(i1, e2)
214 po.upush(undoSetChr, i1, 0)
215 } else {
216
217
218
219
220
221
222
223
224
225
226
227
228 dummy := po.newnode(nil)
229 if (i1^i2)&1 != 0 {
230 po.setchl(dummy, i1r)
231 po.setchr(dummy, e2)
232 po.setchr(i1, newedge(dummy, false))
233 po.upush(undoSetChr, i1, i1r)
234 } else {
235 po.setchl(dummy, i1l)
236 po.setchr(dummy, e2)
237 po.setchl(i1, newedge(dummy, false))
238 po.upush(undoSetChl, i1, i1l)
239 }
240 }
241 }
242
243
244
245 func (po *poset) newnode(n *Value) uint32 {
246 i := po.lastidx + 1
247 po.lastidx++
248 po.nodes = append(po.nodes, posetNode{})
249 if n != nil {
250 if po.values[n.ID] != 0 {
251 panic("newnode for Value already inserted")
252 }
253 po.values[n.ID] = i
254 po.upushnew(n.ID, i)
255 } else {
256 po.upushnew(0, i)
257 }
258 return i
259 }
260
261
262
263 func (po *poset) lookup(n *Value) (uint32, bool) {
264 i, f := po.values[n.ID]
265 if !f && n.isGenericIntConst() {
266 po.newconst(n)
267 i, f = po.values[n.ID]
268 }
269 return i, f
270 }
271
272
273
274
275 func (po *poset) newconst(n *Value) {
276 if !n.isGenericIntConst() {
277 panic("newconst on non-constant")
278 }
279
280
281
282
283 if len(po.constants) == 0 {
284 i := po.newnode(n)
285 po.roots = append(po.roots, i)
286 po.upush(undoNewRoot, i, 0)
287 po.constants = append(po.constants, n)
288 return
289 }
290
291
292
293
294
295
296 var lowerptr, higherptr *Value
297
298 if po.flags&posetFlagUnsigned != 0 {
299 var lower, higher uint64
300 val1 := n.AuxUnsigned()
301 for _, ptr := range po.constants {
302 val2 := ptr.AuxUnsigned()
303 if val1 == val2 {
304 po.aliasnode(ptr, n)
305 return
306 }
307 if val2 < val1 && (lowerptr == nil || val2 > lower) {
308 lower = val2
309 lowerptr = ptr
310 } else if val2 > val1 && (higherptr == nil || val2 < higher) {
311 higher = val2
312 higherptr = ptr
313 }
314 }
315 } else {
316 var lower, higher int64
317 val1 := n.AuxInt
318 for _, ptr := range po.constants {
319 val2 := ptr.AuxInt
320 if val1 == val2 {
321 po.aliasnode(ptr, n)
322 return
323 }
324 if val2 < val1 && (lowerptr == nil || val2 > lower) {
325 lower = val2
326 lowerptr = ptr
327 } else if val2 > val1 && (higherptr == nil || val2 < higher) {
328 higher = val2
329 higherptr = ptr
330 }
331 }
332 }
333
334 if lowerptr == nil && higherptr == nil {
335
336
337 panic("no constant found")
338 }
339
340
341
342
343
344
345 i := po.newnode(n)
346 switch {
347 case lowerptr != nil && higherptr != nil:
348
349 po.addchild(po.values[lowerptr.ID], i, true)
350 po.addchild(i, po.values[higherptr.ID], true)
351
352 case lowerptr != nil:
353
354 po.addchild(po.values[lowerptr.ID], i, true)
355
356 case higherptr != nil:
357
358
359
360
361
362
363
364
365
366
367
368 i2 := po.values[higherptr.ID]
369 r2 := po.findroot(i2)
370 dummy := po.newnode(nil)
371 po.changeroot(r2, dummy)
372 po.upush(undoChangeRoot, dummy, newedge(r2, false))
373 po.addchild(dummy, r2, false)
374 po.addchild(dummy, i, false)
375 po.addchild(i, i2, true)
376 }
377
378 po.constants = append(po.constants, n)
379 }
380
381
382 func (po *poset) aliasnode(n1, n2 *Value) {
383 i1 := po.values[n1.ID]
384 if i1 == 0 {
385 panic("aliasnode for non-existing node")
386 }
387
388 i2 := po.values[n2.ID]
389 if i2 != 0 {
390
391
392 for idx, n := range po.nodes {
393 if uint32(idx) != i1 {
394 l, r := n.l, n.r
395 if l.Target() == i2 {
396 po.setchl(uint32(idx), newedge(i1, l.Strict()))
397 po.upush(undoSetChl, uint32(idx), l)
398 }
399 if r.Target() == i2 {
400 po.setchr(uint32(idx), newedge(i1, r.Strict()))
401 po.upush(undoSetChr, uint32(idx), r)
402 }
403 }
404 }
405
406
407
408 for k, v := range po.values {
409 if v == i2 {
410 po.values[k] = i1
411 po.upushalias(k, i2)
412 }
413 }
414 } else {
415
416 po.values[n2.ID] = i1
417 po.upushalias(n2.ID, 0)
418 }
419 }
420
421 func (po *poset) isroot(r uint32) bool {
422 for i := range po.roots {
423 if po.roots[i] == r {
424 return true
425 }
426 }
427 return false
428 }
429
430 func (po *poset) changeroot(oldr, newr uint32) {
431 for i := range po.roots {
432 if po.roots[i] == oldr {
433 po.roots[i] = newr
434 return
435 }
436 }
437 panic("changeroot on non-root")
438 }
439
440 func (po *poset) removeroot(r uint32) {
441 for i := range po.roots {
442 if po.roots[i] == r {
443 po.roots = append(po.roots[:i], po.roots[i+1:]...)
444 return
445 }
446 }
447 panic("removeroot on non-root")
448 }
449
450
451
452
453
454
455
456
457
458 func (po *poset) dfs(r uint32, strict bool, f func(i uint32) bool) bool {
459 closed := newBitset(int(po.lastidx + 1))
460 open := make([]uint32, 1, 64)
461 open[0] = r
462
463 if strict {
464
465
466
467 next := make([]uint32, 0, 64)
468
469 for len(open) > 0 {
470 i := open[len(open)-1]
471 open = open[:len(open)-1]
472
473
474
475
476
477 if !closed.Test(i) {
478 closed.Set(i)
479
480 l, r := po.children(i)
481 if l != 0 {
482 if l.Strict() {
483 next = append(next, l.Target())
484 } else {
485 open = append(open, l.Target())
486 }
487 }
488 if r != 0 {
489 if r.Strict() {
490 next = append(next, r.Target())
491 } else {
492 open = append(open, r.Target())
493 }
494 }
495 }
496 }
497 open = next
498 closed.Reset()
499 }
500
501 for len(open) > 0 {
502 i := open[len(open)-1]
503 open = open[:len(open)-1]
504
505 if !closed.Test(i) {
506 if f(i) {
507 return true
508 }
509 closed.Set(i)
510 l, r := po.children(i)
511 if l != 0 {
512 open = append(open, l.Target())
513 }
514 if r != 0 {
515 open = append(open, r.Target())
516 }
517 }
518 }
519 return false
520 }
521
522
523
524
525
526 func (po *poset) reaches(i1, i2 uint32, strict bool) bool {
527 return po.dfs(i1, strict, func(n uint32) bool {
528 return n == i2
529 })
530 }
531
532
533
534
535 func (po *poset) findroot(i uint32) uint32 {
536
537
538
539 for _, r := range po.roots {
540 if po.reaches(r, i, false) {
541 return r
542 }
543 }
544 panic("findroot didn't find any root")
545 }
546
547
548 func (po *poset) mergeroot(r1, r2 uint32) uint32 {
549 r := po.newnode(nil)
550 po.setchl(r, newedge(r1, false))
551 po.setchr(r, newedge(r2, false))
552 po.changeroot(r1, r)
553 po.removeroot(r2)
554 po.upush(undoMergeRoot, r, 0)
555 return r
556 }
557
558
559
560
561 func (po *poset) collapsepath(n1, n2 *Value) bool {
562 i1, i2 := po.values[n1.ID], po.values[n2.ID]
563 if po.reaches(i1, i2, true) {
564 return false
565 }
566
567
568 l, r := po.children(i1)
569 if l.Target() == i2 || r.Target() == i2 {
570 po.aliasnode(n1, n2)
571 po.addchild(i1, i2, false)
572 return true
573 }
574 return true
575 }
576
577
578 func (po *poset) isnoneq(id1, id2 ID) bool {
579 if id1 < id2 {
580 id1, id2 = id2, id1
581 }
582
583
584 if bs, ok := po.noneq[id1]; ok && bs.Test(uint32(id2)) {
585 return true
586 }
587 return false
588 }
589
590
591 func (po *poset) setnoneq(id1, id2 ID) {
592 if id1 < id2 {
593 id1, id2 = id2, id1
594 }
595 bs := po.noneq[id1]
596 if bs == nil {
597
598
599
600
601 bs = newBitset(int(id1))
602 po.noneq[id1] = bs
603 } else if bs.Test(uint32(id2)) {
604
605 return
606 }
607 bs.Set(uint32(id2))
608 po.upushneq(id1, id2)
609 }
610
611
612
613 func (po *poset) CheckIntegrity() (err error) {
614
615 constants := newBitset(int(po.lastidx + 1))
616 for _, c := range po.constants {
617 if idx, ok := po.values[c.ID]; !ok {
618 err = errors.New("node missing for constant")
619 return err
620 } else {
621 constants.Set(idx)
622 }
623 }
624
625
626
627 var croot uint32
628 seen := newBitset(int(po.lastidx + 1))
629 for _, r := range po.roots {
630 if r == 0 {
631 err = errors.New("empty root")
632 return
633 }
634
635 po.dfs(r, false, func(i uint32) bool {
636 if seen.Test(i) {
637 err = errors.New("duplicate node")
638 return true
639 }
640 seen.Set(i)
641 if constants.Test(i) {
642 if croot == 0 {
643 croot = r
644 } else if croot != r {
645 err = errors.New("constants are in different DAGs")
646 return true
647 }
648 }
649 return false
650 })
651 if err != nil {
652 return
653 }
654 }
655
656
657 for id, idx := range po.values {
658 if !seen.Test(idx) {
659 err = fmt.Errorf("spurious value [%d]=%d", id, idx)
660 return
661 }
662 }
663
664
665 for i, n := range po.nodes {
666 if n.l|n.r != 0 {
667 if !seen.Test(uint32(i)) {
668 err = fmt.Errorf("children of unknown node %d->%v", i, n)
669 return
670 }
671 if n.l.Target() == uint32(i) || n.r.Target() == uint32(i) {
672 err = fmt.Errorf("self-loop on node %d", i)
673 return
674 }
675 }
676 }
677
678 return
679 }
680
681
682
683
684 func (po *poset) CheckEmpty() error {
685 if len(po.nodes) != 1 {
686 return fmt.Errorf("non-empty nodes list: %v", po.nodes)
687 }
688 if len(po.values) != 0 {
689 return fmt.Errorf("non-empty value map: %v", po.values)
690 }
691 if len(po.roots) != 0 {
692 return fmt.Errorf("non-empty root list: %v", po.roots)
693 }
694 if len(po.constants) != 0 {
695 return fmt.Errorf("non-empty constants: %v", po.constants)
696 }
697 if len(po.undo) != 0 {
698 return fmt.Errorf("non-empty undo list: %v", po.undo)
699 }
700 if po.lastidx != 0 {
701 return fmt.Errorf("lastidx index is not zero: %v", po.lastidx)
702 }
703 for _, bs := range po.noneq {
704 for _, x := range bs {
705 if x != 0 {
706 return fmt.Errorf("non-empty noneq map")
707 }
708 }
709 }
710 return nil
711 }
712
713
714 func (po *poset) DotDump(fn string, title string) error {
715 f, err := os.Create(fn)
716 if err != nil {
717 return err
718 }
719 defer f.Close()
720
721
722 names := make(map[uint32]string)
723 for id, i := range po.values {
724 s := names[i]
725 if s == "" {
726 s = fmt.Sprintf("v%d", id)
727 } else {
728 s += fmt.Sprintf(", v%d", id)
729 }
730 names[i] = s
731 }
732
733
734 consts := make(map[uint32]int64)
735 for _, v := range po.constants {
736 idx := po.values[v.ID]
737 if po.flags&posetFlagUnsigned != 0 {
738 consts[idx] = int64(v.AuxUnsigned())
739 } else {
740 consts[idx] = v.AuxInt
741 }
742 }
743
744 fmt.Fprintf(f, "digraph poset {\n")
745 fmt.Fprintf(f, "\tedge [ fontsize=10 ]\n")
746 for ridx, r := range po.roots {
747 fmt.Fprintf(f, "\tsubgraph root%d {\n", ridx)
748 po.dfs(r, false, func(i uint32) bool {
749 if val, ok := consts[i]; ok {
750
751 var vals string
752 if po.flags&posetFlagUnsigned != 0 {
753 vals = fmt.Sprint(uint64(val))
754 } else {
755 vals = fmt.Sprint(int64(val))
756 }
757 fmt.Fprintf(f, "\t\tnode%d [shape=box style=filled fillcolor=cadetblue1 label=<%s <font point-size=\"6\">%s [%d]</font>>]\n",
758 i, vals, names[i], i)
759 } else {
760
761 fmt.Fprintf(f, "\t\tnode%d [label=<%s <font point-size=\"6\">[%d]</font>>]\n", i, names[i], i)
762 }
763 chl, chr := po.children(i)
764 for _, ch := range []posetEdge{chl, chr} {
765 if ch != 0 {
766 if ch.Strict() {
767 fmt.Fprintf(f, "\t\tnode%d -> node%d [label=\" <\" color=\"red\"]\n", i, ch.Target())
768 } else {
769 fmt.Fprintf(f, "\t\tnode%d -> node%d [label=\" <=\" color=\"green\"]\n", i, ch.Target())
770 }
771 }
772 }
773 return false
774 })
775 fmt.Fprintf(f, "\t}\n")
776 }
777 fmt.Fprintf(f, "\tlabelloc=\"t\"\n")
778 fmt.Fprintf(f, "\tlabeldistance=\"3.0\"\n")
779 fmt.Fprintf(f, "\tlabel=%q\n", title)
780 fmt.Fprintf(f, "}\n")
781 return nil
782 }
783
784
785
786
787
788 func (po *poset) Ordered(n1, n2 *Value) bool {
789 if n1.ID == n2.ID {
790 panic("should not call Ordered with n1==n2")
791 }
792
793 i1, f1 := po.lookup(n1)
794 i2, f2 := po.lookup(n2)
795 if !f1 || !f2 {
796 return false
797 }
798
799 return i1 != i2 && po.reaches(i1, i2, true)
800 }
801
802
803
804
805
806 func (po *poset) OrderedOrEqual(n1, n2 *Value) bool {
807 if n1.ID == n2.ID {
808 panic("should not call Ordered with n1==n2")
809 }
810
811 i1, f1 := po.lookup(n1)
812 i2, f2 := po.lookup(n2)
813 if !f1 || !f2 {
814 return false
815 }
816
817 return i1 == i2 || po.reaches(i1, i2, false)
818 }
819
820
821
822
823
824 func (po *poset) Equal(n1, n2 *Value) bool {
825 if n1.ID == n2.ID {
826 panic("should not call Equal with n1==n2")
827 }
828
829 i1, f1 := po.lookup(n1)
830 i2, f2 := po.lookup(n2)
831 return f1 && f2 && i1 == i2
832 }
833
834
835
836
837
838
839 func (po *poset) NonEqual(n1, n2 *Value) bool {
840 if n1.ID == n2.ID {
841 panic("should not call Equal with n1==n2")
842 }
843 if po.isnoneq(n1.ID, n2.ID) {
844 return true
845 }
846
847
848 if po.Ordered(n1, n2) || po.Ordered(n2, n1) {
849 return true
850 }
851
852 return false
853 }
854
855
856
857 func (po *poset) setOrder(n1, n2 *Value, strict bool) bool {
858
859
860 if !strict && po.isnoneq(n1.ID, n2.ID) {
861 strict = true
862 }
863
864 i1, f1 := po.lookup(n1)
865 i2, f2 := po.lookup(n2)
866
867 switch {
868 case !f1 && !f2:
869
870
871
872 i1, i2 = po.newnode(n1), po.newnode(n2)
873 po.roots = append(po.roots, i1)
874 po.upush(undoNewRoot, i1, 0)
875 po.addchild(i1, i2, strict)
876
877 case f1 && !f2:
878
879
880 i2 = po.newnode(n2)
881 po.addchild(i1, i2, strict)
882
883 case !f1 && f2:
884
885
886
887 i1 = po.newnode(n1)
888
889 if po.isroot(i2) {
890 po.changeroot(i2, i1)
891 po.upush(undoChangeRoot, i1, newedge(i2, strict))
892 po.addchild(i1, i2, strict)
893 return true
894 }
895
896
897
898 r := po.findroot(i2)
899
900
901
902
903
904
905
906
907
908 dummy := po.newnode(nil)
909 po.changeroot(r, dummy)
910 po.upush(undoChangeRoot, dummy, newedge(r, false))
911 po.addchild(dummy, r, false)
912 po.addchild(dummy, i1, false)
913 po.addchild(i1, i2, strict)
914
915 case f1 && f2:
916
917
918 if i1 == i2 {
919 return !strict
920 }
921
922
923
924
925
926 if po.reaches(i1, i2, false) {
927
928
929
930
931
932
933
934
935
936
937 if strict && !po.reaches(i1, i2, true) {
938 po.addchild(i1, i2, true)
939 return true
940 }
941
942
943 return true
944 }
945
946
947 if po.reaches(i2, i1, false) {
948
949
950
951
952
953
954
955
956
957 if strict {
958
959 return false
960 }
961
962
963
964 return po.collapsepath(n2, n1)
965 }
966
967
968
969
970 r1, r2 := po.findroot(i1), po.findroot(i2)
971 if r1 != r2 {
972
973 po.mergeroot(r1, r2)
974 }
975
976
977 po.addchild(i1, i2, strict)
978 }
979
980 return true
981 }
982
983
984
985 func (po *poset) SetOrder(n1, n2 *Value) bool {
986 if n1.ID == n2.ID {
987 panic("should not call SetOrder with n1==n2")
988 }
989 return po.setOrder(n1, n2, true)
990 }
991
992
993
994 func (po *poset) SetOrderOrEqual(n1, n2 *Value) bool {
995 if n1.ID == n2.ID {
996 panic("should not call SetOrder with n1==n2")
997 }
998 return po.setOrder(n1, n2, false)
999 }
1000
1001
1002
1003
1004 func (po *poset) SetEqual(n1, n2 *Value) bool {
1005 if n1.ID == n2.ID {
1006 panic("should not call Add with n1==n2")
1007 }
1008
1009
1010 if po.isnoneq(n1.ID, n2.ID) {
1011 return false
1012 }
1013
1014 i1, f1 := po.lookup(n1)
1015 i2, f2 := po.lookup(n2)
1016
1017 switch {
1018 case !f1 && !f2:
1019 i1 = po.newnode(n1)
1020 po.roots = append(po.roots, i1)
1021 po.upush(undoNewRoot, i1, 0)
1022 po.aliasnode(n1, n2)
1023 case f1 && !f2:
1024 po.aliasnode(n1, n2)
1025 case !f1 && f2:
1026 po.aliasnode(n2, n1)
1027 case f1 && f2:
1028 if i1 == i2 {
1029
1030 return true
1031 }
1032
1033
1034
1035 if po.reaches(i1, i2, false) {
1036 return po.collapsepath(n1, n2)
1037 }
1038 if po.reaches(i2, i1, false) {
1039 return po.collapsepath(n2, n1)
1040 }
1041
1042 r1 := po.findroot(i1)
1043 r2 := po.findroot(i2)
1044 if r1 != r2 {
1045
1046 po.mergeroot(r1, r2)
1047 }
1048
1049
1050
1051 po.aliasnode(n1, n2)
1052
1053
1054
1055 po.addchild(i1, i2, false)
1056 }
1057 return true
1058 }
1059
1060
1061
1062
1063 func (po *poset) SetNonEqual(n1, n2 *Value) bool {
1064 if n1.ID == n2.ID {
1065 panic("should not call Equal with n1==n2")
1066 }
1067
1068
1069 if po.isnoneq(n1.ID, n2.ID) {
1070 return true
1071 }
1072
1073
1074 if po.Equal(n1, n2) {
1075 return false
1076 }
1077
1078
1079 po.setnoneq(n1.ID, n2.ID)
1080
1081
1082
1083 i1, f1 := po.lookup(n1)
1084 i2, f2 := po.lookup(n2)
1085 if f1 && f2 {
1086 if po.reaches(i1, i2, false) && !po.reaches(i1, i2, true) {
1087 po.addchild(i1, i2, true)
1088 }
1089 if po.reaches(i2, i1, false) && !po.reaches(i2, i1, true) {
1090 po.addchild(i2, i1, true)
1091 }
1092 }
1093
1094 return true
1095 }
1096
1097
1098
1099
1100 func (po *poset) Checkpoint() {
1101 po.undo = append(po.undo, posetUndo{typ: undoCheckpoint})
1102 }
1103
1104
1105
1106
1107
1108 func (po *poset) Undo() {
1109 if len(po.undo) == 0 {
1110 panic("empty undo stack")
1111 }
1112
1113 for len(po.undo) > 0 {
1114 pass := po.undo[len(po.undo)-1]
1115 po.undo = po.undo[:len(po.undo)-1]
1116
1117 switch pass.typ {
1118 case undoCheckpoint:
1119 return
1120
1121 case undoSetChl:
1122 po.setchl(pass.idx, pass.edge)
1123
1124 case undoSetChr:
1125 po.setchr(pass.idx, pass.edge)
1126
1127 case undoNonEqual:
1128 po.noneq[pass.ID].Clear(pass.idx)
1129
1130 case undoNewNode:
1131 if pass.idx != po.lastidx {
1132 panic("invalid newnode index")
1133 }
1134 if pass.ID != 0 {
1135 if po.values[pass.ID] != pass.idx {
1136 panic("invalid newnode undo pass")
1137 }
1138 delete(po.values, pass.ID)
1139 }
1140 po.setchl(pass.idx, 0)
1141 po.setchr(pass.idx, 0)
1142 po.nodes = po.nodes[:pass.idx]
1143 po.lastidx--
1144
1145
1146 nc := len(po.constants)
1147 if nc > 0 && po.constants[nc-1].ID == pass.ID {
1148 po.constants = po.constants[:nc-1]
1149 }
1150
1151 case undoAliasNode:
1152 ID, prev := pass.ID, pass.idx
1153 cur := po.values[ID]
1154 if prev == 0 {
1155
1156 delete(po.values, ID)
1157 } else {
1158 if cur == prev {
1159 panic("invalid aliasnode undo pass")
1160 }
1161
1162 po.values[ID] = prev
1163 }
1164
1165 case undoNewRoot:
1166 i := pass.idx
1167 l, r := po.children(i)
1168 if l|r != 0 {
1169 panic("non-empty root in undo newroot")
1170 }
1171 po.removeroot(i)
1172
1173 case undoChangeRoot:
1174 i := pass.idx
1175 l, r := po.children(i)
1176 if l|r != 0 {
1177 panic("non-empty root in undo changeroot")
1178 }
1179 po.changeroot(i, pass.edge.Target())
1180
1181 case undoMergeRoot:
1182 i := pass.idx
1183 l, r := po.children(i)
1184 po.changeroot(i, l.Target())
1185 po.roots = append(po.roots, r.Target())
1186
1187 default:
1188 panic(pass.typ)
1189 }
1190 }
1191 }
1192
View as plain text