]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: teach front-end deadcode about && and ||
authorAustin Clements <austin@google.com>
Fri, 23 Feb 2018 00:58:59 +0000 (19:58 -0500)
committerAustin Clements <austin@google.com>
Fri, 23 Feb 2018 21:59:49 +0000 (21:59 +0000)
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>
src/cmd/compile/internal/gc/inl.go
src/cmd/compile/internal/gc/typecheck.go

index c8296971cd3da008077fa2e46da2774a9948c67a..e2456eb96f789c49eb01831dadc0268d740832c0 100644 (file)
@@ -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--
index 7f1a702b35318147ad3187bba8ede056dabcda1a..75ecaa3d4159226c262e1cd887ff688e50a0f2d1 100644 (file)
@@ -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
+}