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