aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/gc
diff options
context:
space:
mode:
authorDavid Chase <drchase@google.com>2021-01-08 10:15:36 -0500
committerDavid Chase <drchase@google.com>2021-01-13 15:54:19 +0000
commitc41b999ad410c74bea222ee76488226a06ba4046 (patch)
treef50ac1f597df6de6b0a7f5399142d78718d6bfec /src/cmd/compile/internal/gc
parent861707a8c84f0b1ddbcaea0e9f439398ee2175fb (diff)
downloadgo-c41b999ad410c74bea222ee76488226a06ba4046.tar.gz
go-c41b999ad410c74bea222ee76488226a06ba4046.zip
[dev.regabi] cmd/compile: refactor abiutils from "gc" into new "abi"
Needs to be visible to ssagen, and might as well start clean to avoid creating a lot of accidental dependencies. Added some methods for export. Decided to use a pointer instead of value for ABIConfig uses. Tests ended up separate from abiutil itself; otherwise there are import cycles. Change-Id: I5570e1e6a463e303c5e2dc84e8dd4125e7c1adcc Reviewed-on: https://go-review.googlesource.com/c/go/+/282614 Trust: David Chase <drchase@google.com> Run-TryBot: David Chase <drchase@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Than McIntosh <thanm@google.com> Reviewed-by: Jeremy Faller <jeremy@golang.org>
Diffstat (limited to 'src/cmd/compile/internal/gc')
-rw-r--r--src/cmd/compile/internal/gc/abiutils.go351
-rw-r--r--src/cmd/compile/internal/gc/abiutils_test.go273
-rw-r--r--src/cmd/compile/internal/gc/abiutilsaux_test.go155
3 files changed, 0 insertions, 779 deletions
diff --git a/src/cmd/compile/internal/gc/abiutils.go b/src/cmd/compile/internal/gc/abiutils.go
deleted file mode 100644
index 5822c088f9..0000000000
--- a/src/cmd/compile/internal/gc/abiutils.go
+++ /dev/null
@@ -1,351 +0,0 @@
-// Copyright 2020 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package gc
-
-import (
- "cmd/compile/internal/types"
- "cmd/internal/src"
- "fmt"
- "sync"
-)
-
-//......................................................................
-//
-// Public/exported bits of the ABI utilities.
-//
-
-// ABIParamResultInfo stores the results of processing a given
-// function type to compute stack layout and register assignments. For
-// each input and output parameter we capture whether the param was
-// register-assigned (and to which register(s)) or the stack offset
-// for the param if is not going to be passed in registers according
-// to the rules in the Go internal ABI specification (1.17).
-type ABIParamResultInfo struct {
- inparams []ABIParamAssignment // Includes receiver for method calls. Does NOT include hidden closure pointer.
- outparams []ABIParamAssignment
- intSpillSlots int
- floatSpillSlots int
- offsetToSpillArea int64
- config ABIConfig // to enable String() method
-}
-
-// RegIndex stores the index into the set of machine registers used by
-// the ABI on a specific architecture for parameter passing. RegIndex
-// values 0 through N-1 (where N is the number of integer registers
-// used for param passing according to the ABI rules) describe integer
-// registers; values N through M (where M is the number of floating
-// point registers used). Thus if the ABI says there are 5 integer
-// registers and 7 floating point registers, then RegIndex value of 4
-// indicates the 5th integer register, and a RegIndex value of 11
-// indicates the 7th floating point register.
-type RegIndex uint8
-
-// ABIParamAssignment holds information about how a specific param or
-// result will be passed: in registers (in which case 'Registers' is
-// populated) or on the stack (in which case 'Offset' is set to a
-// non-negative stack offset. The values in 'Registers' are indices (as
-// described above), not architected registers.
-type ABIParamAssignment struct {
- Type *types.Type
- Registers []RegIndex
- Offset int32
-}
-
-// RegAmounts holds a specified number of integer/float registers.
-type RegAmounts struct {
- intRegs int
- floatRegs int
-}
-
-// ABIConfig captures the number of registers made available
-// by the ABI rules for parameter passing and result returning.
-type ABIConfig struct {
- // Do we need anything more than this?
- regAmounts RegAmounts
-}
-
-// ABIAnalyze takes a function type 't' and an ABI rules description
-// 'config' and analyzes the function to determine how its parameters
-// and results will be passed (in registers or on the stack), returning
-// an ABIParamResultInfo object that holds the results of the analysis.
-func ABIAnalyze(t *types.Type, config ABIConfig) ABIParamResultInfo {
- setup()
- s := assignState{
- rTotal: config.regAmounts,
- }
- result := ABIParamResultInfo{config: config}
-
- // Receiver
- ft := t.FuncType()
- if t.NumRecvs() != 0 {
- rfsl := ft.Receiver.FieldSlice()
- result.inparams = append(result.inparams,
- s.assignParamOrReturn(rfsl[0].Type))
- }
-
- // Inputs
- ifsl := ft.Params.FieldSlice()
- for _, f := range ifsl {
- result.inparams = append(result.inparams,
- s.assignParamOrReturn(f.Type))
- }
- s.stackOffset = types.Rnd(s.stackOffset, int64(types.RegSize))
-
- // Record number of spill slots needed.
- result.intSpillSlots = s.rUsed.intRegs
- result.floatSpillSlots = s.rUsed.floatRegs
-
- // Outputs
- s.rUsed = RegAmounts{}
- ofsl := ft.Results.FieldSlice()
- for _, f := range ofsl {
- result.outparams = append(result.outparams, s.assignParamOrReturn(f.Type))
- }
- result.offsetToSpillArea = s.stackOffset
-
- return result
-}
-
-//......................................................................
-//
-// Non-public portions.
-
-// regString produces a human-readable version of a RegIndex.
-func (c *RegAmounts) regString(r RegIndex) string {
- if int(r) < c.intRegs {
- return fmt.Sprintf("I%d", int(r))
- } else if int(r) < c.intRegs+c.floatRegs {
- return fmt.Sprintf("F%d", int(r)-c.intRegs)
- }
- return fmt.Sprintf("<?>%d", r)
-}
-
-// toString method renders an ABIParamAssignment in human-readable
-// form, suitable for debugging or unit testing.
-func (ri *ABIParamAssignment) toString(config ABIConfig) string {
- regs := "R{"
- for _, r := range ri.Registers {
- regs += " " + config.regAmounts.regString(r)
- }
- return fmt.Sprintf("%s } offset: %d typ: %v", regs, ri.Offset, ri.Type)
-}
-
-// toString method renders an ABIParamResultInfo in human-readable
-// form, suitable for debugging or unit testing.
-func (ri *ABIParamResultInfo) String() string {
- res := ""
- for k, p := range ri.inparams {
- res += fmt.Sprintf("IN %d: %s\n", k, p.toString(ri.config))
- }
- for k, r := range ri.outparams {
- res += fmt.Sprintf("OUT %d: %s\n", k, r.toString(ri.config))
- }
- res += fmt.Sprintf("intspill: %d floatspill: %d offsetToSpillArea: %d",
- ri.intSpillSlots, ri.floatSpillSlots, ri.offsetToSpillArea)
- return res
-}
-
-// assignState holds intermediate state during the register assigning process
-// for a given function signature.
-type assignState struct {
- rTotal RegAmounts // total reg amounts from ABI rules
- rUsed RegAmounts // regs used by params completely assigned so far
- pUsed RegAmounts // regs used by the current param (or pieces therein)
- stackOffset int64 // current stack offset
-}
-
-// stackSlot returns a stack offset for a param or result of the
-// specified type.
-func (state *assignState) stackSlot(t *types.Type) int64 {
- if t.Align > 0 {
- state.stackOffset = types.Rnd(state.stackOffset, int64(t.Align))
- }
- rv := state.stackOffset
- state.stackOffset += t.Width
- return rv
-}
-
-// allocateRegs returns a set of register indices for a parameter or result
-// that we've just determined to be register-assignable. The number of registers
-// needed is assumed to be stored in state.pUsed.
-func (state *assignState) allocateRegs() []RegIndex {
- regs := []RegIndex{}
-
- // integer
- for r := state.rUsed.intRegs; r < state.rUsed.intRegs+state.pUsed.intRegs; r++ {
- regs = append(regs, RegIndex(r))
- }
- state.rUsed.intRegs += state.pUsed.intRegs
-
- // floating
- for r := state.rUsed.floatRegs; r < state.rUsed.floatRegs+state.pUsed.floatRegs; r++ {
- regs = append(regs, RegIndex(r+state.rTotal.intRegs))
- }
- state.rUsed.floatRegs += state.pUsed.floatRegs
-
- return regs
-}
-
-// regAllocate creates a register ABIParamAssignment object for a param
-// or result with the specified type, as a final step (this assumes
-// that all of the safety/suitability analysis is complete).
-func (state *assignState) regAllocate(t *types.Type) ABIParamAssignment {
- return ABIParamAssignment{
- Type: t,
- Registers: state.allocateRegs(),
- Offset: -1,
- }
-}
-
-// stackAllocate creates a stack memory ABIParamAssignment object for
-// a param or result with the specified type, as a final step (this
-// assumes that all of the safety/suitability analysis is complete).
-func (state *assignState) stackAllocate(t *types.Type) ABIParamAssignment {
- return ABIParamAssignment{
- Type: t,
- Offset: int32(state.stackSlot(t)),
- }
-}
-
-// intUsed returns the number of integer registers consumed
-// at a given point within an assignment stage.
-func (state *assignState) intUsed() int {
- return state.rUsed.intRegs + state.pUsed.intRegs
-}
-
-// floatUsed returns the number of floating point registers consumed at
-// a given point within an assignment stage.
-func (state *assignState) floatUsed() int {
- return state.rUsed.floatRegs + state.pUsed.floatRegs
-}
-
-// regassignIntegral examines a param/result of integral type 't' to
-// determines whether it can be register-assigned. Returns TRUE if we
-// can register allocate, FALSE otherwise (and updates state
-// accordingly).
-func (state *assignState) regassignIntegral(t *types.Type) bool {
- regsNeeded := int(types.Rnd(t.Width, int64(types.PtrSize)) / int64(types.PtrSize))
-
- // Floating point and complex.
- if t.IsFloat() || t.IsComplex() {
- if regsNeeded+state.floatUsed() > state.rTotal.floatRegs {
- // not enough regs
- return false
- }
- state.pUsed.floatRegs += regsNeeded
- return true
- }
-
- // Non-floating point
- if regsNeeded+state.intUsed() > state.rTotal.intRegs {
- // not enough regs
- return false
- }
- state.pUsed.intRegs += regsNeeded
- return true
-}
-
-// regassignArray processes an array type (or array component within some
-// other enclosing type) to determine if it can be register assigned.
-// Returns TRUE if we can register allocate, FALSE otherwise.
-func (state *assignState) regassignArray(t *types.Type) bool {
-
- nel := t.NumElem()
- if nel == 0 {
- return true
- }
- if nel > 1 {
- // Not an array of length 1: stack assign
- return false
- }
- // Visit element
- return state.regassign(t.Elem())
-}
-
-// regassignStruct processes a struct type (or struct component within
-// some other enclosing type) to determine if it can be register
-// assigned. Returns TRUE if we can register allocate, FALSE otherwise.
-func (state *assignState) regassignStruct(t *types.Type) bool {
- for _, field := range t.FieldSlice() {
- if !state.regassign(field.Type) {
- return false
- }
- }
- return true
-}
-
-// synthOnce ensures that we only create the synth* fake types once.
-var synthOnce sync.Once
-
-// synthSlice, synthString, and syncIface are synthesized struct types
-// meant to capture the underlying implementations of string/slice/interface.
-var synthSlice *types.Type
-var synthString *types.Type
-var synthIface *types.Type
-
-// setup performs setup for the register assignment utilities, manufacturing
-// a small set of synthesized types that we'll need along the way.
-func setup() {
- synthOnce.Do(func() {
- fname := types.BuiltinPkg.Lookup
- nxp := src.NoXPos
- unsp := types.Types[types.TUNSAFEPTR]
- ui := types.Types[types.TUINTPTR]
- synthSlice = types.NewStruct(types.NoPkg, []*types.Field{
- types.NewField(nxp, fname("ptr"), unsp),
- types.NewField(nxp, fname("len"), ui),
- types.NewField(nxp, fname("cap"), ui),
- })
- synthString = types.NewStruct(types.NoPkg, []*types.Field{
- types.NewField(nxp, fname("data"), unsp),
- types.NewField(nxp, fname("len"), ui),
- })
- synthIface = types.NewStruct(types.NoPkg, []*types.Field{
- types.NewField(nxp, fname("f1"), unsp),
- types.NewField(nxp, fname("f2"), unsp),
- })
- })
-}
-
-// regassign examines a given param type (or component within some
-// composite) to determine if it can be register assigned. Returns
-// TRUE if we can register allocate, FALSE otherwise.
-func (state *assignState) regassign(pt *types.Type) bool {
- typ := pt.Kind()
- if pt.IsScalar() || pt.IsPtrShaped() {
- return state.regassignIntegral(pt)
- }
- switch typ {
- case types.TARRAY:
- return state.regassignArray(pt)
- case types.TSTRUCT:
- return state.regassignStruct(pt)
- case types.TSLICE:
- return state.regassignStruct(synthSlice)
- case types.TSTRING:
- return state.regassignStruct(synthString)
- case types.TINTER:
- return state.regassignStruct(synthIface)
- default:
- panic("not expected")
- }
-}
-
-// assignParamOrReturn processes a given receiver, param, or result
-// of type 'pt' to determine whether it can be register assigned.
-// The result of the analysis is recorded in the result
-// ABIParamResultInfo held in 'state'.
-func (state *assignState) assignParamOrReturn(pt *types.Type) ABIParamAssignment {
- state.pUsed = RegAmounts{}
- if pt.Width == types.BADWIDTH {
- panic("should never happen")
- } else if pt.Width == 0 {
- return state.stackAllocate(pt)
- } else if state.regassign(pt) {
- return state.regAllocate(pt)
- } else {
- return state.stackAllocate(pt)
- }
-}
diff --git a/src/cmd/compile/internal/gc/abiutils_test.go b/src/cmd/compile/internal/gc/abiutils_test.go
deleted file mode 100644
index 6fd0af1b1f..0000000000
--- a/src/cmd/compile/internal/gc/abiutils_test.go
+++ /dev/null
@@ -1,273 +0,0 @@
-// Copyright 2020 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package gc
-
-import (
- "bufio"
- "cmd/compile/internal/base"
- "cmd/compile/internal/ssagen"
- "cmd/compile/internal/typecheck"
- "cmd/compile/internal/types"
- "cmd/internal/obj"
- "cmd/internal/obj/x86"
- "cmd/internal/src"
- "os"
- "testing"
-)
-
-// AMD64 registers available:
-// - integer: RAX, RBX, RCX, RDI, RSI, R8, R9, r10, R11
-// - floating point: X0 - X14
-var configAMD64 = ABIConfig{
- regAmounts: RegAmounts{
- intRegs: 9,
- floatRegs: 15,
- },
-}
-
-func TestMain(m *testing.M) {
- ssagen.Arch.LinkArch = &x86.Linkamd64
- ssagen.Arch.REGSP = x86.REGSP
- ssagen.Arch.MAXWIDTH = 1 << 50
- types.MaxWidth = ssagen.Arch.MAXWIDTH
- base.Ctxt = obj.Linknew(ssagen.Arch.LinkArch)
- base.Ctxt.DiagFunc = base.Errorf
- base.Ctxt.DiagFlush = base.FlushErrors
- base.Ctxt.Bso = bufio.NewWriter(os.Stdout)
- types.PtrSize = ssagen.Arch.LinkArch.PtrSize
- types.RegSize = ssagen.Arch.LinkArch.RegSize
- typecheck.InitUniverse()
- os.Exit(m.Run())
-}
-
-func TestABIUtilsBasic1(t *testing.T) {
-
- // func(x int32) int32
- i32 := types.Types[types.TINT32]
- ft := mkFuncType(nil, []*types.Type{i32}, []*types.Type{i32})
-
- // expected results
- exp := makeExpectedDump(`
- IN 0: R{ I0 } offset: -1 typ: int32
- OUT 0: R{ I0 } offset: -1 typ: int32
- intspill: 1 floatspill: 0 offsetToSpillArea: 0
-`)
-
- abitest(t, ft, exp)
-}
-
-func TestABIUtilsBasic2(t *testing.T) {
- // func(x int32, y float64) (int32, float64, float64)
- i8 := types.Types[types.TINT8]
- i16 := types.Types[types.TINT16]
- i32 := types.Types[types.TINT32]
- i64 := types.Types[types.TINT64]
- f32 := types.Types[types.TFLOAT32]
- f64 := types.Types[types.TFLOAT64]
- c64 := types.Types[types.TCOMPLEX64]
- c128 := types.Types[types.TCOMPLEX128]
- ft := mkFuncType(nil,
- []*types.Type{
- i8, i16, i32, i64,
- f32, f32, f64, f64,
- i8, i16, i32, i64,
- f32, f32, f64, f64,
- c128, c128, c128, c128, c64,
- i8, i16, i32, i64,
- i8, i16, i32, i64},
- []*types.Type{i32, f64, f64})
- exp := makeExpectedDump(`
- IN 0: R{ I0 } offset: -1 typ: int8
- IN 1: R{ I1 } offset: -1 typ: int16
- IN 2: R{ I2 } offset: -1 typ: int32
- IN 3: R{ I3 } offset: -1 typ: int64
- IN 4: R{ F0 } offset: -1 typ: float32
- IN 5: R{ F1 } offset: -1 typ: float32
- IN 6: R{ F2 } offset: -1 typ: float64
- IN 7: R{ F3 } offset: -1 typ: float64
- IN 8: R{ I4 } offset: -1 typ: int8
- IN 9: R{ I5 } offset: -1 typ: int16
- IN 10: R{ I6 } offset: -1 typ: int32
- IN 11: R{ I7 } offset: -1 typ: int64
- IN 12: R{ F4 } offset: -1 typ: float32
- IN 13: R{ F5 } offset: -1 typ: float32
- IN 14: R{ F6 } offset: -1 typ: float64
- IN 15: R{ F7 } offset: -1 typ: float64
- IN 16: R{ F8 F9 } offset: -1 typ: complex128
- IN 17: R{ F10 F11 } offset: -1 typ: complex128
- IN 18: R{ F12 F13 } offset: -1 typ: complex128
- IN 19: R{ } offset: 0 typ: complex128
- IN 20: R{ F14 } offset: -1 typ: complex64
- IN 21: R{ I8 } offset: -1 typ: int8
- IN 22: R{ } offset: 16 typ: int16
- IN 23: R{ } offset: 20 typ: int32
- IN 24: R{ } offset: 24 typ: int64
- IN 25: R{ } offset: 32 typ: int8
- IN 26: R{ } offset: 34 typ: int16
- IN 27: R{ } offset: 36 typ: int32
- IN 28: R{ } offset: 40 typ: int64
- OUT 0: R{ I0 } offset: -1 typ: int32
- OUT 1: R{ F0 } offset: -1 typ: float64
- OUT 2: R{ F1 } offset: -1 typ: float64
- intspill: 9 floatspill: 15 offsetToSpillArea: 48
-`)
-
- abitest(t, ft, exp)
-}
-
-func TestABIUtilsArrays(t *testing.T) {
- i32 := types.Types[types.TINT32]
- ae := types.NewArray(i32, 0)
- a1 := types.NewArray(i32, 1)
- a2 := types.NewArray(i32, 2)
- aa1 := types.NewArray(a1, 1)
- ft := mkFuncType(nil, []*types.Type{a1, ae, aa1, a2},
- []*types.Type{a2, a1, ae, aa1})
-
- exp := makeExpectedDump(`
- IN 0: R{ I0 } offset: -1 typ: [1]int32
- IN 1: R{ } offset: 0 typ: [0]int32
- IN 2: R{ I1 } offset: -1 typ: [1][1]int32
- IN 3: R{ } offset: 0 typ: [2]int32
- OUT 0: R{ } offset: 8 typ: [2]int32
- OUT 1: R{ I0 } offset: -1 typ: [1]int32
- OUT 2: R{ } offset: 16 typ: [0]int32
- OUT 3: R{ I1 } offset: -1 typ: [1][1]int32
- intspill: 2 floatspill: 0 offsetToSpillArea: 16
-`)
-
- abitest(t, ft, exp)
-}
-
-func TestABIUtilsStruct1(t *testing.T) {
- i8 := types.Types[types.TINT8]
- i16 := types.Types[types.TINT16]
- i32 := types.Types[types.TINT32]
- i64 := types.Types[types.TINT64]
- s := mkstruct([]*types.Type{i8, i8, mkstruct([]*types.Type{}), i8, i16})
- ft := mkFuncType(nil, []*types.Type{i8, s, i64},
- []*types.Type{s, i8, i32})
-
- exp := makeExpectedDump(`
- IN 0: R{ I0 } offset: -1 typ: int8
- IN 1: R{ I1 I2 I3 I4 } offset: -1 typ: struct { int8; int8; struct {}; int8; int16 }
- IN 2: R{ I5 } offset: -1 typ: int64
- OUT 0: R{ I0 I1 I2 I3 } offset: -1 typ: struct { int8; int8; struct {}; int8; int16 }
- OUT 1: R{ I4 } offset: -1 typ: int8
- OUT 2: R{ I5 } offset: -1 typ: int32
- intspill: 6 floatspill: 0 offsetToSpillArea: 0
-`)
-
- abitest(t, ft, exp)
-}
-
-func TestABIUtilsStruct2(t *testing.T) {
- f64 := types.Types[types.TFLOAT64]
- i64 := types.Types[types.TINT64]
- s := mkstruct([]*types.Type{i64, mkstruct([]*types.Type{})})
- fs := mkstruct([]*types.Type{f64, s, mkstruct([]*types.Type{})})
- ft := mkFuncType(nil, []*types.Type{s, s, fs},
- []*types.Type{fs, fs})
-
- exp := makeExpectedDump(`
- IN 0: R{ I0 } offset: -1 typ: struct { int64; struct {} }
- IN 1: R{ I1 } offset: -1 typ: struct { int64; struct {} }
- IN 2: R{ I2 F0 } offset: -1 typ: struct { float64; struct { int64; struct {} }; struct {} }
- OUT 0: R{ I0 F0 } offset: -1 typ: struct { float64; struct { int64; struct {} }; struct {} }
- OUT 1: R{ I1 F1 } offset: -1 typ: struct { float64; struct { int64; struct {} }; struct {} }
- intspill: 3 floatspill: 1 offsetToSpillArea: 0
-`)
-
- abitest(t, ft, exp)
-}
-
-func TestABIUtilsSliceString(t *testing.T) {
- i32 := types.Types[types.TINT32]
- sli32 := types.NewSlice(i32)
- str := types.New(types.TSTRING)
- i8 := types.Types[types.TINT8]
- i64 := types.Types[types.TINT64]
- ft := mkFuncType(nil, []*types.Type{sli32, i8, sli32, i8, str, i8, i64, sli32},
- []*types.Type{str, i64, str, sli32})
-
- exp := makeExpectedDump(`
- IN 0: R{ I0 I1 I2 } offset: -1 typ: []int32
- IN 1: R{ I3 } offset: -1 typ: int8
- IN 2: R{ I4 I5 I6 } offset: -1 typ: []int32
- IN 3: R{ I7 } offset: -1 typ: int8
- IN 4: R{ } offset: 0 typ: string
- IN 5: R{ I8 } offset: -1 typ: int8
- IN 6: R{ } offset: 16 typ: int64
- IN 7: R{ } offset: 24 typ: []int32
- OUT 0: R{ I0 I1 } offset: -1 typ: string
- OUT 1: R{ I2 } offset: -1 typ: int64
- OUT 2: R{ I3 I4 } offset: -1 typ: string
- OUT 3: R{ I5 I6 I7 } offset: -1 typ: []int32
- intspill: 9 floatspill: 0 offsetToSpillArea: 48
-`)
-
- abitest(t, ft, exp)
-}
-
-func TestABIUtilsMethod(t *testing.T) {
- i16 := types.Types[types.TINT16]
- i64 := types.Types[types.TINT64]
- f64 := types.Types[types.TFLOAT64]
-
- s1 := mkstruct([]*types.Type{i16, i16, i16})
- ps1 := types.NewPtr(s1)
- a7 := types.NewArray(ps1, 7)
- ft := mkFuncType(s1, []*types.Type{ps1, a7, f64, i16, i16, i16},
- []*types.Type{a7, f64, i64})
-
- exp := makeExpectedDump(`
- IN 0: R{ I0 I1 I2 } offset: -1 typ: struct { int16; int16; int16 }
- IN 1: R{ I3 } offset: -1 typ: *struct { int16; int16; int16 }
- IN 2: R{ } offset: 0 typ: [7]*struct { int16; int16; int16 }
- IN 3: R{ F0 } offset: -1 typ: float64
- IN 4: R{ I4 } offset: -1 typ: int16
- IN 5: R{ I5 } offset: -1 typ: int16
- IN 6: R{ I6 } offset: -1 typ: int16
- OUT 0: R{ } offset: 56 typ: [7]*struct { int16; int16; int16 }
- OUT 1: R{ F0 } offset: -1 typ: float64
- OUT 2: R{ I0 } offset: -1 typ: int64
- intspill: 7 floatspill: 1 offsetToSpillArea: 112
-`)
-
- abitest(t, ft, exp)
-}
-
-func TestABIUtilsInterfaces(t *testing.T) {
- ei := types.Types[types.TINTER] // interface{}
- pei := types.NewPtr(ei) // *interface{}
- fldt := mkFuncType(types.FakeRecvType(), []*types.Type{},
- []*types.Type{types.UntypedString})
- field := types.NewField(src.NoXPos, nil, fldt)
- // interface{ ...() string }
- nei := types.NewInterface(types.LocalPkg, []*types.Field{field})
-
- i16 := types.Types[types.TINT16]
- tb := types.Types[types.TBOOL]
- s1 := mkstruct([]*types.Type{i16, i16, tb})
-
- ft := mkFuncType(nil, []*types.Type{s1, ei, ei, nei, pei, nei, i16},
- []*types.Type{ei, nei, pei})
-
- exp := makeExpectedDump(`
- IN 0: R{ I0 I1 I2 } offset: -1 typ: struct { int16; int16; bool }
- IN 1: R{ I3 I4 } offset: -1 typ: interface {}
- IN 2: R{ I5 I6 } offset: -1 typ: interface {}
- IN 3: R{ I7 I8 } offset: -1 typ: interface { () untyped string }
- IN 4: R{ } offset: 0 typ: *interface {}
- IN 5: R{ } offset: 8 typ: interface { () untyped string }
- IN 6: R{ } offset: 24 typ: int16
- OUT 0: R{ I0 I1 } offset: -1 typ: interface {}
- OUT 1: R{ I2 I3 } offset: -1 typ: interface { () untyped string }
- OUT 2: R{ I4 } offset: -1 typ: *interface {}
- intspill: 9 floatspill: 0 offsetToSpillArea: 32
-`)
-
- abitest(t, ft, exp)
-}
diff --git a/src/cmd/compile/internal/gc/abiutilsaux_test.go b/src/cmd/compile/internal/gc/abiutilsaux_test.go
deleted file mode 100644
index 9386b554b0..0000000000
--- a/src/cmd/compile/internal/gc/abiutilsaux_test.go
+++ /dev/null
@@ -1,155 +0,0 @@
-// Copyright 2020 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package gc
-
-// This file contains utility routines and harness infrastructure used
-// by the ABI tests in "abiutils_test.go".
-
-import (
- "cmd/compile/internal/ir"
- "cmd/compile/internal/typecheck"
- "cmd/compile/internal/types"
- "cmd/internal/src"
- "fmt"
- "strings"
- "testing"
- "text/scanner"
-)
-
-func mkParamResultField(t *types.Type, s *types.Sym, which ir.Class) *types.Field {
- field := types.NewField(src.NoXPos, s, t)
- n := typecheck.NewName(s)
- n.Class = which
- field.Nname = n
- n.SetType(t)
- return field
-}
-
-// mkstruct is a helper routine to create a struct type with fields
-// of the types specified in 'fieldtypes'.
-func mkstruct(fieldtypes []*types.Type) *types.Type {
- fields := make([]*types.Field, len(fieldtypes))
- for k, t := range fieldtypes {
- if t == nil {
- panic("bad -- field has no type")
- }
- f := types.NewField(src.NoXPos, nil, t)
- fields[k] = f
- }
- s := types.NewStruct(types.LocalPkg, fields)
- return s
-}
-
-func mkFuncType(rcvr *types.Type, ins []*types.Type, outs []*types.Type) *types.Type {
- q := typecheck.Lookup("?")
- inf := []*types.Field{}
- for _, it := range ins {
- inf = append(inf, mkParamResultField(it, q, ir.PPARAM))
- }
- outf := []*types.Field{}
- for _, ot := range outs {
- outf = append(outf, mkParamResultField(ot, q, ir.PPARAMOUT))
- }
- var rf *types.Field
- if rcvr != nil {
- rf = mkParamResultField(rcvr, q, ir.PPARAM)
- }
- return types.NewSignature(types.LocalPkg, rf, inf, outf)
-}
-
-type expectedDump struct {
- dump string
- file string
- line int
-}
-
-func tokenize(src string) []string {
- var s scanner.Scanner
- s.Init(strings.NewReader(src))
- res := []string{}
- for tok := s.Scan(); tok != scanner.EOF; tok = s.Scan() {
- res = append(res, s.TokenText())
- }
- return res
-}
-
-func verifyParamResultOffset(t *testing.T, f *types.Field, r ABIParamAssignment, which string, idx int) int {
- n := ir.AsNode(f.Nname).(*ir.Name)
- if n.FrameOffset() != int64(r.Offset) {
- t.Errorf("%s %d: got offset %d wanted %d t=%v",
- which, idx, r.Offset, n.Offset_, f.Type)
- return 1
- }
- return 0
-}
-
-func makeExpectedDump(e string) expectedDump {
- return expectedDump{dump: e}
-}
-
-func difftokens(atoks []string, etoks []string) string {
- if len(atoks) != len(etoks) {
- return fmt.Sprintf("expected %d tokens got %d",
- len(etoks), len(atoks))
- }
- for i := 0; i < len(etoks); i++ {
- if etoks[i] == atoks[i] {
- continue
- }
-
- return fmt.Sprintf("diff at token %d: expected %q got %q",
- i, etoks[i], atoks[i])
- }
- return ""
-}
-
-func abitest(t *testing.T, ft *types.Type, exp expectedDump) {
-
- types.CalcSize(ft)
-
- // Analyze with full set of registers.
- regRes := ABIAnalyze(ft, configAMD64)
- regResString := strings.TrimSpace(regRes.String())
-
- // Check results.
- reason := difftokens(tokenize(regResString), tokenize(exp.dump))
- if reason != "" {
- t.Errorf("\nexpected:\n%s\ngot:\n%s\nreason: %s",
- strings.TrimSpace(exp.dump), regResString, reason)
- }
-
- // Analyze again with empty register set.
- empty := ABIConfig{}
- emptyRes := ABIAnalyze(ft, empty)
- emptyResString := emptyRes.String()
-
- // Walk the results and make sure the offsets assigned match
- // up with those assiged by dowidth. This checks to make sure that
- // when we have no available registers the ABI assignment degenerates
- // back to the original ABI0.
-
- // receiver
- failed := 0
- rfsl := ft.Recvs().Fields().Slice()
- poff := 0
- if len(rfsl) != 0 {
- failed |= verifyParamResultOffset(t, rfsl[0], emptyRes.inparams[0], "receiver", 0)
- poff = 1
- }
- // params
- pfsl := ft.Params().Fields().Slice()
- for k, f := range pfsl {
- verifyParamResultOffset(t, f, emptyRes.inparams[k+poff], "param", k)
- }
- // results
- ofsl := ft.Results().Fields().Slice()
- for k, f := range ofsl {
- failed |= verifyParamResultOffset(t, f, emptyRes.outparams[k], "result", k)
- }
-
- if failed != 0 {
- t.Logf("emptyres:\n%s\n", emptyResString)
- }
-}