github.com/gocuntian/go@v0.0.0-20160610041250-fee02d270bf8/src/cmd/compile/internal/ssa/phiopt.go (about)

     1  // Copyright 2016 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 ssa
     6  
     7  // phiopt eliminates boolean Phis based on the previous if.
     8  //
     9  // Main use case is to transform:
    10  //   x := false
    11  //   if b {
    12  //     x = true
    13  //   }
    14  // into x = b.
    15  //
    16  // In SSA code this appears as
    17  //
    18  // b0
    19  //   If b -> b1 b2
    20  // b1
    21  //   Plain -> b2
    22  // b2
    23  //   x = (OpPhi (ConstBool [true]) (ConstBool [false]))
    24  //
    25  // In this case we can replace x with a copy of b.
    26  func phiopt(f *Func) {
    27  	for _, b := range f.Blocks {
    28  		if len(b.Preds) != 2 || len(b.Values) == 0 {
    29  			// TODO: handle more than 2 predecessors, e.g. a || b || c.
    30  			continue
    31  		}
    32  
    33  		pb0, b0 := b, b.Preds[0].b
    34  		for len(b0.Succs) == 1 && len(b0.Preds) == 1 {
    35  			pb0, b0 = b0, b0.Preds[0].b
    36  		}
    37  		if b0.Kind != BlockIf {
    38  			continue
    39  		}
    40  		pb1, b1 := b, b.Preds[1].b
    41  		for len(b1.Succs) == 1 && len(b1.Preds) == 1 {
    42  			pb1, b1 = b1, b1.Preds[0].b
    43  		}
    44  		if b1 != b0 {
    45  			continue
    46  		}
    47  		// b0 is the if block giving the boolean value.
    48  
    49  		// reverse is the predecessor from which the truth value comes.
    50  		var reverse int
    51  		if b0.Succs[0].b == pb0 && b0.Succs[1].b == pb1 {
    52  			reverse = 0
    53  		} else if b0.Succs[0].b == pb1 && b0.Succs[1].b == pb0 {
    54  			reverse = 1
    55  		} else {
    56  			b.Fatalf("invalid predecessors\n")
    57  		}
    58  
    59  		for _, v := range b.Values {
    60  			if v.Op != OpPhi || !v.Type.IsBoolean() {
    61  				continue
    62  			}
    63  
    64  			// Replaces
    65  			//   if a { x = true } else { x = false } with x = a
    66  			// and
    67  			//   if a { x = false } else { x = true } with x = !a
    68  			if v.Args[0].Op == OpConstBool && v.Args[1].Op == OpConstBool {
    69  				if v.Args[reverse].AuxInt != v.Args[1-reverse].AuxInt {
    70  					ops := [2]Op{OpNot, OpCopy}
    71  					v.reset(ops[v.Args[reverse].AuxInt])
    72  					v.AddArg(b0.Control)
    73  					if f.pass.debug > 0 {
    74  						f.Config.Warnl(b.Line, "converted OpPhi to %v", v.Op)
    75  					}
    76  					continue
    77  				}
    78  			}
    79  
    80  			// Replaces
    81  			//   if a { x = true } else { x = value } with x = a || value.
    82  			// Requires that value dominates x, meaning that regardless of a,
    83  			// value is always computed. This guarantees that the side effects
    84  			// of value are not seen if a is false.
    85  			if v.Args[reverse].Op == OpConstBool && v.Args[reverse].AuxInt == 1 {
    86  				if tmp := v.Args[1-reverse]; f.sdom.isAncestorEq(tmp.Block, b) {
    87  					v.reset(OpOrB)
    88  					v.SetArgs2(b0.Control, tmp)
    89  					if f.pass.debug > 0 {
    90  						f.Config.Warnl(b.Line, "converted OpPhi to %v", v.Op)
    91  					}
    92  					continue
    93  				}
    94  			}
    95  
    96  			// Replaces
    97  			//   if a { x = value } else { x = false } with x = a && value.
    98  			// Requires that value dominates x, meaning that regardless of a,
    99  			// value is always computed. This guarantees that the side effects
   100  			// of value are not seen if a is false.
   101  			if v.Args[1-reverse].Op == OpConstBool && v.Args[1-reverse].AuxInt == 0 {
   102  				if tmp := v.Args[reverse]; f.sdom.isAncestorEq(tmp.Block, b) {
   103  					v.reset(OpAndB)
   104  					v.SetArgs2(b0.Control, tmp)
   105  					if f.pass.debug > 0 {
   106  						f.Config.Warnl(b.Line, "converted OpPhi to %v", v.Op)
   107  					}
   108  					continue
   109  				}
   110  			}
   111  		}
   112  	}
   113  
   114  }