1
2
3
4
5 package ssacompile
6
7 import (
8 "cmd/compile/internal/ssa"
9 "cmd/compile/internal/ssa/block"
10 "cmd/compile/internal/ssa/ssaop"
11 )
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 func licm(f *ssa.Func) {
43
44 nest := ssa.Loopnestfor(f)
45 if len(nest.Loops) == 0 || nest.HasIrreducible {
46 return
47 }
48
49 uses := uses(f)
50 defer uses.free(f)
51
52 loopDependent := f.Cache.AllocBoolSlice(f.NumValues())
53 defer f.Cache.FreeBoolSlice(loopDependent)
54 queue := f.Cache.AllocValueSlice(f.NumValues())
55 defer f.Cache.FreeValueSlice(queue)
56 queue = queue[:0]
57
58
59 for _, b := range f.Blocks {
60 if loop := nest.B2L[b.ID]; loop == nil || !loop.IsInner {
61
62
63 continue
64 }
65 for _, v := range b.Values {
66 if ssaop.OpcodeTable[v.Op].EarlyOk {
67
68 if v.Type.IsMemory() || ssaop.OpcodeTable[v.Op].NilCheck || ssaop.OpcodeTable[v.Op].HasSideEffects || v.MemoryArg() != nil {
69 v.Fatalf("op %s has bad earlyOk mark", v.Op)
70 }
71 if !v.Type.IsPtr() {
72
73
74
75 continue
76 }
77 }
78 if v.Op == ssaop.OpSelect0 || v.Op == ssaop.OpSelect1 {
79
80 continue
81 }
82 loopDependent[v.ID] = true
83 queue = append(queue, v)
84 }
85 }
86
87
88
89
90 for len(queue) > 0 {
91 v := queue[len(queue)-1]
92 queue = queue[:len(queue)-1]
93
94 for _, u := range uses.get(v) {
95 if loop := nest.B2L[u.Block.ID]; loop == nil || !loop.IsInner {
96 continue
97 }
98 if loopDependent[u.ID] {
99 continue
100 }
101 loopDependent[u.ID] = true
102 queue = append(queue, u)
103 }
104 }
105
106
107 for _, b := range f.Blocks {
108 loop := nest.B2L[b.ID]
109 if loop == nil || !loop.IsInner {
110
111
112
113 continue
114 }
115 if len(loop.Header.Preds) != 2 {
116 continue
117 }
118 anyMoved := false
119 for i, v := range b.Values {
120 if loopDependent[v.ID] {
121 continue
122 }
123
124 h := loop.Header
125 var inIdx int
126 if int(h.Preds[0].B.ID) >= len(nest.B2L) || nest.B2L[h.Preds[0].B.ID] != loop {
127 inIdx = 0
128 } else {
129 inIdx = 1
130 }
131 dest := h.Preds[inIdx].B
132 if dest.Kind != block.BlockPlain {
133 outIdx := h.Preds[inIdx].I
134
135
136 mid := f.NewBlock(block.BlockPlain)
137 mid.Pos = dest.Pos
138
139 mid.Preds = append(mid.Preds, ssa.Edge{B: dest, I: outIdx})
140 mid.Succs = append(mid.Succs, ssa.Edge{B: h, I: inIdx})
141 h.Preds[inIdx] = ssa.Edge{B: mid, I: 0}
142 dest.Succs[outIdx] = ssa.Edge{B: mid, I: 0}
143
144 dest = mid
145 }
146
147 b.Values[i] = nil
148 v.Block = dest
149 dest.Values = append(dest.Values, v)
150 anyMoved = true
151 }
152 if anyMoved {
153
154 i := 0
155 for _, v := range b.Values {
156 if v == nil {
157 continue
158 }
159 b.Values[i] = v
160 i++
161 }
162 b.Values = b.Values[:i]
163 }
164 }
165 }
166
View as plain text