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 clear(target)
89
90
91
92 for _, b := range f.Blocks {
93 for _, v := range b.Values {
94 for i, a := range v.Args {
95 if !canMove[a.ID] {
96 continue
97 }
98 use := b
99 if v.Op == OpPhi {
100 use = b.Preds[i].b
101 }
102 if target[a.ID] == nil {
103 target[a.ID] = use
104 } else {
105 target[a.ID] = lca.find(target[a.ID], use)
106 }
107 }
108 }
109 for _, c := range b.ControlValues() {
110 if !canMove[c.ID] {
111 continue
112 }
113 if target[c.ID] == nil {
114 target[c.ID] = b
115 } else {
116 target[c.ID] = lca.find(target[c.ID], b)
117 }
118 }
119 }
120
121
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 for _, b := range f.Blocks {
141 for i := 0; i < len(b.Values); i++ {
142 v := b.Values[i]
143 t := target[v.ID]
144 if t == nil || t == b {
145
146 continue
147 }
148 if mem := v.MemoryArg(); mem != nil {
149 if startMem[t.ID] != mem {
150
151
152 continue
153 }
154 }
155 if f.pass.debug > 0 {
156 b.Func.Warnl(v.Pos, "%v is moved", v.Op)
157 }
158
159 t.Values = append(t.Values, v)
160 v.Block = t
161 last := len(b.Values) - 1
162 b.Values[i] = b.Values[last]
163 b.Values[last] = nil
164 b.Values = b.Values[:last]
165 changed = true
166 i--
167 }
168 }
169 }
170 }
171
172
173
174
175 func phiTighten(f *Func) {
176 for _, b := range f.Blocks {
177 for _, v := range b.Values {
178 if v.Op != OpPhi {
179 continue
180 }
181 for i, a := range v.Args {
182 if !a.rematerializeable() {
183 continue
184 }
185 if a.Block == b.Preds[i].b {
186 continue
187 }
188
189 v.SetArg(i, a.copyInto(b.Preds[i].b))
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
218
219 func memState(f *Func, startMem, endMem []*Value) {
220
221
222 changed := make([]*Block, 0)
223
224 for _, b := range f.Blocks {
225 for _, v := range b.Values {
226 var mem *Value
227 if v.Op == OpPhi {
228 if v.Type.IsMemory() {
229 mem = v
230 }
231 } else if v.Op == OpInitMem {
232 mem = v
233 } else if a := v.MemoryArg(); a != nil && a.Block != b {
234
235 mem = a
236 }
237 if mem != nil {
238 if old := startMem[b.ID]; old != nil {
239 if old == mem {
240 continue
241 }
242 f.Fatalf("func %s, startMem[%v] has different values, old %v, new %v", f.Name, b, old, mem)
243 }
244 startMem[b.ID] = mem
245 changed = append(changed, b)
246 }
247 }
248 }
249
250
251 for len(changed) != 0 {
252 top := changed[0]
253 changed = changed[1:]
254 mem := startMem[top.ID]
255 for i, p := range top.Preds {
256 pb := p.b
257 if endMem[pb.ID] != nil {
258 continue
259 }
260 if mem.Op == OpPhi && mem.Block == top {
261 endMem[pb.ID] = mem.Args[i]
262 } else {
263 endMem[pb.ID] = mem
264 }
265 if startMem[pb.ID] == nil {
266 startMem[pb.ID] = endMem[pb.ID]
267 changed = append(changed, pb)
268 }
269 }
270 }
271 }
272
View as plain text