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 }