1
0
mirror of https://github.com/golang/go synced 2024-07-05 09:50:19 +00:00

cmd/compile: reuse temporaries in order pass

Instead of allocating a new temporary each time one
is needed, keep a list of temporaries which are free
(have already been VARKILLed on every path) and use
one of them.

Should save a lot of stack space. In a function like this:

func main() {
     fmt.Printf("%d %d\n", 2, 3)
     fmt.Printf("%d %d\n", 4, 5)
     fmt.Printf("%d %d\n", 6, 7)
}

The three [2]interface{} arrays used to hold the ... args
all use the same autotmp, instead of 3 different autotmps
as happened previous to this CL.

Change-Id: I2d728e226f81e05ae68ca8247af62014a1b032d3
Reviewed-on: https://go-review.googlesource.com/c/140301
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
This commit is contained in:
Keith Randall 2018-10-05 08:54:50 -07:00
parent 0e9f8a21f8
commit 389e942745
4 changed files with 75 additions and 43 deletions

View File

@ -42,8 +42,9 @@ import (
// Order holds state during the ordering process.
type Order struct {
out []*Node // list of generated statements
temp []*Node // stack of temporary variables
out []*Node // list of generated statements
temp []*Node // stack of temporary variables
free map[string][]*Node // free list of unused temporaries, by type.LongString().
}
// Order rewrites fn.Nbody to apply the ordering constraints
@ -54,14 +55,30 @@ func order(fn *Node) {
dumplist(s, fn.Nbody)
}
orderBlock(&fn.Nbody)
orderBlock(&fn.Nbody, map[string][]*Node{})
}
// newTemp allocates a new temporary with the given type,
// pushes it onto the temp stack, and returns it.
// If clear is true, newTemp emits code to zero the temporary.
func (o *Order) newTemp(t *types.Type, clear bool) *Node {
v := temp(t)
var v *Node
// Note: LongString is close to the type equality we want,
// but not exactly. We still need to double-check with eqtype.
key := t.LongString()
a := o.free[key]
for i, n := range a {
if eqtype(t, n.Type) {
v = a[i]
a[i] = a[len(a)-1]
a = a[:len(a)-1]
o.free[key] = a
break
}
}
if v == nil {
v = temp(t)
}
if clear {
a := nod(OAS, v, nil)
a = typecheck(a, Etop)
@ -226,6 +243,16 @@ func (o *Order) markTemp() ordermarker {
// Poptemp pops temporaries off the stack until reaching the mark,
// which must have been returned by marktemp.
func (o *Order) popTemp(mark ordermarker) {
for _, n := range o.temp[mark:] {
if n.Type.Etype == types.TUINT8 {
// Don't recycle temps of this type. TUINT8 is used
// as a placeholder for a type to be determined later.
// TODO: fix
continue
}
key := n.Type.LongString()
o.free[key] = append(o.free[key], n)
}
o.temp = o.temp[:mark]
}
@ -266,8 +293,10 @@ func (o *Order) stmtList(l Nodes) {
// orderBlock orders the block of statements in n into a new slice,
// and then replaces the old slice in n with the new slice.
func orderBlock(n *Nodes) {
// free is a map that can be used to obtain temporary variables by type.
func orderBlock(n *Nodes, free map[string][]*Node) {
var order Order
order.free = free
mark := order.markTemp()
order.stmtList(*n)
order.cleanTemp(mark)
@ -280,6 +309,7 @@ func orderBlock(n *Nodes) {
// n.Left = o.exprInPlace(n.Left)
func (o *Order) exprInPlace(n *Node) *Node {
var order Order
order.free = o.free
n = order.expr(n, nil)
n = addinit(n, order.out)
@ -293,8 +323,10 @@ func (o *Order) exprInPlace(n *Node) *Node {
// and replaces it with the resulting statement list.
// The result of orderStmtInPlace MUST be assigned back to n, e.g.
// n.Left = orderStmtInPlace(n.Left)
func orderStmtInPlace(n *Node) *Node {
// free is a map that can be used to obtain temporary variables by type.
func orderStmtInPlace(n *Node, free map[string][]*Node) *Node {
var order Order
order.free = free
mark := order.markTemp()
order.stmt(n)
order.cleanTemp(mark)
@ -643,8 +675,8 @@ func (o *Order) stmt(n *Node) {
t := o.markTemp()
n.Left = o.exprInPlace(n.Left)
n.Nbody.Prepend(o.cleanTempNoPop(t)...)
orderBlock(&n.Nbody)
n.Right = orderStmtInPlace(n.Right)
orderBlock(&n.Nbody, o.free)
n.Right = orderStmtInPlace(n.Right, o.free)
o.out = append(o.out, n)
o.cleanTemp(t)
@ -656,8 +688,8 @@ func (o *Order) stmt(n *Node) {
n.Nbody.Prepend(o.cleanTempNoPop(t)...)
n.Rlist.Prepend(o.cleanTempNoPop(t)...)
o.popTemp(t)
orderBlock(&n.Nbody)
orderBlock(&n.Rlist)
orderBlock(&n.Nbody, o.free)
orderBlock(&n.Rlist, o.free)
o.out = append(o.out, n)
// Special: argument will be converted to interface using convT2E
@ -739,7 +771,7 @@ func (o *Order) stmt(n *Node) {
}
o.exprListInPlace(n.List)
if orderBody {
orderBlock(&n.Nbody)
orderBlock(&n.Nbody, o.free)
}
o.out = append(o.out, n)
o.cleanTemp(t)
@ -857,7 +889,7 @@ func (o *Order) stmt(n *Node) {
tmp2 = typecheck(tmp2, Etop)
n2.Ninit.Append(tmp2)
}
orderBlock(&n2.Ninit)
orderBlock(&n2.Ninit, o.free)
case OSEND:
if r.Ninit.Len() != 0 {
@ -882,7 +914,7 @@ func (o *Order) stmt(n *Node) {
// Also insert any ninit queued during the previous loop.
// (The temporary cleaning must follow that ninit work.)
for _, n3 := range n.List.Slice() {
orderBlock(&n3.Nbody)
orderBlock(&n3.Nbody, o.free)
n3.Nbody.Prepend(o.cleanTempNoPop(t)...)
// TODO(mdempsky): Is this actually necessary?
@ -924,7 +956,7 @@ func (o *Order) stmt(n *Node) {
Fatalf("order switch case %v", ncas.Op)
}
o.exprListInPlace(ncas.List)
orderBlock(&ncas.Nbody)
orderBlock(&ncas.Nbody, o.free)
}
o.out = append(o.out, n)

View File

@ -751,7 +751,7 @@ func fixedlit(ctxt initContext, kind initKind, n *Node, var_ *Node, init *Nodes)
case initKindStatic:
genAsStatic(a)
case initKindDynamic, initKindLocalCode:
a = orderStmtInPlace(a)
a = orderStmtInPlace(a, map[string][]*Node{})
a = walkstmt(a)
init.Append(a)
default:
@ -909,7 +909,7 @@ func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) {
a = nod(OAS, a, value)
a = typecheck(a, Etop)
a = orderStmtInPlace(a)
a = orderStmtInPlace(a, map[string][]*Node{})
a = walkstmt(a)
init.Append(a)
}
@ -918,7 +918,7 @@ func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) {
a = nod(OAS, var_, nod(OSLICE, vauto, nil))
a = typecheck(a, Etop)
a = orderStmtInPlace(a)
a = orderStmtInPlace(a, map[string][]*Node{})
a = walkstmt(a)
init.Append(a)
}

View File

@ -256,8 +256,8 @@ func f16() {
if b {
delete(mi, iface()) // ERROR "stack object .autotmp_[0-9]+ interface \{\}$"
}
delete(mi, iface()) // ERROR "stack object .autotmp_[0-9]+ interface \{\}$"
delete(mi, iface()) // ERROR "stack object .autotmp_[0-9]+ interface \{\}$"
delete(mi, iface())
delete(mi, iface())
}
var m2s map[string]*byte
@ -302,8 +302,8 @@ func f18() {
if b {
z = m2[g18()] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
}
z = m2[g18()] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
z = m2[g18()] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
z = m2[g18()]
z = m2[g18()]
printbytepointer(z)
}
@ -319,8 +319,8 @@ func f19() {
if b {
z = <-ch // ERROR "stack object .autotmp_[0-9]+ \*byte$"
}
z = <-ch // ERROR "stack object .autotmp_[0-9]+ \*byte$"
z = <-ch // ERROR "stack object .autotmp_[0-9]+ \*byte$" "live at call to chanrecv1: .autotmp_[0-9]+$"
z = <-ch
z = <-ch // ERROR "live at call to chanrecv1: .autotmp_[0-9]+$"
printbytepointer(z)
}
@ -329,8 +329,8 @@ func f20() {
if b {
ch <- byteptr() // ERROR "stack object .autotmp_[0-9]+ \*byte$"
}
ch <- byteptr() // ERROR "stack object .autotmp_[0-9]+ \*byte$"
ch <- byteptr() // ERROR "stack object .autotmp_[0-9]+ \*byte$"
ch <- byteptr()
ch <- byteptr()
}
func f21() {
@ -339,8 +339,8 @@ func f21() {
if b {
z = m2[[2]string{"x", "y"}] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
}
z = m2[[2]string{"x", "y"}] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
z = m2[[2]string{"x", "y"}] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
z = m2[[2]string{"x", "y"}]
z = m2[[2]string{"x", "y"}]
printbytepointer(z)
}
@ -351,8 +351,8 @@ func f23() {
if b {
z, ok = m2[[2]string{"x", "y"}] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
}
z, ok = m2[[2]string{"x", "y"}] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
z, ok = m2[[2]string{"x", "y"}] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
z, ok = m2[[2]string{"x", "y"}]
z, ok = m2[[2]string{"x", "y"}]
printbytepointer(z)
print(ok)
}
@ -363,8 +363,8 @@ func f24() {
if b {
m2[[2]string{"x", "y"}] = nil // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
}
m2[[2]string{"x", "y"}] = nil // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
m2[[2]string{"x", "y"}] = nil // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
m2[[2]string{"x", "y"}] = nil
m2[[2]string{"x", "y"}] = nil
}
// defer should not cause spurious ambiguously live variables
@ -389,8 +389,8 @@ func f26(b bool) {
if b {
print26((*int)(nil), (*int)(nil), (*int)(nil)) // ERROR "stack object .autotmp_[0-9]+ \[3\]interface \{\}$"
}
print26((*int)(nil), (*int)(nil), (*int)(nil)) // ERROR "stack object .autotmp_[0-9]+ \[3\]interface \{\}$"
print26((*int)(nil), (*int)(nil), (*int)(nil)) // ERROR "stack object .autotmp_[0-9]+ \[3\]interface \{\}$"
print26((*int)(nil), (*int)(nil), (*int)(nil))
print26((*int)(nil), (*int)(nil), (*int)(nil))
printnl()
}
@ -442,8 +442,8 @@ func f28(b bool) {
if b {
printstring(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10) // ERROR "stack object .autotmp_[0-9]+ \[10\]string$"
}
printstring(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10) // ERROR "stack object .autotmp_[0-9]+ \[10\]string$"
printstring(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10) // ERROR "stack object .autotmp_[0-9]+ \[10\]string$"
printstring(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10)
printstring(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10)
}
// map iterator should die on end of range loop
@ -454,10 +454,10 @@ func f29(b bool) {
printstring(k) // ERROR "live at call to printstring: .autotmp_[0-9]+$"
}
}
for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ map.iter\[string\]int$"
for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$"
printstring(k) // ERROR "live at call to printstring: .autotmp_[0-9]+$"
}
for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ map.iter\[string\]int$"
for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$"
printstring(k) // ERROR "live at call to printstring: .autotmp_[0-9]+$"
}
}
@ -481,10 +481,10 @@ func f30(b bool) {
printintpointer(p.intp) // ERROR "live at call to printintpointer: .autotmp_[0-9]+$"
}
}
for _, p := range pstructarr { // ERROR "stack object .autotmp_[0-9]+ \[10\]pstruct$"
for _, p := range pstructarr {
printintpointer(p.intp) // ERROR "live at call to printintpointer: .autotmp_[0-9]+$"
}
for _, p := range pstructarr { // ERROR "stack object .autotmp_[0-9]+ \[10\]pstruct$"
for _, p := range pstructarr {
printintpointer(p.intp) // ERROR "live at call to printintpointer: .autotmp_[0-9]+$"
}
}
@ -496,10 +496,10 @@ func f31(b1, b2, b3 bool) {
g31(g18()) // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
}
if b2 {
h31(g18()) // ERROR "live at call to convT2E: .autotmp_[0-9]+$" "live at call to newobject: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ \[2\]string$"
h31(g18()) // ERROR "live at call to convT2E: .autotmp_[0-9]+$" "live at call to newobject: .autotmp_[0-9]+$"
}
if b3 {
panic(g18()) // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
panic(g18())
}
print(b3)
}

View File

@ -32,12 +32,12 @@ func G() {
var t int // ERROR "moved to heap"
F1(uintptr(unsafe.Pointer(&t))) // ERROR "live at call to F1: .?autotmp" "&t escapes to heap" "stack object .autotmp_[0-9]+ unsafe.Pointer$"
var t2 int // ERROR "moved to heap"
F3(uintptr(unsafe.Pointer(&t2))) // ERROR "live at call to F3: .?autotmp" "&t2 escapes to heap" "stack object .autotmp_[0-9]+ unsafe.Pointer$"
F3(uintptr(unsafe.Pointer(&t2))) // ERROR "live at call to F3: .?autotmp" "&t2 escapes to heap"
}
func H() {
var v int // ERROR "moved to heap"
F2(0, 1, uintptr(unsafe.Pointer(&v)), 2) // ERROR "live at call to newobject: .?autotmp" "live at call to F2: .?autotmp" "escapes to heap" "stack object .autotmp_[0-9]+ unsafe.Pointer$"
var v2 int // ERROR "moved to heap"
F4(0, 1, uintptr(unsafe.Pointer(&v2)), 2) // ERROR "live at call to newobject: .?autotmp" "live at call to F4: .?autotmp" "escapes to heap" "stack object .autotmp_[0-9]+ unsafe.Pointer$"
F4(0, 1, uintptr(unsafe.Pointer(&v2)), 2) // ERROR "live at call to newobject: .?autotmp" "live at call to F4: .?autotmp" "escapes to heap"
}