aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDavid Chase <drchase@google.com>2021-02-19 17:11:40 -0500
committerDavid Chase <drchase@google.com>2021-03-04 16:19:12 +0000
commita2d92b5143ad6ed1b55b71032c5c1f468ba76fd4 (patch)
tree303c0fae9984d9e23366e183825d0dd5421dc7ae /src
parent868a110c568591d9085996ba05c94593809a437a (diff)
downloadgo-a2d92b5143ad6ed1b55b71032c5c1f468ba76fd4.tar.gz
go-a2d92b5143ad6ed1b55b71032c5c1f468ba76fd4.zip
cmd/compile: register abi, morestack work and mole whacking
Morestack works for non-pointer register parameters Within a function body, pointer-typed parameters are correctly tracked. Results still not hooked up. For #40724. Change-Id: Icaee0b51d0da54af983662d945d939b756088746 Reviewed-on: https://go-review.googlesource.com/c/go/+/294410 Trust: David Chase <drchase@google.com> Reviewed-by: Cherry Zhang <cherryyz@google.com>
Diffstat (limited to 'src')
-rw-r--r--src/cmd/compile/internal/abi/abiutils.go4
-rw-r--r--src/cmd/compile/internal/amd64/ssa.go11
-rw-r--r--src/cmd/compile/internal/ssa/debug.go4
-rw-r--r--src/cmd/compile/internal/ssa/stackalloc.go41
-rw-r--r--src/cmd/compile/internal/ssagen/ssa.go48
-rw-r--r--src/cmd/internal/obj/link.go23
-rw-r--r--src/cmd/internal/obj/x86/obj6.go55
7 files changed, 136 insertions, 50 deletions
diff --git a/src/cmd/compile/internal/abi/abiutils.go b/src/cmd/compile/internal/abi/abiutils.go
index 3eab4b8d8b..f84f8f8e01 100644
--- a/src/cmd/compile/internal/abi/abiutils.go
+++ b/src/cmd/compile/internal/abi/abiutils.go
@@ -5,6 +5,7 @@
package abi
import (
+ "cmd/compile/internal/ir"
"cmd/compile/internal/types"
"cmd/internal/src"
"fmt"
@@ -337,6 +338,9 @@ func (config *ABIConfig) updateOffset(result *ABIParamResultInfo, f *types.Field
if fOffset == types.BOGUS_FUNARG_OFFSET {
// Set the Offset the first time. After that, we may recompute it, but it should never change.
f.Offset = off
+ if f.Nname != nil {
+ f.Nname.(*ir.Name).SetFrameOffset(off)
+ }
} else if fOffset != off {
panic(fmt.Errorf("Offset changed from %d to %d", fOffset, off))
}
diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go
index d83d78f080..60baa4270f 100644
--- a/src/cmd/compile/internal/amd64/ssa.go
+++ b/src/cmd/compile/internal/amd64/ssa.go
@@ -980,6 +980,17 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
ssagen.AddAux(&p.From, v)
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg()
+ case ssa.OpArgIntReg, ssa.OpArgFloatReg:
+ // The assembler needs to wrap the entry safepoint/stack growth code with spill/unspill
+ // The loop only runs once.
+ for _, ap := range v.Block.Func.RegArgs {
+ // Pass the spill/unspill information along to the assembler, offset by size of return PC pushed on stack.
+ addr := ssagen.SpillSlotAddr(ap.Mem(), x86.REG_SP, v.Block.Func.Config.PtrSize)
+ s.FuncInfo().AddSpill(
+ obj.RegSpill{Reg: ap.Reg(), Addr: addr, Unspill: loadByType(ap.Type()), Spill: storeByType(ap.Type())})
+ }
+ v.Block.Func.RegArgs = nil
+ ssagen.CheckArgReg(v)
case ssa.OpAMD64LoweredGetClosurePtr:
// Closure pointer is DX.
ssagen.CheckLoweredGetClosurePtr(v)
diff --git a/src/cmd/compile/internal/ssa/debug.go b/src/cmd/compile/internal/ssa/debug.go
index 68b6ab5fe9..d725fc526e 100644
--- a/src/cmd/compile/internal/ssa/debug.go
+++ b/src/cmd/compile/internal/ssa/debug.go
@@ -901,10 +901,10 @@ func (state *debugState) buildLocationLists(blockLocs []*BlockDebug) {
if opcodeTable[v.Op].zeroWidth {
if changed {
- if v.Op == OpArg || v.Op == OpPhi || v.Op.isLoweredGetClosurePtr() {
+ if hasAnyArgOp(v) || v.Op == OpPhi || v.Op.isLoweredGetClosurePtr() {
// These ranges begin at true beginning of block, not after first instruction
if zeroWidthPending {
- b.Func.Fatalf("Unexpected op mixed with OpArg/OpPhi/OpLoweredGetClosurePtr at beginning of block %s in %s\n%s", b, b.Func.Name, b.Func)
+ panic(fmt.Errorf("Unexpected op '%s' mixed with OpArg/OpPhi/OpLoweredGetClosurePtr at beginning of block %s in %s\n%s", v.LongString(), b, b.Func.Name, b.Func))
}
apcChangedSize = len(state.changedVars.contents())
continue
diff --git a/src/cmd/compile/internal/ssa/stackalloc.go b/src/cmd/compile/internal/ssa/stackalloc.go
index 041e7855f6..45058d4e72 100644
--- a/src/cmd/compile/internal/ssa/stackalloc.go
+++ b/src/cmd/compile/internal/ssa/stackalloc.go
@@ -112,7 +112,7 @@ func (s *stackAllocState) init(f *Func, spillLive [][]ID) {
for _, v := range b.Values {
s.values[v.ID].typ = v.Type
s.values[v.ID].needSlot = !v.Type.IsMemory() && !v.Type.IsVoid() && !v.Type.IsFlags() && f.getHome(v.ID) == nil && !v.rematerializeable() && !v.OnWasmStack
- s.values[v.ID].isArg = v.Op == OpArg
+ s.values[v.ID].isArg = hasAnyArgOp(v)
if f.pass.debug > stackDebug && s.values[v.ID].needSlot {
fmt.Printf("%s needs a stack slot\n", v)
}
@@ -151,28 +151,29 @@ func (s *stackAllocState) stackalloc() {
// Allocate args to their assigned locations.
for _, v := range f.Entry.Values {
- if v.Op != OpArg { // && v.Op != OpArgFReg && v.Op != OpArgIReg {
+ if !hasAnyArgOp(v) {
continue
}
if v.Aux == nil {
f.Fatalf("%s has nil Aux\n", v.LongString())
}
- var loc LocalSlot
- var name *ir.Name
- var offset int64
if v.Op == OpArg {
- name = v.Aux.(*ir.Name)
- offset = v.AuxInt
- } else {
- nameOff := v.Aux.(*AuxNameOffset)
- name = nameOff.Name
- offset = nameOff.Offset
+ loc := LocalSlot{N: v.Aux.(*ir.Name), Type: v.Type, Off: v.AuxInt}
+ if f.pass.debug > stackDebug {
+ fmt.Printf("stackalloc OpArg %s to %s\n", v, loc)
+ }
+ f.setHome(v, loc)
+ continue
}
- loc = LocalSlot{N: name, Type: v.Type, Off: offset}
+
+ nameOff := v.Aux.(*AuxNameOffset)
+ loc := LocalSlot{N: nameOff.Name, Type: v.Type, Off: nameOff.Offset}
if f.pass.debug > stackDebug {
- fmt.Printf("stackalloc %s to %s\n", v, loc)
+ fmt.Printf("stackalloc Op%s %s to %s\n", v.Op, v, loc)
}
- f.setHome(v, loc)
+ // register args already allocated to registers, but need to know the stack allocation for later
+ reg := f.getHome(v.ID).(*Register)
+ f.RegArgs = append(f.RegArgs, ArgPair{reg: reg, mem: loc})
}
// For each type, we keep track of all the stack slots we
@@ -209,7 +210,7 @@ func (s *stackAllocState) stackalloc() {
s.nNotNeed++
continue
}
- if v.Op == OpArg {
+ if hasAnyArgOp(v) {
s.nArgSlot++
continue // already picked
}
@@ -396,7 +397,7 @@ func (s *stackAllocState) buildInterferenceGraph() {
for _, id := range live.contents() {
// Note: args can have different types and still interfere
// (with each other or with other values). See issue 23522.
- if s.values[v.ID].typ.Compare(s.values[id].typ) == types.CMPeq || v.Op == OpArg || s.values[id].isArg {
+ if s.values[v.ID].typ.Compare(s.values[id].typ) == types.CMPeq || hasAnyArgOp(v) || s.values[id].isArg {
s.interfere[v.ID] = append(s.interfere[v.ID], id)
s.interfere[id] = append(s.interfere[id], v.ID)
}
@@ -407,13 +408,15 @@ func (s *stackAllocState) buildInterferenceGraph() {
live.add(a.ID)
}
}
- if v.Op == OpArg && s.values[v.ID].needSlot {
+ if hasAnyArgOp(v) && s.values[v.ID].needSlot {
// OpArg is an input argument which is pre-spilled.
// We add back v.ID here because we want this value
// to appear live even before this point. Being live
// all the way to the start of the entry block prevents other
// values from being allocated to the same slot and clobbering
// the input value before we have a chance to load it.
+
+ // TODO(register args) this is apparently not wrong for register args -- is it necessary?
live.add(v.ID)
}
}
@@ -430,3 +433,7 @@ func (s *stackAllocState) buildInterferenceGraph() {
}
}
}
+
+func hasAnyArgOp(v *Value) bool {
+ return v.Op == OpArg || v.Op == OpArgIntReg || v.Op == OpArgFloatReg
+}
diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go
index 05dd0c62a9..9ee855343f 100644
--- a/src/cmd/compile/internal/ssagen/ssa.go
+++ b/src/cmd/compile/internal/ssagen/ssa.go
@@ -221,7 +221,7 @@ func AbiForFunc(fn *ir.Func) *abi.ABIConfig {
// 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 {
+ if !regabiEnabledForAllCompilation() {
a = abi0
}
if fn != nil && fn.Pragma&ir.RegisterParams != 0 { // TODO(register args) remove after register abi is working
@@ -235,6 +235,11 @@ func abiForFunc(fn *ir.Func, abi0, abi1 *abi.ABIConfig) *abi.ABIConfig {
return a
}
+func regabiEnabledForAllCompilation() bool {
+ // TODO compiler does not yet change behavior for GOEXPERIMENT=regabi
+ return false && objabi.Regabi_enabled != 0
+}
+
// 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
@@ -6404,6 +6409,10 @@ type State struct {
OnWasmStackSkipped int
}
+func (s *State) FuncInfo() *obj.FuncInfo {
+ return s.pp.CurFunc.LSym.Func()
+}
+
// Prog appends a new Prog.
func (s *State) Prog(as obj.As) *obj.Prog {
p := s.pp.Prog(as)
@@ -6561,11 +6570,9 @@ func genssa(f *ssa.Func, pp *objw.Progs) {
// memory arg needs no code
case ssa.OpArg:
// input args need no code
- case ssa.OpArgIntReg, ssa.OpArgFloatReg:
- CheckArgReg(v)
case ssa.OpSP, ssa.OpSB:
// nothing to do
- case ssa.OpSelect0, ssa.OpSelect1, ssa.OpSelectN:
+ case ssa.OpSelect0, ssa.OpSelect1, ssa.OpSelectN, ssa.OpMakeResult:
// nothing to do
case ssa.OpGetG:
// nothing to do when there's a g register,
@@ -7470,6 +7477,39 @@ func deferstruct(stksize int64) *types.Type {
return s
}
+// SlotAddr uses LocalSlot information to initialize an obj.Addr
+// The resulting addr is used in a non-standard context -- in the prologue
+// of a function, before the frame has been constructed, so the standard
+// addressing for the parameters will be wrong.
+func SpillSlotAddr(slot *ssa.LocalSlot, baseReg int16, extraOffset int64) obj.Addr {
+ n, off := slot.N, slot.Off
+ if n.Class != ir.PPARAM && n.Class != ir.PPARAMOUT {
+ panic("Only expected to see param and returns here")
+ }
+ return obj.Addr{
+ Name: obj.NAME_NONE,
+ Type: obj.TYPE_MEM,
+ Reg: baseReg,
+ Offset: off + extraOffset + n.FrameOffset(),
+ }
+}
+
+// AddrForParamSlot fills in an Addr appropriately for a Spill,
+// Restore, or VARLIVE.
+func AddrForParamSlot(slot *ssa.LocalSlot, addr *obj.Addr) {
+ // TODO replace this boilerplate in a couple of places.
+ n, off := slot.N, slot.Off
+ addr.Type = obj.TYPE_MEM
+ addr.Sym = n.Linksym()
+ addr.Offset = off
+ if n.Class == ir.PPARAM || n.Class == ir.PPARAMOUT {
+ addr.Name = obj.NAME_PARAM
+ addr.Offset += n.FrameOffset()
+ } else {
+ addr.Name = obj.NAME_AUTO
+ }
+}
+
var (
BoundsCheckFunc [ssa.BoundsKindCount]*obj.LSym
ExtendCheckFunc [ssa.BoundsKindCount]*obj.LSym
diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go
index c74de779d2..448f45b47b 100644
--- a/src/cmd/internal/obj/link.go
+++ b/src/cmd/internal/obj/link.go
@@ -473,6 +473,7 @@ type FuncInfo struct {
Autot map[*LSym]struct{}
Pcln Pcln
InlMarks []InlMark
+ spills []RegSpill
dwarfInfoSym *LSym
dwarfLocSym *LSym
@@ -552,6 +553,11 @@ func (fi *FuncInfo) AddInlMark(p *Prog, id int32) {
fi.InlMarks = append(fi.InlMarks, InlMark{p: p, id: id})
}
+// AddSpill appends a spill record to the list for FuncInfo fi
+func (fi *FuncInfo) AddSpill(s RegSpill) {
+ fi.spills = append(fi.spills, s)
+}
+
// Record the type symbol for an auto variable so that the linker
// an emit DWARF type information for the type.
func (fi *FuncInfo) RecordAutoType(gotype *LSym) {
@@ -803,12 +809,12 @@ type Auto struct {
Gotype *LSym
}
-// RegArg provides spill/fill information for a register-resident argument
+// RegSpill provides spill/fill information for a register-resident argument
// to a function. These need spilling/filling in the safepoint/stackgrowth case.
// At the time of fill/spill, the offset must be adjusted by the architecture-dependent
// adjustment to hardware SP that occurs in a call instruction. E.g., for AMD64,
// at Offset+8 because the return address was pushed.
-type RegArg struct {
+type RegSpill struct {
Addr Addr
Reg int16
Spill, Unspill As
@@ -844,7 +850,6 @@ type Link struct {
DebugInfo func(fn *LSym, info *LSym, curfn interface{}) ([]dwarf.Scope, dwarf.InlCalls) // if non-nil, curfn is a *gc.Node
GenAbstractFunc func(fn *LSym)
Errors int
- RegArgs []RegArg
InParallel bool // parallel backend phase in effect
UseBASEntries bool // use Base Address Selection Entries in location lists and PC ranges
@@ -893,9 +898,11 @@ func (ctxt *Link) Logf(format string, args ...interface{}) {
ctxt.Bso.Flush()
}
-func (ctxt *Link) SpillRegisterArgs(last *Prog, pa ProgAlloc) *Prog {
+// SpillRegisterArgs emits the code to spill register args into whatever
+// locations the spill records specify.
+func (fi *FuncInfo) SpillRegisterArgs(last *Prog, pa ProgAlloc) *Prog {
// Spill register args.
- for _, ra := range ctxt.RegArgs {
+ for _, ra := range fi.spills {
spill := Appendp(last, pa)
spill.As = ra.Spill
spill.From.Type = TYPE_REG
@@ -906,9 +913,11 @@ func (ctxt *Link) SpillRegisterArgs(last *Prog, pa ProgAlloc) *Prog {
return last
}
-func (ctxt *Link) UnspillRegisterArgs(last *Prog, pa ProgAlloc) *Prog {
+// UnspillRegisterArgs emits the code to restore register args from whatever
+// locations the spill records specify.
+func (fi *FuncInfo) UnspillRegisterArgs(last *Prog, pa ProgAlloc) *Prog {
// Unspill any spilled register args
- for _, ra := range ctxt.RegArgs {
+ for _, ra := range fi.spills {
unspill := Appendp(last, pa)
unspill.As = ra.Unspill
unspill.From = ra.Addr
diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go
index bc3a3b4bbe..d70cbebc5e 100644
--- a/src/cmd/internal/obj/x86/obj6.go
+++ b/src/cmd/internal/obj/x86/obj6.go
@@ -135,7 +135,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
p.To.Index = REG_NONE
}
} else {
- // load_g_cx, below, always inserts the 1-instruction sequence. Rewrite it
+ // load_g, below, always inserts the 1-instruction sequence. Rewrite it
// as the 2-instruction sequence if necessary.
// MOVQ 0(TLS), BX
// becomes
@@ -644,8 +644,12 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
regg = REGG // use the g register directly in ABIInternal
} else {
p = obj.Appendp(p, newprog)
- p = load_g_cx(ctxt, p, newprog) // load g into CX
regg = REG_CX
+ if ctxt.Arch.Family == sys.AMD64 {
+ // Using this register means that stacksplit works w/ //go:registerparams even when objabi.Regabi_enabled == 0
+ regg = REGG // == REG_R14
+ }
+ p = load_g(ctxt, p, newprog, regg) // load g into regg
}
}
@@ -963,7 +967,7 @@ func indir_cx(ctxt *obj.Link, a *obj.Addr) {
// Overwriting p is unusual but it lets use this in both the
// prologue (caller must call appendp first) and in the epilogue.
// Returns last new instruction.
-func load_g_cx(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) *obj.Prog {
+func load_g(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc, rg int16) *obj.Prog {
p.As = AMOVQ
if ctxt.Arch.PtrSize == 4 {
p.As = AMOVL
@@ -972,7 +976,7 @@ func load_g_cx(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) *obj.Prog {
p.From.Reg = REG_TLS
p.From.Offset = 0
p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_CX
+ p.To.Reg = rg
next := p.Link
progedit(ctxt, p, newprog)
@@ -1027,9 +1031,14 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
// unnecessarily. See issue #35470.
p = ctxt.StartUnsafePoint(p, newprog)
} else if framesize <= objabi.StackBig {
+ tmp := int16(REG_AX) // use AX for 32-bit
+ if ctxt.Arch.Family == sys.AMD64 {
+ // for 64-bit, stay away from register ABI parameter registers, even w/o GOEXPERIMENT=regabi
+ tmp = int16(REG_R13)
+ }
// large stack: SP-framesize <= stackguard-StackSmall
- // LEAQ -xxx(SP), AX
- // CMPQ AX, stackguard
+ // LEAQ -xxx(SP), tmp
+ // CMPQ tmp, stackguard
p = obj.Appendp(p, newprog)
p.As = lea
@@ -1037,12 +1046,12 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
p.From.Reg = REG_SP
p.From.Offset = -(int64(framesize) - objabi.StackSmall)
p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_AX
+ p.To.Reg = tmp
p = obj.Appendp(p, newprog)
p.As = cmp
p.From.Type = obj.TYPE_REG
- p.From.Reg = REG_AX
+ p.From.Reg = tmp
p.To.Type = obj.TYPE_MEM
p.To.Reg = rg
p.To.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
@@ -1052,6 +1061,12 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
p = ctxt.StartUnsafePoint(p, newprog) // see the comment above
} else {
+ tmp1 := int16(REG_SI)
+ tmp2 := int16(REG_AX)
+ if ctxt.Arch.Family == sys.AMD64 {
+ tmp1 = int16(REG_R13) // register ABI uses REG_SI and REG_AX for parameters.
+ tmp2 = int16(REG_R12)
+ }
// Such a large stack we need to protect against wraparound.
// If SP is close to zero:
// SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
@@ -1060,12 +1075,12 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
//
// Preemption sets stackguard to StackPreempt, a very large value.
// That breaks the math above, so we have to check for that explicitly.
- // MOVQ stackguard, SI
+ // MOVQ stackguard, tmp1
// CMPQ SI, $StackPreempt
// JEQ label-of-call-to-morestack
- // LEAQ StackGuard(SP), AX
- // SUBQ SI, AX
- // CMPQ AX, $(framesize+(StackGuard-StackSmall))
+ // LEAQ StackGuard(SP), tmp2
+ // SUBQ tmp1, tmp2
+ // CMPQ tmp2, $(framesize+(StackGuard-StackSmall))
p = obj.Appendp(p, newprog)
@@ -1077,14 +1092,14 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
}
p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_SI
+ p.To.Reg = tmp1
p = ctxt.StartUnsafePoint(p, newprog) // see the comment above
p = obj.Appendp(p, newprog)
p.As = cmp
p.From.Type = obj.TYPE_REG
- p.From.Reg = REG_SI
+ p.From.Reg = tmp1
p.To.Type = obj.TYPE_CONST
p.To.Offset = objabi.StackPreempt
if ctxt.Arch.Family == sys.I386 {
@@ -1102,19 +1117,19 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
p.From.Reg = REG_SP
p.From.Offset = int64(objabi.StackGuard)
p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_AX
+ p.To.Reg = tmp2
p = obj.Appendp(p, newprog)
p.As = sub
p.From.Type = obj.TYPE_REG
- p.From.Reg = REG_SI
+ p.From.Reg = tmp1
p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_AX
+ p.To.Reg = tmp2
p = obj.Appendp(p, newprog)
p.As = cmp
p.From.Type = obj.TYPE_REG
- p.From.Reg = REG_AX
+ p.From.Reg = tmp2
p.To.Type = obj.TYPE_CONST
p.To.Offset = int64(framesize) + (int64(objabi.StackGuard) - objabi.StackSmall)
}
@@ -1139,7 +1154,7 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
pcdata := ctxt.EmitEntryStackMap(cursym, spfix, newprog)
spill := ctxt.StartUnsafePoint(pcdata, newprog)
- pcdata = ctxt.SpillRegisterArgs(spill, newprog)
+ pcdata = cursym.Func().SpillRegisterArgs(spill, newprog)
call := obj.Appendp(pcdata, newprog)
call.Pos = cursym.Func().Text.Pos
@@ -1164,7 +1179,7 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
progedit(ctxt, callend.Link, newprog)
}
- pcdata = ctxt.UnspillRegisterArgs(callend, newprog)
+ pcdata = cursym.Func().UnspillRegisterArgs(callend, newprog)
pcdata = ctxt.EndUnsafePoint(pcdata, newprog, -1)
jmp := obj.Appendp(pcdata, newprog)