aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/deadcode/deadcode.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/compile/internal/deadcode/deadcode.go')
-rw-r--r--src/cmd/compile/internal/deadcode/deadcode.go247
1 files changed, 0 insertions, 247 deletions
diff --git a/src/cmd/compile/internal/deadcode/deadcode.go b/src/cmd/compile/internal/deadcode/deadcode.go
deleted file mode 100644
index 46a2239f48..0000000000
--- a/src/cmd/compile/internal/deadcode/deadcode.go
+++ /dev/null
@@ -1,247 +0,0 @@
-// Copyright 2009 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.
-
-package deadcode
-
-import (
- "go/constant"
- "go/token"
-
- "cmd/compile/internal/base"
- "cmd/compile/internal/ir"
-)
-
-func Func(fn *ir.Func) {
- stmts(&fn.Body)
-
- if len(fn.Body) == 0 {
- return
- }
-
- for _, n := range fn.Body {
- if len(n.Init()) > 0 {
- return
- }
- switch n.Op() {
- case ir.OIF:
- n := n.(*ir.IfStmt)
- if !ir.IsConst(n.Cond, constant.Bool) || len(n.Body) > 0 || len(n.Else) > 0 {
- return
- }
- case ir.OFOR:
- n := n.(*ir.ForStmt)
- if !ir.IsConst(n.Cond, constant.Bool) || ir.BoolVal(n.Cond) {
- return
- }
- default:
- return
- }
- }
-
- ir.VisitList(fn.Body, markHiddenClosureDead)
- fn.Body = []ir.Node{ir.NewBlockStmt(base.Pos, nil)}
-}
-
-func stmts(nn *ir.Nodes) {
- var lastLabel = -1
- for i, n := range *nn {
- if n != nil && n.Op() == ir.OLABEL {
- lastLabel = i
- }
- }
- for i, n := range *nn {
- // 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() == ir.OIF {
- n := n.(*ir.IfStmt)
- n.Cond = expr(n.Cond)
- if ir.IsConst(n.Cond, constant.Bool) {
- var body ir.Nodes
- if ir.BoolVal(n.Cond) {
- ir.VisitList(n.Else, markHiddenClosureDead)
- n.Else = ir.Nodes{}
- body = n.Body
- } else {
- ir.VisitList(n.Body, markHiddenClosureDead)
- n.Body = ir.Nodes{}
- body = n.Else
- }
- // 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.
- // We must be careful not to deadcode-remove labels, as they
- // might be the target of a goto. See issue 28616.
- if body := body; len(body) != 0 {
- switch body[(len(body) - 1)].Op() {
- case ir.ORETURN, ir.OTAILCALL, ir.OPANIC:
- if i > lastLabel {
- cut = true
- }
- }
- }
- }
- }
- if n.Op() == ir.OSWITCH {
- n := n.(*ir.SwitchStmt)
- // Use a closure wrapper here so we can use "return" to abort the analysis.
- func() {
- if n.Tag != nil && n.Tag.Op() == ir.OTYPESW {
- return // no special type-switch case yet.
- }
- var x constant.Value // value we're switching on
- if n.Tag != nil {
- if ir.ConstType(n.Tag) == constant.Unknown {
- return
- }
- x = n.Tag.Val()
- } else {
- x = constant.MakeBool(true) // switch { ... } => switch true { ... }
- }
- var def *ir.CaseClause
- for _, cas := range n.Cases {
- if len(cas.List) == 0 { // default case
- def = cas
- continue
- }
- for _, c := range cas.List {
- if ir.ConstType(c) == constant.Unknown {
- return // can't statically tell if it matches or not - give up.
- }
- if constant.Compare(x, token.EQL, c.Val()) {
- for _, n := range cas.Body {
- if n.Op() == ir.OFALL {
- return // fallthrough makes it complicated - abort.
- }
- }
- // This switch entry is the one that always triggers.
- for _, cas2 := range n.Cases {
- for _, c2 := range cas2.List {
- ir.Visit(c2, markHiddenClosureDead)
- }
- if cas2 != cas {
- ir.VisitList(cas2.Body, markHiddenClosureDead)
- }
- }
-
- // Rewrite to switch { case true: ... }
- n.Tag = nil
- cas.List[0] = ir.NewBool(c.Pos(), true)
- cas.List = cas.List[:1]
- n.Cases[0] = cas
- n.Cases = n.Cases[:1]
- return
- }
- }
- }
- if def != nil {
- for _, n := range def.Body {
- if n.Op() == ir.OFALL {
- return // fallthrough makes it complicated - abort.
- }
- }
- for _, cas := range n.Cases {
- if cas != def {
- ir.VisitList(cas.List, markHiddenClosureDead)
- ir.VisitList(cas.Body, markHiddenClosureDead)
- }
- }
- n.Cases[0] = def
- n.Cases = n.Cases[:1]
- return
- }
-
- // TODO: handle case bodies ending with panic/return as we do in the IF case above.
-
- // entire switch is a nop - no case ever triggers
- for _, cas := range n.Cases {
- ir.VisitList(cas.List, markHiddenClosureDead)
- ir.VisitList(cas.Body, markHiddenClosureDead)
- }
- n.Cases = n.Cases[:0]
- }()
- }
-
- if len(n.Init()) != 0 {
- stmts(n.(ir.InitNode).PtrInit())
- }
- switch n.Op() {
- case ir.OBLOCK:
- n := n.(*ir.BlockStmt)
- stmts(&n.List)
- case ir.OFOR:
- n := n.(*ir.ForStmt)
- stmts(&n.Body)
- case ir.OIF:
- n := n.(*ir.IfStmt)
- stmts(&n.Body)
- stmts(&n.Else)
- case ir.ORANGE:
- n := n.(*ir.RangeStmt)
- stmts(&n.Body)
- case ir.OSELECT:
- n := n.(*ir.SelectStmt)
- for _, cas := range n.Cases {
- stmts(&cas.Body)
- }
- case ir.OSWITCH:
- n := n.(*ir.SwitchStmt)
- for _, cas := range n.Cases {
- stmts(&cas.Body)
- }
- }
-
- if cut {
- ir.VisitList((*nn)[i+1:len(*nn)], markHiddenClosureDead)
- *nn = (*nn)[:i+1]
- break
- }
- }
-}
-
-func expr(n ir.Node) ir.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 ir.OANDAND:
- n := n.(*ir.LogicalExpr)
- n.X = expr(n.X)
- n.Y = expr(n.Y)
- if ir.IsConst(n.X, constant.Bool) {
- if ir.BoolVal(n.X) {
- return n.Y // true && x => x
- } else {
- return n.X // false && x => false
- }
- }
- case ir.OOROR:
- n := n.(*ir.LogicalExpr)
- n.X = expr(n.X)
- n.Y = expr(n.Y)
- if ir.IsConst(n.X, constant.Bool) {
- if ir.BoolVal(n.X) {
- return n.X // true || x => true
- } else {
- return n.Y // false || x => x
- }
- }
- }
- return n
-}
-
-func markHiddenClosureDead(n ir.Node) {
- if n.Op() != ir.OCLOSURE {
- return
- }
- clo := n.(*ir.ClosureExpr)
- if clo.Func.IsHiddenClosure() {
- clo.Func.SetIsDeadcodeClosure(true)
- }
- ir.VisitList(clo.Func.Body, markHiddenClosureDead)
-}