1
2
3
4
5 package liveness
6
7 import (
8 "fmt"
9
10 "cmd/compile/internal/base"
11 "cmd/compile/internal/bitvec"
12 "cmd/compile/internal/ir"
13 "cmd/compile/internal/objw"
14 "cmd/compile/internal/ssa"
15 "cmd/internal/obj"
16 "cmd/internal/objabi"
17 )
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 const allLiveIdx = -1
45
46
47 type nameOff struct {
48 n *ir.Name
49 off int64
50 }
51
52 func (a nameOff) FrameOffset() int64 { return a.n.FrameOffset() + a.off }
53 func (a nameOff) String() string { return fmt.Sprintf("%v+%d", a.n, a.off) }
54
55 type blockArgEffects struct {
56 livein bitvec.BitVec
57 liveout bitvec.BitVec
58 }
59
60 type argLiveness struct {
61 fn *ir.Func
62 f *ssa.Func
63 args []nameOff
64 idx map[nameOff]int32
65
66 be []blockArgEffects
67
68 bvset bvecSet
69
70
71
72
73
74 blockIdx map[ssa.ID]int
75 valueIdx map[ssa.ID]int
76 }
77
78
79
80
81
82
83 func ArgLiveness(fn *ir.Func, f *ssa.Func, pp *objw.Progs) (blockIdx, valueIdx map[ssa.ID]int) {
84 if f.OwnAux.ABIInfo().InRegistersUsed() == 0 || base.Flag.N != 0 {
85
86
87 return nil, nil
88 }
89
90 lv := &argLiveness{
91 fn: fn,
92 f: f,
93 idx: make(map[nameOff]int32),
94 be: make([]blockArgEffects, f.NumBlocks()),
95 blockIdx: make(map[ssa.ID]int),
96 valueIdx: make(map[ssa.ID]int),
97 }
98
99 for _, a := range f.OwnAux.ABIInfo().InParams() {
100 n, ok := a.Name.(*ir.Name)
101 if !ok || len(a.Registers) == 0 {
102 continue
103 }
104 _, offs := a.RegisterTypesAndOffsets()
105 for _, off := range offs {
106 if n.FrameOffset()+off > 0xff {
107
108
109 continue
110 }
111 lv.args = append(lv.args, nameOff{n, off})
112 }
113 }
114 if len(lv.args) > 10 {
115 lv.args = lv.args[:10]
116 }
117
118
119 alwaysLive := func(n *ir.Name) bool { return n.Addrtaken() || !f.Frontend().CanSSA(n.Type()) }
120
121
122
123 for len(lv.args) > 0 && alwaysLive(lv.args[0].n) {
124 lv.args = lv.args[1:]
125 }
126 if len(lv.args) == 0 {
127 return
128 }
129
130 for i, a := range lv.args {
131 lv.idx[a] = int32(i)
132 }
133
134 nargs := int32(len(lv.args))
135 bulk := bitvec.NewBulk(nargs, int32(len(f.Blocks)*2))
136 for _, b := range f.Blocks {
137 be := &lv.be[b.ID]
138 be.livein = bulk.Next()
139 be.liveout = bulk.Next()
140
141
142 be.livein.Not()
143 be.liveout.Not()
144 }
145
146 entrybe := &lv.be[f.Entry.ID]
147 entrybe.livein.Clear()
148 for i, a := range lv.args {
149 if alwaysLive(a.n) {
150 entrybe.livein.Set(int32(i))
151 }
152 }
153
154
155 po := f.Postorder()
156 for i := len(po) - 1; i >= 0; i-- {
157 b := po[i]
158 be := &lv.be[b.ID]
159
160
161 for _, pred := range b.Preds {
162 pb := pred.Block()
163 be.livein.And(be.livein, lv.be[pb.ID].liveout)
164 }
165
166 be.liveout.Copy(be.livein)
167 for _, v := range b.Values {
168 lv.valueEffect(v, be.liveout)
169 }
170 }
171
172
173
174 live := bitvec.New(nargs)
175 addToSet := func(bv bitvec.BitVec) (int, bool) {
176 if bv.Count() == int(nargs) {
177 return allLiveIdx, false
178 }
179 return lv.bvset.add(bv)
180 }
181 for _, b := range lv.f.Blocks {
182 be := &lv.be[b.ID]
183 lv.blockIdx[b.ID], _ = addToSet(be.livein)
184
185 live.Copy(be.livein)
186 var lastv *ssa.Value
187 for i, v := range b.Values {
188 if lv.valueEffect(v, live) {
189
190
191
192 lastv = v
193 }
194 if lastv != nil && (mayFault(v) || i == len(b.Values)-1) {
195
196
197
198 var added bool
199 lv.valueIdx[lastv.ID], added = addToSet(live)
200 if added {
201
202
203 t := live
204 live = bitvec.New(nargs)
205 live.Copy(t)
206 }
207 lastv = nil
208 }
209 }
210
211
212 if !live.Eq(be.liveout) {
213 panic("wrong arg liveness map at block end")
214 }
215 }
216
217
218 lsym := lv.emit()
219 fn.LSym.Func().ArgLiveInfo = lsym
220
221
222
223 p := pp.Prog(obj.AFUNCDATA)
224 p.From.SetConst(objabi.FUNCDATA_ArgLiveInfo)
225 p.To.Type = obj.TYPE_MEM
226 p.To.Name = obj.NAME_EXTERN
227 p.To.Sym = lsym
228
229 return lv.blockIdx, lv.valueIdx
230 }
231
232
233 func (lv *argLiveness) valueEffect(v *ssa.Value, live bitvec.BitVec) bool {
234 if v.Op != ssa.OpStoreReg {
235 return false
236 }
237 n, off := ssa.AutoVar(v)
238 if n.Class != ir.PPARAM {
239 return false
240 }
241 i, ok := lv.idx[nameOff{n, off}]
242 if !ok || live.Get(i) {
243 return false
244 }
245 live.Set(i)
246 return true
247 }
248
249 func mayFault(v *ssa.Value) bool {
250 switch v.Op {
251 case ssa.OpLoadReg, ssa.OpStoreReg, ssa.OpCopy, ssa.OpPhi,
252 ssa.OpVarDef, ssa.OpVarKill, ssa.OpVarLive, ssa.OpKeepAlive,
253 ssa.OpSelect0, ssa.OpSelect1, ssa.OpSelectN, ssa.OpMakeResult,
254 ssa.OpConvert, ssa.OpInlMark, ssa.OpGetG:
255 return false
256 }
257 if len(v.Args) == 0 {
258 return false
259 }
260 return true
261 }
262
263 func (lv *argLiveness) print() {
264 fmt.Println("argument liveness:", lv.f.Name)
265 live := bitvec.New(int32(len(lv.args)))
266 for _, b := range lv.f.Blocks {
267 be := &lv.be[b.ID]
268
269 fmt.Printf("%v: live in: ", b)
270 lv.printLivenessVec(be.livein)
271 if idx, ok := lv.blockIdx[b.ID]; ok {
272 fmt.Printf(" #%d", idx)
273 }
274 fmt.Println()
275
276 for _, v := range b.Values {
277 if lv.valueEffect(v, live) {
278 fmt.Printf(" %v: ", v)
279 lv.printLivenessVec(live)
280 if idx, ok := lv.valueIdx[v.ID]; ok {
281 fmt.Printf(" #%d", idx)
282 }
283 fmt.Println()
284 }
285 }
286
287 fmt.Printf("%v: live out: ", b)
288 lv.printLivenessVec(be.liveout)
289 fmt.Println()
290 }
291 fmt.Println("liveness maps data:", lv.fn.LSym.Func().ArgLiveInfo.P)
292 }
293
294 func (lv *argLiveness) printLivenessVec(bv bitvec.BitVec) {
295 for i, a := range lv.args {
296 if bv.Get(int32(i)) {
297 fmt.Printf("%v ", a)
298 }
299 }
300 }
301
302 func (lv *argLiveness) emit() *obj.LSym {
303 livenessMaps := lv.bvset.extractUnique()
304
305
306 argOffsets := make([]uint8, len(lv.args))
307 for i, a := range lv.args {
308 off := a.FrameOffset()
309 if off > 0xff {
310 panic("offset too large")
311 }
312 argOffsets[i] = uint8(off)
313 }
314
315 idx2off := make([]int, len(livenessMaps))
316
317 lsym := base.Ctxt.Lookup(lv.fn.LSym.Name + ".argliveinfo")
318 lsym.Set(obj.AttrContentAddressable, true)
319
320 off := objw.Uint8(lsym, 0, argOffsets[0])
321 for idx, live := range livenessMaps {
322 idx2off[idx] = off
323 off = objw.BitVec(lsym, off, live)
324 }
325
326
327 for i, x := range lv.blockIdx {
328 if x != allLiveIdx {
329 lv.blockIdx[i] = idx2off[x]
330 }
331 }
332 for i, x := range lv.valueIdx {
333 if x != allLiveIdx {
334 lv.valueIdx[i] = idx2off[x]
335 }
336 }
337
338 return lsym
339 }
340
View as plain text