Skip to content

Commit c1370e9

Browse files
committed
[dev.regabi] cmd/compile: add code to support register ABI spills around morestack calls
This is a selected copy from the register ABI experiment CL, focused on the files and data structures that handle spilling around morestack. Unnecessary code from the experiment was removed, other code was adapted. Would it make sense to leave comments in the experiment as pieces are brought over? Experiment CL (for comparison purposes) https://go-review.googlesource.com/c/go/+/28832 Change-Id: I92136f070351d4fcca1407b52ecf9b80898fed95 Reviewed-on: https://go-review.googlesource.com/c/go/+/279520 Trust: David Chase <[email protected]> Run-TryBot: David Chase <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Jeremy Faller <[email protected]>
1 parent 2abd24f commit c1370e9

File tree

4 files changed

+76
-7
lines changed

4 files changed

+76
-7
lines changed

src/cmd/compile/internal/ssa/func.go

+3
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ type Func struct {
5858
// of keys to make iteration order deterministic.
5959
Names []LocalSlot
6060

61+
// RegArgs is a slice of register-memory pairs that must be spilled and unspilled in the uncommon path of function entry.
62+
RegArgs []ArgPair
63+
6164
// WBLoads is a list of Blocks that branch on the write
6265
// barrier flag. Safe-points are disabled from the OpLoad that
6366
// reads the write-barrier flag until the control flow rejoins

src/cmd/compile/internal/ssa/location.go

+26
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,29 @@ func (t LocPair) String() string {
8787
}
8888
return fmt.Sprintf("<%s,%s>", n0, n1)
8989
}
90+
91+
type ArgPair struct {
92+
reg *Register
93+
mem LocalSlot
94+
}
95+
96+
func (ap *ArgPair) Reg() int16 {
97+
return ap.reg.objNum
98+
}
99+
100+
func (ap *ArgPair) Type() *types.Type {
101+
return ap.mem.Type
102+
}
103+
104+
func (ap *ArgPair) Mem() *LocalSlot {
105+
return &ap.mem
106+
}
107+
108+
func (t ArgPair) String() string {
109+
n0 := "nil"
110+
if t.reg != nil {
111+
n0 = t.reg.String()
112+
}
113+
n1 := t.mem.String()
114+
return fmt.Sprintf("<%s,%s>", n0, n1)
115+
}

src/cmd/internal/obj/link.go

+41-3
Original file line numberDiff line numberDiff line change
@@ -766,6 +766,17 @@ type Auto struct {
766766
Gotype *LSym
767767
}
768768

769+
// RegArg provides spill/fill information for a register-resident argument
770+
// to a function. These need spilling/filling in the safepoint/stackgrowth case.
771+
// At the time of fill/spill, the offset must be adjusted by the architecture-dependent
772+
// adjustment to hardware SP that occurs in a call instruction. E.g., for AMD64,
773+
// at Offset+8 because the return address was pushed.
774+
type RegArg struct {
775+
Addr Addr
776+
Reg int16
777+
Spill, Unspill As
778+
}
779+
769780
// Link holds the context for writing object code from a compiler
770781
// to be linker input or for reading that input into the linker.
771782
type Link struct {
@@ -796,10 +807,11 @@ type Link struct {
796807
DebugInfo func(fn *LSym, info *LSym, curfn interface{}) ([]dwarf.Scope, dwarf.InlCalls) // if non-nil, curfn is a *gc.Node
797808
GenAbstractFunc func(fn *LSym)
798809
Errors int
810+
RegArgs []RegArg
799811

800-
InParallel bool // parallel backend phase in effect
801-
UseBASEntries bool // use Base Address Selection Entries in location lists and PC ranges
802-
IsAsm bool // is the source assembly language, which may contain surprising idioms (e.g., call tables)
812+
InParallel bool // parallel backend phase in effect
813+
UseBASEntries bool // use Base Address Selection Entries in location lists and PC ranges
814+
IsAsm bool // is the source assembly language, which may contain surprising idioms (e.g., call tables)
803815

804816
// state for writing objects
805817
Text []*LSym
@@ -844,6 +856,32 @@ func (ctxt *Link) Logf(format string, args ...interface{}) {
844856
ctxt.Bso.Flush()
845857
}
846858

859+
func (ctxt *Link) SpillRegisterArgs(last *Prog, pa ProgAlloc) *Prog {
860+
// Spill register args.
861+
for _, ra := range ctxt.RegArgs {
862+
spill := Appendp(last, pa)
863+
spill.As = ra.Spill
864+
spill.From.Type = TYPE_REG
865+
spill.From.Reg = ra.Reg
866+
spill.To = ra.Addr
867+
last = spill
868+
}
869+
return last
870+
}
871+
872+
func (ctxt *Link) UnspillRegisterArgs(last *Prog, pa ProgAlloc) *Prog {
873+
// Unspill any spilled register args
874+
for _, ra := range ctxt.RegArgs {
875+
unspill := Appendp(last, pa)
876+
unspill.As = ra.Unspill
877+
unspill.From = ra.Addr
878+
unspill.To.Type = TYPE_REG
879+
unspill.To.Reg = ra.Reg
880+
last = unspill
881+
}
882+
return last
883+
}
884+
847885
// The smallest possible offset from the hardware stack pointer to a local
848886
// variable on the stack. Architectures that use a link register save its value
849887
// on the stack in the function prologue and so always have a pointer between

src/cmd/internal/obj/x86/obj6.go

+6-4
Original file line numberDiff line numberDiff line change
@@ -1114,7 +1114,8 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
11141114
spfix.Spadj = -framesize
11151115

11161116
pcdata := ctxt.EmitEntryStackMap(cursym, spfix, newprog)
1117-
pcdata = ctxt.StartUnsafePoint(pcdata, newprog)
1117+
spill := ctxt.StartUnsafePoint(pcdata, newprog)
1118+
pcdata = ctxt.SpillRegisterArgs(spill, newprog)
11181119

11191120
call := obj.Appendp(pcdata, newprog)
11201121
call.Pos = cursym.Func().Text.Pos
@@ -1139,17 +1140,18 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
11391140
progedit(ctxt, callend.Link, newprog)
11401141
}
11411142

1142-
pcdata = ctxt.EndUnsafePoint(callend, newprog, -1)
1143+
pcdata = ctxt.UnspillRegisterArgs(callend, newprog)
1144+
pcdata = ctxt.EndUnsafePoint(pcdata, newprog, -1)
11431145

11441146
jmp := obj.Appendp(pcdata, newprog)
11451147
jmp.As = obj.AJMP
11461148
jmp.To.Type = obj.TYPE_BRANCH
11471149
jmp.To.SetTarget(cursym.Func().Text.Link)
11481150
jmp.Spadj = +framesize
11491151

1150-
jls.To.SetTarget(call)
1152+
jls.To.SetTarget(spill)
11511153
if q1 != nil {
1152-
q1.To.SetTarget(call)
1154+
q1.To.SetTarget(spill)
11531155
}
11541156

11551157
return end

0 commit comments

Comments
 (0)