Commit 3c1a4c19 authored by Keith Randall's avatar Keith Randall

cmd/compile: don't nilcheck newobject and return values from mapaccess{1,2}

They are guaranteed to be non-nil, no point in inserting
nil checks for them.

Fixes #15390

Change-Id: I3b9a0f2319affc2139dcc446d0a56c6785ae5a86
Reviewed-on: https://go-review.googlesource.com/22291Reviewed-by: 's avatarJosh Bleecher Snyder <josharian@gmail.com>
parent 32302d62
......@@ -978,7 +978,11 @@ func Agenr(n *Node, a *Node, res *Node) {
case OIND:
Cgenr(n.Left, a, res)
Cgen_checknil(a)
if !n.Left.NonNil {
Cgen_checknil(a)
} else if Debug_checknil != 0 && n.Lineno > 1 {
Warnl(n.Lineno, "removed nil check")
}
case OINDEX:
if Ctxt.Arch.Family == sys.ARM {
......@@ -1587,7 +1591,11 @@ func Agen(n *Node, res *Node) {
case OIND:
Cgen(nl, res)
Cgen_checknil(res)
if !nl.NonNil {
Cgen_checknil(res)
} else if Debug_checknil != 0 && n.Lineno > 1 {
Warnl(n.Lineno, "removed nil check")
}
case ODOT:
Agen(nl, res)
......@@ -1597,7 +1605,11 @@ func Agen(n *Node, res *Node) {
case ODOTPTR:
Cgen(nl, res)
Cgen_checknil(res)
if !nl.NonNil {
Cgen_checknil(res)
} else if Debug_checknil != 0 && n.Lineno > 1 {
Warnl(n.Lineno, "removed nil check")
}
if n.Xoffset != 0 {
addOffset(res, n.Xoffset)
}
......@@ -1658,7 +1670,11 @@ func Igen(n *Node, a *Node, res *Node) {
case ODOTPTR:
Cgenr(n.Left, a, res)
Cgen_checknil(a)
if !n.Left.NonNil {
Cgen_checknil(a)
} else if Debug_checknil != 0 && n.Lineno > 1 {
Warnl(n.Lineno, "removed nil check")
}
a.Op = OINDREG
a.Xoffset += n.Xoffset
a.Type = n.Type
......
......@@ -319,6 +319,12 @@ func Jconv(n *Node, flag FmtFlag) string {
if n.Assigned {
buf.WriteString(" assigned")
}
if n.Bounded {
buf.WriteString(" bounded")
}
if n.NonNil {
buf.WriteString(" nonnil")
}
if c == 0 && n.Used {
fmt.Fprintf(&buf, " used(%v)", n.Used)
......
......@@ -1938,8 +1938,7 @@ func (s *state) expr(n *Node) *ssa.Value {
return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
case OIND:
p := s.expr(n.Left)
s.nilCheck(p)
p := s.exprPtr(n.Left, false, n.Lineno)
return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
case ODOT:
......@@ -1952,8 +1951,7 @@ func (s *state) expr(n *Node) *ssa.Value {
return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
case ODOTPTR:
p := s.expr(n.Left)
s.nilCheck(p)
p := s.exprPtr(n.Left, false, n.Lineno)
p = s.newValue1I(ssa.OpOffPtr, p.Type, n.Xoffset, p)
return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
......@@ -2778,19 +2776,12 @@ func (s *state) addr(n *Node, bounded bool) *ssa.Value {
return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Elem()), a, i)
}
case OIND:
p := s.expr(n.Left)
if !bounded {
s.nilCheck(p)
}
return p
return s.exprPtr(n.Left, bounded, n.Lineno)
case ODOT:
p := s.addr(n.Left, bounded)
return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p)
case ODOTPTR:
p := s.expr(n.Left)
if !bounded {
s.nilCheck(p)
}
p := s.exprPtr(n.Left, bounded, n.Lineno)
return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p)
case OCLOSUREVAR:
return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset,
......@@ -2892,6 +2883,19 @@ func canSSAType(t *Type) bool {
}
}
// exprPtr evaluates n to a pointer and nil-checks it.
func (s *state) exprPtr(n *Node, bounded bool, lineno int32) *ssa.Value {
p := s.expr(n)
if bounded || n.NonNil {
if s.f.Config.Debug_checknil() && lineno > 1 {
s.f.Config.Warnl(lineno, "removed nil check")
}
return p
}
s.nilCheck(p)
return p
}
// nilCheck generates nil pointer checking code.
// Starts a new block on return, unless nil checks are disabled.
// Used only for automatically inserted nil checks,
......
......@@ -54,6 +54,7 @@ type Node struct {
Addable bool // addressable
Etype EType // op for OASOP, etype for OTYPE, exclam for export, 6g saved reg, ChanDir for OTCHAN
Bounded bool // bounds check unnecessary
NonNil bool // guaranteed to be non-nil
Class Class // PPARAM, PAUTO, PEXTERN, etc
Embedded uint8 // ODCLFIELD embedded type
Colas bool // OAS resulting from :=
......
......@@ -886,6 +886,7 @@ opswitch:
if !isblank(a) {
var_ := temp(Ptrto(t.Val()))
var_.Typecheck = 1
var_.NonNil = true // mapaccess always returns a non-nil pointer
n.List.SetIndex(0, var_)
n = walkexpr(n, init)
init.Append(n)
......@@ -895,8 +896,6 @@ opswitch:
n = typecheck(n, Etop)
n = walkexpr(n, init)
// TODO: ptr is always non-nil, so disable nil check for this OIND op.
case ODELETE:
init.AppendNodes(&n.Ninit)
map_ := n.List.First()
......@@ -1224,7 +1223,6 @@ opswitch:
// standard version takes key by reference.
// orderexpr made sure key is addressable.
key = Nod(OADDR, n.Right, nil)
p = "mapaccess1"
}
......@@ -1235,6 +1233,7 @@ opswitch:
z := zeroaddr(w)
n = mkcall1(mapfn(p, t), Ptrto(t.Val()), init, typename(t), n.Left, key, z)
}
n.NonNil = true // mapaccess always returns a non-nil pointer
n = Nod(OIND, n, nil)
n.Type = t.Val()
n.Typecheck = 1
......@@ -2015,7 +2014,9 @@ func callnew(t *Type) *Node {
dowidth(t)
fn := syslook("newobject")
fn = substArgTypes(fn, t)
return mkcall1(fn, Ptrto(t), nil, typename(t))
v := mkcall1(fn, Ptrto(t), nil, typename(t))
v.NonNil = true
return v
}
func iscallret(n *Node) bool {
......
......@@ -4,8 +4,6 @@
package ssa
// TODO: return value from newobject/newarray is non-nil.
// nilcheckelim eliminates unnecessary nil checks.
func nilcheckelim(f *Func) {
// A nil check is redundant if the same nil check was successful in a
......
......@@ -193,3 +193,24 @@ func f4(x *[10]int) {
x = y
_ = &x[9] // ERROR "removed repeated nil check"
}
func m1(m map[int][80]byte) byte {
v := m[3] // ERROR "removed nil check"
return v[5]
}
func m2(m map[int][800]byte) byte {
v := m[3] // ERROR "removed nil check"
return v[5]
}
func m3(m map[int][80]byte) (byte, bool) {
v, ok := m[3] // ERROR "removed nil check"
return v[5], ok
}
func m4(m map[int][800]byte) (byte, bool) {
v, ok := m[3] // ERROR "removed nil check"
return v[5], ok
}
func p1() byte {
p := new([100]byte)
return p[5] // ERROR "removed nil check"
}
......@@ -207,3 +207,24 @@ func f6(p, q *T) {
x := *p // ERROR "removed nil check"
*q = x // ERROR "removed nil check"
}
func m1(m map[int][80]byte) byte {
v := m[3] // ERROR "removed nil check"
return v[5]
}
func m2(m map[int][800]byte) byte {
v := m[3] // ERROR "removed nil check"
return v[5]
}
func m3(m map[int][80]byte) (byte, bool) {
v, ok := m[3] // ERROR "removed nil check"
return v[5], ok
}
func m4(m map[int][800]byte) (byte, bool) {
v, ok := m[3] // ERROR "removed nil check"
return v[5], ok
}
func p1() byte {
p := new([100]byte)
return p[5] // ERROR "removed nil check"
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment