type ABIParamResultInfo … func (a *ABIParamResultInfo) Config() *ABIConfig { … } func (a *ABIParamResultInfo) InParams() []ABIParamAssignment { … } func (a *ABIParamResultInfo) OutParams() []ABIParamAssignment { … } func (a *ABIParamResultInfo) InRegistersUsed() int { … } func (a *ABIParamResultInfo) OutRegistersUsed() int { … } func (a *ABIParamResultInfo) InParam(i int) *ABIParamAssignment { … } func (a *ABIParamResultInfo) OutParam(i int) *ABIParamAssignment { … } func (a *ABIParamResultInfo) SpillAreaOffset() int64 { … } func (a *ABIParamResultInfo) SpillAreaSize() int64 { … } // ArgWidth returns the amount of stack needed for all the inputs // and outputs of a function or method, including ABI-defined parameter // slots and ABI-defined spill slots for register-resident parameters. // The name is inherited from (*Type).ArgWidth(), which it replaces. func (a *ABIParamResultInfo) ArgWidth() int64 { … } type RegIndex … type ABIParamAssignment … // Offset returns the stack offset for addressing the parameter that "a" describes. // This will panic if "a" describes a register-allocated parameter. func (a *ABIParamAssignment) Offset() int32 { … } // RegisterTypes returns a slice of the types of the registers // corresponding to a slice of parameters. The returned slice // has capacity for one more, likely a memory type. func RegisterTypes(apa []ABIParamAssignment) []*types.Type { … } func (pa *ABIParamAssignment) RegisterTypesAndOffsets() ([]*types.Type, []int64) { … } func appendParamTypes(rts []*types.Type, t *types.Type) []*types.Type { … } // appendParamOffsets appends the offset(s) of type t, starting from "at", // to input offsets, and returns the longer slice and the next unused offset. // at should already be aligned for t. func appendParamOffsets(offsets []int64, at int64, t *types.Type) ([]int64, int64) { … } // FrameOffset returns the frame-pointer-relative location that a function // would spill its input or output parameter to, if such a spill slot exists. // If there is none defined (e.g., register-allocated outputs) it panics. // For register-allocated inputs that is their spill offset reserved for morestack; // for stack-allocated inputs and outputs, that is their location on the stack. // (In a future version of the ABI, register-resident inputs may lose their defined // spill area to help reduce stack sizes.) func (a *ABIParamAssignment) FrameOffset(i *ABIParamResultInfo) int64 { … } type RegAmounts … type ABIConfig … // NewABIConfig returns a new ABI configuration for an architecture with // iRegsCount integer/pointer registers and fRegsCount floating point registers. func NewABIConfig(iRegsCount, fRegsCount int, offsetForLocals int64, which uint8) *ABIConfig { … } // Copy returns config. // // TODO(mdempsky): Remove. func (config *ABIConfig) Copy() *ABIConfig { … } // Which returns the ABI number func (config *ABIConfig) Which() obj.ABI { … } // LocalsOffset returns the architecture-dependent offset from SP for args and results. // In theory this is only used for debugging; it ought to already be incorporated into // results from the ABI-related methods func (config *ABIConfig) LocalsOffset() int64 { … } // FloatIndexFor translates r into an index in the floating point parameter // registers. If the result is negative, the input index was actually for the // integer parameter registers. func (config *ABIConfig) FloatIndexFor(r RegIndex) int64 { … } // NumParamRegs returns the total number of registers used to // represent a parameter of the given type, which must be register // assignable. func (config *ABIConfig) NumParamRegs(typ *types.Type) int { … } // ABIAnalyzeTypes takes slices of parameter and result types, and returns an ABIParamResultInfo, // based on the given configuration. This is the same result computed by config.ABIAnalyze applied to the // corresponding method/function type, except that all the embedded parameter names are nil. // This is intended for use by ssagen/ssa.go:(*state).rtcall, for runtime functions that lack a parsed function type. func (config *ABIConfig) ABIAnalyzeTypes(params, results []*types.Type) *ABIParamResultInfo { … } // ABIAnalyzeFuncType takes a function type 'ft' 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 (config *ABIConfig) ABIAnalyzeFuncType(ft *types.Type) *ABIParamResultInfo { … } // ABIAnalyze returns the same result as ABIAnalyzeFuncType, but also // updates the offsets of all the receiver, input, and output fields. // If setNname is true, it also sets the FrameOffset of the Nname for // the field(s); this is for use when compiling a function and figuring out // spill locations. Doing this for callers can cause races for register // outputs because their frame location transitions from BOGUS_FUNARG_OFFSET // to zero to an as-if-AUTO offset that has no use for callers. func (config *ABIConfig) ABIAnalyze(t *types.Type, setNname bool) *ABIParamResultInfo { … } func (config *ABIConfig) updateOffset(result *ABIParamResultInfo, f *types.Field, a ABIParamAssignment, isResult, setNname bool) { … } // regString produces a human-readable version of a RegIndex. func (c *RegAmounts) regString(r RegIndex) string { … } // ToString method renders an ABIParamAssignment in human-readable // form, suitable for debugging or unit testing. func (ri *ABIParamAssignment) ToString(config *ABIConfig, extra bool) string { … } // String method renders an ABIParamResultInfo in human-readable // form, suitable for debugging or unit testing. func (ri *ABIParamResultInfo) String() string { … } type assignState … // align returns a rounded up to t's alignment. func align(a int64, t *types.Type) int64 { … } // alignTo returns a rounded up to t, where t must be 0 or a power of 2. func alignTo(a int64, t int) int64 { … } // nextSlot allocates the next available slot for typ. func nextSlot(offsetp *int64, typ *types.Type) int64 { … } // allocateRegs returns an ordered list 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(regs []RegIndex, t *types.Type) []RegIndex { … } var synthOnce … var synthSlice … var synthString … var synthIface … // setup performs setup for the register assignment utilities, manufacturing // a small set of synthesized types that we'll need along the way. func setup() { … } // assignParam processes a given receiver, param, or result // 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) assignParam(typ *types.Type, name *ir.Name, isResult bool) ABIParamAssignment { … } // tryAllocRegs attempts to allocate registers to represent a // parameter of the given type. If unsuccessful, it returns nil. func (state *assignState) tryAllocRegs(typ *types.Type) []RegIndex { … } // ComputePadding returns a list of "post element" padding values in // the case where we have a structure being passed in registers. Given // a param assignment corresponding to a struct, it returns a list // containing padding values for each field, e.g. the Kth element in // the list is the amount of padding between field K and the following // field. For things that are not structs (or structs without padding) // it returns a list of zeros. Example: // // type small struct { // x uint16 // y uint8 // z int32 // w int32 // } // // For this struct we would return a list [0, 1, 0, 0], meaning that // we have one byte of padding after the second field, and no bytes of // padding after any of the other fields. Input parameter "storage" is // a slice with enough capacity to accommodate padding elements for // the architected register set in question. func (pa *ABIParamAssignment) ComputePadding(storage []uint64) []uint64 { … }