1
0
mirror of https://github.com/golang/go synced 2024-11-11 18:21:40 -07:00

cmd/compile: extend ssa.go to handle 1-element array and 1-field struct

Assinging to 1-element array/1-field struct variable is considered clobbering
the whole variable. By emitting OpVarDef in this case, liveness analysis
can now know the variable is redefined.

Also, the isfat is not necessary anymore, and will be removed in follow up CL.

Fixes #33916

Change-Id: Iece0d90b05273f333d59d6ee5b12ee7dc71908c2
Reviewed-on: https://go-review.googlesource.com/c/go/+/192979
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
Cuong Manh Le 2019-09-03 23:24:35 +07:00 committed by Matthew Dempsky
parent 9da7abd2eb
commit d2f958d8d1
3 changed files with 31 additions and 6 deletions

View File

@ -2767,10 +2767,14 @@ func (s *state) assign(left *Node, right *ssa.Value, deref bool, skip skipMask)
s.addNamedValue(left, right)
return
}
// Left is not ssa-able. Compute its address.
if left.Op == ONAME && left.Class() != PEXTERN && skip == 0 {
s.vars[&memVar] = s.newValue1Apos(ssa.OpVarDef, types.TypeMem, left, s.mem(), !left.IsAutoTmp())
// If this assignment clobbers an entire local variable, then emit
// OpVarDef so liveness analysis knows the variable is redefined.
if base := clobberBase(left); base.Op == ONAME && base.Class() != PEXTERN && skip == 0 {
s.vars[&memVar] = s.newValue1Apos(ssa.OpVarDef, types.TypeMem, base, s.mem(), !base.IsAutoTmp())
}
// Left is not ssa-able. Compute its address.
addr := s.addr(left, false)
if isReflectHeaderDataField(left) {
// Package unsafe's documentation says storing pointers into
@ -6210,3 +6214,13 @@ func (n *Node) StorageClass() ssa.StorageClass {
return 0
}
}
func clobberBase(n *Node) *Node {
if n.Op == ODOT && n.Left.Type.NumFields() == 1 {
return clobberBase(n.Left)
}
if n.Op == OINDEX && n.Left.Type.IsArray() && n.Left.Type.NumElem() == 1 {
return clobberBase(n.Left)
}
return n
}

View File

@ -659,7 +659,7 @@ func bad40() {
func good40() {
ret := T40{} // ERROR "stack object ret T40$"
ret.m = make(map[int]int) // ERROR "live at call to fastrand: .autotmp_[0-9]+ ret$" "stack object .autotmp_[0-9]+ map.hdr\[int\]int$"
ret.m = make(map[int]int) // ERROR "live at call to fastrand: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ map.hdr\[int\]int$"
t := &ret
printnl() // ERROR "live at call to printnl: ret$"
// Note: ret is live at the printnl because the compiler moves &ret
@ -704,3 +704,14 @@ func f42() {
//go:noescape
func f43(a []*int)
// Assigning to a sub-element that makes up an entire local variable
// should clobber that variable.
func f44(f func() [2]*int) interface{} { // ERROR "live at entry to f44: f"
type T struct {
s [1][2]*int
}
ret := T{}
ret.s[0] = f()
return ret // ERROR "stack object .autotmp_5 T"
}

View File

@ -27,14 +27,14 @@ func newT40() *T40 {
}
func bad40() {
t := newT40() // ERROR "live at call to makemap: ret$" "stack object ret T40$" "stack object .autotmp_[0-9]+ map.hdr\[int\]int$"
t := newT40() // ERROR "stack object ret T40$" "stack object .autotmp_[0-9]+ map.hdr\[int\]int$"
printnl() // ERROR "live at call to printnl: ret$"
useT40(t)
}
func good40() {
ret := T40{} // ERROR "stack object ret T40$"
ret.m = make(map[int]int, 42) // ERROR "live at call to makemap: ret$" "stack object .autotmp_[0-9]+ map.hdr\[int\]int$"
ret.m = make(map[int]int, 42) // ERROR "stack object .autotmp_[0-9]+ map.hdr\[int\]int$"
t := &ret
printnl() // ERROR "live at call to printnl: ret$"
useT40(t)