}
return fmt.Sprintf("<%s,%s>", n0, n1)
}
+
+type ArgPair struct {
+ reg *Register
+ mem LocalSlot
+}
+
+func (ap *ArgPair) Reg() int16 {
+ return ap.reg.objNum
+}
+
+func (ap *ArgPair) Type() *types.Type {
+ return ap.mem.Type
+}
+
+func (ap *ArgPair) Mem() *LocalSlot {
+ return &ap.mem
+}
+
+func (t ArgPair) String() string {
+ n0 := "nil"
+ if t.reg != nil {
+ n0 = t.reg.String()
+ }
+ n1 := t.mem.String()
+ return fmt.Sprintf("<%s,%s>", n0, n1)
+}
Gotype *LSym
}
+// RegArg 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 {
+ Addr Addr
+ Reg int16
+ Spill, Unspill As
+}
+
// Link holds the context for writing object code from a compiler
// to be linker input or for reading that input into the linker.
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
- IsAsm bool // is the source assembly language, which may contain surprising idioms (e.g., call tables)
+ InParallel bool // parallel backend phase in effect
+ UseBASEntries bool // use Base Address Selection Entries in location lists and PC ranges
+ IsAsm bool // is the source assembly language, which may contain surprising idioms (e.g., call tables)
// state for writing objects
Text []*LSym
ctxt.Bso.Flush()
}
+func (ctxt *Link) SpillRegisterArgs(last *Prog, pa ProgAlloc) *Prog {
+ // Spill register args.
+ for _, ra := range ctxt.RegArgs {
+ spill := Appendp(last, pa)
+ spill.As = ra.Spill
+ spill.From.Type = TYPE_REG
+ spill.From.Reg = ra.Reg
+ spill.To = ra.Addr
+ last = spill
+ }
+ return last
+}
+
+func (ctxt *Link) UnspillRegisterArgs(last *Prog, pa ProgAlloc) *Prog {
+ // Unspill any spilled register args
+ for _, ra := range ctxt.RegArgs {
+ unspill := Appendp(last, pa)
+ unspill.As = ra.Unspill
+ unspill.From = ra.Addr
+ unspill.To.Type = TYPE_REG
+ unspill.To.Reg = ra.Reg
+ last = unspill
+ }
+ return last
+}
+
// The smallest possible offset from the hardware stack pointer to a local
// variable on the stack. Architectures that use a link register save its value
// on the stack in the function prologue and so always have a pointer between
spfix.Spadj = -framesize
pcdata := ctxt.EmitEntryStackMap(cursym, spfix, newprog)
- pcdata = ctxt.StartUnsafePoint(pcdata, newprog)
+ spill := ctxt.StartUnsafePoint(pcdata, newprog)
+ pcdata = ctxt.SpillRegisterArgs(spill, newprog)
call := obj.Appendp(pcdata, newprog)
call.Pos = cursym.Func().Text.Pos
progedit(ctxt, callend.Link, newprog)
}
- pcdata = ctxt.EndUnsafePoint(callend, newprog, -1)
+ pcdata = ctxt.UnspillRegisterArgs(callend, newprog)
+ pcdata = ctxt.EndUnsafePoint(pcdata, newprog, -1)
jmp := obj.Appendp(pcdata, newprog)
jmp.As = obj.AJMP
jmp.To.SetTarget(cursym.Func().Text.Link)
jmp.Spadj = +framesize
- jls.To.SetTarget(call)
+ jls.To.SetTarget(spill)
if q1 != nil {
- q1.To.SetTarget(call)
+ q1.To.SetTarget(spill)
}
return end