]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: do not allocate space for unspilled in-register results
authorCherry Zhang <cherryyz@google.com>
Fri, 9 Apr 2021 22:02:48 +0000 (18:02 -0400)
committerCherry Zhang <cherryyz@google.com>
Mon, 12 Apr 2021 17:56:06 +0000 (17:56 +0000)
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 <cherryyz@google.com>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
src/cmd/compile/internal/ssagen/pgen.go

index 0cb506fb74c38f1691af407de9153a74b02285aa..92f6f562f3683f5fa88574aa94b7635784e08403 100644 (file)
@@ -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() {