diff options
Diffstat (limited to 'src/cmd/compile/internal/deadcode/deadcode.go')
| -rw-r--r-- | src/cmd/compile/internal/deadcode/deadcode.go | 247 |
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) -} |
