1
0
mirror of https://github.com/golang/go synced 2024-09-24 09:20:15 -06:00
go/test/nilptr3.go
Keith Randall 256a605faa cmd/compile: don't use nilcheck information until the next block
When nilcheck runs, the values in a block are not in any particular
order.  So any facts derived from examining the blocks shouldn't be
used until we reach the next block.

This is suboptimal as it won't eliminate nil checks within a block.
But it's probably a better fix for now as it is a much smaller change
than other strategies for fixing this bug.

nilptr3.go changes are mostly because for this pattern:
  _ = *p
  _ = *p
either nil check is fine to keep, and this CL changes which one
the compiler tends to keep.
There are a few regressions from code like this:
  _ = *p
  f()
  _ = *p
For this pattern, after this CL we issue 2 nil checks instead of one.
(For the curious, this happens because intra-block nil check
 elimination now falls to CSE, not nilcheck proper.  The former
 pattern has two nil checks with the same store argument.  The latter
 pattern has two nil checks with different store arguments.)

Fixes #18725

Change-Id: I3721b494c8bc9ba1142dc5c4361ea55c66920ac8
Reviewed-on: https://go-review.googlesource.com/35485
Reviewed-by: Cherry Zhang <cherryyz@google.com>
2017-01-20 20:21:55 +00:00

257 lines
5.8 KiB
Go

// errorcheck -0 -d=nil
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Test that nil checks are removed.
// Optimization is enabled.
package p
type Struct struct {
X int
Y float64
}
type BigStruct struct {
X int
Y float64
A [1 << 20]int
Z string
}
type Empty struct {
}
type Empty1 struct {
Empty
}
var (
intp *int
arrayp *[10]int
array0p *[0]int
bigarrayp *[1 << 26]int
structp *Struct
bigstructp *BigStruct
emptyp *Empty
empty1p *Empty1
)
func f1() {
_ = *intp // ERROR "removed nil check"
// This one should be removed but the block copy needs
// to be turned into its own pseudo-op in order to see
// the indirect.
_ = *arrayp // ERROR "removed nil check"
// 0-byte indirect doesn't suffice.
// we don't registerize globals, so there are no removed.* nil checks.
_ = *array0p // ERROR "removed nil check"
_ = *array0p // ERROR "generated nil check"
_ = *intp // ERROR "generated nil check"
_ = *arrayp // ERROR "removed nil check"
_ = *structp // ERROR "generated nil check"
_ = *emptyp // ERROR "generated nil check"
_ = *arrayp // ERROR "generated nil check"
}
func f2() {
var (
intp *int
arrayp *[10]int
array0p *[0]int
bigarrayp *[1 << 20]int
structp *Struct
bigstructp *BigStruct
emptyp *Empty
empty1p *Empty1
)
_ = *intp // ERROR "removed.* nil check"
_ = *arrayp // ERROR "removed.* nil check"
_ = *array0p // ERROR "removed.* nil check"
_ = *array0p // ERROR "generated nil check"
_ = *intp // ERROR "generated nil check"
_ = *arrayp // ERROR "removed.* nil check"
_ = *structp // ERROR "generated nil check"
_ = *emptyp // ERROR "generated nil check"
_ = *arrayp // ERROR "generated nil check"
_ = *bigarrayp // ERROR "generated nil check" ARM removed nil check before indirect!!
_ = *bigstructp // ERROR "generated nil check"
_ = *empty1p // ERROR "generated nil check"
}
func fx10k() *[10000]int
var b bool
func f3(x *[10000]int) {
// Using a huge type and huge offsets so the compiler
// does not expect the memory hardware to fault.
_ = x[9999] // ERROR "generated nil check"
for {
if x[9999] != 0 { // ERROR "removed nil check"
break
}
}
x = fx10k()
_ = x[9999] // ERROR "generated nil check"
if b {
_ = x[9999] // ERROR "removed.* nil check"
} else {
_ = x[9999] // ERROR "removed.* nil check"
}
_ = x[9999] // ERROR "removed nil check"
x = fx10k()
if b {
_ = x[9999] // ERROR "generated nil check"
} else {
_ = x[9999] // ERROR "generated nil check"
}
_ = x[9999] // ERROR "generated nil check"
fx10k()
// This one is a bit redundant, if we figured out that
// x wasn't going to change across the function call.
// But it's a little complex to do and in practice doesn't
// matter enough.
_ = x[9999] // ERROR "generated nil check" // TODO: fix
}
func f3a() {
x := fx10k()
y := fx10k()
z := fx10k()
_ = &x[9] // ERROR "removed.* nil check"
y = z
_ = &x[9] // ERROR "generated nil check"
x = y
_ = &x[9] // ERROR "generated nil check"
}
func f3b() {
x := fx10k()
y := fx10k()
_ = &x[9] // ERROR "removed.* nil check"
y = x
_ = &x[9] // ERROR "removed.* nil check"
x = y
_ = &x[9] // ERROR "generated nil check"
}
func fx10() *[10]int
func f4(x *[10]int) {
// Most of these have no checks because a real memory reference follows,
// and the offset is small enough that if x is nil, the address will still be
// in the first unmapped page of memory.
_ = x[9] // ERROR "generated nil check" // bug: would like to remove this check (but nilcheck and load are in different blocks)
for {
if x[9] != 0 { // ERROR "removed nil check"
break
}
}
x = fx10()
_ = x[9] // ERROR "generated nil check" // bug would like to remove before indirect
if b {
_ = x[9] // ERROR "removed nil check"
} else {
_ = x[9] // ERROR "removed nil check"
}
_ = x[9] // ERROR "removed nil check"
x = fx10()
if b {
_ = x[9] // ERROR "generated nil check" // bug would like to remove before indirect
} else {
_ = &x[9] // ERROR "generated nil check"
}
_ = x[9] // ERROR "generated nil check" // bug would like to remove before indirect
fx10()
_ = x[9] // ERROR "generated nil check" // TODO: fix
x = fx10()
y := fx10()
_ = &x[9] // ERROR "removed[a-z ]* nil check"
y = x
_ = &x[9] // ERROR "removed[a-z ]* nil check"
x = y
_ = &x[9] // ERROR "generated nil check"
}
func f5(p *float32, q *float64, r *float32, s *float64) float64 {
x := float64(*p) // ERROR "removed nil check"
y := *q // ERROR "removed nil check"
*r = 7 // ERROR "removed nil check"
*s = 9 // ERROR "removed nil check"
return x + y
}
type T [29]byte
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"
}
// make sure not to do nil check for access of PAUTOHEAP
//go:noinline
func (p *Struct) m() {}
func c1() {
var x Struct
func() { x.m() }() // ERROR "removed nil check"
}
type SS struct {
x byte
}
type TT struct {
SS
}
func f(t *TT) *byte {
// See issue 17242.
s := &t.SS // ERROR "removed nil check"
return &s.x // ERROR "generated nil check"
}
// make sure not to do nil check for newobject
func f7() (*Struct, float64) {
t := new(Struct)
p := &t.Y // ERROR "removed nil check"
return t, *p // ERROR "removed nil check"
}