argStart := Ctxt.FixedFrameSize()
fn := r.n.Left
stksize := fn.Type.ArgWidth()
+ var ACArgs []ssa.Param
+ var ACResults []ssa.Param
if r.rcvr != nil {
// rcvr in case of OCALLINTER
v := s.load(r.rcvr.Type.Elem(), r.rcvr)
addr := s.constOffPtrSP(s.f.Config.Types.UintptrPtr, argStart)
+ ACArgs = append(ACArgs, ssa.Param{Type: types.Types[TUINTPTR], Offset: int32(argStart)})
s.store(types.Types[TUINTPTR], addr, v)
}
for j, argAddrVal := range r.argVals {
f := getParam(r.n, j)
pt := types.NewPtr(f.Type)
addr := s.constOffPtrSP(pt, argStart+f.Offset)
+ ACArgs = append(ACArgs, ssa.Param{Type: types.Types[TUINTPTR], Offset: int32(argStart + f.Offset)})
if !canSSAType(f.Type) {
s.move(f.Type, addr, argAddrVal)
} else {
call = s.newValue3A(ssa.OpClosureCall, types.TypeMem, ssa.ClosureAuxCall(), codeptr, v, s.mem())
} else {
// Do a static call if the original call was a static function or method
- call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(fn.Sym.Linksym()), s.mem())
+ call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(fn.Sym.Linksym(), ACArgs, ACResults), s.mem())
}
call.AuxInt = stksize
s.vars[&memVar] = call
var codeptr *ssa.Value // ptr to target code (if dynamic)
var rcvr *ssa.Value // receiver to set
fn := n.Left
+ var ACArgs []ssa.Param
+ var ACResults []ssa.Param
+ res := n.Left.Type.Results()
+ if k == callNormal {
+ nf := res.NumFields()
+ for i := 0; i < nf; i++ {
+ fp := res.Field(i)
+ ACResults = append(ACResults, ssa.Param{Type: fp.Type, Offset: int32(fp.Offset + Ctxt.FixedFrameSize())})
+ }
+ }
+
switch n.Op {
case OCALLFUNC:
if k == callNormal && fn.Op == ONAME && fn.Class() == PFUNC {
// Call runtime.deferprocStack with pointer to _defer record.
arg0 := s.constOffPtrSP(types.Types[TUINTPTR], Ctxt.FixedFrameSize())
s.store(types.Types[TUINTPTR], arg0, addr)
- call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(deferprocStack), s.mem())
+ ACArgs = append(ACArgs, ssa.Param{Type: types.Types[TUINTPTR], Offset: int32(Ctxt.FixedFrameSize())})
+ call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(deferprocStack, ACArgs, ACResults), s.mem())
if stksize < int64(Widthptr) {
// We need room for both the call to deferprocStack and the call to
// the deferred function.
+ // TODO Revisit this if/when we pass args in registers.
stksize = int64(Widthptr)
}
call.AuxInt = stksize
// Write argsize and closure (args to newproc/deferproc).
argsize := s.constInt32(types.Types[TUINT32], int32(stksize))
addr := s.constOffPtrSP(s.f.Config.Types.UInt32Ptr, argStart)
+ ACArgs = append(ACArgs, ssa.Param{Type: types.Types[TUINT32], Offset: int32(argStart)})
s.store(types.Types[TUINT32], addr, argsize)
addr = s.constOffPtrSP(s.f.Config.Types.UintptrPtr, argStart+int64(Widthptr))
+ ACArgs = append(ACArgs, ssa.Param{Type: types.Types[TUINTPTR], Offset: int32(argStart) + int32(Widthptr)})
s.store(types.Types[TUINTPTR], addr, closure)
stksize += 2 * int64(Widthptr)
argStart += 2 * int64(Widthptr)
// Set receiver (for interface calls).
if rcvr != nil {
addr := s.constOffPtrSP(s.f.Config.Types.UintptrPtr, argStart)
+ ACArgs = append(ACArgs, ssa.Param{Type: types.Types[TUINTPTR], Offset: int32(argStart)})
s.store(types.Types[TUINTPTR], addr, rcvr)
}
args := n.Rlist.Slice()
if n.Op == OCALLMETH {
f := t.Recv()
- s.storeArg(args[0], f.Type, argStart+f.Offset)
+ ACArgs = append(ACArgs, s.storeArg(args[0], f.Type, argStart+f.Offset))
args = args[1:]
}
for i, n := range args {
f := t.Params().Field(i)
- s.storeArg(n, f.Type, argStart+f.Offset)
+ ACArgs = append(ACArgs, s.storeArg(n, f.Type, argStart+f.Offset))
}
// call target
switch {
case k == callDefer:
- call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(deferproc), s.mem())
+ call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(deferproc, ACArgs, ACResults), s.mem())
case k == callGo:
- call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(newproc), s.mem())
+ call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(newproc, ACArgs, ACResults), s.mem())
case closure != nil:
// rawLoad because loading the code pointer from a
// closure is always safe, but IsSanitizerSafeAddr
codeptr = s.rawLoad(types.Types[TUINTPTR], closure)
call = s.newValue3A(ssa.OpClosureCall, types.TypeMem, ssa.ClosureAuxCall(), codeptr, closure, s.mem())
case codeptr != nil:
- call = s.newValue2A(ssa.OpInterCall, types.TypeMem, ssa.InterfaceAuxCall(), codeptr, s.mem())
+ call = s.newValue2A(ssa.OpInterCall, types.TypeMem, ssa.InterfaceAuxCall(ACArgs, ACResults), codeptr, s.mem())
case sym != nil:
- call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(sym.Linksym()), s.mem())
+ call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(sym.Linksym(), ACArgs, ACResults), s.mem())
default:
s.Fatalf("bad call type %v %v", n.Op, n)
}
s.startBlock(bNext)
}
- res := n.Left.Type.Results()
if res.NumFields() == 0 || k != callNormal {
// call has no return value. Continue with the next statement.
return nil
func (s *state) rtcall(fn *obj.LSym, returns bool, results []*types.Type, args ...*ssa.Value) []*ssa.Value {
// Write args to the stack
off := Ctxt.FixedFrameSize()
+ var ACArgs []ssa.Param
+ var ACResults []ssa.Param
for _, arg := range args {
t := arg.Type
off = Rnd(off, t.Alignment())
ptr := s.constOffPtrSP(t.PtrTo(), off)
size := t.Size()
+ ACArgs = append(ACArgs, ssa.Param{Type: t, Offset: int32(off)})
s.store(t, ptr, arg)
off += size
}
off = Rnd(off, int64(Widthreg))
+ // Accumulate results types and offsets
+ offR := off
+ for _, t := range results {
+ offR = Rnd(offR, t.Alignment())
+ ACResults = append(ACResults, ssa.Param{Type: t, Offset: int32(offR)})
+ offR += t.Size()
+ }
+
// Issue call
- call := s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(fn), s.mem())
+ call := s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(fn, ACArgs, ACResults), s.mem())
s.vars[&memVar] = call
if !returns {
}
}
-func (s *state) storeArg(n *Node, t *types.Type, off int64) {
+func (s *state) storeArg(n *Node, t *types.Type, off int64) ssa.Param {
s.storeArgWithBase(n, t, s.sp, off)
+ return ssa.Param{Type: t, Offset: int32(off)}
}
func (s *state) storeArgWithBase(n *Node, t *types.Type, base *ssa.Value, off int64) {
package ssa
import (
+ "cmd/compile/internal/types"
"cmd/internal/obj"
"fmt"
)
type auxType int8
+type Param struct {
+ Type *types.Type
+ Offset int32 // TODO someday this will be a register
+}
+
type AuxCall struct {
- Fn *obj.LSym
+ Fn *obj.LSym
+ args []Param // Includes receiver for method calls. Does NOT include hidden closure pointer.
+ results []Param
}
func (a *AuxCall) String() string {
+ var fn string
if a.Fn == nil {
- return "AuxCall(nil)"
+ fn = "AuxCall{nil" // could be interface/closure etc.
+ } else {
+ fn = fmt.Sprintf("AuxCall{%v", a.Fn)
+ }
+
+ if len(a.args) == 0 {
+ fn += "()"
+ } else {
+ s := "("
+ for _, arg := range a.args {
+ fn += fmt.Sprintf("%s[%v,%v]", s, arg.Type, arg.Offset)
+ s = ","
+ }
+ fn += ")"
}
- return fmt.Sprintf("AuxCall(%v)", a.Fn)
+
+ if len(a.results) > 0 { // usual is zero or one; only some RT calls have more than one.
+ if len(a.results) == 1 {
+ fn += fmt.Sprintf("[%v,%v]", a.results[0].Type, a.results[0].Offset)
+ } else {
+ s := "("
+ for _, result := range a.results {
+ fn += fmt.Sprintf("%s[%v,%v]", s, result.Type, result.Offset)
+ s = ","
+ }
+ fn += ")"
+ }
+ }
+
+ return fn + "}"
}
// StaticAuxCall returns an AuxCall for a static call.
-func StaticAuxCall(sym *obj.LSym) *AuxCall {
- return &AuxCall{Fn: sym}
+func StaticAuxCall(sym *obj.LSym, args []Param, results []Param) *AuxCall {
+ return &AuxCall{Fn: sym, args: args, results: results}
}
// InterfaceAuxCall returns an AuxCall for an interface call.
-func InterfaceAuxCall() *AuxCall {
- return &AuxCall{}
+func InterfaceAuxCall(args []Param, results []Param) *AuxCall {
+ return &AuxCall{Fn: nil, args: args, results: results}
}
// ClosureAuxCall returns an AuxCall for a closure call.
// put arguments on stack
off := config.ctxt.FixedFrameSize()
+ var ACArgs []Param
if typ != nil { // for typedmemmove
taddr := b.NewValue1A(pos, OpAddr, b.Func.Config.Types.Uintptr, typ, sb)
off = round(off, taddr.Type.Alignment())
arg := b.NewValue1I(pos, OpOffPtr, taddr.Type.PtrTo(), off, sp)
mem = b.NewValue3A(pos, OpStore, types.TypeMem, ptr.Type, arg, taddr, mem)
+ ACArgs = append(ACArgs, Param{Type: b.Func.Config.Types.Uintptr, Offset: int32(off)})
off += taddr.Type.Size()
}
off = round(off, ptr.Type.Alignment())
arg := b.NewValue1I(pos, OpOffPtr, ptr.Type.PtrTo(), off, sp)
mem = b.NewValue3A(pos, OpStore, types.TypeMem, ptr.Type, arg, ptr, mem)
+ ACArgs = append(ACArgs, Param{Type: ptr.Type, Offset: int32(off)})
off += ptr.Type.Size()
if val != nil {
off = round(off, val.Type.Alignment())
arg = b.NewValue1I(pos, OpOffPtr, val.Type.PtrTo(), off, sp)
mem = b.NewValue3A(pos, OpStore, types.TypeMem, val.Type, arg, val, mem)
+ ACArgs = append(ACArgs, Param{Type: val.Type, Offset: int32(off)})
off += val.Type.Size()
}
off = round(off, config.PtrSize)
// issue call
- mem = b.NewValue1A(pos, OpStaticCall, types.TypeMem, StaticAuxCall(fn), mem)
+ mem = b.NewValue1A(pos, OpStaticCall, types.TypeMem, StaticAuxCall(fn, ACArgs, nil), mem)
mem.AuxInt = off - config.ctxt.FixedFrameSize()
return mem
}