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