Commit 729abfa3 authored by David Chase's avatar David Chase

[dev.ssa] cmd/compile: default compile+test with SSA

Some tests disabled, some bifurcated into _ssa and not,
with appropriate logging added to compiler.

"tests/live.go" in particular needs attention.

SSA-specific testing removed, since it's all SSA now.

Added "-run_skips" option to tests/run.go to simplify
checking whether a test still fails (or how it fails)
on a skipped platform.

The compiler now compiles with SSA by default.
If you don't want SSA, specify GOSSAHASH=n (or N) as
an environment variable.  Function names ending in "_ssa"
are always SSA-compiled.

GOSSAFUNC=fname retains its "SSA for fname, log to ssa.html"
GOSSAPKG=pkg only has an effect when GOSSAHASH=n
GOSSAHASH=10101 etc retains its name-hash-matching behavior
for purposes of debugging.

See #13068

Change-Id: I8217bfeb34173533eaeb391b5f6935483c7d6b43
Reviewed-on: https://go-review.googlesource.com/16299Reviewed-by: 's avatarKeith Randall <khr@golang.org>
Run-TryBot: David Chase <drchase@google.com>
parent cdc36252
...@@ -34,10 +34,10 @@ func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) { ...@@ -34,10 +34,10 @@ func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) {
// 1. IF GOSSAFUNC == current function name THEN // 1. IF GOSSAFUNC == current function name THEN
// compile this function with SSA and log output to ssa.html // compile this function with SSA and log output to ssa.html
// 2. IF GOSSAHASH == "y" or "Y" THEN // 2. IF GOSSAHASH == "" THEN
// compile this function (and everything else) with SSA // compile this function (and everything else) with SSA
// 3. IF GOSSAHASH == "" THEN // 3. IF GOSSAHASH == "n" or "N"
// IF GOSSAPKG == current package name THEN // IF GOSSAPKG == current package name THEN
// compile this function (and everything in this package) with SSA // compile this function (and everything in this package) with SSA
// ELSE // ELSE
...@@ -49,9 +49,10 @@ func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) { ...@@ -49,9 +49,10 @@ func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) {
// ELSE // ELSE
// compile this function with the old back end. // compile this function with the old back end.
// Plan is for 3 to be remove, and the 2) dependence on GOSSAHASH changes // Plan is for 3 to be removed when the tests are revised.
// from "y"/"Y" to empty -- then SSA is default, and is disabled by setting // SSA is now default, and is disabled by setting
// GOSSAHASH to a value that is neither 0 nor 1 (e.g., "N" or "X") // GOSSAHASH to n or N, or selectively with strings of
// 0 and 1.
if usessa { if usessa {
fmt.Println("generating SSA for", name) fmt.Println("generating SSA for", name)
...@@ -183,10 +184,11 @@ func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) { ...@@ -183,10 +184,11 @@ func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) {
// Main call to ssa package to compile function // Main call to ssa package to compile function
ssa.Compile(s.f) ssa.Compile(s.f)
if usessa || gossahash == "y" || gossahash == "Y" { // gossahash = "y" is historical/symmetric-with-"n" -- i.e., not really needed.
if usessa || gossahash == "" || gossahash == "y" || gossahash == "Y" {
return s.f, true return s.f, true
} }
if gossahash == "" { if gossahash == "n" || gossahash == "N" {
if localpkg.Name != os.Getenv("GOSSAPKG") { if localpkg.Name != os.Getenv("GOSSAPKG") {
return s.f, false return s.f, false
} }
...@@ -298,9 +300,11 @@ func (s *state) label(sym *Sym) *ssaLabel { ...@@ -298,9 +300,11 @@ func (s *state) label(sym *Sym) *ssaLabel {
return lab return lab
} }
func (s *state) Logf(msg string, args ...interface{}) { s.config.Logf(msg, args...) } func (s *state) Logf(msg string, args ...interface{}) { s.config.Logf(msg, args...) }
func (s *state) Fatalf(msg string, args ...interface{}) { s.config.Fatalf(msg, args...) } func (s *state) Fatalf(msg string, args ...interface{}) { s.config.Fatalf(msg, args...) }
func (s *state) Unimplementedf(msg string, args ...interface{}) { s.config.Unimplementedf(msg, args...) } func (s *state) Unimplementedf(msg string, args ...interface{}) { s.config.Unimplementedf(msg, args...) }
func (s *state) Warnl(line int, msg string, args ...interface{}) { s.config.Warnl(line, msg, args...) }
func (s *state) Debug_checknil() bool { return s.config.Debug_checknil() }
var ( var (
// dummy node for the memory variable // dummy node for the memory variable
...@@ -1997,7 +2001,7 @@ func (s *state) expr(n *Node) *ssa.Value { ...@@ -1997,7 +2001,7 @@ func (s *state) expr(n *Node) *ssa.Value {
if haspointers(et) { if haspointers(et) {
// TODO: just one write barrier call for all of these writes? // TODO: just one write barrier call for all of these writes?
// TODO: maybe just one writeBarrierEnabled check? // TODO: maybe just one writeBarrierEnabled check?
s.insertWB(et, addr) s.insertWB(et, addr, n.Lineno)
} }
} }
...@@ -2044,7 +2048,7 @@ func (s *state) assign(left *Node, right *ssa.Value, wb bool) { ...@@ -2044,7 +2048,7 @@ func (s *state) assign(left *Node, right *ssa.Value, wb bool) {
} }
s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, t.Size(), addr, right, s.mem()) s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, t.Size(), addr, right, s.mem())
if wb { if wb {
s.insertWB(left.Type, addr) s.insertWB(left.Type, addr, left.Lineno)
} }
} }
...@@ -2566,7 +2570,7 @@ func (s *state) rtcall(fn *Node, returns bool, results []*Type, args ...*ssa.Val ...@@ -2566,7 +2570,7 @@ func (s *state) rtcall(fn *Node, returns bool, results []*Type, args ...*ssa.Val
// been stored at location p. Tell the runtime about this write. // been stored at location p. Tell the runtime about this write.
// Note: there must be no GC suspension points between the write and // Note: there must be no GC suspension points between the write and
// the call that this function inserts. // the call that this function inserts.
func (s *state) insertWB(t *Type, p *ssa.Value) { func (s *state) insertWB(t *Type, p *ssa.Value, line int32) {
// if writeBarrierEnabled { // if writeBarrierEnabled {
// typedmemmove_nostore(&t, p) // typedmemmove_nostore(&t, p)
// } // }
...@@ -2586,6 +2590,10 @@ func (s *state) insertWB(t *Type, p *ssa.Value) { ...@@ -2586,6 +2590,10 @@ func (s *state) insertWB(t *Type, p *ssa.Value) {
taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Types[TUINTPTR], typenamesym(t)}, s.sb) taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Types[TUINTPTR], typenamesym(t)}, s.sb)
s.rtcall(typedmemmove_nostore, true, nil, taddr, p) s.rtcall(typedmemmove_nostore, true, nil, taddr, p)
if Debug_wb > 0 {
Warnl(int(line), "write barrier")
}
b.AddEdgeTo(s.curBlock) b.AddEdgeTo(s.curBlock)
} }
...@@ -2985,6 +2993,10 @@ func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) { ...@@ -2985,6 +2993,10 @@ func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
Fatalf("dottype needs a direct iface type %s", n.Type) Fatalf("dottype needs a direct iface type %s", n.Type)
} }
if Debug_typeassert > 0 {
Warnl(int(n.Lineno), "type assertion inlined")
}
// TODO: If we have a nonempty interface and its itab field is nil, // TODO: If we have a nonempty interface and its itab field is nil,
// then this test is redundant and ifaceType should just branch directly to bFail. // then this test is redundant and ifaceType should just branch directly to bFail.
cond := s.newValue2(ssa.OpEqPtr, Types[TBOOL], typ, target) cond := s.newValue2(ssa.OpEqPtr, Types[TBOOL], typ, target)
...@@ -4523,6 +4535,16 @@ func (e *ssaExport) Unimplementedf(msg string, args ...interface{}) { ...@@ -4523,6 +4535,16 @@ func (e *ssaExport) Unimplementedf(msg string, args ...interface{}) {
e.unimplemented = true e.unimplemented = true
} }
// Warnl reports a "warning", which is usually flag-triggered
// logging output for the benefit of tests.
func (e *ssaExport) Warnl(line int, fmt_ string, args ...interface{}) {
Warnl(line, fmt_, args...)
}
func (e *ssaExport) Debug_checknil() bool {
return Debug_checknil != 0
}
func (n *Node) Typ() ssa.Type { func (n *Node) Typ() ssa.Type {
return n.Type return n.Type
} }
...@@ -49,6 +49,12 @@ type Logger interface { ...@@ -49,6 +49,12 @@ type Logger interface {
// Unimplemented reports that the function cannot be compiled. // Unimplemented reports that the function cannot be compiled.
// It will be removed once SSA work is complete. // It will be removed once SSA work is complete.
Unimplementedf(msg string, args ...interface{}) Unimplementedf(msg string, args ...interface{})
// Warnl writes compiler messages in the form expected by "errorcheck" tests
Warnl(line int, fmt_ string, args ...interface{})
// Fowards the Debug_checknil flag from gc
Debug_checknil() bool
} }
type Frontend interface { type Frontend interface {
...@@ -100,9 +106,11 @@ func (c *Config) NewFunc() *Func { ...@@ -100,9 +106,11 @@ func (c *Config) NewFunc() *Func {
return &Func{Config: c, NamedValues: map[GCNode][]*Value{}} return &Func{Config: c, NamedValues: map[GCNode][]*Value{}}
} }
func (c *Config) Logf(msg string, args ...interface{}) { c.fe.Logf(msg, args...) } func (c *Config) Logf(msg string, args ...interface{}) { c.fe.Logf(msg, args...) }
func (c *Config) Fatalf(msg string, args ...interface{}) { c.fe.Fatalf(msg, args...) } func (c *Config) Fatalf(msg string, args ...interface{}) { c.fe.Fatalf(msg, args...) }
func (c *Config) Unimplementedf(msg string, args ...interface{}) { c.fe.Unimplementedf(msg, args...) } func (c *Config) Unimplementedf(msg string, args ...interface{}) { c.fe.Unimplementedf(msg, args...) }
func (c *Config) Warnl(line int, msg string, args ...interface{}) { c.fe.Warnl(line, msg, args...) }
func (c *Config) Debug_checknil() bool { return c.fe.Debug_checknil() }
// TODO(khr): do we really need a separate Config, or can we just // TODO(khr): do we really need a separate Config, or can we just
// store all its fields inside a Func? // store all its fields inside a Func?
...@@ -32,9 +32,11 @@ func (DummyFrontend) Auto(t Type) GCNode { ...@@ -32,9 +32,11 @@ func (DummyFrontend) Auto(t Type) GCNode {
return nil return nil
} }
func (d DummyFrontend) Logf(msg string, args ...interface{}) { d.t.Logf(msg, args...) } func (d DummyFrontend) Logf(msg string, args ...interface{}) { d.t.Logf(msg, args...) }
func (d DummyFrontend) Fatalf(msg string, args ...interface{}) { d.t.Fatalf(msg, args...) } func (d DummyFrontend) Fatalf(msg string, args ...interface{}) { d.t.Fatalf(msg, args...) }
func (d DummyFrontend) Unimplementedf(msg string, args ...interface{}) { d.t.Fatalf(msg, args...) } func (d DummyFrontend) Unimplementedf(msg string, args ...interface{}) { d.t.Fatalf(msg, args...) }
func (d DummyFrontend) Warnl(line int, msg string, args ...interface{}) { d.t.Logf(msg, args...) }
func (d DummyFrontend) Debug_checknil() bool { return false }
func (d DummyFrontend) TypeBool() Type { return TypeBool } func (d DummyFrontend) TypeBool() Type { return TypeBool }
func (d DummyFrontend) TypeInt8() Type { return TypeInt8 } func (d DummyFrontend) TypeInt8() Type { return TypeInt8 }
......
...@@ -88,6 +88,13 @@ func nilcheckelim(f *Func) { ...@@ -88,6 +88,13 @@ func nilcheckelim(f *Func) {
// Eliminate the nil check. // Eliminate the nil check.
// The deadcode pass will remove vestigial values, // The deadcode pass will remove vestigial values,
// and the fuse pass will join this block with its successor. // and the fuse pass will join this block with its successor.
// Logging in the style of the former compiler -- and omit line 1,
// which is usually in generated code.
if f.Config.Debug_checknil() && int(node.block.Control.Line) > 1 {
f.Config.Warnl(int(node.block.Control.Line), "removed nil check")
}
switch node.block.Kind { switch node.block.Kind {
case BlockIf: case BlockIf:
node.block.Kind = BlockFirst node.block.Kind = BlockFirst
......
...@@ -13,7 +13,6 @@ import ( ...@@ -13,7 +13,6 @@ import (
"log" "log"
"os" "os"
"os/exec" "os/exec"
"path"
"path/filepath" "path/filepath"
"regexp" "regexp"
"strconv" "strconv"
...@@ -276,31 +275,6 @@ func (t *tester) registerStdTest(pkg string) { ...@@ -276,31 +275,6 @@ func (t *tester) registerStdTest(pkg string) {
}) })
} }
// TODO: Remove when SSA codegen is used by default.
func (t *tester) registerSSATest(pkg string) {
t.tests = append(t.tests, distTest{
name: "go_test_ssa:" + pkg,
heading: "Testing packages with SSA codegen.",
fn: func() error {
args := []string{
"test",
"-short",
t.timeout(180 * 3), // SSA generates slower code right now
"-gcflags=" + os.Getenv("GO_GCFLAGS"),
}
if t.race {
args = append(args, "-race")
}
args = append(args, pkg)
cmd := exec.Command("go", args...)
cmd.Env = mergeEnvLists([]string{"GOSSAPKG=" + path.Base(pkg)}, os.Environ())
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
},
})
}
func (t *tester) registerRaceBenchTest(pkg string) { func (t *tester) registerRaceBenchTest(pkg string) {
testName := "go_test_bench:" + pkg testName := "go_test_bench:" + pkg
if t.runRx == nil || t.runRx.MatchString(testName) { if t.runRx == nil || t.runRx.MatchString(testName) {
...@@ -344,9 +318,6 @@ func (t *tester) registerTests() { ...@@ -344,9 +318,6 @@ func (t *tester) registerTests() {
if strings.HasPrefix(name, "go_test_bench:") { if strings.HasPrefix(name, "go_test_bench:") {
t.registerRaceBenchTest(strings.TrimPrefix(name, "go_test_bench:")) t.registerRaceBenchTest(strings.TrimPrefix(name, "go_test_bench:"))
} }
if t.goarch == "amd64" && strings.HasPrefix(name, "go_test_ssa:") {
t.registerSSATest(strings.TrimPrefix(name, "go_test_ssa:"))
}
} }
} else { } else {
// Use a format string to only list packages and commands that have tests. // Use a format string to only list packages and commands that have tests.
...@@ -363,11 +334,6 @@ func (t *tester) registerTests() { ...@@ -363,11 +334,6 @@ func (t *tester) registerTests() {
for _, pkg := range pkgs { for _, pkg := range pkgs {
t.registerStdTest(pkg) t.registerStdTest(pkg)
} }
if t.goarch == "amd64" {
for _, pkg := range pkgs {
t.registerSSATest(pkg)
}
}
if t.race { if t.race {
for _, pkg := range pkgs { for _, pkg := range pkgs {
t.registerRaceBenchTest(pkg) t.registerRaceBenchTest(pkg)
......
// +build !amd64
// errorcheck -0 -l -live -wb=0 // errorcheck -0 -l -live -wb=0
// Copyright 2014 The Go Authors. All rights reserved. // Copyright 2014 The Go Authors. All rights reserved.
......
// +build !amd64
// errorcheck -0 -live -wb=0 // errorcheck -0 -live -wb=0
// Copyright 2014 The Go Authors. All rights reserved. // Copyright 2014 The Go Authors. All rights reserved.
......
// +build !amd64
// errorcheck -0 -N -d=nil // errorcheck -0 -N -d=nil
// Copyright 2013 The Go Authors. All rights reserved. // Copyright 2013 The Go Authors. All rights reserved.
...@@ -17,7 +18,7 @@ type Struct struct { ...@@ -17,7 +18,7 @@ type Struct struct {
type BigStruct struct { type BigStruct struct {
X int X int
Y float64 Y float64
A [1<<20]int A [1 << 20]int
Z string Z string
} }
...@@ -29,86 +30,86 @@ type Empty1 struct { ...@@ -29,86 +30,86 @@ type Empty1 struct {
} }
var ( var (
intp *int intp *int
arrayp *[10]int arrayp *[10]int
array0p *[0]int array0p *[0]int
bigarrayp *[1<<26]int bigarrayp *[1 << 26]int
structp *Struct structp *Struct
bigstructp *BigStruct bigstructp *BigStruct
emptyp *Empty emptyp *Empty
empty1p *Empty1 empty1p *Empty1
) )
func f1() { func f1() {
_ = *intp // ERROR "nil check" _ = *intp // ERROR "nil check"
_ = *arrayp // ERROR "nil check" _ = *arrayp // ERROR "nil check"
_ = *array0p // ERROR "nil check" _ = *array0p // ERROR "nil check"
_ = *array0p // ERROR "nil check" _ = *array0p // ERROR "nil check"
_ = *intp // ERROR "nil check" _ = *intp // ERROR "nil check"
_ = *arrayp // ERROR "nil check" _ = *arrayp // ERROR "nil check"
_ = *structp // ERROR "nil check" _ = *structp // ERROR "nil check"
_ = *emptyp // ERROR "nil check" _ = *emptyp // ERROR "nil check"
_ = *arrayp // ERROR "nil check" _ = *arrayp // ERROR "nil check"
} }
func f2() { func f2() {
var ( var (
intp *int intp *int
arrayp *[10]int arrayp *[10]int
array0p *[0]int array0p *[0]int
bigarrayp *[1<<20]int bigarrayp *[1 << 20]int
structp *Struct structp *Struct
bigstructp *BigStruct bigstructp *BigStruct
emptyp *Empty emptyp *Empty
empty1p *Empty1 empty1p *Empty1
) )
_ = *intp // ERROR "nil check" _ = *intp // ERROR "nil check"
_ = *arrayp // ERROR "nil check" _ = *arrayp // ERROR "nil check"
_ = *array0p // ERROR "nil check" _ = *array0p // ERROR "nil check"
_ = *array0p // ERROR "nil check" _ = *array0p // ERROR "nil check"
_ = *intp // ERROR "nil check" _ = *intp // ERROR "nil check"
_ = *arrayp // ERROR "nil check" _ = *arrayp // ERROR "nil check"
_ = *structp // ERROR "nil check" _ = *structp // ERROR "nil check"
_ = *emptyp // ERROR "nil check" _ = *emptyp // ERROR "nil check"
_ = *arrayp // ERROR "nil check" _ = *arrayp // ERROR "nil check"
_ = *bigarrayp // ERROR "nil check" _ = *bigarrayp // ERROR "nil check"
_ = *bigstructp // ERROR "nil check" _ = *bigstructp // ERROR "nil check"
_ = *empty1p // ERROR "nil check" _ = *empty1p // ERROR "nil check"
} }
func fx10k() *[10000]int func fx10k() *[10000]int
var b bool
var b bool
func f3(x *[10000]int) { func f3(x *[10000]int) {
// Using a huge type and huge offsets so the compiler // Using a huge type and huge offsets so the compiler
// does not expect the memory hardware to fault. // does not expect the memory hardware to fault.
_ = x[9999] // ERROR "nil check" _ = x[9999] // ERROR "nil check"
for { for {
if x[9999] != 0 { // ERROR "nil check" if x[9999] != 0 { // ERROR "nil check"
break break
} }
} }
x = fx10k() x = fx10k()
_ = x[9999] // ERROR "nil check" _ = x[9999] // ERROR "nil check"
if b { if b {
_ = x[9999] // ERROR "nil check" _ = x[9999] // ERROR "nil check"
} else { } else {
_ = x[9999] // ERROR "nil check" _ = x[9999] // ERROR "nil check"
} }
_ = x[9999] // ERROR "nil check" _ = x[9999] // ERROR "nil check"
x = fx10k() x = fx10k()
if b { if b {
_ = x[9999] // ERROR "nil check" _ = x[9999] // ERROR "nil check"
} else { } else {
_ = x[9999] // ERROR "nil check" _ = x[9999] // ERROR "nil check"
} }
_ = x[9999] // ERROR "nil check" _ = x[9999] // ERROR "nil check"
fx10k() fx10k()
// This one is a bit redundant, if we figured out that // This one is a bit redundant, if we figured out that
// x wasn't going to change across the function call. // x wasn't going to change across the function call.
...@@ -138,7 +139,7 @@ func f3b() { ...@@ -138,7 +139,7 @@ func f3b() {
_ = &x[9] // ERROR "nil check" _ = &x[9] // ERROR "nil check"
} }
func fx10() *[10]int func fx10() *[10]int
func f4(x *[10]int) { func f4(x *[10]int) {
// Most of these have no checks because a real memory reference follows, // Most of these have no checks because a real memory reference follows,
...@@ -146,33 +147,33 @@ func f4(x *[10]int) { ...@@ -146,33 +147,33 @@ func f4(x *[10]int) {
// in the first unmapped page of memory. // in the first unmapped page of memory.
_ = x[9] // ERROR "nil check" _ = x[9] // ERROR "nil check"
for { for {
if x[9] != 0 { // ERROR "nil check" if x[9] != 0 { // ERROR "nil check"
break break
} }
} }
x = fx10() x = fx10()
_ = x[9] // ERROR "nil check" _ = x[9] // ERROR "nil check"
if b { if b {
_ = x[9] // ERROR "nil check" _ = x[9] // ERROR "nil check"
} else { } else {
_ = x[9] // ERROR "nil check" _ = x[9] // ERROR "nil check"
} }
_ = x[9] // ERROR "nil check" _ = x[9] // ERROR "nil check"
x = fx10() x = fx10()
if b { if b {
_ = x[9] // ERROR "nil check" _ = x[9] // ERROR "nil check"
} else { } else {
_ = &x[9] // ERROR "nil check" _ = &x[9] // ERROR "nil check"
} }
_ = x[9] // ERROR "nil check" _ = x[9] // ERROR "nil check"
fx10() fx10()
_ = x[9] // ERROR "nil check" _ = x[9] // ERROR "nil check"
x = fx10() x = fx10()
y := fx10() y := fx10()
_ = &x[9] // ERROR "nil check" _ = &x[9] // ERROR "nil check"
......
// +build amd64
// errorcheck -0 -N -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 inserted.
// Optimization is disabled, so redundant checks are not removed.
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 "nil check"
_ = *arrayp // ERROR "nil check"
_ = *array0p // ERROR "nil check"
_ = *array0p // ERROR "nil check"
_ = *intp // ERROR "nil check"
_ = *arrayp // ERROR "nil check"
_ = *structp // ERROR "nil check"
_ = *emptyp // ERROR "nil check"
_ = *arrayp // ERROR "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 "nil check"
_ = *arrayp // ERROR "nil check"
_ = *array0p // ERROR "nil check"
_ = *array0p // ERROR "removed nil check"
_ = *intp // ERROR "removed nil check"
_ = *arrayp // ERROR "removed nil check"
_ = *structp // ERROR "nil check"
_ = *emptyp // ERROR "nil check"
_ = *arrayp // ERROR "removed nil check"
_ = *bigarrayp // ERROR "nil check"
_ = *bigstructp // ERROR "nil check"
_ = *empty1p // ERROR "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 "nil check"
for {
if x[9999] != 0 { // ERROR "removed nil check"
break
}
}
x = fx10k()
_ = x[9999] // ERROR "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 "nil check"
} else {
_ = x[9999] // ERROR "nil check"
}
_ = x[9999] // ERROR "nil check"
fx10k()
// SSA nilcheck removal works across calls.
_ = x[9999] // ERROR "removed nil check"
}
func f3a() {
x := fx10k()
y := fx10k()
z := fx10k()
_ = &x[9] // ERROR "nil check"
y = z
_ = &x[9] // ERROR "removed nil check"
x = y
_ = &x[9] // ERROR "nil check"
}
func f3b() {
x := fx10k()
y := fx10k()
_ = &x[9] // ERROR "nil check"
y = x
_ = &x[9] // ERROR "removed nil check"
x = y
_ = &x[9] // ERROR "removed 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 "nil check"
for {
if x[9] != 0 { // ERROR "removed nil check"
break
}
}
x = fx10()
_ = x[9] // ERROR "nil check"
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 "nil check"
} else {
_ = &x[9] // ERROR "nil check"
}
_ = x[9] // ERROR "nil check"
fx10()
_ = x[9] // ERROR "removed nil check"
x = fx10()
y := fx10()
_ = &x[9] // ERROR "nil check"
y = x
_ = &x[9] // ERROR "removed nil check"
x = y
_ = &x[9] // ERROR "removed nil check"
}
func f5(m map[string]struct{}) bool {
// Existence-only map lookups should not generate a nil check
_, ok := m[""]
return ok
}
// errorcheck -0 -d=nil // errorcheck -0 -d=nil
// Fails on ppc64x because of incomplete optimization. // Fails on ppc64x because of incomplete optimization.
// See issues 9058. // See issues 9058.
// +build !ppc64,!ppc64le // +build !ppc64,!ppc64le,!amd64
// Copyright 2013 The Go Authors. All rights reserved. // Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
......
// errorcheck -0 -d=nil
// Fails on ppc64x because of incomplete optimization.
// See issues 9058.
// +build !ppc64,!ppc64le,amd64
// 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 "generated 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 "generated nil check"
// 0-byte indirect doesn't suffice.
// we don't registerize globals, so there are no removed.* nil checks.
_ = *array0p // ERROR "generated nil check"
_ = *array0p // ERROR "removed nil check"
_ = *intp // ERROR "removed nil check"
_ = *arrayp // ERROR "removed nil check"
_ = *structp // ERROR "generated nil check"
_ = *emptyp // ERROR "generated nil check"
_ = *arrayp // ERROR "removed 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 "generated nil check"
_ = *arrayp // ERROR "generated nil check"
_ = *array0p // ERROR "generated nil check"
_ = *array0p // ERROR "removed.* nil check"
_ = *intp // ERROR "removed.* nil check"
_ = *arrayp // ERROR "removed.* nil check"
_ = *structp // ERROR "generated nil check"
_ = *emptyp // ERROR "generated nil check"
_ = *arrayp // ERROR "removed.* 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 "removed nil check"
}
func f3a() {
x := fx10k()
y := fx10k()
z := fx10k()
_ = &x[9] // ERROR "generated nil check"
y = z
_ = &x[9] // ERROR "removed.* nil check"
x = y
_ = &x[9] // ERROR "generated nil check"
}
func f3b() {
x := fx10k()
y := fx10k()
_ = &x[9] // ERROR "generated nil check"
y = x
_ = &x[9] // ERROR "removed.* nil check"
x = y
_ = &x[9] // ERROR "removed.* 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 before indirect
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 "removed nil check"
x = fx10()
y := fx10()
_ = &x[9] // ERROR "generated nil check"
y = x
_ = &x[9] // ERROR "removed[a-z ]* nil check"
x = y
_ = &x[9] // ERROR "removed[a-z ]* nil check"
}
...@@ -37,6 +37,7 @@ var ( ...@@ -37,6 +37,7 @@ var (
numParallel = flag.Int("n", runtime.NumCPU(), "number of parallel tests to run") numParallel = flag.Int("n", runtime.NumCPU(), "number of parallel tests to run")
summary = flag.Bool("summary", false, "show summary of results") summary = flag.Bool("summary", false, "show summary of results")
showSkips = flag.Bool("show_skips", false, "show skipped tests") showSkips = flag.Bool("show_skips", false, "show skipped tests")
runSkips = flag.Bool("run_skips", false, "run skipped tests (ignore skip and build tags)")
updateErrors = flag.Bool("update_errors", false, "update error messages in test file based on compiler output") updateErrors = flag.Bool("update_errors", false, "update error messages in test file based on compiler output")
runoutputLimit = flag.Int("l", defaultRunOutputLimit(), "number of parallel runoutput tests to run") runoutputLimit = flag.Int("l", defaultRunOutputLimit(), "number of parallel runoutput tests to run")
...@@ -328,6 +329,9 @@ type context struct { ...@@ -328,6 +329,9 @@ type context struct {
// shouldTest looks for build tags in a source file and returns // shouldTest looks for build tags in a source file and returns
// whether the file should be used according to the tags. // whether the file should be used according to the tags.
func shouldTest(src string, goos, goarch string) (ok bool, whyNot string) { func shouldTest(src string, goos, goarch string) (ok bool, whyNot string) {
if *runSkips {
return true, ""
}
for _, line := range strings.Split(src, "\n") { for _, line := range strings.Split(src, "\n") {
line = strings.TrimSpace(line) line = strings.TrimSpace(line)
if strings.HasPrefix(line, "//") { if strings.HasPrefix(line, "//") {
...@@ -470,6 +474,9 @@ func (t *test) run() { ...@@ -470,6 +474,9 @@ func (t *test) run() {
args = args[1:] args = args[1:]
} }
case "skip": case "skip":
if *runSkips {
break
}
t.action = "skip" t.action = "skip"
return return
default: default:
......
// +build !amd64
// errorcheck -0 -d=append,slice // errorcheck -0 -d=append,slice
// Copyright 2015 The Go Authors. All rights reserved. // Copyright 2015 The Go Authors. All rights reserved.
......
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