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 }