1
2
3
4
5 package ssagen
6
7 import (
8 "fmt"
9 "internal/buildcfg"
10 "os"
11 "sort"
12 "sync"
13
14 "cmd/compile/internal/base"
15 "cmd/compile/internal/ir"
16 "cmd/compile/internal/objw"
17 "cmd/compile/internal/ssa"
18 "cmd/compile/internal/types"
19 "cmd/internal/obj"
20 "cmd/internal/objabi"
21 "cmd/internal/src"
22 )
23
24
25 func cmpstackvarlt(a, b *ir.Name) bool {
26
27 if needAlloc(a) != needAlloc(b) {
28 return needAlloc(b)
29 }
30
31
32
33 if !needAlloc(a) {
34 return a.FrameOffset() < b.FrameOffset()
35 }
36
37
38
39
40
41 if a.Used() != b.Used() {
42 return a.Used()
43 }
44
45
46
47 ap := a.Type().HasPointers()
48 bp := b.Type().HasPointers()
49 if ap != bp {
50 return ap
51 }
52
53
54
55 ap = a.Needzero()
56 bp = b.Needzero()
57 if ap != bp {
58 return ap
59 }
60
61
62
63 if a.Type().Alignment() != b.Type().Alignment() {
64 return a.Type().Alignment() > b.Type().Alignment()
65 }
66
67
68
69
70 if a.OpenDeferSlot() != b.OpenDeferSlot() {
71 return a.OpenDeferSlot()
72 }
73
74
75
76
77
78
79 if a.OpenDeferSlot() {
80 return a.FrameOffset() > b.FrameOffset()
81 }
82
83
84 return a.Sym().Name < b.Sym().Name
85 }
86
87
88 type byStackVar []*ir.Name
89
90 func (s byStackVar) Len() int { return len(s) }
91 func (s byStackVar) Less(i, j int) bool { return cmpstackvarlt(s[i], s[j]) }
92 func (s byStackVar) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
93
94
95
96
97 func needAlloc(n *ir.Name) bool {
98 if n.Op() != ir.ONAME {
99 base.FatalfAt(n.Pos(), "%v has unexpected Op %v", n, n.Op())
100 }
101
102 switch n.Class {
103 case ir.PAUTO:
104 return true
105 case ir.PPARAM:
106 return false
107 case ir.PPARAMOUT:
108 return n.IsOutputParamInRegisters()
109
110 default:
111 base.FatalfAt(n.Pos(), "%v has unexpected Class %v", n, n.Class)
112 return false
113 }
114 }
115
116 func (s *ssafn) AllocFrame(f *ssa.Func) {
117 s.stksize = 0
118 s.stkptrsize = 0
119 s.stkalign = int64(types.RegSize)
120 fn := s.curfn
121
122
123 for _, ln := range fn.Dcl {
124 if ln.OpenDeferSlot() {
125
126
127
128
129 continue
130 }
131
132 if needAlloc(ln) {
133 ln.SetUsed(false)
134 }
135 }
136
137 for _, l := range f.RegAlloc {
138 if ls, ok := l.(ssa.LocalSlot); ok {
139 ls.N.SetUsed(true)
140 }
141 }
142
143 for _, b := range f.Blocks {
144 for _, v := range b.Values {
145 if n, ok := v.Aux.(*ir.Name); ok {
146 switch n.Class {
147 case ir.PPARAMOUT:
148 if n.IsOutputParamInRegisters() && v.Op == ssa.OpVarDef {
149
150
151 continue
152 }
153 fallthrough
154 case ir.PPARAM, ir.PAUTO:
155 n.SetUsed(true)
156 }
157 }
158 }
159 }
160
161
162
163
164 sort.Stable(byStackVar(fn.Dcl))
165
166
167 lastHasPtr := false
168 for i, n := range fn.Dcl {
169 if n.Op() != ir.ONAME || n.Class != ir.PAUTO && !(n.Class == ir.PPARAMOUT && n.IsOutputParamInRegisters()) {
170
171 continue
172 }
173 if !n.Used() {
174 fn.DebugInfo.(*ssa.FuncDebug).OptDcl = fn.Dcl[i:]
175 fn.Dcl = fn.Dcl[:i]
176 break
177 }
178
179 types.CalcSize(n.Type())
180 w := n.Type().Size()
181 if w >= types.MaxWidth || w < 0 {
182 base.Fatalf("bad width")
183 }
184 if w == 0 && lastHasPtr {
185
186
187
188
189 w = 1
190 }
191 s.stksize += w
192 s.stksize = types.RoundUp(s.stksize, n.Type().Alignment())
193 if n.Type().Alignment() > int64(types.RegSize) {
194 s.stkalign = n.Type().Alignment()
195 }
196 if n.Type().HasPointers() {
197 s.stkptrsize = s.stksize
198 lastHasPtr = true
199 } else {
200 lastHasPtr = false
201 }
202 n.SetFrameOffset(-s.stksize)
203 }
204
205 s.stksize = types.RoundUp(s.stksize, s.stkalign)
206 s.stkptrsize = types.RoundUp(s.stkptrsize, s.stkalign)
207 }
208
209 const maxStackSize = 1 << 30
210
211
212
213
214
215 func Compile(fn *ir.Func, worker int) {
216 f := buildssa(fn, worker)
217
218 if f.Frontend().(*ssafn).stksize >= maxStackSize || f.OwnAux.ArgWidth() >= maxStackSize {
219 largeStackFramesMu.Lock()
220 largeStackFrames = append(largeStackFrames, largeStack{locals: f.Frontend().(*ssafn).stksize, args: f.OwnAux.ArgWidth(), pos: fn.Pos()})
221 largeStackFramesMu.Unlock()
222 return
223 }
224 pp := objw.NewProgs(fn, worker)
225 defer pp.Free()
226 genssa(f, pp)
227
228
229
230
231
232
233 if pp.Text.To.Offset >= maxStackSize {
234 largeStackFramesMu.Lock()
235 locals := f.Frontend().(*ssafn).stksize
236 largeStackFrames = append(largeStackFrames, largeStack{locals: locals, args: f.OwnAux.ArgWidth(), callee: pp.Text.To.Offset - locals, pos: fn.Pos()})
237 largeStackFramesMu.Unlock()
238 return
239 }
240
241 pp.Flush()
242
243
244
245
246 if fn.IsPackageInit() && base.Debug.WrapGlobalMapCtl != 1 {
247 weakenGlobalMapInitRelocs(fn)
248 }
249
250
251 fieldtrack(pp.Text.From.Sym, fn.FieldTrack)
252 }
253
254
255
256 var globalMapInitLsyms map[*obj.LSym]struct{}
257
258
259
260 func RegisterMapInitLsym(s *obj.LSym) {
261 if globalMapInitLsyms == nil {
262 globalMapInitLsyms = make(map[*obj.LSym]struct{})
263 }
264 globalMapInitLsyms[s] = struct{}{}
265 }
266
267
268
269
270
271 func weakenGlobalMapInitRelocs(fn *ir.Func) {
272 if globalMapInitLsyms == nil {
273 return
274 }
275 for i := range fn.LSym.R {
276 tgt := fn.LSym.R[i].Sym
277 if tgt == nil {
278 continue
279 }
280 if _, ok := globalMapInitLsyms[tgt]; !ok {
281 continue
282 }
283 if base.Debug.WrapGlobalMapDbg > 1 {
284 fmt.Fprintf(os.Stderr, "=-= weakify fn %v reloc %d %+v\n", fn, i,
285 fn.LSym.R[i])
286 }
287
288 fn.LSym.R[i].Type |= objabi.R_WEAK
289 }
290 }
291
292
293
294
295 func StackOffset(slot ssa.LocalSlot) int32 {
296 n := slot.N
297 var off int64
298 switch n.Class {
299 case ir.PPARAM, ir.PPARAMOUT:
300 if !n.IsOutputParamInRegisters() {
301 off = n.FrameOffset() + base.Ctxt.Arch.FixedFrameSize
302 break
303 }
304 fallthrough
305 case ir.PAUTO:
306 off = n.FrameOffset()
307 if base.Ctxt.Arch.FixedFrameSize == 0 {
308 off -= int64(types.PtrSize)
309 }
310 if buildcfg.FramePointerEnabled {
311 off -= int64(types.PtrSize)
312 }
313 }
314 return int32(off + slot.Off)
315 }
316
317
318
319 func fieldtrack(fnsym *obj.LSym, tracked map[*obj.LSym]struct{}) {
320 if fnsym == nil {
321 return
322 }
323 if !buildcfg.Experiment.FieldTrack || len(tracked) == 0 {
324 return
325 }
326
327 trackSyms := make([]*obj.LSym, 0, len(tracked))
328 for sym := range tracked {
329 trackSyms = append(trackSyms, sym)
330 }
331 sort.Slice(trackSyms, func(i, j int) bool { return trackSyms[i].Name < trackSyms[j].Name })
332 for _, sym := range trackSyms {
333 r := obj.Addrel(fnsym)
334 r.Sym = sym
335 r.Type = objabi.R_USEFIELD
336 }
337 }
338
339
340 type largeStack struct {
341 locals int64
342 args int64
343 callee int64
344 pos src.XPos
345 }
346
347 var (
348 largeStackFramesMu sync.Mutex
349 largeStackFrames []largeStack
350 )
351
352 func CheckLargeStacks() {
353
354 sort.Slice(largeStackFrames, func(i, j int) bool {
355 return largeStackFrames[i].pos.Before(largeStackFrames[j].pos)
356 })
357 for _, large := range largeStackFrames {
358 if large.callee != 0 {
359 base.ErrorfAt(large.pos, 0, "stack frame too large (>1GB): %d MB locals + %d MB args + %d MB callee", large.locals>>20, large.args>>20, large.callee>>20)
360 } else {
361 base.ErrorfAt(large.pos, 0, "stack frame too large (>1GB): %d MB locals + %d MB args", large.locals>>20, large.args>>20)
362 }
363 }
364 }
365
View as plain text