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