From 865d2bc78e5b6170c8b773880dc5fa3405791dc2 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Fri, 9 Apr 2021 18:02:48 -0400 Subject: [PATCH] cmd/compile: do not allocate space for unspilled in-register results For function results, if in register, we allocate spill slots within the frame like locals. Currently, even if we never spill to it the slot is still allocated. This CL makes it not allocate the slot if it is never used. Change-Id: Idbd4e3096cfac6d2bdfb501d8efde48ee2191d7b Reviewed-on: https://go-review.googlesource.com/c/go/+/309150 Trust: Cherry Zhang Reviewed-by: David Chase Reviewed-by: Than McIntosh --- src/cmd/compile/internal/ssagen/pgen.go | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/cmd/compile/internal/ssagen/pgen.go b/src/cmd/compile/internal/ssagen/pgen.go index 0cb506fb74..92f6f562f3 100644 --- a/src/cmd/compile/internal/ssagen/pgen.go +++ b/src/cmd/compile/internal/ssagen/pgen.go @@ -32,11 +32,11 @@ import ( // the top of the stack and increasing in size. // Non-autos sort on offset. func cmpstackvarlt(a, b *ir.Name) bool { - if (a.Class == ir.PAUTO) != (b.Class == ir.PAUTO) { - return b.Class == ir.PAUTO + if needAlloc(a) != needAlloc(b) { + return needAlloc(b) } - if a.Class != ir.PAUTO { + if !needAlloc(a) { return a.FrameOffset() < b.FrameOffset() } @@ -70,6 +70,13 @@ func (s byStackVar) Len() int { return len(s) } func (s byStackVar) Less(i, j int) bool { return cmpstackvarlt(s[i], s[j]) } func (s byStackVar) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +// needAlloc reports whether n is within the current frame, for which we need to +// allocate space. In particular, it excludes arguments and results, which are in +// the callers frame. +func needAlloc(n *ir.Name) bool { + return n.Class == ir.PAUTO || n.Class == ir.PPARAMOUT && n.IsOutputParamInRegisters() +} + func (s *ssafn) AllocFrame(f *ssa.Func) { s.stksize = 0 s.stkptrsize = 0 @@ -77,7 +84,7 @@ func (s *ssafn) AllocFrame(f *ssa.Func) { // Mark the PAUTO's unused. for _, ln := range fn.Dcl { - if ln.Class == ir.PAUTO { + if needAlloc(ln) { ln.SetUsed(false) } } @@ -92,7 +99,14 @@ func (s *ssafn) AllocFrame(f *ssa.Func) { for _, v := range b.Values { if n, ok := v.Aux.(*ir.Name); ok { switch n.Class { - case ir.PPARAM, ir.PPARAMOUT, ir.PAUTO: + case ir.PPARAMOUT: + if n.IsOutputParamInRegisters() && v.Op == ssa.OpVarDef { + // ignore VarDef, look for "real" uses. + // TODO: maybe do this for PAUTO as well? + continue + } + fallthrough + case ir.PPARAM, ir.PAUTO: n.SetUsed(true) } } @@ -106,7 +120,6 @@ func (s *ssafn) AllocFrame(f *ssa.Func) { for i, n := range fn.Dcl { if n.Op() != ir.ONAME || n.Class != ir.PAUTO && !(n.Class == ir.PPARAMOUT && n.IsOutputParamInRegisters()) { // i.e., stack assign if AUTO, or if PARAMOUT in registers (which has no predefined spill locations) - // TODO figure out when we don't need to spill output params. continue } if !n.Used() { -- 2.50.0