1
2
3
4
5 package ssacompile
6
7 import (
8 "cmd/compile/internal/ssa"
9 "cmd/compile/internal/ssa/block"
10 "cmd/compile/internal/ssa/ssaop"
11 )
12
13
14
15
16 func flagalloc(f *ssa.Func) {
17
18
19
20 end := f.Cache.AllocValueSlice(f.NumBlocks())
21 defer f.Cache.FreeValueSlice(end)
22 po := f.Postorder()
23 for n := 0; n < 2; n++ {
24 for _, b := range po {
25
26
27
28 var flag *ssa.Value
29 for _, c := range b.ControlValues() {
30 if c.Type.IsFlags() {
31 if flag != nil {
32 panic("cannot have multiple controls using flags")
33 }
34 flag = c
35 }
36 }
37 if flag == nil {
38 flag = end[b.ID]
39 }
40 for j := len(b.Values) - 1; j >= 0; j-- {
41 v := b.Values[j]
42 if v == flag {
43 flag = nil
44 }
45 if v.ClobbersFlags() {
46 flag = nil
47 }
48 for _, a := range v.Args {
49 if a.Type.IsFlags() {
50 flag = a
51 }
52 }
53 }
54 if flag != nil {
55 for _, e := range b.Preds {
56 p := e.B
57 end[p.ID] = flag
58 }
59 }
60 }
61 }
62
63
64
65
66 for _, b := range f.Blocks {
67 if b.Kind == block.BlockDefer {
68
69 end[b.ID] = nil
70 continue
71 }
72 for _, v := range b.ControlValues() {
73 if v.Type.IsFlags() && end[b.ID] != v {
74 end[b.ID] = nil
75 }
76 }
77 }
78
79
80 spill := map[ssa.ID]bool{}
81 for _, b := range f.Blocks {
82 var flag *ssa.Value
83 if len(b.Preds) > 0 {
84 flag = end[b.Preds[0].B.ID]
85 }
86 for _, v := range b.Values {
87 for _, a := range v.Args {
88 if !a.Type.IsFlags() {
89 continue
90 }
91 if a == flag {
92 continue
93 }
94
95 spill[a.ID] = true
96 flag = a
97 }
98 if v.ClobbersFlags() {
99 flag = nil
100 }
101 if v.Type.IsFlags() {
102 flag = v
103 }
104 }
105 for _, v := range b.ControlValues() {
106 if v != flag && v.Type.IsFlags() {
107 spill[v.ID] = true
108 }
109 }
110 if v := end[b.ID]; v != nil && v != flag {
111 spill[v.ID] = true
112 }
113 }
114
115
116 var remove []*ssa.Value
117 var oldSched []*ssa.Value
118 for _, b := range f.Blocks {
119 oldSched = append(oldSched[:0], b.Values...)
120 b.Values = b.Values[:0]
121
122 var flag *ssa.Value
123 if len(b.Preds) > 0 {
124 flag = end[b.Preds[0].B.ID]
125
126 for _, e := range b.Preds[1:] {
127 p := e.B
128 if end[p.ID] != flag {
129 f.Fatalf("live flag in %s's predecessors not consistent", b)
130 }
131 }
132 }
133 for _, v := range oldSched {
134 if v.Op == ssaop.OpPhi && v.Type.IsFlags() {
135 f.Fatalf("phi of flags not supported: %s", v.LongString())
136 }
137
138
139
140 if spill[v.ID] && v.MemoryArg() != nil {
141 remove = append(remove, v)
142 if !f.Config.SplitLoad(v) {
143 f.Fatalf("can't split flag generator: %s", v.LongString())
144 }
145 }
146
147
148
149 for i, a := range v.Args {
150 if !a.Type.IsFlags() {
151 continue
152 }
153 if a == flag {
154 continue
155 }
156
157 c := copyFlags(a, b)
158
159 v.SetArg(i, c)
160
161 flag = a
162 }
163
164 b.Values = append(b.Values, v)
165 if v.ClobbersFlags() {
166 flag = nil
167 }
168 if v.Type.IsFlags() {
169 flag = v
170 }
171 }
172 for i, v := range b.ControlValues() {
173 if v != flag && v.Type.IsFlags() {
174
175 remove = append(remove, v)
176 c := copyFlags(v, b)
177 b.ReplaceControl(i, c)
178 flag = v
179 }
180 }
181 if v := end[b.ID]; v != nil && v != flag {
182
183
184 remove = append(remove, v)
185 copyFlags(v, b)
186
187
188
189
190
191
192
193 }
194 }
195
196
197 for _, b := range f.Blocks {
198 b.FlagsLiveAtEnd = end[b.ID] != nil
199 }
200
201
202
203
204
205
206
207 for i := 0; i < len(remove); i++ {
208 v := remove[i]
209 if v.Uses == 0 {
210 v.Reset(ssaop.OpInvalid)
211 continue
212 }
213
214 last := len(remove) - 1
215 remove[i] = remove[last]
216 remove[last] = nil
217 remove = remove[:last]
218 i--
219 }
220
221 if len(remove) == 0 {
222 return
223 }
224
225 removeBlocks := f.NewSparseSet(f.NumBlocks())
226 defer f.RetSparseSet(removeBlocks)
227 for _, v := range remove {
228 removeBlocks.Add(v.Block.ID)
229 }
230
231
232 for _, b := range f.Blocks {
233 if !removeBlocks.Contains(b.ID) {
234 continue
235 }
236 i := 0
237 for j := 0; j < len(b.Values); j++ {
238 v := b.Values[j]
239 if v.Op == ssaop.OpInvalid {
240 continue
241 }
242 b.Values[i] = v
243 i++
244 }
245 b.TruncateValues(i)
246 }
247 }
248
249
250
251 func copyFlags(v *ssa.Value, b *ssa.Block) *ssa.Value {
252 flagsArgs := make(map[int]*ssa.Value)
253 for i, a := range v.Args {
254 if a.Type.IsFlags() || a.Type.IsTuple() {
255 flagsArgs[i] = copyFlags(a, b)
256 }
257 }
258 c := v.CopyInto(b)
259 for i, a := range flagsArgs {
260 c.SetArg(i, a)
261 }
262 return c
263 }
264
View as plain text