github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/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  			continue
    30  		}
    31  
    32  		pb0, b0 := b, b.Preds[0]
    33  		for len(b0.Succs) == 1 && len(b0.Preds) == 1 {
    34  			pb0, b0 = b0, b0.Preds[0]
    35  		}
    36  		if b0.Kind != BlockIf {
    37  			continue
    38  		}
    39  		pb1, b1 := b, b.Preds[1]
    40  		for len(b1.Succs) == 1 && len(b1.Preds) == 1 {
    41  			pb1, b1 = b1, b1.Preds[0]
    42  		}
    43  		if b1 != b0 {
    44  			continue
    45  		}
    46  		// b0 is the if block giving the boolean value.
    47  
    48  		var reverse bool
    49  		if b0.Succs[0] == pb0 && b0.Succs[1] == pb1 {
    50  			reverse = false
    51  		} else if b0.Succs[0] == pb1 && b0.Succs[1] == pb0 {
    52  			reverse = true
    53  		} else {
    54  			b.Fatalf("invalid predecessors\n")
    55  		}
    56  
    57  		for _, v := range b.Values {
    58  			if v.Op != OpPhi || !v.Type.IsBoolean() || v.Args[0].Op != OpConstBool || v.Args[1].Op != OpConstBool {
    59  				continue
    60  			}
    61  
    62  			ok, isCopy := false, false
    63  			if v.Args[0].AuxInt == 1 && v.Args[1].AuxInt == 0 {
    64  				ok, isCopy = true, !reverse
    65  			} else if v.Args[0].AuxInt == 0 && v.Args[1].AuxInt == 1 {
    66  				ok, isCopy = true, reverse
    67  			}
    68  
    69  			// (Phi (ConstBool [x]) (ConstBool [x])) is already handled by opt / phielim.
    70  
    71  			if ok && isCopy {
    72  				if f.pass.debug > 0 {
    73  					f.Config.Warnl(b.Line, "converted OpPhi to OpCopy")
    74  				}
    75  				v.reset(OpCopy)
    76  				v.AddArg(b0.Control)
    77  				continue
    78  			}
    79  			if ok && !isCopy {
    80  				if f.pass.debug > 0 {
    81  					f.Config.Warnl(b.Line, "converted OpPhi to OpNot")
    82  				}
    83  				v.reset(OpNot)
    84  				v.AddArg(b0.Control)
    85  				continue
    86  			}
    87  		}
    88  	}
    89  
    90  }