...
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 loops.calculateDepths()
86
87 changed := true
88 for changed {
89 changed = false
90
91
92 clear(target)
93
94
95
96 for _, b := range f.Blocks {
97 for _, v := range b.Values {
98 for i, a := range v.Args {
99 if !canMove[a.ID] {
100 continue
101 }
102 use := b
103 if v.Op == OpPhi {
104 use = b.Preds[i].b
105 }
106 if target[a.ID] == nil {
107 target[a.ID] = use
108 } else {
109 target[a.ID] = lca.find(target[a.ID], use)
110 }
111 }
112 }
113 for _, c := range b.ControlValues() {
114 if !canMove[c.ID] {
115 continue
116 }
117 if target[c.ID] == nil {
118 target[c.ID] = b
119 } else {
120 target[c.ID] = lca.find(target[c.ID], b)
121 }
122 }
123 }
124
125
126
127 if !loops.hasIrreducible {
128
129 for _, b := range f.Blocks {
130 origloop := loops.b2l[b.ID]
131 for _, v := range b.Values {
132 t := target[v.ID]
133 if t == nil {
134 continue
135 }
136 targetloop := loops.b2l[t.ID]
137 for targetloop != nil && (origloop == nil || targetloop.depth > origloop.depth) {
138 t = idom[targetloop.header.ID]
139 target[v.ID] = t
140 targetloop = loops.b2l[t.ID]
141 }
142 }
143 }
144 }
145
146
147 for _, b := range f.Blocks {
148 for i := 0; i < len(b.Values); i++ {
149 v := b.Values[i]
150 t := target[v.ID]
151 if t == nil || t == b {
152
153 continue
154 }
155 if mem := v.MemoryArg(); mem != nil {
156 if startMem[t.ID] != mem {
157
158
159 continue
160 }
161 }
162 if f.pass.debug > 0 {
163 b.Func.Warnl(v.Pos, "%v is moved", v.Op)
164 }
165
166 t.Values = append(t.Values, v)
167 v.Block = t
168 last := len(b.Values) - 1
169 b.Values[i] = b.Values[last]
170 b.Values[last] = nil
171 b.Values = b.Values[:last]
172 changed = true
173 i--
174 }
175 }
176 }
177 }
178
179
180
181
182 func phiTighten(f *Func) {
183 for _, b := range f.Blocks {
184 for _, v := range b.Values {
185 if v.Op != OpPhi {
186 continue
187 }
188 for i, a := range v.Args {
189 if !a.rematerializeable() {
190 continue
191 }
192 if a.Block == b.Preds[i].b {
193 continue
194 }
195
196 v.SetArg(i, a.copyInto(b.Preds[i].b))
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
226 func memState(f *Func, startMem, endMem []*Value) {
227
228
229 changed := make([]*Block, 0)
230
231 for _, b := range f.Blocks {
232 for _, v := range b.Values {
233 var mem *Value
234 if v.Op == OpPhi {
235 if v.Type.IsMemory() {
236 mem = v
237 }
238 } else if v.Op == OpInitMem {
239 mem = v
240 } else if a := v.MemoryArg(); a != nil && a.Block != b {
241
242 mem = a
243 }
244 if mem != nil {
245 if old := startMem[b.ID]; old != nil {
246 if old == mem {
247 continue
248 }
249 f.Fatalf("func %s, startMem[%v] has different values, old %v, new %v", f.Name, b, old, mem)
250 }
251 startMem[b.ID] = mem
252 changed = append(changed, b)
253 }
254 }
255 }
256
257
258 for len(changed) != 0 {
259 top := changed[0]
260 changed = changed[1:]
261 mem := startMem[top.ID]
262 for i, p := range top.Preds {
263 pb := p.b
264 if endMem[pb.ID] != nil {
265 continue
266 }
267 if mem.Op == OpPhi && mem.Block == top {
268 endMem[pb.ID] = mem.Args[i]
269 } else {
270 endMem[pb.ID] = mem
271 }
272 if startMem[pb.ID] == nil {
273 startMem[pb.ID] = endMem[pb.ID]
274 changed = append(changed, pb)
275 }
276 }
277 }
278 }
279
View as plain text