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