From: isharipo Date: Thu, 1 Feb 2018 17:37:23 +0000 (+0300) Subject: cmd/compile: make DCE remove nodes after terminating if X-Git-Tag: go1.11beta1~998 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=dcaf3fb134d5ca3b74a85b765c39aa5b632638cd;p=gostls13.git cmd/compile: make DCE remove nodes after terminating if This change makes compiler frontend dead code elimination of const expr if statements introduced in https://golang.org/cl/38773 treat both if constCondTrue { ...; returnStmt } toBeRemoved... if constCondFalse { ...; } else { returnStmt } toBeRemoved... identically to: if constCondTrue { ...; returnStmt } else { toBeRemoved... } Where "constCondTrue" is a an expression that can be evaluated to "true" during compile time. The additional checks are only triggered for const expr if conditions that evaluate to true. name old time/op new time/op delta Template 431ms ± 2% 429ms ± 1% ~ (p=0.491 n=8+6) Unicode 198ms ± 4% 201ms ± 2% ~ (p=0.234 n=7+6) GoTypes 1.40s ± 1% 1.41s ± 2% ~ (p=0.053 n=7+7) Compiler 6.72s ± 2% 6.81s ± 1% +1.35% (p=0.011 n=7+7) SSA 17.3s ± 1% 17.3s ± 2% ~ (p=0.731 n=6+7) Flate 275ms ± 2% 275ms ± 2% ~ (p=0.902 n=7+7) GoParser 340ms ± 2% 339ms ± 2% ~ (p=0.902 n=7+7) Reflect 910ms ± 2% 905ms ± 1% ~ (p=0.310 n=6+6) Tar 403ms ± 1% 403ms ± 2% ~ (p=0.366 n=7+6) XML 486ms ± 1% 490ms ± 1% ~ (p=0.065 n=6+6) StdCmd 56.2s ± 1% 56.6s ± 2% ~ (p=0.620 n=7+7) name old user-time/op new user-time/op delta Template 559ms ± 8% 557ms ± 7% ~ (p=0.713 n=8+7) Unicode 266ms ±13% 277ms ± 9% ~ (p=0.157 n=8+7) GoTypes 1.83s ± 2% 1.84s ± 1% ~ (p=0.522 n=8+7) Compiler 8.67s ± 4% 8.89s ± 4% ~ (p=0.077 n=7+7) SSA 23.9s ± 1% 24.2s ± 1% +1.31% (p=0.005 n=7+7) Flate 351ms ± 4% 342ms ± 5% ~ (p=0.105 n=7+7) GoParser 437ms ± 2% 423ms ± 5% -3.14% (p=0.016 n=7+7) Reflect 1.16s ± 3% 1.15s ± 2% ~ (p=0.362 n=7+7) Tar 517ms ± 4% 511ms ± 3% ~ (p=0.538 n=7+7) XML 619ms ± 3% 617ms ± 4% ~ (p=0.483 n=7+7) Fixes #23521 Change-Id: I165a7827d869aeb93ce6047d026ff873d039a4f3 Reviewed-on: https://go-review.googlesource.com/91056 Run-TryBot: Iskander Sharipov TryBot-Result: Gobot Gobot Reviewed-by: Josh Bleecher Snyder --- diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index 1bff3431a0..02cac2e86c 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -3926,24 +3926,45 @@ func deadcode(fn *Node) { } func deadcodeslice(nn Nodes) { - for _, n := range nn.Slice() { + for i, n := range nn.Slice() { + // Cut is set to true when all nodes after i'th position + // should be removed. + // In other words, it marks whole slice "tail" as dead. + cut := false if n == nil { continue } if n.Op == OIF { n.Left = deadcodeexpr(n.Left) if Isconst(n.Left, CTBOOL) { + var body Nodes if n.Left.Bool() { n.Rlist = Nodes{} + body = n.Nbody } else { n.Nbody = Nodes{} + body = n.Rlist + } + // If "then" or "else" branch ends with panic or return statement, + // it is safe to remove all statements after this node. + // isterminating is not used to avoid goto-related complications. + if body := body.Slice(); len(body) != 0 { + switch body[(len(body) - 1)].Op { + case ORETURN, ORETJMP, OPANIC: + cut = true + } } } } + deadcodeslice(n.Ninit) deadcodeslice(n.Nbody) deadcodeslice(n.List) deadcodeslice(n.Rlist) + if cut { + *nn.slice = nn.Slice()[:i+1] + break + } } } diff --git a/test/fixedbugs/issue23521.go b/test/fixedbugs/issue23521.go new file mode 100644 index 0000000000..159e03238c --- /dev/null +++ b/test/fixedbugs/issue23521.go @@ -0,0 +1,43 @@ +// errorcheck -0 -m + +// Copyright 2018 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. + +// Issue 23521: improve early DCE for if without explicit else. + +package p + +//go:noinline +func nonleaf() {} + +const truth = true + +func f() int { // ERROR "can inline f" + if truth { + return 0 + } + // If everything below is removed, as it should, + // function f should be inlineable. + nonleaf() + for { + panic("") + } +} + +func g() int { // ERROR "can inline g" + return f() // ERROR "inlining call to f" +} + +func f2() int { // ERROR "can inline f2" + if !truth { + nonleaf() + } else { + return 0 + } + panic("") +} + +func g2() int { // ERROR "can inline g2" + return f2() // ERROR "inlining call to f2" +}