aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/ssagen/ssa.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/compile/internal/ssagen/ssa.go')
-rw-r--r--src/cmd/compile/internal/ssagen/ssa.go67
1 files changed, 41 insertions, 26 deletions
diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go
index 865630dd3e..938c1e8b62 100644
--- a/src/cmd/compile/internal/ssagen/ssa.go
+++ b/src/cmd/compile/internal/ssagen/ssa.go
@@ -7,6 +7,7 @@ package ssagen
import (
"bufio"
"bytes"
+ "cmd/compile/internal/abi"
"encoding/binary"
"fmt"
"go/constant"
@@ -208,6 +209,32 @@ func InitConfig() {
ir.Syms.SigPanic = typecheck.LookupRuntimeFunc("sigpanic")
}
+// AbiForFunc returns the ABI for a function, used to figure out arg/result mapping for rtcall and bodyless functions.
+// This follows policy for GOEXPERIMENT=regabi, //go:registerparams, and currently defined ABIInternal.
+// Policy is subject to change....
+// This always returns a freshly copied ABI.
+func AbiForFunc(fn *ir.Func) *abi.ABIConfig {
+ return abiForFunc(fn, ssaConfig.ABI0, ssaConfig.ABI1).Copy() // No idea what races will result, be safe
+}
+
+// abiForFunc implements ABI policy for a function, but does not return a copy of the ABI.
+// Passing a nil function returns ABIInternal.
+func abiForFunc(fn *ir.Func, abi0, abi1 *abi.ABIConfig) *abi.ABIConfig {
+ a := abi1
+ if true || objabi.Regabi_enabled == 0 {
+ a = abi0
+ }
+ if fn != nil && fn.Pragma&ir.RegisterParams != 0 { // TODO(register args) remove after register abi is working
+ name := ir.FuncName(fn)
+ if strings.Contains(name, ".") {
+ base.ErrorfAt(fn.Pos(), "Calls to //go:registerparams method %s won't work, remove the pragma from the declaration.", name)
+ }
+ a = abi1
+ base.WarnfAt(fn.Pos(), "declared function %v has register params", fn)
+ }
+ return a
+}
+
// getParam returns the Field of ith param of node n (which is a
// function/method/interface call), where the receiver of a method call is
// considered as the 0th parameter. This does not include the receiver of an
@@ -357,25 +384,10 @@ func buildssa(fn *ir.Func, worker int) *ssa.Func {
if fn.Pragma&ir.Nosplit != 0 {
s.f.NoSplit = true
}
- s.f.ABI0 = ssaConfig.ABI0.Copy() // Make a copy to avoid racy map operations in type-width cache.
+ s.f.ABI0 = ssaConfig.ABI0.Copy() // Make a copy to avoid racy map operations in type-register-width cache.
s.f.ABI1 = ssaConfig.ABI1.Copy()
-
- s.f.ABIDefault = s.f.ABI1 // Default ABI for function calls with no parsed signature for a pragma, e.g. rtcall
- // TODO(register args) -- remove "true ||"; in the short run, turning on the register ABI experiment still leaves the compiler defaulting to ABI0.
- // TODO(register args) -- remove this conditional entirely when register ABI is not an experiment.
- if true || objabi.Regabi_enabled == 0 {
- s.f.ABIDefault = s.f.ABI0 // reset
- }
-
- s.f.ABISelf = s.f.ABIDefault
-
- if fn.Pragma&ir.RegisterParams != 0 { // TODO(register args) remove after register abi is working
- s.f.ABISelf = s.f.ABI1
- if strings.Contains(name, ".") {
- base.ErrorfAt(fn.Pos(), "Calls to //go:registerparams method %s won't work, remove the pragma from the declaration.", name)
- }
- s.f.Warnl(fn.Pos(), "declared function %v has register params", fn)
- }
+ s.f.ABIDefault = abiForFunc(nil, s.f.ABI0, s.f.ABI1)
+ s.f.ABISelf = abiForFunc(fn, s.f.ABI0, s.f.ABI1)
s.panics = map[funcLine]*ssa.Block{}
s.softFloat = s.config.SoftFloat
@@ -4731,7 +4743,7 @@ func (s *state) openDeferExit() {
v := s.load(r.closure.Type.Elem(), r.closure)
s.maybeNilCheckClosure(v, callDefer)
codeptr := s.rawLoad(types.Types[types.TUINTPTR], v)
- aux := ssa.ClosureAuxCall(ACArgs, ACResults)
+ aux := ssa.ClosureAuxCall(ACArgs, ACResults, s.f.ABIDefault.ABIAnalyzeTypes(nil, ssa.ACParamsToTypes(ACArgs), ssa.ACParamsToTypes(ACResults)))
call = s.newValue2A(ssa.OpClosureLECall, aux.LateExpansionResultType(), aux, codeptr, v)
} else {
aux := ssa.StaticAuxCall(fn.(*ir.Name).Linksym(), ACArgs, ACResults,
@@ -4842,7 +4854,7 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val
} else {
o = p.SpillOffset() + int32(params.SpillAreaOffset())
}
- ACResults = append(ACResults, ssa.Param{Type: p.Type, Offset: o + int32(base.Ctxt.FixedFrameSize()), Reg: r})
+ ACResults = append(ACResults, ssa.Param{Type: p.Type, Offset: o, Reg: r})
}
}
@@ -4913,21 +4925,23 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val
// Store arguments to stack, including defer/go arguments and receiver for method calls.
// These are written in SP-offset order.
argStart := base.Ctxt.FixedFrameSize()
+ // argExtra is for combining with ABI-derived offsets; argStart is for old ABI0 code (defer, go).
+ argExtra := int32(0) // TODO(register args) untangle this mess when fully transition to abiutils, defer/go sanitized.
// Defer/go args.
if k != callNormal {
// Write argsize and closure (args to newproc/deferproc).
argsize := s.constInt32(types.Types[types.TUINT32], int32(stksize))
- ACArgs = append(ACArgs, ssa.Param{Type: types.Types[types.TUINT32], Offset: int32(argStart)})
+ ACArgs = append(ACArgs, ssa.Param{Type: types.Types[types.TUINT32], Offset: int32(argStart)}) // not argExtra
callArgs = append(callArgs, argsize)
ACArgs = append(ACArgs, ssa.Param{Type: types.Types[types.TUINTPTR], Offset: int32(argStart) + int32(types.PtrSize)})
callArgs = append(callArgs, closure)
stksize += 2 * int64(types.PtrSize)
argStart += 2 * int64(types.PtrSize)
+ argExtra = 2 * int32(types.PtrSize)
}
// Set receiver (for interface calls).
if rcvr != nil {
- // ACArgs = append(ACArgs, ssa.Param{Type: types.Types[types.TUINTPTR], Offset: int32(argStart)})
callArgs = append(callArgs, rcvr)
}
@@ -4938,7 +4952,7 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val
base.Fatalf("OCALLMETH missed by walkCall")
}
- for _, p := range params.InParams() {
+ for _, p := range params.InParams() { // includes receiver for interface calls
r := p.Registers
var o int32
if len(r) == 0 {
@@ -4946,7 +4960,7 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val
} else {
o = p.SpillOffset() + int32(params.SpillAreaOffset())
}
- ACArg := ssa.Param{Type: p.Type, Offset: int32(argStart) + o, Reg: r}
+ ACArg := ssa.Param{Type: p.Type, Offset: argExtra + o, Reg: r} // o from ABI includes any architecture-dependent offsets.
ACArgs = append(ACArgs, ACArg)
}
for i, n := range args {
@@ -4972,10 +4986,11 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val
// critical that we not clobber any arguments already
// stored onto the stack.
codeptr = s.rawLoad(types.Types[types.TUINTPTR], closure)
- aux := ssa.ClosureAuxCall(ACArgs, ACResults)
+ aux := ssa.ClosureAuxCall(ACArgs, ACResults, s.f.ABIDefault.ABIAnalyzeTypes(nil, ssa.ACParamsToTypes(ACArgs), ssa.ACParamsToTypes(ACResults)))
call = s.newValue2A(ssa.OpClosureLECall, aux.LateExpansionResultType(), aux, codeptr, closure)
case codeptr != nil:
- aux := ssa.InterfaceAuxCall(ACArgs, ACResults)
+ // Note that the "receiver" parameter is nil because the actual receiver is the first input parameter.
+ aux := ssa.InterfaceAuxCall(ACArgs, ACResults, s.f.ABIDefault.ABIAnalyzeTypes(nil, ssa.ACParamsToTypes(ACArgs), ssa.ACParamsToTypes(ACResults)))
call = s.newValue1A(ssa.OpInterLECall, aux.LateExpansionResultType(), aux, codeptr)
case callee != nil:
aux := ssa.StaticAuxCall(callTargetLSym(callee, s.curfn.LSym), ACArgs, ACResults, params)