Keith Randall | d8a6567 | 2016-01-25 09:21:17 -0800 | [diff] [blame] | 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 | // Shortcircuit finds situations where branch directions |
| 8 | // are always correlated and rewrites the CFG to take |
| 9 | // advantage of that fact. |
| 10 | // This optimization is useful for compiling && and || expressions. |
| 11 | func shortcircuit(f *Func) { |
| 12 | // Step 1: Replace a phi arg with a constant if that arg |
| 13 | // is the control value of a preceding If block. |
| 14 | // b1: |
| 15 | // If a goto b2 else b3 |
| 16 | // b2: <- b1 ... |
| 17 | // x = phi(a, ...) |
| 18 | // |
| 19 | // We can replace the "a" in the phi with the constant true. |
Robert Griesemer | cfd17f5 | 2016-12-07 18:14:35 -0800 | [diff] [blame^] | 20 | ct := f.ConstBool(f.Entry.Pos, f.Config.fe.TypeBool(), true) |
| 21 | cf := f.ConstBool(f.Entry.Pos, f.Config.fe.TypeBool(), false) |
Keith Randall | d8a6567 | 2016-01-25 09:21:17 -0800 | [diff] [blame] | 22 | for _, b := range f.Blocks { |
| 23 | for _, v := range b.Values { |
| 24 | if v.Op != OpPhi { |
| 25 | continue |
| 26 | } |
| 27 | if !v.Type.IsBoolean() { |
| 28 | continue |
| 29 | } |
| 30 | for i, a := range v.Args { |
Keith Randall | 4fa0500 | 2016-04-28 16:52:47 -0700 | [diff] [blame] | 31 | e := b.Preds[i] |
| 32 | p := e.b |
Keith Randall | d8a6567 | 2016-01-25 09:21:17 -0800 | [diff] [blame] | 33 | if p.Kind != BlockIf { |
| 34 | continue |
| 35 | } |
| 36 | if p.Control != a { |
| 37 | continue |
| 38 | } |
Keith Randall | 4fa0500 | 2016-04-28 16:52:47 -0700 | [diff] [blame] | 39 | if e.i == 0 { |
Keith Randall | 56e0ecc | 2016-03-15 20:45:50 -0700 | [diff] [blame] | 40 | v.SetArg(i, ct) |
Keith Randall | d8a6567 | 2016-01-25 09:21:17 -0800 | [diff] [blame] | 41 | } else { |
Keith Randall | 56e0ecc | 2016-03-15 20:45:50 -0700 | [diff] [blame] | 42 | v.SetArg(i, cf) |
Keith Randall | d8a6567 | 2016-01-25 09:21:17 -0800 | [diff] [blame] | 43 | } |
| 44 | } |
| 45 | } |
| 46 | } |
| 47 | |
| 48 | // Step 2: Compute which values are live across blocks. |
| 49 | live := make([]bool, f.NumValues()) |
| 50 | for _, b := range f.Blocks { |
| 51 | for _, v := range b.Values { |
| 52 | for _, a := range v.Args { |
| 53 | if a.Block != v.Block { |
| 54 | live[a.ID] = true |
| 55 | } |
| 56 | } |
| 57 | } |
| 58 | if b.Control != nil && b.Control.Block != b { |
| 59 | live[b.Control.ID] = true |
| 60 | } |
| 61 | } |
| 62 | |
| 63 | // Step 3: Redirect control flow around known branches. |
| 64 | // p: |
| 65 | // ... goto b ... |
| 66 | // b: <- p ... |
| 67 | // v = phi(true, ...) |
| 68 | // if v goto t else u |
| 69 | // We can redirect p to go directly to t instead of b. |
| 70 | // (If v is not live after b). |
| 71 | for _, b := range f.Blocks { |
| 72 | if b.Kind != BlockIf { |
| 73 | continue |
| 74 | } |
| 75 | if len(b.Values) != 1 { |
| 76 | continue |
| 77 | } |
| 78 | v := b.Values[0] |
| 79 | if v.Op != OpPhi { |
| 80 | continue |
| 81 | } |
| 82 | if b.Control != v { |
| 83 | continue |
| 84 | } |
| 85 | if live[v.ID] { |
| 86 | continue |
| 87 | } |
| 88 | for i := 0; i < len(v.Args); i++ { |
| 89 | a := v.Args[i] |
| 90 | if a.Op != OpConstBool { |
| 91 | continue |
| 92 | } |
| 93 | |
| 94 | // The predecessor we come in from. |
Keith Randall | 4fa0500 | 2016-04-28 16:52:47 -0700 | [diff] [blame] | 95 | e1 := b.Preds[i] |
| 96 | p := e1.b |
| 97 | pi := e1.i |
| 98 | |
Keith Randall | d8a6567 | 2016-01-25 09:21:17 -0800 | [diff] [blame] | 99 | // The successor we always go to when coming in |
| 100 | // from that predecessor. |
Keith Randall | 4fa0500 | 2016-04-28 16:52:47 -0700 | [diff] [blame] | 101 | e2 := b.Succs[1-a.AuxInt] |
| 102 | t := e2.b |
| 103 | ti := e2.i |
Keith Randall | d8a6567 | 2016-01-25 09:21:17 -0800 | [diff] [blame] | 104 | |
Keith Randall | 4fa0500 | 2016-04-28 16:52:47 -0700 | [diff] [blame] | 105 | // Remove b's incoming edge from p. |
| 106 | b.removePred(i) |
| 107 | n := len(b.Preds) |
Keith Randall | 56e0ecc | 2016-03-15 20:45:50 -0700 | [diff] [blame] | 108 | v.Args[i].Uses-- |
Keith Randall | d8a6567 | 2016-01-25 09:21:17 -0800 | [diff] [blame] | 109 | v.Args[i] = v.Args[n] |
| 110 | v.Args[n] = nil |
| 111 | v.Args = v.Args[:n] |
Keith Randall | 4fa0500 | 2016-04-28 16:52:47 -0700 | [diff] [blame] | 112 | |
| 113 | // Redirect p's outgoing edge to t. |
| 114 | p.Succs[pi] = Edge{t, len(t.Preds)} |
| 115 | |
| 116 | // Fix up t to have one more predecessor. |
| 117 | t.Preds = append(t.Preds, Edge{p, pi}) |
| 118 | for _, w := range t.Values { |
| 119 | if w.Op != OpPhi { |
| 120 | continue |
| 121 | } |
| 122 | w.AddArg(w.Args[ti]) |
| 123 | } |
| 124 | |
| 125 | if len(b.Preds) == 1 { |
Keith Randall | d8a6567 | 2016-01-25 09:21:17 -0800 | [diff] [blame] | 126 | v.Op = OpCopy |
| 127 | // No longer a phi, stop optimizing here. |
| 128 | break |
| 129 | } |
| 130 | i-- |
| 131 | } |
| 132 | } |
| 133 | } |