]> Cypherpunks.ru repositories - gostls13.git/commitdiff
cmd/compile: don't nilcheck newobject and return values from mapaccess{1,2}
authorKeith Randall <khr@golang.org>
Wed, 20 Apr 2016 04:06:53 +0000 (21:06 -0700)
committerKeith Randall <khr@golang.org>
Fri, 22 Apr 2016 16:18:42 +0000 (16:18 +0000)
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/22291
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
src/cmd/compile/internal/gc/cgen.go
src/cmd/compile/internal/gc/fmt.go
src/cmd/compile/internal/gc/ssa.go
src/cmd/compile/internal/gc/syntax.go
src/cmd/compile/internal/gc/walk.go
src/cmd/compile/internal/ssa/nilcheck.go
test/nilptr3.go
test/nilptr3_ssa.go

index 5c5bedaa314d8e64ac5f6ba9e9b24ba898f62908..a9393a6d9e1880e90514583cc397ce2ba4618ac3 100644 (file)
@@ -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
index bfb031aac58cfc22177bdc34aaa910498b4784e6..e5977c0905fe822b797432f1437c2daf0d3f8501 100644 (file)
@@ -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)
index ad665fbfbc07fbf670008a17899e049db44a5ada..218f720a61f50a650dab8b4c2407b269af236592 100644 (file)
@@ -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,
index 2f3b98a8ef84be40d9375ccd07f5946905fffe90..8a675ac1579881f7efb70eb3bba83e81ec240397 100644 (file)
@@ -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 :=
index 0e74365c76aecf4287d419dcb4a7495223ba4bad..27ff045028a12a72560ec6ad01e166653d0e623c 100644 (file)
@@ -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 {
index 753e48aad5773db5cb8aa21d759134244ba79835..62eb0c8ea6138737aae18b786461c1e71f6990c8 100644 (file)
@@ -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
index 817d2aec74add66eed466668ef881631a79a0e94..1bec833fe32c879e9cf5d083cecb6d9daa94aa9f 100644 (file)
@@ -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"
+}
index ba60a64602b11fdfaca9964521cf9309975ce533..6eefbac7d8022287392ae03eb5dacffa9f1af4fa 100644 (file)
@@ -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"
+}