...
Source file src/pkg/cmd/compile/internal/ssa/lca.go
1
2
3
4
5 package ssa
6
7
8
9
10
11
12
13 type lcaRange struct {
14
15 blocks []lcaRangeBlock
16
17
18
19
20 rangeMin [][]ID
21 }
22
23 type lcaRangeBlock struct {
24 b *Block
25 parent ID
26 firstChild ID
27 sibling ID
28 pos int32
29 depth int32
30 }
31
32 func makeLCArange(f *Func) *lcaRange {
33 dom := f.Idom()
34
35
36 blocks := make([]lcaRangeBlock, f.NumBlocks())
37 for _, b := range f.Blocks {
38 blocks[b.ID].b = b
39 if dom[b.ID] == nil {
40 continue
41 }
42 parent := dom[b.ID].ID
43 blocks[b.ID].parent = parent
44 blocks[b.ID].sibling = blocks[parent].firstChild
45 blocks[parent].firstChild = b.ID
46 }
47
48
49
50 tour := make([]ID, 0, f.NumBlocks()*2-1)
51 type queueEntry struct {
52 bid ID
53 cid ID
54 }
55 q := []queueEntry{{f.Entry.ID, 0}}
56 for len(q) > 0 {
57 n := len(q) - 1
58 bid := q[n].bid
59 cid := q[n].cid
60 q = q[:n]
61
62
63 blocks[bid].pos = int32(len(tour))
64 tour = append(tour, bid)
65
66
67 if cid == 0 {
68
69 blocks[bid].depth = blocks[blocks[bid].parent].depth + 1
70
71 cid = blocks[bid].firstChild
72 } else {
73
74 cid = blocks[cid].sibling
75 }
76 if cid != 0 {
77 q = append(q, queueEntry{bid, cid}, queueEntry{cid, 0})
78 }
79 }
80
81
82 var rangeMin [][]ID
83 rangeMin = append(rangeMin, tour)
84 for logS, s := 1, 2; s < len(tour); logS, s = logS+1, s*2 {
85 r := make([]ID, len(tour)-s+1)
86 for i := 0; i < len(tour)-s+1; i++ {
87 bid := rangeMin[logS-1][i]
88 bid2 := rangeMin[logS-1][i+s/2]
89 if blocks[bid2].depth < blocks[bid].depth {
90 bid = bid2
91 }
92 r[i] = bid
93 }
94 rangeMin = append(rangeMin, r)
95 }
96
97 return &lcaRange{blocks: blocks, rangeMin: rangeMin}
98 }
99
100
101 func (lca *lcaRange) find(a, b *Block) *Block {
102 if a == b {
103 return a
104 }
105
106 p1 := lca.blocks[a.ID].pos
107 p2 := lca.blocks[b.ID].pos
108 if p1 > p2 {
109 p1, p2 = p2, p1
110 }
111
112
113
114
115
116 logS := uint(log2(int64(p2 - p1)))
117 bid1 := lca.rangeMin[logS][p1]
118 bid2 := lca.rangeMin[logS][p2-1<<logS+1]
119 if lca.blocks[bid1].depth < lca.blocks[bid2].depth {
120 return lca.blocks[bid1].b
121 }
122 return lca.blocks[bid2].b
123 }
124
View as plain text