diff --git a/src/cmd/compile/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go index 616945685c..4913e3c11a 100644 --- a/src/cmd/compile/internal/gc/order.go +++ b/src/cmd/compile/internal/gc/order.go @@ -183,7 +183,23 @@ func isaddrokay(n *Node) bool { // Orderaddrtemp ensures that n is okay to pass by address to runtime routines. // If the original argument n is not okay, orderaddrtemp creates a tmp, emits // tmp = n, and then returns tmp. +// The result of orderaddrtemp MUST be assigned back to n, e.g. +// n.Left = orderaddrtemp(n.Left, order) func orderaddrtemp(n *Node, order *Order) *Node { + if consttype(n) >= 0 { + // TODO: expand this to all static composite literal nodes? + n = defaultlit(n, nil) + dowidth(n.Type) + vstat := staticname(n.Type) + vstat.Name.Readonly = true + var out []*Node + staticassign(vstat, n, &out) + if out != nil { + Fatalf("staticassign of const generated code: %+v", n) + } + vstat = typecheck(vstat, Erv) + return vstat + } if isaddrokay(n) { return n } diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index d5da170119..ba4b1af4ff 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -889,20 +889,29 @@ opswitch: n = l break } - // Optimize convT2{E,I} when T is not pointer-shaped. - // We make the interface by initializing a stack temporary to - // the value we want to put in the interface, then using the address of - // that stack temporary for the interface data word. - if !n.Left.Type.IsInterface() && n.Esc == EscNone && n.Left.Type.Width <= 1024 { - tmp := temp(n.Left.Type) - init.Append(typecheck(nod(OAS, tmp, n.Left), Etop)) + + // Optimize convT2{E,I} when T is not pointer-shaped, + // but the value does not escape or is a readonly global. + var value *Node + switch { + case !n.Left.Type.IsInterface() && n.Esc == EscNone && n.Left.Type.Width <= 1024: + // Initializing a stack temporary to the value we want to put in the interface, + // then using the address of that stack temporary for the interface data word. + value = temp(n.Left.Type) + init.Append(typecheck(nod(OAS, value, n.Left), Etop)) + case n.Left.Class == PEXTERN && n.Left.Name != nil && n.Left.Name.Readonly: + // readonly global; use directly. + value = n.Left + } + + if value != nil { var t *Node if n.Type.IsEmptyInterface() { t = typename(n.Left.Type) } else { t = itabname(n.Left.Type, n.Type) } - l := nod(OEFACE, t, typecheck(nod(OADDR, tmp, nil), Erv)) + l := nod(OEFACE, t, typecheck(nod(OADDR, value, nil), Erv)) l.Type = n.Type l.Typecheck = n.Typecheck n = l diff --git a/src/cmd/internal/obj/data.go b/src/cmd/internal/obj/data.go index d5565f24dc..114841dedb 100644 --- a/src/cmd/internal/obj/data.go +++ b/src/cmd/internal/obj/data.go @@ -70,7 +70,7 @@ func (s *LSym) GrowCap(c int64) { // prepwrite prepares to write data of size siz into s at offset off. func (s *LSym) prepwrite(ctxt *Link, off int64, siz int) { if off < 0 || siz < 0 || off >= 1<<30 { - log.Fatalf("prepwrite: bad off=%d siz=%d", off, siz) + log.Fatalf("prepwrite: bad off=%d siz=%d s=%v", off, siz, s) } if s.Type == SBSS || s.Type == STLSBSS { ctxt.Diag("cannot supply data for BSS var") diff --git a/test/live.go b/test/live.go index b23e1509e0..462f3ef12e 100644 --- a/test/live.go +++ b/test/live.go @@ -141,7 +141,7 @@ var i9 interface{} func f9() bool { g8() x := i9 - y := interface{}(99.0i) // ERROR "live at call to convT2E: x.data x.type$" + y := interface{}(str()) // ERROR "live at call to convT2E: .autotmp_[0-9]+ x.data x.type$" "live at call to str: x.data x.type$" i9 = y // make y escape so the line above has to call convT2E return x != y } @@ -256,12 +256,15 @@ func g15() string var m map[string]int +// str is used to ensure that a temp is required for runtime calls below. +func str() string + func f16() { if b { - delete(m, "hi") // ERROR "live at call to mapdelete: .autotmp_[0-9]+$" + delete(m, str()) // ERROR "live at call to mapdelete: .autotmp_[0-9]+$" } - delete(m, "hi") // ERROR "live at call to mapdelete: .autotmp_[0-9]+$" - delete(m, "hi") // ERROR "live at call to mapdelete: .autotmp_[0-9]+$" + delete(m, str()) // ERROR "live at call to mapdelete: .autotmp_[0-9]+$" + delete(m, str()) // ERROR "live at call to mapdelete: .autotmp_[0-9]+$" } var m2s map[string]*byte @@ -280,19 +283,19 @@ func f17a(p *byte) { // ERROR "live at entry to f17a: p$" func f17b(p *byte) { // ERROR "live at entry to f17b: p$" // key temporary if b { - m2s["x"] = p // ERROR "live at call to mapassign: p .autotmp_[0-9]+$" + m2s[str()] = p // ERROR "live at call to mapassign: p .autotmp_[0-9]+$" "live at call to str: p$" } - m2s["x"] = p // ERROR "live at call to mapassign: p .autotmp_[0-9]+$" - m2s["x"] = p // ERROR "live at call to mapassign: p .autotmp_[0-9]+$" + m2s[str()] = p // ERROR "live at call to mapassign: p .autotmp_[0-9]+$" "live at call to str: p$" + m2s[str()] = p // ERROR "live at call to mapassign: p .autotmp_[0-9]+$" "live at call to str: p$" } func f17c() { // key and value temporaries if b { - m2s["x"] = f17d() // ERROR "live at call to f17d: .autotmp_[0-9]+$" "live at call to mapassign: .autotmp_[0-9]+ .autotmp_[0-9]+$" + m2s[str()] = f17d() // ERROR "live at call to f17d: .autotmp_[0-9]+$" "live at call to mapassign: .autotmp_[0-9]+ .autotmp_[0-9]+$" } - m2s["x"] = f17d() // ERROR "live at call to f17d: .autotmp_[0-9]+$" "live at call to mapassign: .autotmp_[0-9]+ .autotmp_[0-9]+$" - m2s["x"] = f17d() // ERROR "live at call to f17d: .autotmp_[0-9]+$" "live at call to mapassign: .autotmp_[0-9]+ .autotmp_[0-9]+$" + m2s[str()] = f17d() // ERROR "live at call to f17d: .autotmp_[0-9]+$" "live at call to mapassign: .autotmp_[0-9]+ .autotmp_[0-9]+$" + m2s[str()] = f17d() // ERROR "live at call to f17d: .autotmp_[0-9]+$" "live at call to mapassign: .autotmp_[0-9]+ .autotmp_[0-9]+$" } func f17d() *byte @@ -313,6 +316,9 @@ func f18() { var ch chan *byte +// byteptr is used to ensure that a temp is required for runtime calls below. +func byteptr() *byte + func f19() { // dest temporary for channel receive. var z *byte @@ -328,10 +334,10 @@ func f19() { func f20() { // src temporary for channel send if b { - ch <- nil // ERROR "live at call to chansend1: .autotmp_[0-9]+$" + ch <- byteptr() // ERROR "live at call to chansend1: .autotmp_[0-9]+$" } - ch <- nil // ERROR "live at call to chansend1: .autotmp_[0-9]+$" - ch <- nil // ERROR "live at call to chansend1: .autotmp_[0-9]+$" + ch <- byteptr() // ERROR "live at call to chansend1: .autotmp_[0-9]+$" + ch <- byteptr() // ERROR "live at call to chansend1: .autotmp_[0-9]+$" } func f21() { @@ -488,13 +494,13 @@ func f30(b bool) { func f31(b1, b2, b3 bool) { if b1 { - g31("a") // ERROR "live at call to convT2E: .autotmp_[0-9]+$" "live at call to g31: .autotmp_[0-9]+$" + g31(str()) // ERROR "live at call to convT2E: .autotmp_[0-9]+$" "live at call to g31: .autotmp_[0-9]+$" } if b2 { - h31("b") // ERROR "live at call to convT2E: .autotmp_[0-9]+ .autotmp_[0-9]+$" "live at call to h31: .autotmp_[0-9]+$" "live at call to newobject: .autotmp_[0-9]+$" + h31(str()) // ERROR "live at call to convT2E: .autotmp_[0-9]+ .autotmp_[0-9]+$" "live at call to h31: .autotmp_[0-9]+$" "live at call to newobject: .autotmp_[0-9]+$" } if b3 { - panic("asdf") // ERROR "live at call to convT2E: .autotmp_[0-9]+$" "live at call to gopanic: .autotmp_[0-9]+$" + panic(str()) // ERROR "live at call to convT2E: .autotmp_[0-9]+$" "live at call to gopanic: .autotmp_[0-9]+$" } print(b3) } @@ -529,7 +535,7 @@ func call32(func()) var m33 map[interface{}]int func f33() { - if m33[nil] == 0 { // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$" + if m33[byteptr()] == 0 { // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$" printnl() return } else { @@ -539,7 +545,7 @@ func f33() { } func f34() { - if m33[nil] == 0 { // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$" + if m33[byteptr()] == 0 { // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$" printnl() return } @@ -547,7 +553,7 @@ func f34() { } func f35() { - if m33[nil] == 0 && m33[nil] == 0 { // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$" + if m33[byteptr()] == 0 && m33[byteptr()] == 0 { // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$" printnl() return } @@ -555,7 +561,7 @@ func f35() { } func f36() { - if m33[nil] == 0 || m33[nil] == 0 { // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$" + if m33[byteptr()] == 0 || m33[byteptr()] == 0 { // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$" printnl() return } @@ -563,7 +569,7 @@ func f36() { } func f37() { - if (m33[nil] == 0 || m33[nil] == 0) && m33[nil] == 0 { // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$" + if (m33[byteptr()] == 0 || m33[byteptr()] == 0) && m33[byteptr()] == 0 { // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$" printnl() return }