1
2
3
4
5 package ssacompile
6
7 import (
8 "cmd/compile/internal/base"
9 "cmd/compile/internal/ssa"
10 "cmd/compile/internal/ssa/ssaop"
11 )
12
13
14
15
16
17
18 func tighten(f *ssa.Func) {
19 if base.Flag.N != 0 && len(f.Blocks) < 10000 {
20
21
22
23 return
24 }
25
26 canMove := f.Cache.AllocBoolSlice(f.NumValues())
27 defer f.Cache.FreeBoolSlice(canMove)
28
29
30 startMem := f.Cache.AllocValueSlice(f.NumBlocks())
31 defer f.Cache.FreeValueSlice(startMem)
32 endMem := f.Cache.AllocValueSlice(f.NumBlocks())
33 defer f.Cache.FreeValueSlice(endMem)
34 distinctArgs := f.NewSparseSet(f.NumValues())
35 defer f.RetSparseSet(distinctArgs)
36 memState(f, startMem, endMem)
37
38 for _, b := range f.Blocks {
39 for _, v := range b.Values {
40 if v.Op.IsLoweredGetClosurePtr() {
41
42 continue
43 }
44 switch v.Op {
45 case ssaop.OpPhi, ssaop.OpArg, ssaop.OpArgIntReg, ssaop.OpArgFloatReg, ssaop.OpSelect0, ssaop.OpSelect1, ssaop.OpSelectN:
46
47
48
49
50 continue
51 }
52 if ssaop.OpcodeTable[v.Op].NilCheck {
53
54 continue
55 }
56
57 distinctArgs.Clear()
58
59 for _, a := range v.Args {
60
61
62 if a.NeedRegister() && a.Op != ssaop.OpSB && a.Op != ssaop.OpSP {
63 distinctArgs.Add(a.ID)
64 }
65 }
66
67 if distinctArgs.Size() >= 2 && !v.Type.IsFlags() {
68
69
70
71
72 continue
73 }
74 canMove[v.ID] = true
75 }
76 }
77
78
79 lca := makeLCArange(f)
80
81
82 target := f.Cache.AllocBlockSlice(f.NumValues())
83 defer f.Cache.FreeBlockSlice(target)
84
85
86
87 idom := f.Idom()
88 loops := f.Loopnest()
89
90 changed := true
91 for changed {
92 changed = false
93
94
95 clear(target)
96
97
98
99 for _, b := range f.Blocks {
100 for _, v := range b.Values {
101 for i, a := range v.Args {
102 if !canMove[a.ID] {
103 continue
104 }
105 use := b
106 if v.Op == ssaop.OpPhi {
107 use = b.Preds[i].B
108 }
109 if target[a.ID] == nil {
110 target[a.ID] = use
111 } else {
112 target[a.ID] = lca.find(target[a.ID], use)
113 }
114 }
115 }
116 for _, c := range b.ControlValues() {
117 if !canMove[c.ID] {
118 continue
119 }
120 if target[c.ID] == nil {
121 target[c.ID] = b
122 } else {
123 target[c.ID] = lca.find(target[c.ID], b)
124 }
125 }
126 }
127
128
129
130 if !loops.HasIrreducible {
131
132 for _, b := range f.Blocks {
133 origloop := loops.B2L[b.ID]
134 for _, v := range b.Values {
135 t := target[v.ID]
136 if t == nil {
137 continue
138 }
139 targetloop := loops.B2L[t.ID]
140 for targetloop != nil && (origloop == nil || targetloop.Depth > origloop.Depth) {
141 t = idom[targetloop.Header.ID]
142 target[v.ID] = t
143 targetloop = loops.B2L[t.ID]
144 }
145 }
146 }
147 }
148
149
150 for _, b := range f.Blocks {
151 for i := 0; i < len(b.Values); i++ {
152 v := b.Values[i]
153 t := target[v.ID]
154 if t == nil || t == b {
155
156 continue
157 }
158 if mem := v.MemoryArg(); mem != nil {
159 if startMem[t.ID] != mem {
160
161
162 continue
163 }
164 }
165 if f.Pass.Debug > 0 {
166 b.Func.Warnl(v.Pos, "%v is moved", v.Op)
167 }
168
169 t.Values = append(t.Values, v)
170 v.Block = t
171 last := len(b.Values) - 1
172 b.Values[i] = b.Values[last]
173 b.Values[last] = nil
174 b.Values = b.Values[:last]
175 changed = true
176 i--
177 }
178 }
179 }
180 }
181
182
183
184
185 func phiTighten(f *ssa.Func) {
186 for _, b := range f.Blocks {
187 for _, v := range b.Values {
188 if v.Op != ssaop.OpPhi {
189 continue
190 }
191 for i, a := range v.Args {
192 if !a.Rematerializeable() {
193 continue
194 }
195 if a.Block == b.Preds[i].B {
196 continue
197 }
198
199 v.SetArg(i, a.CopyInto(b.Preds[i].B))
200 }
201 }
202 }
203 }
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229 func memState(f *ssa.Func, startMem, endMem []*ssa.Value) {
230
231
232 changed := make([]*ssa.Block, 0)
233
234 for _, b := range f.Blocks {
235 for _, v := range b.Values {
236 var mem *ssa.Value
237 if v.Op == ssaop.OpPhi {
238 if v.Type.IsMemory() {
239 mem = v
240 }
241 } else if v.Op == ssaop.OpInitMem {
242 mem = v
243 } else if a := v.MemoryArg(); a != nil && a.Block != b {
244
245 mem = a
246 }
247 if mem != nil {
248 if old := startMem[b.ID]; old != nil {
249 if old == mem {
250 continue
251 }
252 f.Fatalf("func %s, startMem[%v] has different values, old %v, new %v", f.Name, b, old, mem)
253 }
254 startMem[b.ID] = mem
255 changed = append(changed, b)
256 }
257 }
258 }
259
260
261 for len(changed) != 0 {
262 top := changed[0]
263 changed = changed[1:]
264 mem := startMem[top.ID]
265 for i, p := range top.Preds {
266 pb := p.B
267 if endMem[pb.ID] != nil {
268 continue
269 }
270 if mem.Op == ssaop.OpPhi && mem.Block == top {
271 endMem[pb.ID] = mem.Args[i]
272 } else {
273 endMem[pb.ID] = mem
274 }
275 if startMem[pb.ID] == nil {
276 startMem[pb.ID] = endMem[pb.ID]
277 changed = append(changed, pb)
278 }
279 }
280 }
281 }
282
View as plain text