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 for _, b := range f.Blocks {
128 origloop := loops.b2l[b.ID]
129 for _, v := range b.Values {
130 t := target[v.ID]
131 if t == nil {
132 continue
133 }
134 targetloop := loops.b2l[t.ID]
135 for targetloop != nil && (origloop == nil || targetloop.depth > origloop.depth) {
136 t = idom[targetloop.header.ID]
137 target[v.ID] = t
138 targetloop = loops.b2l[t.ID]
139 }
140 }
141 }
142
143
144 for _, b := range f.Blocks {
145 for i := 0; i < len(b.Values); i++ {
146 v := b.Values[i]
147 t := target[v.ID]
148 if t == nil || t == b {
149
150 continue
151 }
152 if mem := v.MemoryArg(); mem != nil {
153 if startMem[t.ID] != mem {
154
155
156 continue
157 }
158 }
159 if f.pass.debug > 0 {
160 b.Func.Warnl(v.Pos, "%v is moved", v.Op)
161 }
162
163 t.Values = append(t.Values, v)
164 v.Block = t
165 last := len(b.Values) - 1
166 b.Values[i] = b.Values[last]
167 b.Values[last] = nil
168 b.Values = b.Values[:last]
169 changed = true
170 i--
171 }
172 }
173 }
174 }
175
176
177
178
179 func phiTighten(f *Func) {
180 for _, b := range f.Blocks {
181 for _, v := range b.Values {
182 if v.Op != OpPhi {
183 continue
184 }
185 for i, a := range v.Args {
186 if !a.rematerializeable() {
187 continue
188 }
189 if a.Block == b.Preds[i].b {
190 continue
191 }
192
193 v.SetArg(i, a.copyInto(b.Preds[i].b))
194 }
195 }
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 func memState(f *Func, startMem, endMem []*Value) {
224
225
226 changed := make([]*Block, 0)
227
228 for _, b := range f.Blocks {
229 for _, v := range b.Values {
230 var mem *Value
231 if v.Op == OpPhi {
232 if v.Type.IsMemory() {
233 mem = v
234 }
235 } else if v.Op == OpInitMem {
236 mem = v
237 } else if a := v.MemoryArg(); a != nil && a.Block != b {
238
239 mem = a
240 }
241 if mem != nil {
242 if old := startMem[b.ID]; old != nil {
243 if old == mem {
244 continue
245 }
246 f.Fatalf("func %s, startMem[%v] has different values, old %v, new %v", f.Name, b, old, mem)
247 }
248 startMem[b.ID] = mem
249 changed = append(changed, b)
250 }
251 }
252 }
253
254
255 for len(changed) != 0 {
256 top := changed[0]
257 changed = changed[1:]
258 mem := startMem[top.ID]
259 for i, p := range top.Preds {
260 pb := p.b
261 if endMem[pb.ID] != nil {
262 continue
263 }
264 if mem.Op == OpPhi && mem.Block == top {
265 endMem[pb.ID] = mem.Args[i]
266 } else {
267 endMem[pb.ID] = mem
268 }
269 if startMem[pb.ID] == nil {
270 startMem[pb.ID] = endMem[pb.ID]
271 changed = append(changed, pb)
272 }
273 }
274 }
275 }
276
View as plain text