aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAustin Clements <austin@google.com>2018-02-22 19:58:59 -0500
committerAustin Clements <austin@google.com>2018-02-23 21:59:49 +0000
commit2dbf15e88ea33c04ccc1d0762b2cfcb3bfd8a039 (patch)
tree03c1ae444900adab0a0c844a1d2fde1158e5efe3 /src
parent33b76920ec3bde98e58e0a6cb0816eb7be28bb4e (diff)
downloadgo-2dbf15e88ea33c04ccc1d0762b2cfcb3bfd8a039.tar.xz
cmd/compile: teach front-end deadcode about && and ||
The front-end dead code elimination is very simple. Currently, it just looks for if statements with constant boolean conditions. Its main purpose is to reduce load on the compiler and shrink code before inlining computes hairiness. This CL teaches front-end dead code elimination about short-circuiting boolean expressions && and ||, since they're essentially the same as if statements. This also teaches the inliner that the constant 'if' form left behind by deadcode is free. These changes will help with runtime modifications in the next CL that would otherwise inhibit inlining in some hot code paths. Currently, however, they have no significant impact on benchmarks. Change-Id: I886203b3c4acdbfef08148fddd7f3a7af5afc7c1 Reviewed-on: https://go-review.googlesource.com/96778 Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Diffstat (limited to 'src')
-rw-r--r--src/cmd/compile/internal/gc/inl.go6
-rw-r--r--src/cmd/compile/internal/gc/typecheck.go42
2 files changed, 43 insertions, 5 deletions
diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go
index c8296971cd..e2456eb96f 100644
--- a/src/cmd/compile/internal/gc/inl.go
+++ b/src/cmd/compile/internal/gc/inl.go
@@ -344,6 +344,12 @@ func (v *hairyVisitor) visit(n *Node) bool {
case ODCLCONST, OEMPTY, OFALL, OLABEL:
// These nodes don't produce code; omit from inlining budget.
return false
+
+ case OIF:
+ if Isconst(n.Left, CTBOOL) {
+ // This if and the condition cost nothing.
+ return v.visitList(n.Nbody) || v.visitList(n.Rlist)
+ }
}
v.budget--
diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go
index 7f1a702b35..75ecaa3d41 100644
--- a/src/cmd/compile/internal/gc/typecheck.go
+++ b/src/cmd/compile/internal/gc/typecheck.go
@@ -3919,11 +3919,14 @@ func deadcodeslice(nn Nodes) {
if n == nil {
continue
}
- if n.Op == OIF && Isconst(n.Left, CTBOOL) {
- if n.Left.Bool() {
- n.Rlist = Nodes{}
- } else {
- n.Nbody = Nodes{}
+ if n.Op == OIF {
+ n.Left = deadcodeexpr(n.Left)
+ if Isconst(n.Left, CTBOOL) {
+ if n.Left.Bool() {
+ n.Rlist = Nodes{}
+ } else {
+ n.Nbody = Nodes{}
+ }
}
}
deadcodeslice(n.Ninit)
@@ -3932,3 +3935,32 @@ func deadcodeslice(nn Nodes) {
deadcodeslice(n.Rlist)
}
}
+
+func deadcodeexpr(n *Node) *Node {
+ // Perform dead-code elimination on short-circuited boolean
+ // expressions involving constants with the intent of
+ // producing a constant 'if' condition.
+ switch n.Op {
+ case OANDAND:
+ n.Left = deadcodeexpr(n.Left)
+ n.Right = deadcodeexpr(n.Right)
+ if Isconst(n.Left, CTBOOL) {
+ if n.Left.Bool() {
+ return n.Right // true && x => x
+ } else {
+ return n.Left // false && x => false
+ }
+ }
+ case OOROR:
+ n.Left = deadcodeexpr(n.Left)
+ n.Right = deadcodeexpr(n.Right)
+ if Isconst(n.Left, CTBOOL) {
+ if n.Left.Bool() {
+ return n.Left // true || x => true
+ } else {
+ return n.Right // false || x => x
+ }
+ }
+ }
+ return n
+}