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