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