aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/abi/abiutils.go
diff options
context:
space:
mode:
authorDavid Chase <drchase@google.com>2021-02-01 13:26:47 -0500
committerDavid Chase <drchase@google.com>2021-02-24 23:05:10 +0000
commitd0d21b7c4c92df8bf60059cbea4c20cfe4ae5fee (patch)
treef4bb4649d1d39a35620e93d51a2a5859649ae360 /src/cmd/compile/internal/abi/abiutils.go
parent8027343b6395536aa8bef8158bad8f4c290dd650 (diff)
downloadgo-d0d21b7c4c92df8bf60059cbea4c20cfe4ae5fee.tar.gz
go-d0d21b7c4c92df8bf60059cbea4c20cfe4ae5fee.zip
cmd/compile: plumb abi info into expandCalls
Work in progress. TODO: - insert debugging output for all the steps listed below - emit modified call instructions w/ multiple register inputs and Result-typed outputs (next CL) - initially just change output from "mem" to "Result{mem}" = most places this hits will be future work. - change OpArg to use registerized variants - (done) match abi paramresultinfo with particular arg, use Name - (this CL) push register offsets for "loads" and "stores" into recursive decomposition. - hand registerized Result to exit block For #40724. Change-Id: Ie5de9d71f8fd4e092f5ee9260b54de35abf91016 Reviewed-on: https://go-review.googlesource.com/c/go/+/293390 Trust: David Chase <drchase@google.com> Run-TryBot: David Chase <drchase@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Jeremy Faller <jeremy@golang.org>
Diffstat (limited to 'src/cmd/compile/internal/abi/abiutils.go')
-rw-r--r--src/cmd/compile/internal/abi/abiutils.go68
1 files changed, 38 insertions, 30 deletions
diff --git a/src/cmd/compile/internal/abi/abiutils.go b/src/cmd/compile/internal/abi/abiutils.go
index 7b388ec3dc..4bd27efb59 100644
--- a/src/cmd/compile/internal/abi/abiutils.go
+++ b/src/cmd/compile/internal/abi/abiutils.go
@@ -30,6 +30,10 @@ type ABIParamResultInfo struct {
config *ABIConfig // to enable String() method
}
+func (a *ABIParamResultInfo) Config() *ABIConfig {
+ return a.config
+}
+
func (a *ABIParamResultInfo) InParams() []ABIParamAssignment {
return a.inparams
}
@@ -68,10 +72,11 @@ 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.
+// non-negative stack offset. The values in 'Registers' are indices
+// (as described above), not architected registers.
type ABIParamAssignment struct {
Type *types.Type
+ Name types.Object // should always be *ir.Name, used to match with a particular ssa.OpArg.
Registers []RegIndex
offset int32
}
@@ -126,37 +131,36 @@ func (a *ABIConfig) Copy() *ABIConfig {
// NumParamRegs returns the number of parameter registers used for a given type,
// without regard for the number available.
func (a *ABIConfig) NumParamRegs(t *types.Type) int {
+ var n int
if n, ok := a.regsForTypeCache[t]; ok {
return n
}
if t.IsScalar() || t.IsPtrShaped() {
- var n int
if t.IsComplex() {
n = 2
} else {
n = (int(t.Size()) + types.RegSize - 1) / types.RegSize
}
- a.regsForTypeCache[t] = n
- return n
- }
- typ := t.Kind()
- n := 0
- switch typ {
- case types.TARRAY:
- n = a.NumParamRegs(t.Elem()) * int(t.NumElem())
- case types.TSTRUCT:
- for _, f := range t.FieldSlice() {
- n += a.NumParamRegs(f.Type)
+ } else {
+ typ := t.Kind()
+ switch typ {
+ case types.TARRAY:
+ n = a.NumParamRegs(t.Elem()) * int(t.NumElem())
+ case types.TSTRUCT:
+ for _, f := range t.FieldSlice() {
+ n += a.NumParamRegs(f.Type)
+ }
+ case types.TSLICE:
+ n = a.NumParamRegs(synthSlice)
+ case types.TSTRING:
+ n = a.NumParamRegs(synthString)
+ case types.TINTER:
+ n = a.NumParamRegs(synthIface)
}
- case types.TSLICE:
- n = a.NumParamRegs(synthSlice)
- case types.TSTRING:
- n = a.NumParamRegs(synthString)
- case types.TINTER:
- n = a.NumParamRegs(synthIface)
}
a.regsForTypeCache[t] = n
+
return n
}
@@ -176,14 +180,14 @@ func (config *ABIConfig) ABIAnalyze(t *types.Type) *ABIParamResultInfo {
if t.NumRecvs() != 0 {
rfsl := ft.Receiver.FieldSlice()
result.inparams = append(result.inparams,
- s.assignParamOrReturn(rfsl[0].Type, false))
+ s.assignParamOrReturn(rfsl[0], false))
}
// Inputs
ifsl := ft.Params.FieldSlice()
for _, f := range ifsl {
result.inparams = append(result.inparams,
- s.assignParamOrReturn(f.Type, false))
+ s.assignParamOrReturn(f, false))
}
s.stackOffset = types.Rnd(s.stackOffset, int64(types.RegSize))
@@ -191,7 +195,7 @@ func (config *ABIConfig) ABIAnalyze(t *types.Type) *ABIParamResultInfo {
s.rUsed = RegAmounts{}
ofsl := ft.Results.FieldSlice()
for _, f := range ofsl {
- result.outparams = append(result.outparams, s.assignParamOrReturn(f.Type, true))
+ result.outparams = append(result.outparams, s.assignParamOrReturn(f, true))
}
// The spill area is at a register-aligned offset and its size is rounded up to a register alignment.
// TODO in theory could align offset only to minimum required by spilled data types.
@@ -299,7 +303,7 @@ func (state *assignState) allocateRegs() []RegIndex {
// 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, isReturn bool) ABIParamAssignment {
+func (state *assignState) regAllocate(t *types.Type, name types.Object, isReturn bool) ABIParamAssignment {
spillLoc := int64(-1)
if !isReturn {
// Spill for register-resident t must be aligned for storage of a t.
@@ -308,6 +312,7 @@ func (state *assignState) regAllocate(t *types.Type, isReturn bool) ABIParamAssi
}
return ABIParamAssignment{
Type: t,
+ Name: name,
Registers: state.allocateRegs(),
offset: int32(spillLoc),
}
@@ -316,9 +321,10 @@ func (state *assignState) regAllocate(t *types.Type, isReturn bool) ABIParamAssi
// 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 {
+func (state *assignState) stackAllocate(t *types.Type, name types.Object) ABIParamAssignment {
return ABIParamAssignment{
Type: t,
+ Name: name,
offset: int32(state.stackSlot(t)),
}
}
@@ -451,18 +457,20 @@ func (state *assignState) regassign(pt *types.Type) bool {
}
// assignParamOrReturn processes a given receiver, param, or result
-// of type 'pt' to determine whether it can be register assigned.
+// of field f 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, isReturn bool) ABIParamAssignment {
+func (state *assignState) assignParamOrReturn(f *types.Field, isReturn bool) ABIParamAssignment {
+ // TODO(register args) ? seems like "struct" and "fields" is not right anymore for describing function parameters
+ pt := f.Type
state.pUsed = RegAmounts{}
if pt.Width == types.BADWIDTH {
panic("should never happen")
} else if pt.Width == 0 {
- return state.stackAllocate(pt)
+ return state.stackAllocate(pt, f.Nname)
} else if state.regassign(pt) {
- return state.regAllocate(pt, isReturn)
+ return state.regAllocate(pt, f.Nname, isReturn)
} else {
- return state.stackAllocate(pt)
+ return state.stackAllocate(pt, f.Nname)
}
}