]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.ssa] cmd/compile: Rematerialize in regalloc
authorKeith Randall <khr@golang.org>
Mon, 19 Oct 2015 17:57:03 +0000 (10:57 -0700)
committerKeith Randall <khr@golang.org>
Mon, 19 Oct 2015 19:01:24 +0000 (19:01 +0000)
Rematerialize constants instead of spilling and loading them.
"Constants" includes constant offsets from SP and SB.

Should help somewhat with stack frame sizes.  I'm not sure
exactly how much yet.

Change-Id: I44dbad97aae870cf31cb6e89c92fe4f6a2b9586f
Reviewed-on: https://go-review.googlesource.com/16029
Run-TryBot: Keith Randall <khr@golang.org>
Reviewed-by: David Chase <drchase@google.com>
src/cmd/compile/internal/ssa/regalloc.go

index 9d0aab64cca49f9a218f081a5de9eb372ef859e4..6418bb375d61d641953305a4c2bfe7085748fcb3 100644 (file)
@@ -399,6 +399,12 @@ func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool) *Val
                        panic("bad register state")
                }
                c = s.curBlock.NewValue1(v.Line, OpCopy, v.Type, s.regs[r2].c)
+       } else if v.rematerializeable() {
+               // Rematerialize instead of loading from the spill location.
+               c = s.curBlock.NewValue0(v.Line, v.Op, v.Type)
+               c.Aux = v.Aux
+               c.AuxInt = v.AuxInt
+               c.AddArgs(v.Args...)
        } else {
                switch {
                // It is difficult to spill and reload flags on many architectures.
@@ -433,7 +439,6 @@ func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool) *Val
                        c.AddArgs(args...)
 
                // Load v from its spill location.
-               // TODO: rematerialize if we can.
                case vi.spill2 != nil:
                        if logSpills {
                                fmt.Println("regalloc: load spill2")
@@ -737,8 +742,13 @@ func (s *regAllocState) regalloc(f *Func) {
                                continue
                        }
 
-                       // TODO: If value is rematerializeable, don't issue it here.
-                       // Instead, rely on argument loading code to put it in a register when needed.
+                       if v.rematerializeable() {
+                               // Value is rematerializeable, don't issue it here.
+                               // It will get issued just before each use (see
+                               // allocValueToReg).
+                               pc++
+                               continue
+                       }
 
                        // Move arguments to registers
                        for _, i := range regspec.inputs {
@@ -962,6 +972,26 @@ func (s *regAllocState) regalloc(f *Func) {
        f.RegAlloc = s.home
 }
 
+func (v *Value) rematerializeable() bool {
+       // TODO: add a flags field to opInfo for this test?
+
+       // rematerializeable ops must be able to fill any register.
+       outputs := opcodeTable[v.Op].reg.outputs
+       if len(outputs) == 0 || countRegs(outputs[0]) <= 1 {
+               // Note: this case handles OpAMD64LoweredGetClosurePtr
+               // which can't be moved.
+               return false
+       }
+       // TODO: maybe not OpAMD64LoweredGetG?
+       if len(v.Args) == 0 {
+               return true
+       }
+       if len(v.Args) == 1 && (v.Args[0].Op == OpSP || v.Args[0].Op == OpSB) {
+               return true
+       }
+       return false
+}
+
 // live returns a map from block ID and successor edge index to a list
 // of value IDs live on that edge.
 // TODO: this could be quadratic if lots of variables are live across lots of