1
2
3
4
5 package abi
6
7 import (
8 "cmd/compile/internal/base"
9 "cmd/compile/internal/ir"
10 "cmd/compile/internal/types"
11 "cmd/internal/obj"
12 "cmd/internal/src"
13 "fmt"
14 "math"
15 "sync"
16 )
17
18
19
20
21
22
23
24
25
26
27
28
29 type ABIParamResultInfo struct {
30 inparams []ABIParamAssignment
31 outparams []ABIParamAssignment
32 offsetToSpillArea int64
33 spillAreaSize int64
34 inRegistersUsed int
35 outRegistersUsed int
36 config *ABIConfig
37 }
38
39 func (a *ABIParamResultInfo) Config() *ABIConfig {
40 return a.config
41 }
42
43 func (a *ABIParamResultInfo) InParams() []ABIParamAssignment {
44 return a.inparams
45 }
46
47 func (a *ABIParamResultInfo) OutParams() []ABIParamAssignment {
48 return a.outparams
49 }
50
51 func (a *ABIParamResultInfo) InRegistersUsed() int {
52 return a.inRegistersUsed
53 }
54
55 func (a *ABIParamResultInfo) OutRegistersUsed() int {
56 return a.outRegistersUsed
57 }
58
59 func (a *ABIParamResultInfo) InParam(i int) *ABIParamAssignment {
60 return &a.inparams[i]
61 }
62
63 func (a *ABIParamResultInfo) OutParam(i int) *ABIParamAssignment {
64 return &a.outparams[i]
65 }
66
67 func (a *ABIParamResultInfo) SpillAreaOffset() int64 {
68 return a.offsetToSpillArea
69 }
70
71 func (a *ABIParamResultInfo) SpillAreaSize() int64 {
72 return a.spillAreaSize
73 }
74
75
76
77
78
79 func (a *ABIParamResultInfo) ArgWidth() int64 {
80 return a.spillAreaSize + a.offsetToSpillArea - a.config.LocalsOffset()
81 }
82
83
84
85
86
87
88
89
90
91
92 type RegIndex uint8
93
94
95
96
97
98
99 type ABIParamAssignment struct {
100 Type *types.Type
101 Name *ir.Name
102 Registers []RegIndex
103 offset int32
104 }
105
106
107
108 func (a *ABIParamAssignment) Offset() int32 {
109 if len(a.Registers) > 0 {
110 base.Fatalf("register allocated parameters have no offset")
111 }
112 return a.offset
113 }
114
115
116
117
118 func RegisterTypes(apa []ABIParamAssignment) []*types.Type {
119 rcount := 0
120 for _, pa := range apa {
121 rcount += len(pa.Registers)
122 }
123 if rcount == 0 {
124
125 return make([]*types.Type, 0, 1)
126 }
127 rts := make([]*types.Type, 0, rcount+1)
128 for _, pa := range apa {
129 if len(pa.Registers) == 0 {
130 continue
131 }
132 rts = appendParamTypes(rts, pa.Type)
133 }
134 return rts
135 }
136
137 func (pa *ABIParamAssignment) RegisterTypesAndOffsets() ([]*types.Type, []int64) {
138 l := len(pa.Registers)
139 if l == 0 {
140 return nil, nil
141 }
142 typs := make([]*types.Type, 0, l)
143 offs := make([]int64, 0, l)
144 offs, _ = appendParamOffsets(offs, 0, pa.Type)
145 return appendParamTypes(typs, pa.Type), offs
146 }
147
148 func appendParamTypes(rts []*types.Type, t *types.Type) []*types.Type {
149 w := t.Size()
150 if w == 0 {
151 return rts
152 }
153 if t.IsScalar() || t.IsPtrShaped() || t.IsSIMD() {
154 if t.IsComplex() {
155 c := types.FloatForComplex(t)
156 return append(rts, c, c)
157 } else {
158 if int(t.Size()) <= types.RegSize || t.IsSIMD() {
159 return append(rts, t)
160 }
161
162
163 if t.IsSigned() {
164 rts = append(rts, types.Types[types.TINT32])
165 } else {
166 rts = append(rts, types.Types[types.TUINT32])
167 }
168 return append(rts, types.Types[types.TUINT32])
169 }
170 } else {
171 typ := t.Kind()
172 switch typ {
173 case types.TARRAY:
174 for i := int64(0); i < t.NumElem(); i++ {
175 rts = appendParamTypes(rts, t.Elem())
176 }
177 case types.TSTRUCT:
178 for _, f := range t.Fields() {
179 if f.Type.Size() > 0 {
180 rts = appendParamTypes(rts, f.Type)
181 }
182 }
183 case types.TSLICE:
184 return appendParamTypes(rts, synthSlice)
185 case types.TSTRING:
186 return appendParamTypes(rts, synthString)
187 case types.TINTER:
188 return appendParamTypes(rts, synthIface)
189 }
190 }
191 return rts
192 }
193
194
195
196
197 func appendParamOffsets(offsets []int64, at int64, t *types.Type) ([]int64, int64) {
198 w := t.Size()
199 if w == 0 {
200 return offsets, at
201 }
202 if t.IsSIMD() {
203 return append(offsets, at), at + w
204 }
205 if t.IsScalar() || t.IsPtrShaped() {
206 if t.IsComplex() || int(t.Size()) > types.RegSize {
207 s := w / 2
208 return append(offsets, at, at+s), at + w
209 } else {
210 return append(offsets, at), at + w
211 }
212 } else {
213 typ := t.Kind()
214 switch typ {
215 case types.TARRAY:
216 te := t.Elem()
217 for i := int64(0); i < t.NumElem(); i++ {
218 at = align(at, te)
219 offsets, at = appendParamOffsets(offsets, at, te)
220 }
221 case types.TSTRUCT:
222 at0 := at
223 for i, f := range t.Fields() {
224 at = at0 + f.Offset
225 offsets, at = appendParamOffsets(offsets, at, f.Type)
226 if f.Type.Size() == 0 && i == t.NumFields()-1 {
227 at++
228 }
229 }
230 at = align(at, t)
231 case types.TSLICE:
232 return appendParamOffsets(offsets, at, synthSlice)
233 case types.TSTRING:
234 return appendParamOffsets(offsets, at, synthString)
235 case types.TINTER:
236 return appendParamOffsets(offsets, at, synthIface)
237 }
238 }
239 return offsets, at
240 }
241
242
243
244
245
246
247
248
249 func (a *ABIParamAssignment) FrameOffset(i *ABIParamResultInfo) int64 {
250 if a.offset == -1 {
251 base.Fatalf("function parameter has no ABI-defined frame-pointer offset")
252 }
253 if len(a.Registers) == 0 {
254 return int64(a.offset) - i.config.LocalsOffset()
255 }
256
257 return int64(a.offset) + i.SpillAreaOffset() - i.config.LocalsOffset()
258 }
259
260
261 type RegAmounts struct {
262 intRegs int
263 floatRegs int
264 }
265
266
267
268 type ABIConfig struct {
269
270 offsetForLocals int64
271 regAmounts RegAmounts
272 which obj.ABI
273 }
274
275
276
277 func NewABIConfig(iRegsCount, fRegsCount int, offsetForLocals int64, which uint8) *ABIConfig {
278 return &ABIConfig{offsetForLocals: offsetForLocals, regAmounts: RegAmounts{iRegsCount, fRegsCount}, which: obj.ABI(which)}
279 }
280
281
282
283
284 func (config *ABIConfig) Copy() *ABIConfig {
285 return config
286 }
287
288
289 func (config *ABIConfig) Which() obj.ABI {
290 return config.which
291 }
292
293
294
295
296 func (config *ABIConfig) LocalsOffset() int64 {
297 return config.offsetForLocals
298 }
299
300
301
302
303 func (config *ABIConfig) FloatIndexFor(r RegIndex) int64 {
304 return int64(r) - int64(config.regAmounts.intRegs)
305 }
306
307
308
309
310 func (config *ABIConfig) NumParamRegs(typ *types.Type) int {
311 intRegs, floatRegs := typ.Registers()
312 if intRegs == math.MaxUint8 && floatRegs == math.MaxUint8 {
313 base.Fatalf("cannot represent parameters of type %v in registers", typ)
314 }
315 return int(intRegs) + int(floatRegs)
316 }
317
318
319
320
321
322 func (config *ABIConfig) ABIAnalyzeTypes(params, results []*types.Type) *ABIParamResultInfo {
323 setup()
324 s := assignState{
325 stackOffset: config.offsetForLocals,
326 rTotal: config.regAmounts,
327 }
328
329 assignParams := func(params []*types.Type, isResult bool) []ABIParamAssignment {
330 res := make([]ABIParamAssignment, len(params))
331 for i, param := range params {
332 res[i] = s.assignParam(param, nil, isResult)
333 }
334 return res
335 }
336
337 info := &ABIParamResultInfo{config: config}
338
339
340 info.inparams = assignParams(params, false)
341 s.stackOffset = types.RoundUp(s.stackOffset, int64(types.RegSize))
342 info.inRegistersUsed = s.rUsed.intRegs + s.rUsed.floatRegs
343
344
345 s.rUsed = RegAmounts{}
346 info.outparams = assignParams(results, true)
347
348
349 info.offsetToSpillArea = alignTo(s.stackOffset, types.RegSize)
350 info.spillAreaSize = alignTo(s.spillOffset, types.RegSize)
351 info.outRegistersUsed = s.rUsed.intRegs + s.rUsed.floatRegs
352
353 return info
354 }
355
356
357
358
359
360 func (config *ABIConfig) ABIAnalyzeFuncType(ft *types.Type) *ABIParamResultInfo {
361 setup()
362 s := assignState{
363 stackOffset: config.offsetForLocals,
364 rTotal: config.regAmounts,
365 }
366
367 assignParams := func(params []*types.Field, isResult bool) []ABIParamAssignment {
368 res := make([]ABIParamAssignment, len(params))
369 for i, param := range params {
370 var name *ir.Name
371 if param.Nname != nil {
372 name = param.Nname.(*ir.Name)
373 }
374 res[i] = s.assignParam(param.Type, name, isResult)
375 }
376 return res
377 }
378
379 info := &ABIParamResultInfo{config: config}
380
381
382 info.inparams = assignParams(ft.RecvParams(), false)
383 s.stackOffset = types.RoundUp(s.stackOffset, int64(types.RegSize))
384 info.inRegistersUsed = s.rUsed.intRegs + s.rUsed.floatRegs
385
386
387 s.rUsed = RegAmounts{}
388 info.outparams = assignParams(ft.Results(), true)
389
390
391 info.offsetToSpillArea = alignTo(s.stackOffset, types.RegSize)
392 info.spillAreaSize = alignTo(s.spillOffset, types.RegSize)
393 info.outRegistersUsed = s.rUsed.intRegs + s.rUsed.floatRegs
394 return info
395 }
396
397
398
399
400
401
402
403
404 func (config *ABIConfig) ABIAnalyze(t *types.Type, setNname bool) *ABIParamResultInfo {
405 result := config.ABIAnalyzeFuncType(t)
406
407
408 for i, f := range t.RecvParams() {
409 config.updateOffset(result, f, result.inparams[i], false, setNname)
410 }
411 for i, f := range t.Results() {
412 config.updateOffset(result, f, result.outparams[i], true, setNname)
413 }
414 return result
415 }
416
417 func (config *ABIConfig) updateOffset(result *ABIParamResultInfo, f *types.Field, a ABIParamAssignment, isResult, setNname bool) {
418 if f.Offset != types.BADWIDTH {
419 base.Fatalf("field offset for %s at %s has been set to %d", f.Sym, base.FmtPos(f.Pos), f.Offset)
420 }
421
422
423 if !isResult || len(a.Registers) == 0 {
424
425
426 off := a.FrameOffset(result)
427 if setNname && f.Nname != nil {
428 f.Nname.(*ir.Name).SetFrameOffset(off)
429 f.Nname.(*ir.Name).SetIsOutputParamInRegisters(false)
430 }
431 } else {
432 if setNname && f.Nname != nil {
433 fname := f.Nname.(*ir.Name)
434 fname.SetIsOutputParamInRegisters(true)
435 fname.SetFrameOffset(0)
436 }
437 }
438 }
439
440
441
442
443
444
445 func (c *RegAmounts) regString(r RegIndex) string {
446 if int(r) < c.intRegs {
447 return fmt.Sprintf("I%d", int(r))
448 } else if int(r) < c.intRegs+c.floatRegs {
449 return fmt.Sprintf("F%d", int(r)-c.intRegs)
450 }
451 return fmt.Sprintf("<?>%d", r)
452 }
453
454
455
456 func (ri *ABIParamAssignment) ToString(config *ABIConfig, extra bool) string {
457 regs := "R{"
458 offname := "spilloffset"
459 if len(ri.Registers) == 0 {
460 offname = "offset"
461 }
462 for _, r := range ri.Registers {
463 regs += " " + config.regAmounts.regString(r)
464 if extra {
465 regs += fmt.Sprintf("(%d)", r)
466 }
467 }
468 if extra {
469 regs += fmt.Sprintf(" | #I=%d, #F=%d", config.regAmounts.intRegs, config.regAmounts.floatRegs)
470 }
471 return fmt.Sprintf("%s } %s: %d typ: %v", regs, offname, ri.offset, ri.Type)
472 }
473
474
475
476 func (ri *ABIParamResultInfo) String() string {
477 res := ""
478 for k, p := range ri.inparams {
479 res += fmt.Sprintf("IN %d: %s\n", k, p.ToString(ri.config, false))
480 }
481 for k, r := range ri.outparams {
482 res += fmt.Sprintf("OUT %d: %s\n", k, r.ToString(ri.config, false))
483 }
484 res += fmt.Sprintf("offsetToSpillArea: %d spillAreaSize: %d",
485 ri.offsetToSpillArea, ri.spillAreaSize)
486 return res
487 }
488
489
490
491 type assignState struct {
492 rTotal RegAmounts
493 rUsed RegAmounts
494 stackOffset int64
495 spillOffset int64
496 }
497
498
499 func align(a int64, t *types.Type) int64 {
500 return alignTo(a, int(uint8(t.Alignment())))
501 }
502
503
504 func alignTo(a int64, t int) int64 {
505 if t == 0 {
506 return a
507 }
508 return types.RoundUp(a, int64(t))
509 }
510
511
512 func nextSlot(offsetp *int64, typ *types.Type) int64 {
513 offset := align(*offsetp, typ)
514 *offsetp = offset + typ.Size()
515 return offset
516 }
517
518
519
520
521 func (state *assignState) allocateRegs(regs []RegIndex, t *types.Type) []RegIndex {
522 if t.Size() == 0 {
523 return regs
524 }
525 ri := state.rUsed.intRegs
526 rf := state.rUsed.floatRegs
527 if t.IsScalar() || t.IsPtrShaped() || t.IsSIMD() {
528 if t.IsComplex() {
529 regs = append(regs, RegIndex(rf+state.rTotal.intRegs), RegIndex(rf+1+state.rTotal.intRegs))
530 rf += 2
531 } else if t.IsFloat() || t.IsSIMD() {
532 regs = append(regs, RegIndex(rf+state.rTotal.intRegs))
533 rf += 1
534 } else {
535 n := (int(t.Size()) + types.RegSize - 1) / types.RegSize
536 for i := 0; i < n; i++ {
537 regs = append(regs, RegIndex(ri))
538 ri += 1
539 }
540 }
541 state.rUsed.intRegs = ri
542 state.rUsed.floatRegs = rf
543 return regs
544 } else {
545 typ := t.Kind()
546 switch typ {
547 case types.TARRAY:
548 for i := int64(0); i < t.NumElem(); i++ {
549 regs = state.allocateRegs(regs, t.Elem())
550 }
551 return regs
552 case types.TSTRUCT:
553 for _, f := range t.Fields() {
554 regs = state.allocateRegs(regs, f.Type)
555 }
556 return regs
557 case types.TSLICE:
558 return state.allocateRegs(regs, synthSlice)
559 case types.TSTRING:
560 return state.allocateRegs(regs, synthString)
561 case types.TINTER:
562 return state.allocateRegs(regs, synthIface)
563 }
564 }
565 base.Fatalf("was not expecting type %s", t)
566 panic("unreachable")
567 }
568
569
570 var synthOnce sync.Once
571
572
573
574 var synthSlice *types.Type
575 var synthString *types.Type
576 var synthIface *types.Type
577
578
579
580 func setup() {
581 synthOnce.Do(func() {
582 fname := types.BuiltinPkg.Lookup
583 nxp := src.NoXPos
584 bp := types.NewPtr(types.Types[types.TUINT8])
585 it := types.Types[types.TINT]
586 synthSlice = types.NewStruct([]*types.Field{
587 types.NewField(nxp, fname("ptr"), bp),
588 types.NewField(nxp, fname("len"), it),
589 types.NewField(nxp, fname("cap"), it),
590 })
591 types.CalcStructSize(synthSlice)
592 synthString = types.NewStruct([]*types.Field{
593 types.NewField(nxp, fname("data"), bp),
594 types.NewField(nxp, fname("len"), it),
595 })
596 types.CalcStructSize(synthString)
597 unsp := types.Types[types.TUNSAFEPTR]
598 synthIface = types.NewStruct([]*types.Field{
599 types.NewField(nxp, fname("f1"), unsp),
600 types.NewField(nxp, fname("f2"), unsp),
601 })
602 types.CalcStructSize(synthIface)
603 })
604 }
605
606
607
608
609
610 func (state *assignState) assignParam(typ *types.Type, name *ir.Name, isResult bool) ABIParamAssignment {
611 registers := state.tryAllocRegs(typ)
612
613 var offset int64 = -1
614 if registers == nil {
615 offset = nextSlot(&state.stackOffset, typ)
616 } else if !isResult {
617 offset = nextSlot(&state.spillOffset, typ)
618 }
619
620 return ABIParamAssignment{
621 Type: typ,
622 Name: name,
623 Registers: registers,
624 offset: int32(offset),
625 }
626 }
627
628
629
630 func (state *assignState) tryAllocRegs(typ *types.Type) []RegIndex {
631 if typ.Size() == 0 {
632 return nil
633 }
634
635 intRegs, floatRegs := typ.Registers()
636 if int(intRegs) > state.rTotal.intRegs-state.rUsed.intRegs || int(floatRegs) > state.rTotal.floatRegs-state.rUsed.floatRegs {
637 return nil
638 }
639
640 regs := make([]RegIndex, 0, int(intRegs)+int(floatRegs))
641 return state.allocateRegs(regs, typ)
642 }
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664 func (pa *ABIParamAssignment) ComputePadding(storage []uint64) []uint64 {
665 nr := len(pa.Registers)
666 padding := storage[:nr]
667 clear(padding)
668 if pa.Type.Kind() != types.TSTRUCT || nr == 0 {
669 return padding
670 }
671 types := make([]*types.Type, 0, nr)
672 types = appendParamTypes(types, pa.Type)
673 if len(types) != nr {
674 panic("internal error")
675 }
676 offsets, _ := appendParamOffsets([]int64{}, 0, pa.Type)
677 for idx, t := range types {
678 ts := t.Size()
679 off := offsets[idx] + ts
680 if idx < len(types)-1 {
681 noff := offsets[idx+1]
682 if noff != off {
683 padding[idx] = uint64(noff - off)
684 }
685 }
686 }
687 return padding
688 }
689
View as plain text