Source file src/cmd/compile/internal/deadcode/deadcode.go

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package deadcode
     6  
     7  import (
     8  	"go/constant"
     9  
    10  	"cmd/compile/internal/base"
    11  	"cmd/compile/internal/ir"
    12  )
    13  
    14  func Func(fn *ir.Func) {
    15  	stmts(&fn.Body)
    16  
    17  	if len(fn.Body) == 0 {
    18  		return
    19  	}
    20  
    21  	for _, n := range fn.Body {
    22  		if len(n.Init()) > 0 {
    23  			return
    24  		}
    25  		switch n.Op() {
    26  		case ir.OIF:
    27  			n := n.(*ir.IfStmt)
    28  			if !ir.IsConst(n.Cond, constant.Bool) || len(n.Body) > 0 || len(n.Else) > 0 {
    29  				return
    30  			}
    31  		case ir.OFOR:
    32  			n := n.(*ir.ForStmt)
    33  			if !ir.IsConst(n.Cond, constant.Bool) || ir.BoolVal(n.Cond) {
    34  				return
    35  			}
    36  		default:
    37  			return
    38  		}
    39  	}
    40  
    41  	ir.VisitList(fn.Body, markHiddenClosureDead)
    42  	fn.Body = []ir.Node{ir.NewBlockStmt(base.Pos, nil)}
    43  }
    44  
    45  func stmts(nn *ir.Nodes) {
    46  	var lastLabel = -1
    47  	for i, n := range *nn {
    48  		if n != nil && n.Op() == ir.OLABEL {
    49  			lastLabel = i
    50  		}
    51  	}
    52  	for i, n := range *nn {
    53  		// Cut is set to true when all nodes after i'th position
    54  		// should be removed.
    55  		// In other words, it marks whole slice "tail" as dead.
    56  		cut := false
    57  		if n == nil {
    58  			continue
    59  		}
    60  		if n.Op() == ir.OIF {
    61  			n := n.(*ir.IfStmt)
    62  			n.Cond = expr(n.Cond)
    63  			if ir.IsConst(n.Cond, constant.Bool) {
    64  				var body ir.Nodes
    65  				if ir.BoolVal(n.Cond) {
    66  					ir.VisitList(n.Else, markHiddenClosureDead)
    67  					n.Else = ir.Nodes{}
    68  					body = n.Body
    69  				} else {
    70  					ir.VisitList(n.Body, markHiddenClosureDead)
    71  					n.Body = ir.Nodes{}
    72  					body = n.Else
    73  				}
    74  				// If "then" or "else" branch ends with panic or return statement,
    75  				// it is safe to remove all statements after this node.
    76  				// isterminating is not used to avoid goto-related complications.
    77  				// We must be careful not to deadcode-remove labels, as they
    78  				// might be the target of a goto. See issue 28616.
    79  				if body := body; len(body) != 0 {
    80  					switch body[(len(body) - 1)].Op() {
    81  					case ir.ORETURN, ir.OTAILCALL, ir.OPANIC:
    82  						if i > lastLabel {
    83  							cut = true
    84  						}
    85  					}
    86  				}
    87  			}
    88  		}
    89  
    90  		if len(n.Init()) != 0 {
    91  			stmts(n.(ir.InitNode).PtrInit())
    92  		}
    93  		switch n.Op() {
    94  		case ir.OBLOCK:
    95  			n := n.(*ir.BlockStmt)
    96  			stmts(&n.List)
    97  		case ir.OFOR:
    98  			n := n.(*ir.ForStmt)
    99  			stmts(&n.Body)
   100  		case ir.OIF:
   101  			n := n.(*ir.IfStmt)
   102  			stmts(&n.Body)
   103  			stmts(&n.Else)
   104  		case ir.ORANGE:
   105  			n := n.(*ir.RangeStmt)
   106  			stmts(&n.Body)
   107  		case ir.OSELECT:
   108  			n := n.(*ir.SelectStmt)
   109  			for _, cas := range n.Cases {
   110  				stmts(&cas.Body)
   111  			}
   112  		case ir.OSWITCH:
   113  			n := n.(*ir.SwitchStmt)
   114  			for _, cas := range n.Cases {
   115  				stmts(&cas.Body)
   116  			}
   117  		}
   118  
   119  		if cut {
   120  			ir.VisitList((*nn)[i+1:len(*nn)], markHiddenClosureDead)
   121  			*nn = (*nn)[:i+1]
   122  			break
   123  		}
   124  	}
   125  }
   126  
   127  func expr(n ir.Node) ir.Node {
   128  	// Perform dead-code elimination on short-circuited boolean
   129  	// expressions involving constants with the intent of
   130  	// producing a constant 'if' condition.
   131  	switch n.Op() {
   132  	case ir.OANDAND:
   133  		n := n.(*ir.LogicalExpr)
   134  		n.X = expr(n.X)
   135  		n.Y = expr(n.Y)
   136  		if ir.IsConst(n.X, constant.Bool) {
   137  			if ir.BoolVal(n.X) {
   138  				return n.Y // true && x => x
   139  			} else {
   140  				return n.X // false && x => false
   141  			}
   142  		}
   143  	case ir.OOROR:
   144  		n := n.(*ir.LogicalExpr)
   145  		n.X = expr(n.X)
   146  		n.Y = expr(n.Y)
   147  		if ir.IsConst(n.X, constant.Bool) {
   148  			if ir.BoolVal(n.X) {
   149  				return n.X // true || x => true
   150  			} else {
   151  				return n.Y // false || x => x
   152  			}
   153  		}
   154  	}
   155  	return n
   156  }
   157  
   158  func markHiddenClosureDead(n ir.Node) {
   159  	if n.Op() != ir.OCLOSURE {
   160  		return
   161  	}
   162  	clo := n.(*ir.ClosureExpr)
   163  	if clo.Func.IsHiddenClosure() {
   164  		clo.Func.SetIsDeadcodeClosure(true)
   165  	}
   166  	ir.VisitList(clo.Func.Body, markHiddenClosureDead)
   167  }
   168  

View as plain text